5
\$\begingroup\$

Because we haven't had enough of these, let's do another weird language!

  • + increments the accumulator
  • - decrements the accumulator
  • # outputs the character with the codepoint of the accumulator modulo 127, and then resets the accumulator
  • $ is like # but it doesn't reset the accumulator
  • % reads a single character of input and then set the accumulator to that. If it is EOF, exit the program
  • ! sets the accumulator to 0

At the end of the program, if the accumulator is 0, exit, otherwise, start again from the beginning, preserving the accumulator state.

Note that this language has no implementation so it is defined by this post.

Challenge

Given a valid +-#$%! program (containing only those characters) and the program input (containing only printable ASCII characters), return its output.

Examples

program, input -> output // comments
%$, hello -> hello // CAT program
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#, -> Hi there
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++$+++++++++++++++++++++++++++++++++$++++++++++++++++++++++++++++++++++++++++++++++++++++++$++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++$+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++$++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++$+++++++++++++$++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++$!, -> Hi there
\$\endgroup\$
  • 5
    \$\begingroup\$ I promise you this is the last similar challenge you'll see from me for a long time. \$\endgroup\$ – HyperNeutrino May 24 '17 at 4:51
  • 4
    \$\begingroup\$ so many "languages" even w/o turing complete... \$\endgroup\$ – tsh May 24 '17 at 5:30
  • 3
    \$\begingroup\$ Next time, at least add some kind of control flow statements. \$\endgroup\$ – Sanchises May 24 '17 at 7:38
  • 3
    \$\begingroup\$ I'm kinda getting tired of these... \$\endgroup\$ – programmer5000 May 24 '17 at 13:34
  • 6
    \$\begingroup\$ If your going to make a language, make it Turing Complete. \$\endgroup\$ – mbomb007 May 24 '17 at 13:36

12 Answers 12

11
\$\begingroup\$

><>, 112 bytes

You may be thinking "Is ><> really the best language to write an interpreter in?", to which my answer is "no, but let's try anyway!"

i:}b(?v
0(?;v0<o}\.24;!?:}\    /}~51. /}1-32./}1+32./}~i:
6*bb< o:}\?="#":  \?(b:\?="!":\?="-":\?="+":\?="%":$%+

Try it online, or at the fish pond!

Takes input from STDIN: first the +-#$%! code, then optionally a newline and any extra input.

This could do with some explanation.

  • The first loop is i:}b(?v. This reads from STDIN to the stack until it hits a character less than b = 11, which means either a newline (charcode 10) or EOF (charcode -1).

  • Once that's done, the fish swims down…

      v
    v0<
    <
    

    …into the main loop, adding a 0 to the stack to use as the accumulator.

  • First, the fish sees bb*6+% — this computes 127 = 11*11+6 and takes the modulus of the accumulator. Then $ brings forward the first character from the stack.

  • Now, we get to the bulk of the code — reading the character. There are seven branches in this bit of the code. (I think I've tetrissed the branches as much as I can, but there might be more blank space that can be removed here.)

    0(?;                                       /}~i:
                                               \?="%":
    

    Note that the fish starts from the bottom right, moving left, and wraps when it hits the side of the code. If the character is a literal "%", we shift it to the back of the stack for safekeeping, delete the accumulator, replace it with the first character in STDIN, check if that's EOF (that is, if its charcode is negative), and end the program if so. We then hit the start of the main loop again.

                                 /}1-32./}1+32.
                                 \?="-":\?="+":
    

    If the character is "+", we put it on the back of the stack again, add 1 to the accumulator, and jump to the start of the main loop. The "-" case is similar.

                          /}~51.
                          \?="!":
    

    If the character is "!", delete the accumulator and jump to just before the start of the main loop, where we first created the accumulator by adding a 0 to the stack.

             .24;!?:}\
                     \?(b:
    

    If the character is EOF or newline, check if the accumulator is 0, and terminate the program if so; otherwise, jump back to the start of the main loop. We kept all the used characters on the stack, so now we're back at the start of the program anyway.

          o}\
            \?="#":
    

    If the character is "#", output the accumulator as a character. We're then conveniently back just before the main loop, where we created the accumulator with a 0.

     
         o:}
    

    If we've reached this branch, the character can only be "$", since the stack only contained the characters +-#$%! and EOF or linefeed. Therefore we print a copy of the accumulator, and we're back at the start of the main loop.

\$\endgroup\$
  • 7
    \$\begingroup\$ why is 'fish playground' not called 'fish pond' instead? \$\endgroup\$ – Display name May 24 '17 at 12:16
  • 1
    \$\begingroup\$ @Orangesandlemons: I don't know, but I'm going to call it that anyway! \$\endgroup\$ – Not a tree May 24 '17 at 12:23
  • 2
    \$\begingroup\$ Well this somehow beats the Python answer. Nice. \$\endgroup\$ – HyperNeutrino May 24 '17 at 12:23
2
\$\begingroup\$

Python 2, 186 bytes

