Make a 3var interpreter!

24

3

3var is a variant of deadfish which uses three variables called A, B and R. A and B are accumulators, while R is used as a result variable.

In this challenge, you need to make an interpreter for a stripped-down version of this language.

Required Commands:

i   Increments A
d   Decrements A
s   Squares A
p   Prints A
P   Prints the ASCII character of A
>   Sets A to R
a   Increments B
k   Decrements B
m   Squares B
o   Prints B
O   Prints the ASCII character of B
<   Sets B to R
+   Adds A and B, stores in R
-   Subtracts B from A, stores in R
*   Multiplies A and B, stores in R
/   Divides A by B, stores in R
w   Prints R
@   Resets A to 0
#   Resets B to 0
e   Resets R to 0

Everything else (including whitespaces) is ignored.

Clarifications

  • o and p should output without anything after it.
  • Division is integer division.
  • Numbers above 255 and numbers below 0 are supported.
  • 'w' should output a space or a newline after R
  • Division by 0 halts without errors. (No output to STDERR)
  • A, B and R are initially 0

Rules

  • This is so the shortest answer wins.
  • In the event of a tie, the oldest answer wins.
  • The file will be provided through command line arguments or STDIN.
  • Any language is allowed.
  • Eval is allowed.

Test Cases

Hello world! (taken from Esolangs)

iisssaa/>e
maa->e#
aamam->e#
dddddddddddddddddddddddddPiiiiiiiiiiiiiiiiiiiiiiiii
iiiiPiiiiiiiPPiiiP
@#e
iis
aamaaaa
*>P
@#e
iisssaa/>e
maa->e#
aamam->e#
iiiiiiiiiiiiiiiiiiiiiiP
ddddddddP
iiiP
ddddddP
ddddddddP
@#e
iiss
aa*>
iP

Outputs 20spooky22me:

iipois+iis<-<aaaO<OkOOkkkkOP@#iippisa+<m+>PaO

Outputs 9P-1420 100 3Q-1 162 0:

iiispsdPkokmo/w<+w#aaaommO-w@ii*wew

Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=63008,OVERRIDE_USER=45220;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

DJgamer98

Posted 2015-11-05T13:16:48.803

Reputation: 594

Should the output of o be followed by a newline? – LegionMammal978 – 2015-11-05T13:20:21.530

@LegionMammal978 No, it outputs the ascii value stored in B as a number. – DJgamer98 – 2015-11-05T13:21:37.100

That would be O. – LegionMammal978 – 2015-11-05T13:22:36.777

@LegionMammal978 Yeah, sorry. o prints it as a number, O prints it as a character. – DJgamer98 – 2015-11-05T13:23:25.660

1@Sp3000 Speaking of it, I recently helped fix a nested loop bug in the interpreter. – LegionMammal978 – 2015-11-05T13:33:34.980

2Additional clarifications for people familiar with Deadfish: dddddp results in -5 and iiiissp results in 256 as you'd expect, rather than 0. – Sp3000 – 2015-11-05T13:35:04.200

1In the test Case What dose r do? its not included on your list of valid commands – JimmyJazzx – 2015-11-05T14:17:01.967

I have an answer but fail with your example using r command – edc65 – 2015-11-05T14:17:58.990

@Sp3000 Thanks for the extra test case – DJgamer98 – 2015-11-05T15:35:42.253

@edc65 Sp3000 edited the test case so it should work now. – DJgamer98 – 2015-11-05T15:36:00.880

1@JimmyJazzx The testcase is now edited, but in the full 3var language r resets everything. It's the same as @#e. – DJgamer98 – 2015-11-05T15:36:44.047

Added clarifications to the post. – DJgamer98 – 2015-11-05T15:44:14.520

@DJgamer98 Deleted my comments - would you mind adding another test case: iiispsdPkokmo/w<+w#aaaommO-w@ii*wew? I also see you added that division by 0 halts without errors - does this mean no output to STDERR, exit code 0 or...? – Sp3000 – 2015-11-05T15:48:53.010

@Sp3000 No output to STDERR. – DJgamer98 – 2015-11-05T15:51:50.260

(er... test case means posting the expected output/s along with it) – Sp3000 – 2015-11-05T15:56:40.603

@Sp3000 Whoops. I'm currently on mobile, i'll post it when i get home – DJgamer98 – 2015-11-05T16:09:28.673

Prints A I assume this means print the numerical value of A, right? – Digital Trauma – 2015-11-05T16:27:46.083

