7
\$\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\$
17
  • 5
    \$\begingroup\$ I promise you this is the last similar challenge you'll see from me for a long time. \$\endgroup\$
    – hyperneutrino
    Commented May 24, 2017 at 4:51
  • 4
    \$\begingroup\$ so many "languages" even w/o turing complete... \$\endgroup\$
    – tsh
    Commented May 24, 2017 at 5:30
  • 3
    \$\begingroup\$ Next time, at least add some kind of control flow statements. \$\endgroup\$
    – Sanchises
    Commented May 24, 2017 at 7:38
  • 3
    \$\begingroup\$ I'm kinda getting tired of these... \$\endgroup\$
    – user58826
    Commented May 24, 2017 at 13:34
  • 6
    \$\begingroup\$ If your going to make a language, make it Turing Complete. \$\endgroup\$
    – mbomb007
    Commented May 24, 2017 at 13:36

13 Answers 13

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\$
3
  • 7
    \$\begingroup\$ why is 'fish playground' not called 'fish pond' instead? \$\endgroup\$
    – user69654
    Commented May 24, 2017 at 12:16
  • 1
    \$\begingroup\$ @Orangesandlemons: I don't know, but I'm going to call it that anyway! \$\endgroup\$
    – Not a tree
    Commented May 24, 2017 at 12:23
  • 2
    \$\begingroup\$ Well this somehow beats the Python answer. Nice. \$\endgroup\$
    – hyperneutrino
    Commented May 24, 2017 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\$
3
  • \$\begingroup\$ Well, it seems that you don't need f. \$\endgroup\$ Commented May 24, 2017 at 13:57
  • \$\begingroup\$ @EriktheOutgolfer this will break when the accumulator gets negative \$\endgroup\$
    – ovs
    Commented May 24, 2017 at 14:15
  • \$\begingroup\$ why not a*=c<'#'? \$\endgroup\$
    – Cyoce
    Commented May 24, 2017 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\$
2
  • \$\begingroup\$ Welcome to PPCG, amazing first golf! \$\endgroup\$
    – Adalynn
    Commented Aug 10, 2017 at 22:07
  • \$\begingroup\$ If you reach the end and the accumulator isn't 0, you need to restart from the beginning \$\endgroup\$
    – ovs
    Commented Sep 9, 2017 at 10:13
1
\$\begingroup\$

Java 8, 225 194 187 183 bytes

s->d(s,0);void d(char[]s,int n){for(int c:s){n+=c>44?-1:c/43;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>0)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
-11 bytes thanks to @ceilingcat

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

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/43;                 //   Else if the character is '+':
                              //    Increase `n` by 1
                              //   Else:
                              //    Leave `n` the same (by increasing with 0)
  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
  if(n>0)                     //  If `n` is now larger than 0:
    d(s,n);}                  //   Do a recursive-call while leaving `n` as is
\$\endgroup\$
2
  • \$\begingroup\$ Is it possible to accept the argument s of c as a char array? \$\endgroup\$
    – Adalynn
    Commented Aug 10, 2017 at 22:11
  • \$\begingroup\$ @Zacharý Thanks. I've also converted it to Java 8, answer golfed two more small things. \$\endgroup\$ Commented Aug 11, 2017 at 6:51
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\$
3
  • 1
    \$\begingroup\$ You can test such C code online, here \$\endgroup\$ Commented May 25, 2017 at 22:20
  • \$\begingroup\$ char **v => char**v. \$\endgroup\$
    – Adalynn
    Commented Aug 10, 2017 at 22:07
  • \$\begingroup\$ 124 bytes \$\endgroup\$
    – ceilingcat
    Commented Sep 11, 2020 at 3:24
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\$

APL (Dyalog Unicode), 112 bytes

a←0
f←⎕UCS 127|⊢
{⍎¨('∆'(≠⊆⊢)'a+←1∆a-←1∆⍞←f a⋄a←0∆⍞←f a∆a←⎕UCS{×≢⍵:⊃⍵⋄⎕UCS 0}i⋄i←1↓i∆a←0')['+-#$%!'⍳⍞]}⍣{a=0}i←⍞

Try it online!

maps each instruction to a string, then executes it.

Inputs are taken in reverse, output is given in the debug window.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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