p,i=input()
a=0;f=1;r=''
while a^f:
 f=0
 for c in p:
	if c in'#$':r+=chr(a%127);a=a*(c>'#')
	if'%'==c:
	 if i:a=ord(i[0]);i=i[1:]
	 else:a=0;break
	a+=(c=='+')-(c>'+')-a*(c<'"')
print r

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Well, it seems that you don't need f. \$\endgroup\$ – Erik the Outgolfer May 24 '17 at 13:57
  • \$\begingroup\$ @EriktheOutgolfer this will break when the accumulator gets negative \$\endgroup\$ – ovs May 24 '17 at 14:15
  • \$\begingroup\$ why not a*=c<'#'? \$\endgroup\$ – Cyoce May 24 '17 at 18:40
2
\$\begingroup\$

Pyth, 89 bytes

KwJ1WJ=J0FHKIqH\+=+J1)IqH\-=-J1)IqH\#pC%J127=J0)IqH\$pC%J127)IqH\!=J0)IqH\%IqzkB=JChz=ztz

Takes the input in the first line and the output in the second. It's just a simple for loop over the input with some ifs. I'm sure it could be much shorter, but i don't care enough right now.

Try it!

Python code it compiles to:

assign('z',input())
assign("K",input())
assign("J",1)
while J:
 assign('J',0)
 for H in num_to_range(K):
  if equal(H,"+"):
   assign('J',plus(J,1))
  if equal(H,"-"):
   assign('J',minus(J,1))
  if equal(H,"#"):
   Pprint(Pchr(mod(J,127)))
   assign('J',0)
  if equal(H,"$"):
   Pprint(Pchr(mod(J,127)))
  if equal(H,"!"):
   assign('J',0)
  if equal(H,"%"):
   if equal(z,k):
    break
   assign('J',Pchr(head(z)))
   assign('z',tail(z))
\$\endgroup\$
1
\$\begingroup\$

Bash/gcc, 184 172

This first reads the program on stdin, then after an EOF, reads program input. Looks valid to me.

gcc -x c -<<<"a;main(){do{$(sed -e's/#/$!/g' -e's/./&;/g' -e's/[+-]/a&&/g' -es/!/a=0/g -e's,%,a=getchar();if(a==-1)exit(0),g' -e's/\$/putchar(a%127)/g')}while(a);}"
./a.out

If you didn't already notice, I'm just constructing, compiling and running a C program on the fly. Note: your compiler might complain loudly about the horrible code generated, but I believe we were allowed extra output on stderr.

Before I began, I expected this to be shorter than it turned out; I'm really unhappy with the % handling. Suggestions welcome :)

\$\endgroup\$
1
\$\begingroup\$

Python 3, 121 bytes

x,i=0,int
for c in input():
 if c in'$#':print(end=chr(x%128))
 x+=i(c=='+')-i(c=='-')-i(c in'!#')*x
 if'%'==c:x=input()
\$\endgroup\$
  • \$\begingroup\$ Welcome to PPCG, amazing first golf! \$\endgroup\$ – Zacharý Aug 10 '17 at 22:07
  • \$\begingroup\$ If you reach the end and the accumulator isn't 0, you need to restart from the beginning \$\endgroup\$ – ovs Sep 9 '17 at 10:13
0
\$\begingroup\$

JavaScript (ES6), 197 bytes

(s,i="")=>(i=[...i].map(c=>c.charCodeAt()),a=0,o="",u=_=>{[...s].map(c=>eval(["a++","a--",p="o+=a?String.fromCharCode(a%127):''",r="a=0",p+","+r,"a=i.shift()"]["+-$!#%".indexOf(c)])),a&&u()},u(),o)

Cleaned up

(s, i="") => (
    i = [...i].map(c=>c.charCodeAt()),
    a = 0,
    o = "",
    u = _ => {
        [...s].map(c => eval(
            ["a++", "a--", p="o+=a?String.fromCharCode(a%127):''", r="a=0", p+","+r, "a=i.shift()"][ "+-$!#%".indexOf(c) ]
        )),
        a && u()
    },
    u(),
    o
)

Test Snippet

f=
(s,i="")=>(i=[...i].map(c=>c.charCodeAt()),a=0,o="",u=_=>{[...s].map(c=>eval(["a++","a--",p="o+=a?String.fromCharCode(a%127):''",r="a=0",p+","+r,"a=i.shift()"]["+-$!#%".indexOf(c)])),a&&u()},u(),o)
<style>*{font-family:Consolas;}</style>
Code:&nbsp;
<textarea id="C" rows="2" cols="50"></textarea><br>
Input: <input id="I"><br>
<button onclick="O.innerHTML=f(C.value, I.value)">Run</button><br>
<pre id="O"></pre>

\$\endgroup\$
0
\$\begingroup\$

Ruby, 143 149 146 bytes

First line of STDIN is the code, the rest is the input.

Whoops, getc doesn't actually exist directly.