@Digital Trauma 1. Prints A means Print the numerical value of A. 2. It's the same thing. I'll edit the post. – DJgamer98 – 2015-11-05T16:31:55.363

You should add test cases for the clarifications – aditsu quit because SE is EVIL – 2015-11-06T00:30:59.350

1Are A, B, and R initialized to 0 when the interpreter starts? – Tony Ennis – 2015-11-06T08:33:00.003

@TonyEnnis Yes. – DJgamer98 – 2015-11-06T08:41:56.840

It's too bad this language doesn't seem to have any means of accepting input - then you could write a 3var interpreter IN 3var. (Probably wouldn't be very golfable, but would still be impressive...) – Darrel Hoffman – 2015-11-06T15:29:15.987

@DarrelHoffman The full language has input.

– DJgamer98 – 2015-11-06T15:31:20.860

Which numbers are "about 255"? – Bakuriu – 2015-11-07T21:18:17.847

@Bakuriu It should have said "above". Edited the post. – DJgamer98 – 2015-11-08T12:30:08.813

Answers

7

CJam, 112

q{"+-*/dspP>@ikmoO<#awe"_@#\4<"X2 U|{TU :V;}P?"S/f*'T"( _*T cT;V;0)"2/f+":T;"f+_'Tf/'Uf*+"VS 0:V; "S/++=~}%Pa/0=

Try it online

Explanation:

The program builds an array of pieces of code to be executed, and executes the corresponding piece for each character. Dealing with the division by zero is more difficult, because CJam doesn't yet have a "break" operator. Instead, the program pushes π as a marker (since no floating point number can appear otherwise), and at the end it keeps only the output before the first π.
Also, the program uses variables T, U and V instead of A, B and R, because they are preinitialized with 0 in CJam.

q            read the input
{…}%         transform each character
  "…"        push a string with all the 3var commands, in a convenient order
  _@         duplicate the string and bring the current character to the top
  #          find the index of the character in the string (or -1 if not found)
  \          swap with the other string copy
  4<         keep only the first 4 characters ("+-*/")
  "…"        push a string that will be used for implementing those operators
  S/         split by space into ["X2" "U|{TU" ":V;}P?"]
  f*         join with each of '+', '-', '*', '/' -> 4 strings
  'T         push the 'T' character
  "…"        push a string with implementations of commands involving A
  2/         split into pieces of length 2
  f+         prepend 'T' to each piece
  ":T;"f+    append ":T;"to each piece
  _          duplicate the array (containing full A-command implementations)
  'Tf/       split each piece by the 'T' character
  'Uf*       join each split piece using the 'U' character
              practically replacing 'T' with 'U'
              to obtain B-command implementations
  +          concatenate the 2 arrays
  "…"        push a string containing implementations for "w" and "e", 
              separated by space; the string also ends with a space
  S/         split by space, obtaining the implementations for "w" and "e"
              and an empty string, for handling unrecognized characters
  ++         concatenate with the A and B command and +-*/ implementations
  =          get the corresponding string implementing the current command
              if the character was not found, -1 will get the empty string (no-op)
  ~          execute it
Pa/          split the array of results by the π separator
0=           get the first piece (before the first π, if any)

The actual command implementations (constructed by the program):

+: X2+U|{TU+:V;}P?    if (1+2)|U != 0, set V=T+U, else push π
-: X2-U|{TU-:V;}P?    if (1-2)|U != 0, set V=T-U, else push π
*: X2*U|{TU*:V;}P?    if (1*2)|U != 0, set V=T*U, else push π
/: X2/U|{TU/:V;}P?    if (1/2)|U != 0, set V=T/U, else push π
d: T( :T;             set T=T-1
s: T_*:T;             set T=T*T
p: TT :T;             push T and set T=T (no-op)
P: TcT:T;             push T converted to character and set T=T (no-op)
>: T;V:T;             push and pop T (no-op) and set T=V
@: T;0:T;             push and pop T (no-op) and set T=0
i: T):T;              set T=T+1
k: U( :U;             set U=U-1
m: U_*:U;             set U=U*U
o: UU :U;             push U and set U=U (no-op)
O: UcU:U;             push U converted to character and set U=U (no-op)
<: U;V:U;             push and pop U (no-op) and set U=V
#: U;0:U;             push and pop U (no-op) and set U=0
a: U):U;              set U=U+1
w: VS                 push V and a space
e: 0:V;               set V=0
(default): (empty)    no-op

aditsu quit because SE is EVIL

Posted 2015-11-05T13:16:48.803

Reputation: 22 326

10

JavaScript (ES7) 208 213 223 237 241 311

Edit3 Copying each other, I and Dendrobium are collapsing together.

Edit2 Using EcmaScript 7 to save just 2 bytes, joined together handling of A and B

Edit Following the changes of the rules.

Note, I added the r command that is not required in the question, just to run the old example Hello world

V=p=>(o='',[for(c of'@#e'+p)eval('++x,--x,x*=x,x=R,x=0,o+=x,o+=String.fromCharCode(x),R=A+B,R=A-B,R=A*B,R=A/B|0,R=0,o+=R+` `'.replace(/x/g,(k='ids>@pP+-*/ewakm<#oO'.indexOf(c))<13?'A':'B').split`,`[k%13])],o)

// More readable
U=p=>(
  o='',
  [for(c of'@#e'+p)
   eval(
   '++x,--x,x*=x,x=R,x=0,o+=x,o+=String.fromCharCode(x),R=A+B,R=A-B,R=A*B,R=A/B|0,R=0,o+=R+` `'
   .replace(/x/g,(k='ids>@pP+-*/ewakm<#oO'.indexOf(c))<13?'A':'B')
   .split`,`[k%13])]
  ,o
)

// ES6, no array comprehension, 2 bytes more
W=p=>
  [...'@#e'+p].map(c=>
    eval(
    '++x,--x,x*=x,x=R,x=0,o+=x,o+=String.fromCharCode(x),R=A+B,R=A-B,R=A*B,R=A/B|0,R=0,o+=R+` `'
    .replace(/x/g,(k='ids>@pP+-*/ewakm<#oO'.indexOf(c))<13?'A':'B')
    .split`,`[k%13]),
    o=''
  )&&o

// Test
function test() 
{ 
  OUT.innerHTML = V(I.value) 
}

test()
textarea { width: 75%; height: 8em }
Test program <button onclick="test()">Run</button><br><textarea id=I>
iisssaa/>e
maa->e#
aamam->e#
dddddddddddddddddddddddddPiiiiiiiiiiiiiiiiiiiiiiiii
iiiiPiiiiiiiPPiiiP
@#e
iis
aamaaaa
*>P
@#e
iisssaa/>e
maa->e#
aamam->e#
iiiiiiiiiiiiiiiiiiiiiiP
ddddddddP
iiiP
ddddddP
ddddddddP
@#e
iiss
aa*>
iP
</textarea><br>Output<pre id=OUT></pre>

edc65

Posted 2015-11-05T13:16:48.803

Reputation: 31 086

You could save 2 bytes by removing A=B=R=0, and setting those variables using the actual 3var functions before processing the string, like: [...'@#e'+p]. – insertusernamehere – 2015-11-05T21:13:52.890

2@insertusernamehere thx, I love this one – edc65 – 2015-11-05T21:20:41.003

8

Javascript ES6 ES7, 217 215 213 208 bytes

f=s=>(O='',[for(c of'@#e'+s)eval('v=0,++v,--v,v*=v,O+=v,O+=String.fromCharCode(v),v=R,R=0,R=A+B,R=A-B,R=A*B,R=A/B|0,O+=R+" "'.replace(/v/g,'AB'[(x='@idspP>e+-*/w#akmoO<'.indexOf(c))/13|0]).split`,`[x%13])],O)

Ungolfed

f=s=>(
    O='',                                                                   // initialize output to empty string
    [for(c of'@#e'+s)eval(                                                  // initialize A, B, and R, loop over all chars in input, eval returned function string
        'v=0,++v,--v,v*=v,O+=v,O+=String.fromCharCode(v),v=R,R=0,R=A+B,R=A-B,R=A*B,R=A/B|0,O+=R+" "' // operation list
            .replace(/v/g,'AB'[(x='@idspP>e+-*/w#akmoO<'.indexOf(c))/13|0]) // replace all instances of v with either A or B
            .split`,`[x%13])],                                              // split ops list, select corresponding function string
    O)                                                                      // return output string

Dendrobium

Posted 2015-11-05T13:16:48.803

Reputation: 2 412

1+1 Not far from mine, but better. Now I'll have to try something different – edc65 – 2015-11-05T19:10:53.077

1You could save 2 bytes by removing A=B=R=0, and setting those variables using the actual 3var functions before processing the string, like: for(c of '@#e'+s). – insertusernamehere – 2015-11-05T21:14:16.303

1@insertusernamehere Aha, thats pretty clever, thanks! – Dendrobium – 2015-11-05T21:20:15.813

Revising your answer, I see that you don't output a newline for command w – edc65 – 2015-11-06T15:40:22.510

@edc65 One of the clarification bullets states "'w' should output a space or a newline after R" – Dendrobium – 2015-11-06T16:41:15.143

8

GNU Sed (with eval option to evaluate dc expression), 254

Deadfish maps fairly nicely to a subset of dc. So we use sed to do that mapping:

s/^/@#e/
s/\+/AB+r/g
s/-/AB-r/g
s/\*/AB*r/g
s|/|AB/r|g
s/a/B1+b/g
s/i/A1+a/g
s/d/A1-a/g
s/s/Ad*a/g
s/p/An/g
s/P/AP/g
s/>/Ra/g
s/k/B1-b/g
s/m/Bd*b/g
s/o/Bn/g
s/O/BP/g
s/</Rb/g
s/w/Rn/g
s/@/0a/g
s/#/0b/g
s/e/0r/g
s/[ABR]/l&/g
s/[abr]/s\u&/g
s/.*/dc -e'&'/e

Digital Trauma

Posted 2015-11-05T13:16:48.803

Reputation: 64 644

6

APL, 191

{0::→⋄A B R←0⋄{⍵∊G←'aikdms<>':⍎'AB'[1+2|G⍳⍵],'+-*∘'[M],'←','112R'[M←⌈2÷⍨G⍳⍵]⋄⍵∊G←'PpOo':⍞←⎕UCS⍣(2|G⍳⍵)⊢A B[⌈2÷⍨G⍳⍵]⋄⍵∊G←'+-*/':R∘←⌊A(⍎'+-×÷'[G⍳⍵])B⋄⍵∊G←'@#e':⍎'ABR'[G⍳⍵],'∘←0'⋄⍵='w':⍞←R}¨⍵}

This is a function that takes the program as an argument, e.g:

      ∆3var←{0::→⋄A B R←0⋄{⍵∊G←'aikdms<>':⍎'AB'[1+2|G⍳⍵],'+-*∘'[M],'←','112R'[M←⌈2÷⍨G⍳⍵]⋄⍵∊G←'PpOo':⍞←⎕UCS⍣(2|G⍳⍵)⊢A B[⌈2÷⍨G⍳⍵]⋄⍵∊G←'+-*/':R∘←⌊A(⍎'+-×÷'[G⍳⍵])B⋄⍵∊G←'@#e':⍎'ABR'[G⍳⍵],'∘←0'⋄⍵='w':⍞←R}¨⍵}
      ∆3var 'iipois+iis<-<aaaO<OkOOkkkkOP@#iippisa+<m+>PaO'
20spooky22me

It can be used as an anonymous function, I just gave it a name for clarity.

Explanation:

  • 0::→: if an error occurs (say, division by zero), halt without printing the error message
  • A B R←0: initialize variables
  • {...}¨⍵: for each command:

    • ⍵∊G←'aikdms<>': If the command is one of the type var ← fn(var, x), find the proper fn and x, substitute them in and then evaluate it:
      • : evaluate
      • 'AB'[1+2|G⍳⍵: A if the position of in 'aikdms<>' is even, B otherwise.
      • '+-*∘'[M]: add, subtract, power, or nothing, depending on M (defined later)
      • '←': assign
      • '112R'[M←⌈2÷⍨G⍳⍵]: 1 (for adding and subtracting), 2 (for power), and R (for nothing, i.e. it just sets the variable to R), depending on M, which is whether the command belongs to the first, second, third or fourth pair.
    • ⍵∊G←'PpOo': output:
      • ⍞←: output
      • ⎕UCS⍣(2|G⍳⍵): ASCII (well, Unicode) or number depending on whether the command was on an odd or even position in PpOo,
      • ⊢A B[⌈2÷⍨G⍳⍵]: A or B, depending on whether the command was in the first or second half.
    • ⍵∊G←'+-*/: math:
      • R∘←⌊A(⍎'+-×÷'[G⍳⍵])B: set R to the result of applying the given operator to A and B.
    • ⍵∊G←'@#e': reset:

      • : evaluate
      • 'ABR'[G⍳⍵]: select the right variable
      • '∘←0': set to zero
    • ⍵='w':⍞←R: if the command is w, output R.

marinus

Posted 2015-11-05T13:16:48.803

Reputation: 30 224

4

VBA, 484, 453 380 Bytes

To long to win but A super Simple way of doings things, Nothing Fancy just good old Select Case

Adding in Integer Division and Div 0 Error Handling Ate a lot of Bytes
Removed Error Handling as it seems the normal error handling results in the same functionality. Fixed Int Division to work as expected. Was also shorter.

Function Y(x)
For Z=1 To Len(x)
w=Mid(x,Z,1)
Select Case w
Case"i":A=A+1
Case"d":A=A-1
Case"s":A=A^2
Case"p":Y=Y &A
Case"P":Y=Y &Chr(A)
Case">":A=R
Case"a":B=B+1
Case"k":B=B-1
Case"m":B=B^2
Case"o":Y=Y &B
Case"O":Y=Y &Chr(B)
Case"<":B=R
Case"+":R=A+B
Case"-":R=A-B
Case"*":R=A*B
Case"/":R=A\B
Case"w":Y=Y &R &vbCrLf
Case"@":A=0
Case"#":B=0
Case"e":R=0
End Select
Next
End Function

Thanks to Henrik Ilgen for saving 31 104 bytes

JimmyJazzx

Posted 2015-11-05T13:16:48.803

Reputation: 691

2Not entirely sure if this works in VBA (it does in VB6), but you could save a bunch of bytes by using DefInt A-Z, thereby omitting the need to explicitly declaring A, B and R as Integer: DefInt A-Z:Dim A, B, R. It might as well work to just assign them, without declaration: A=0:B=0:R=0. The calculations should work on variants, too. – Henrik Ilgen – 2015-11-06T11:37:59.227

@HenrikIlgen thanks alot, Forgot about DefInt Not Something I use everyday but going to be super useful golfing VBA in the future. Sadly A=0 will just make it act like a double from my tests. There for making iiiaa/w produce a decimal result rather then a whole. – JimmyJazzx – 2015-11-06T15:31:48.433

1Try \ for integer division ;) – Henrik Ilgen – 2015-11-09T08:34:40.407

1

You can condense it down to 405 bytes if you make it a function and use the return value to "build" the result, assuming you don't have to actually print the result :)

– Henrik Ilgen – 2015-11-09T08:58:15.017

4

C, 253 241 bytes

#define _ c--?c--?c--
k="id@s>ak#m<e+-*/wpoPO",*p;main(c,a,b,r){for(a=b=r=0;~c;c=getchar())c=strchr(k,c),c&&(c-=k,p=&a+c/5,*p=_?_?_?_?_?printf(c?c<3?"%d":"%c":"%d ",c?c%2?a:b:r):a/(b?b:exit()):a*b:a-b:a+b:0:r:b*b:0:b-1:b+1:r:a*a:0:a-1:a+1);}

This code uses the string id@s>ak#m<e+-*/wpoPO as a table of commands. The string is arranged according to the destination of the calculated expression. It just so happens that there are 5 commands that update each of the variables:

  • id@s> - update a
  • ak#m< - update b
  • e+-*/ - update r
  • wpoPO - update... the memory location after a, b and r. I hope it's not too important :)

So after locating the input character in the string of commands, its index is repeatedly decreased, and depending on when it reaches 0, an expression is chosen.

If it doesn't reach 0 after 15 subtractions, it's a printf with some properly chosen arguments.

Also, when dividing, it avoids division by 0 by calling exit().

This code should be compiled without optimizations, because it assumes that a, b and r are located at adjacent addresses on stack (not in CPU registers).

Also, it should be compiled in 32-bit mode, because it converts pointers to integers and vice-versa.

anatolyg

Posted 2015-11-05T13:16:48.803

Reputation: 10 719

3

PHP, 310 bytes

First time in my life using eval:

for($A=$B=$R=0;$c=$argv[1][$i++];)eval([i=>'++$A',d=>'--$A',s=>'$A*=$A',p=>'echo$A',P=>'echo chr($A)','>'=>'$A=$R',a=>'++$B',k=>'--$B',m=>'$B*=$B',o=>'echo$B',O=>'echo chr($B)','<'=>'$B=$R','+'=>'$R=$A+$B','-'=>'$R=$A-$B','*'=>'$R=$A*$B','/'=>'$R=$A/$B',w=>'echo$R','@'=>'$A=0','#'=>'$B=0',e=>'$R=0'][$c].';');

Takes the first command line input:

php 3var.php "iipois+iis<-<aaaO<OkOOkkkkOP@#iippisa+<m+>PaO"

Output from the examples:

Hello world!
20spooky22me

insertusernamehere

Posted 2015-11-05T13:16:48.803

Reputation: 4 551

3

C, 357

Macros FTW!

(Who am I kidding - c will never win this one)

#define X(p,e) case p:e;break;
#define Y(p,a,b,c,d,e,f) X(a,p++)X(b,p--)X(c,p*=p)X(d,printf("%d",p))X(e,printf("%c",p%256))X(f,p=R)
A,B,R;main(int C,char**V){for(;*V[1];)switch(*V[1]++){Y(A,'i','d','s','p','P','>')Y(B,'a','k','m','o','O','<')X('+',R=A+B)X('-',R=A-B)X('*',R=A*B)X('/',R=A/(B?B:exit(0),1))X('w',printf("%d",R))X('@',A=0)X('#',B=0)X('e',R=0)}}

Digital Trauma

Posted 2015-11-05T13:16:48.803

Reputation: 64 644

2

JavaScript (ES6), 293 262 bytes

f=x=>(o="",a=b=r=0,p=String.fromCharCode,[...x].map(c=>{if(eval(`m={i_a++,d_a--,s_a*=a,p_o+=a,P_o+=p(a),">"_a=r,a_b++,k_b--,m_b*=b,o_o+=b,O_o+=p(b),"<"_b=r,"+"_r=a+b,"-"_r=a-b,"*"_r=a*b,"/"_r=a/b|0,w_o+=r,"@"_a=0,"#"_b=0,e_r=0}[c]`.replace(/_/g,":_=>")))m()}),o)

Usage

f(`iisssaa/>e
maa->e#
aamam->e#
dddddddddddddddddddddddddPiiiiiiiiiiiiiiiiiiiiiiiii
iiiiPiiiiiiiPPiiiP
@#e
iis
aamaaaa
*>P
@#e
iisssaa/>e
maa->e#
aamam->e#
iiiiiiiiiiiiiiiiiiiiiiP
ddddddddP
iiiP
ddddddP
ddddddddP
@#e
iiss
aa*>
iP`)

=> "Hello world!"

Explanation

There are a few details of the language that I'm unsure about (integer sizes, handling unrecognised characters, etc) but this solution seems to work sufficiently and ignores whitespace characters like the new-lines in the test case.

f=x=>(
  o="",                           // o = output string
  a=b=r=0,
  p=String.fromCharCode,
  [...x].map(c=>{                 // iterate through each character
    if(                           // if used for NOP characters (whitespace)

      // Functions:
      eval(`m={
        i_a++,
        d_a--,
        s_a*=a,
        p_o+=a,
        P_o+=p(a),
        ">"_a=r,
        a_b++,
        k_b--,
        m_b*=b,
        o_o+=b,
        O_o+=p(b),
        "<"_b=r,
        "+"_r=a+b,
        "-"_r=a-b,
        "*"_r=a*b,
        "/"_r=a/b|0,
        w_o+=r,
        "@"_a=0,
        "#"_b=0,
        e_r=0
      }[c]`.replace(/_/g,":_=>")) // dynamically add common characters

    )m()                          // execute the function
  }),
  o                               // return the output string
)

user81655

Posted 2015-11-05T13:16:48.803

Reputation: 10 181

1I think you could save a few bytes by enclosing the dictionary within an eval whilst replacing all :$=> with $, then adding a replace for the string. – Conor O'Brien – 2015-11-05T14:44:41.060

2

Simplex v.0.8, 211 bytes

(UTF-8 encoded.)

h@u]u2ƒ§I]ƒ§M]ƒ§^O]ƒ§o]ƒ§s]ƒ§@]ƒ§Ah]ƒ§Sh]ƒ§Mh]ƒ§Vh]ƒ§&oh]ƒðI]ƒðM]ƒð^O]ƒðo]ƒðs]ƒð@]ƒðAh]ƒðSh]ƒðMh]ƒðVh]ƒð&oh]ƒ§z]ƒðz]ƒuz@]{"idspP>akmoO<+-*/w@#e"RlyG^u·u†vøÏ}

Explanation

Since this is the longest simplex program I have thus far written, I will generally explain how this works in bullet points.

  • h@u] - defines macro 0. This macro simply writes to the register and makes a lambda return nothing.
  • u2 - goes to the above strip and sets the current byte to 2; this defines the arity of the lambdas to be defined.
  • ƒ - begin lambda expression; once completed by ], will push lambda function to the lambda stack. It acts by taking (arity) cells from the pointer into its local strip, and, after completion, will set its local strip to the taken cells, unless the current byte is unwritten. The pointer is not affected. Macro 0 allows for a function to return without modifying anything in the strip.
  • § - moves to the first written cell in the current strip i.e. A.
  • ð - moves to the last written cell in the current strip i.e. B.
  • {"idspP>akmoO<+-*/w@#e"RlyG^u·u†vøÏ}
    • {...Ï} repeat until the input stack is empty
    • "idspP>akmoO<+-*/w@#e" - the commands
    • Rly - put the strip into a tuple
    • G^u - the index of the input in the tuple
    • · - load the current byteth into the lambda evaluator
    • uRL - goes to the strip holding A and B (writes A and B if they don't exist)
    • - executes lambda (this is the lambda evaluator)
    • - resets below strip

phew I'm impressed. It's long for Simplex, but short for everything else. ;)