a=0
e=i=gets
i.chars{|c|eval Hash["+a+=1 -a-=1 #P;a=0 $P %a=$<.getc||exit !a=0".gsub(?P,"$><<(a%127).chr").scan /(\S)(\S+)/][c]||"";e=a}while e!=0

Try it online!

\$\endgroup\$
0
\$\begingroup\$

shortC, 95 bytes

c,a;AO;~c;c=G)c==43?a++:c==45?a--:c==35?Pa%127),a=0:c==36?Pa%127:c==37?!~(a=G)?T0:0:c==33?a=0:0;
\$\endgroup\$
0
\$\begingroup\$

C, 170 bytes

main(int c,char **v){for(int A=0,i=0;c=v[1][i++];A+1)A=c==0?i=0,A?A:-1:c=='+'?A+1:c=='-'?A-1:c=='!'?0:c=='$'?putchar(A%127),A:c=='#'?putchar(A%127),0:c=='%'?getchar():A;}

Ungolfed

main(int c,char **v){
    for(int A=0,i=0;c=v[1][i++];A+1)
        A=
            c==0 ? i=0, A?A:-1:    // EOF == -1
            c=='+' ? A+1:
            c=='-' ? A-1:
            c=='!' ? 0:
            c=='$' ? putchar(A%127),A:
            c=='#' ? putchar(A%127),0:
            c=='%' ? getchar():
            A;
}

6 bytes can be saved by replacing +-!$#% with decimal equivalents, but that would obfuscate the code. 9 bytes can be saved when using a K&R compatible compiler by moving the declaration int A=0,i=0 to the start of main, A,i,main(... However I only posted code that I could test.

Corrected in response to comments by Dave. Also switched to using the value of EOF (-1) instead of "EOF".

\$\endgroup\$
  • 1
    \$\begingroup\$ You can test such C code online, here \$\endgroup\$ – Conor O'Brien May 25 '17 at 22:20
  • \$\begingroup\$ char **v => char**v. \$\endgroup\$ – Zacharý Aug 10 '17 at 22:07
0
\$\begingroup\$

C, 145 139 bytes

c,a;f(){for(;~c;c=getchar())c==43?a++:c==45?a--:c==35?putchar(a%127),a=0:c==36?putchar(a%127):c==37?!~(a=getchar())?exit(0):0:c==33?a=0:0;}

That was easy. I definitely recommend compiling with all warnings off (-w). Will golf.

\$\endgroup\$
0
\$\begingroup\$

OCaml, 202 bytes

let c c=print_char(char_of_int(c mod 127))
let rec f a p=match Array.fold_left(fun a->function '+'->a+1|'-'->a-1|'#'->c
a;0|'$'->c a;a|'%'->Scanf.scanf"%c"int_of_char|'!'->0|_->a)a p with
0->()|a->f a p

Takes the program as an array of char because OCaml does not have String.fold*

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Java 8, 225 194 bytes

s->d(s,0);void d(char[]s,int n){for(int c:s){n+=c>44?-1:c>42?1:0;System.out.print(c>34&c<37?(char)(n%127):c==37?new java.util.Scanner(System.in).nextLine():"");n=c<36?0:n;}if(n<1)return;d(s,n);}

-15 bytes by converting Java 7 to Java 8.
-14 bytes thanks to @Zacharý by replacing String input with char-array input.
-2 bytes by some small fixes

Explanation:

Try it here: first test case with user-input.
Try it here: other two test-cases.

s->                            // Method (1) with char-array parameter and no return-type
  d(s,0)                       //  Call another method with the char-array and 0
;                              // End of method (1)

void d(char[]s,int n){         // Method (2) with character-array and integer parameters
  for(int c:s){                //  Loop over the characters of the input
  n+=c>44?                     //   If the character is '-':
      -1                       //    Decrease `n` by 1
     :c>42?                    //   Else if the character is '+':
      1                        //    Increase `n` by 1
     :                         //   Else:
      0;                       //    Leave `n` the same
  System.out.print(c>34&c<37?  //   If the character is '#' or '$':
    (char)(n%127)              //    Print the `n modulo 127` as character
   :c==37?                     //   Else-if the character is '%':
    new java.util.Scanner(System.in).nextLine()
                               //    Read & output the user-input
   :                           //   Else:
    "");                       //    Output nothing
  n=c<36?                      //   Then, if the character is '#' or '!':
     0                         //    Reset `n` to 0
    :                          //   Else:
     n;                        //    Leave `n` the same
  }                            //  End of loop
  if(n<1)                      //  If `n` is now 0:
    return;                    //   We're done
  d(s,n);                      //  Else: recursive-call while leaving `n` as is
}                              // End of method (2)
\$\endgroup\$
  • \$\begingroup\$ Is it possible to accept the argument s of c as a char array? \$\endgroup\$ – Zacharý Aug 10 '17 at 22:11
  • \$\begingroup\$ @Zacharý Thanks. I've also converted it to Java 8, answer golfed two more small things. \$\endgroup\$ – Kevin Cruijssen Aug 11 '17 at 6:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.