Conor O'Brien

Posted 2015-11-05T13:16:48.803

Reputation: 36 228

2

Minkolang 0.11, 222 bytes

I'm sure this can be golfed further, but it was fun. Also, first Minkolang interpreter of another language!

>I3&000V$Vod?.45*[di1q=5&]x00wx1i2+kw
idspP>akmoO<+-*/w@#e
vr1+r
vr1-r
vr2;r
v0c1$((dl%"0"+$rl:d)$Ok
v0cO
vrx0cr
v1g1+1G
v1g1-1G
v1g2;1G
v1c1$((dl%"0"+$rl:d)$Ok
v1cO
v1gxd1G
vx$d+
vx$d-
vx$d*
vx$dd?.:
vdN
vrx0r
v1gx01G
vx0

Try it here.

Explanation

>I3&000                    Initializes A, B, and R if they don't already exist.
V$V                        An idiom that ensures no time-travel.
od?.                       Reads in a character and halts if input is empty.
45*[di1q=5&]               Looks through the second row for a matching character.
            x00w           Jumps back to beginning if no match.
                x1i2+kw    Jumps to corresponding line upon match.

The rest of the lines are pretty simple, perhaps with the exception of those with 1$((dl%"0"+$rl:d)$Ok, which is an idiom that prints a number without a trailing space. (I haven't yet implemented the convert-this-number-to-a-string functionality, which will be 1Z.) Oh, yes, they all have a v at the beginning, which takes it back to the beginning.

El'endia Starman

Posted 2015-11-05T13:16:48.803

Reputation: 14 504

2

GNU Sed (with eval option to evaluate dc expression), 289

Inspired by Digital Trauma who sadly failed to realize, that a) illegal characters need to be ignored, b) dc needs the entire converted program in one argument and c) division by 0 must terminate the program without error.

If all these rules wouldn't apply, my solution would only be 235 bytes long ;)

H
$!d
x
s/^/@#e/
s:[^-a><de/+i*k@w#opsmOP]::g
s:[e@#]:0&:g
s:[-*+/pPid]:Q&:g
s:[-kaoO*+/]:H&:g
s:[><w]:Z&:g
s:[diak]:1&:g
s:s:Q2^>:g
s:m:H2^<:g
s:[-+*/]:&e:g
s:[ia]:+&:g
s:[dk]:-&:g
y:Oop:Pnn:
s:w:n32P:g
s:[id>@]:sq:g
s:e:sz:g
s:[#<ka]:sh:g
s:[QHZ]:l\l&:g
s:/:d0=t/:g
s/.*/dc -e'[q]st&'/e

Bodo Thiesen

Posted 2015-11-05T13:16:48.803

Reputation: 121

2

AWK, 311 309

func p(z,f,x){if(c~z)printf"%"f,x}BEGIN{FS=z}{for(i=0;++i<=NF;){c=$i;A=c~/i/?A+1:c~/d/?A-1:c~/s/?A*A:c~/@/?0:c~/>/?R:A;p("p","d",A);p("P","c",A);B=c~/a/?B+1:c~/k/?B-1:c~/m/?B*B:c~/#/?0:c~/</?R:B;p("o","d",B);p("O","c",B);R=c~/+/?A+B:c~/-/?A-B:c~/*/?A*B:c~/e/?0:R;if(c~"/")if(B)R=A/B;else exit;p("w","d ",R)}}

TIL parenthesis were not needed around printf. 2 bytes saved!

Ungolfed version for easier reading:

func p(z,f,x) {
    if(c~z) printf "%"f,x
}

BEGIN {
    FS=z
}

{
    for(i=0;++i<=NF;){
        c=$i;
        A=c~/i/?A+1:c~/d/?A-1:c~/s/?A*A:c~/@/?0:c~/>/?R:A;
        p("p","d",A);
        p("P","c",A);
        B=c~/a/?B+1:c~/k/?B-1:c~/m/?B*B:c~/#/?0:c~/</?R:B;
        p("o","d",B);
        p("O","c",B);
        R=c~/+/?A+B:c~/-/?A-B:c~/*/?A*B:c~/e/?0:R;
        if(c~"/")if(B)R=A/B;else exit;
        p("w","d ",R)
    }
}

LeFauve

Posted 2015-11-05T13:16:48.803

Reputation: 402

1

Python 2, 272

import sys;a,b,r=0,0,0;exec';'.join(filter(None,map(dict(x.split(':')for x in"a:b+=1|@:a=0|#:b=0|/:r=a/b|d:a-=1|PXchr(a)|i:a+=1|-:r=a-b|k:b-=1|*:r=a*b|m:b*=b|oXb|pXa|s:a*=a|OXchr(b)|wXr|+:r=a+b|e:r=0|<:b=r|>:a=r".replace('X',':print ').split('|')).get,sys.stdin.read())))

dieter

Posted 2015-11-05T13:16:48.803

Reputation: 2 010

This doesn't work. Your print statements include a trailing newline. – Griffin – 2015-11-10T19:39:53.917

1

Ruby, 199 bytes

a=b=r=0
$<.read.chars{|c|eval %w{a+=1
a-=1
a*=a
$><<a
$><<a.chr
a=r
b+=1
b-=1
b*=b
$><<b
$><<b.chr
b=r
r=a+b
r=a-b
r=a*b
b==0&&exit||r=a/b
puts\ r
a=0
b=0
r=0
p}["idspP>akmoO<+-*/w@#e".index(c)||-1]}

5 bytes can be saved by removing .read from the second line if you can tolerate a warning being printed to stderr on newer version of Ruby.

daniero

Posted 2015-11-05T13:16:48.803

Reputation: 17 193

1

Python, 244

import sys;P=sys.stdout.write;A=B=R=0;exec';'.join(filter(None,map(dict(zip('idspP>akmoO<+-*/w@#e','A+=1 A-=1 A**=2 P(`A`) P(chr(A)) A=R B+=1 B-=1 B**=2 P(`B`) P(chr(B)) B=R R=A+B R=A-B R=A*B R=A/B print(R) A=0 B=0 R=0'.split())).get,input())))

Bit late but I wanted to have a go.

Griffin

Posted 2015-11-05T13:16:48.803

Reputation: 4 349

1

Prolog, 759 bytes

Not the shortest program, but at least it's structured and readable.

q(A,B,R,i,X,B,R):-X is A+1.
q(A,B,R,d,X,B,R):-X is A-1.
q(A,B,R,s,X,B,R):-X is A*A.
q(_,B,R,>,R,B,R).
q(A,B,R,a,A,X,R):-X is B+1.
q(A,B,R,k,A,X,R):-X is B-1.
q(A,B,R,m,A,X,R):-X is B*B.
q(A,_,R,<,A,R,R).
q(A,B,_,+,A,B,X):-X is A+B.
q(A,B,_,-,A,B,X):-X is A-B.
q(A,B,_,*,A,B,X):-X is A*B.
q(_,0,_,/,_,_,_):-!,1=2.
q(A,B,_,/,A,B,X):-B>0,X is A/B.
q(_,B,R,@,0,B,R).
q(A,_,R,#,A,0,R).
q(A,B,_,e,A,B,0).
q(A,B,R,p,A,B,R):-write(A).
q(A,B,R,'P',A,B,R):-A>0,format('~c',A).
q(A,B,R,'P',A,B,R):-write(A).
q(A,B,R,o,A,B,R):-write(B).
q(A,B,R,'O',A,B,R):-format('~c',B).
q(A,B,R,'O',A,B,R):-write(B).
q(A,B,R,w,A,B,R):-write(R),nl.
q(A,B,R,_,A,B,R).
f([],_,_,_).
f([H|T],A,B,R):-q(A,B,R,H,X,Y,Z),f(T,X,Y,Z),!.
p(X):-atom_chars(X,Y),f(Y,0,0,0).

Example input

p('iipois+iis<-<aaaO<OkOOkkkkOP@#iippisa+<m+>PaO').

Try it out online here

Emigna

Posted 2015-11-05T13:16:48.803

Reputation: 50 798