148
\$\begingroup\$

Write the shortest program in your favourite language to interpret a brainfuck program.

You should take a string of source code, containing only valid brainfuck commands +-[]<>.,, and a string of ASCII input to the program, and return the output of the brainfuck program.

The program operates on a tape of at least 30000 cells each containing an unsigned 8-bit integer (i.e. 0 to 255). It has a tape pointer, which initially points to the first cell in the tape, and an instruction pointer which points to the first character of the source code.

Brainfuck has eight instructions:

  • + increments the cell at the tape pointer by 1.
  • - decrements the cell at the tape pointer by 1.
  • < moves the tape pointer left by one cell.
  • > moves the tape pointer right by one cell.
  • , reads a byte of input into the cell at the tape pointer. Reading past the end of input is undefined behaviour.
  • . prints the cell at the tape pointer as an ASCII character.
  • [ jumps to its matching ] if the cell at the tape pointer is zero.
  • ] jumps to the instruction before its matching [. You can assume [ and ] are balanced in the input.

After executing an instruction, the instruction pointer is moved forward by one character.

The cells should contain at least 8-bit unsigned integers (i.e. 0 to 255), and incrementing a cell containing 255 or decrementing 0 is undefined behaviour. Likewise, the tape should contain at least 30000 cellls, and going past these is undefined behaviour. This means that you can implement arbitrarily large integers and an arbitrarily large tape, but the program will never attempt to use values outside of 0...255 or more than 30000 cells.

Here's a test case that reads a decimal integer from input, followed by a newline, and outputs a list of primes up to that number:

>++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,----------[<+>-------------------------------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]++++++++++.[-]

Its output will look something like this:

Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

Additionally, a few smaller test cases:

  • ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. should take no input and output Hello World!
  • ++++++++[->+>++++++<<]>++[->.+<] should output 0123456789
  • ,[.,] is a cat program - it should output the string given as input
\$\endgroup\$
27
  • 10
    \$\begingroup\$ You should clarify about 1) size of memory 2) is memory circled 4) maybe any other details \$\endgroup\$
    – Nakilon
    Commented Jan 28, 2011 at 1:37
  • 3
    \$\begingroup\$ I wonder if there should be two categories: Those programs that use eval (or shell out to compile) -- and those that don't. \$\endgroup\$ Commented Feb 15, 2011 at 7:52
  • 47
    \$\begingroup\$ I'd love to see someone answer this in brainfuck. \$\endgroup\$
    – Hannesh
    Commented Mar 14, 2011 at 19:15
  • 10
    \$\begingroup\$ What does "no EOF symbol" mean? That the cell value remains unchanged when trying , on EOF? Or that it's up to us to choose a value when trying , on EOF? Or is EOF undefined behaviour altogether? \$\endgroup\$ Commented Apr 1, 2016 at 14:07
  • 6
    \$\begingroup\$ Likewise, what should happen when someone tries to leave the 30k cells to either side? Should the tape head remain in place or is this undefined behaviour? \$\endgroup\$ Commented Apr 1, 2016 at 14:09

86 Answers 86

1 2
3
2
\$\begingroup\$

Binary Lambda Calculus 104 bytes (829 bits)

I didn't come up with this solution. Go credit whoever put it on wikipedia. However it is amazing.

( λ 11 ) ( λ ( λ λ λ 1 ( λ ( λ 2111 ( λ λ 133 ( λ λ 1 ( λ λ ( λ 7 ( 1 ( 3 ( λ λ λ λ λ 10 ̲ ( 1 ( λ 6143 ) ) ( λ 15 ( 65432 ) ) ) ( λ λ 2 ( ( λ 11 ) ( λ λ λ 2 ( λ λ λ 662 ( λ λ 6 ( λ 1 ( 26 ) 3 ) ( 15 ̲ ( 51 ( λ 1 ) ) ( 5 ( λ 1 ) 1 ) ) ) ) ( 12 ( λ λ λ 312 ) ) ) 1 ( λ λ 2 ) ) ) ) ) ( 3 ( 1 ( λ λ λ λ 9 ( 1 ( λ 51 ( λ 154 ) ) ) ( 24 ( λ 142 ) ) ) ) ( 5 ( 11 ̲ ( λ 1 ) ) ( 12 ̲ ( λ 2 ( ( λ 11 ) ( λ λ λ 1 ( ( λ 11 ) ( λ λ λ 2 ( 1 ( 33 ) ) ( λ 8 ( 771 ) ) ) ) 21 ) ) ) ) ) ) ) ( λ 12 ̲ ( λ 12 ̲ ( λ 3 ( 21 ) ) ) ) ) ) ) ) ( λ λ 1 ) ) ) ( 11 ) ) ( λ ( λ 11 ) ( λ λ 1 ( ( λ 1 ( 1 ( 1 ( λ λ 1 ( λ λ 2 ) 2 ) ) ) ) ( λ λ 2 ( 21 ) ) ( λ λ 1 ) ) ( 22 ) ) ( 1 ( λ λ λ λ λ λ 1 ) ) 1)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I'm not sure that this actually fulfills the criteria – it doesn't handle non-brainfuck-syntax as comments, and it has an unbounded tape instead of the bounded one required by the question. \$\endgroup\$ Commented Nov 29, 2015 at 10:15
  • 1
    \$\begingroup\$ I wrote that code for my IOCCC submission at ioccc.org/2012/tromp/hint.html Handling comments or bounding the tape is not required. \$\endgroup\$
    – John Tromp
    Commented Oct 21 at 19:26
2
\$\begingroup\$

VB.net, 730 bytes

If P.Aggregate(Of Int32)(0,Function(s,i)If(s<0,s,If(i="["c,s+1,If(i="]"c,s-1,s))))=0 Then Dim C=0,O=0,M(30000)As Int32:Dim J As Func(Of Int32,Int32,Int32,Char,Char,Int32)=Function(x,n,l,g,t)If(P(x)=g,J(x+n,n,l+1,g,t),If(P(x)=t,If(l=1,x,J(x+n,n,l-1,g,t)),J(x+n,n,l,g,t))):Dim Q As New Dictionary(Of Char,Action)From{{"+"c,Sub()M(O)=If(M(O)=255,255,M(O)+ 1)},{"-"c,Sub()M(O)=If(M(O)=0,0,M(O)-1)},{"<"c,Sub()O=If(O=0,M.Length,O-1)},{">"c,Sub()O=If(O=M.Length-1,0,O+1)},{"["c,Sub()C=If(M(O)=0,J(C,+1,0,"["c,"]"c),C)},{"]"c,Sub()C=If(M(O)=0,C,J(C,-1,0,"]"c,"["c))},{","c,Sub()M(O)=Console.Read()},{"."c,Sub()Console.Write(Convert.ToChar(M(O)))}}:For C=0To P.Length-1:Dim a=If(Q.ContainsKey(P(C)),Sub()Q(P(C))(),Sub()Exit Sub):a():Next
\$\endgroup\$
1
  • \$\begingroup\$ The C# version has the potential to be smaller I think. \$\endgroup\$ Commented Dec 11, 2013 at 3:31
2
\$\begingroup\$

PynTree, 123 bytes

Æp+"Dw[0]Dy0"Ƭ+"æ#wy%+1#wy256"-"æ#wy%_#wy1 256"."ƤȮ#wy","æ#wy%OĊ256">";ß+y1æSwy"<"¿yß_y1æIw0 0"["¡#wy¤"]'}}JfxSėx"+-.,[]<>"

Try it online!

Transpiles Brainfuck to PynTree and then calls pyntree_eval on it. PynTree transpiles directly to Python.

\$\endgroup\$
2
\$\begingroup\$

Powershell, 175 195 183 175 173 bytes, Transpiler

,'$p=0
$c=@{}'+(gc $args|% t*y|%{(-split'$p++
$p--
$c.$p++
$c.$p--
$c.$p=[console]::Read()
write-host([char]$c.$p)-n
for(;$c.$p){
}
#')[('><+-,.[]'|% i*f $_)]
})-join'
'|iex

Explanation:

The script is transpiler from a brainfuck source code to a powershell source code. Finally, the script evaulates the result powershell code by command iex.

  • init commands $p=0 and $c=@{}
  • gc $args|% t*y|%{ - for each character from file
  • ('><+-,.[]'|% i*f $_)+1 - treats a current char as index in the array of code snippets. If character match no code snippet, the script uses the comment char #.
  • and iex evaulates the result powershell code

Compared to Joey's answer, this script fixes a bug "Index operation failed; the array index evaluated to null" ($p=0 in the init block)

Known issues:

  • [console]::Read() eats first char in VSCode. This expression work correct in a powershell window.

Less golfed test script:

$f = {

'$p=0',
'$c=@{}'+
(gc $args|% t*y|%{
    $bfcmd_Idx='><+-,.[]'.IndexOf($_)     # IndexOf returns -1 if char $_ does not found.
    @(  '$p++',
        '$p--',
        '$c.$p++',
        '$c.$p--',
        '$c.$p=[console]::Read()',
        'write-host([char]$c.$p)-n',
        'for(;$c.$p){',
        '}',
        '#'
    )[$bfcmd_Idx]      # push to pipe an element. -1 means last element
})-join"`n"|Invoke-Expression

}

&$f interpret-brainf-hello.bf
&$f interpret-brainf-prime.bf

Output:

Hello World!
Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

File interpret-brainf-prime.bf contains a test script from the question.

File interpret-brainf-hello.bf (from wiki):

[ This program prints "Hello World!" and a newline to the screen, its
  length is 106 active command characters. [It is not the shortest.]

  This loop is an "initial comment loop", a simple way of adding a comment
  to a BF program such that you don't have to worry about any command
  characters. Any ".", ",", "+", "-", "<" and ">" characters are simply
  ignored, the "[" and "]" characters just have to be balanced. This
  loop and the commands it contains are ignored because the current cell
  defaults to a value of 0; the 0 value causes this loop to be skipped.
]

++++++++               Set Cell #0 to 8
[
    >++++               Add 4 to Cell #1; this will always set Cell #1 to 4
    [                   as the cell will be cleared by the loop
        >++             Add 2 to Cell #2
        >+++            Add 3 to Cell #3
        >+++            Add 3 to Cell #4
        >+              Add 1 to Cell #5
        <<<<-           Decrement the loop counter in Cell #1
    ]                   Loop till Cell #1 is zero; number of iterations is 4
    >+                  Add 1 to Cell #2
    >+                  Add 1 to Cell #3
    >-                  Subtract 1 from Cell #4
    >>+                 Add 1 to Cell #6
    [<]                 Move back to the first zero cell you find; this will
                        be Cell #1 which was cleared by the previous loop
    <-                  Decrement the loop Counter in Cell #0
]                       Loop till Cell #0 is zero; number of iterations is 8

The result of this is:
Cell No :   0   1   2   3   4   5   6
Contents:   0   0  72 104  88  32   8
Pointer :   ^

>>.                     Cell #2 has value 72 which is 'H'
>---.                   Subtract 3 from Cell #3 to get 101 which is 'e'
+++++++..+++.           Likewise for 'llo' from Cell #3
>>.                     Cell #5 is 32 for the space
<-.                     Subtract 1 from Cell #4 for 87 to give a 'W'
<.                      Cell #3 was set to 'o' from the end of 'Hello'
+++.------.--------.    Cell #3 for 'rl' and 'd'
>>+.                    Add 1 to Cell #5 gives us an exclamation point
>++.                    And finally a newline from Cell #6

Powershell, 257 bytes, Interpreter

$c=@{}
$p=$i=0
$m={for(;($b+=($s[$i]-92)|?{$_-in-1,1})){$i+=$args[0]}}
for($s=gc $args -ra;$i-lt$s.Length){switch($s[$i]-40){22{$p++}20{$p--}3{$c.$p++}5{$c.$p--}4{$c.$p=[console]::Read()}6{write-host([char]$c.$p)-n}51{if(!$c.$p){.$m 1}}53{.$m -1;$i--}}$i++}

Less golfed test script:

$f = {

$c=@{}                                      # $c - hashtable
$p=$i=0                                     # $p - ptr (a key in the hashtable), $i - IC (Instruction Counter)
$m={
    for(;($b+=($s[$i]-92)|?{$_-in-1,1})){   # $b - balance of the brackets
        $i+=$args[0]                        # move IC forward or backward
    }                                       # while balance of the brackets is not 0
}
for($s=gc $args -ra;$i-lt$s.Length){        # -ra is shortcut for -raw parameter = get-content as char array
    switch($s[$i]-40){                      # '-40' needs to convert into [int] and to reduce cases 43 44 45 46 into 3 4 5 6 (-2 bytes)
        22{$p++}
        20{$p--}
        3{$c.$p++}
        5{$c.$p--}
        4{$c.$p=[console]::Read()}          # it eats a first char in a VSCode, it works correct in a Powershell terminal
        6{write-host([char]$c.$p)-n}
        51{if(!$c.$p){.$m 1}}               # dot source the script block m
        53{.$m -1;$i--}                     # dot sourcing does not create a new scope https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
    }
    $i++
}

}

&$f interpret-brainf-hello.bf
&$f interpret-brainf-prime.bf

Output:

Hello World!
Primes up to: 20
2 3 5 7 11 13 17 19
\$\endgroup\$
2
\$\begingroup\$

Javascript - 342 bytes

This is pretty much a complete ripoff of https://codegolf.stackexchange.com/a/220/85546, but I've translated it to Javascript, which was mostly simple except for the converting of character codes, which required some extra lines of code.

d=l=>{i=0,b=new Array(300).fill(0),t="",q=[];r=new Response(l).text().then(q=>(q.split("").forEach(e=>{t+=["i++;","i--;","b[i]++;","b[i]--;","n=new Buffer(1);n[0]=b[i];q.push(n.toString());","b[i]=prompt().charCodeAt(0);","while (b[i]){","}"]["><+-.,[]".indexOf(e)]||"\n",i+=(92-e.charCodeAt(0))*(e.indexOf("][")>-1)});eval(t);return q))}

It reads input from a Blob (l), and returns the output as an array of numbers/strings/whatever. All other input is taken as a prompt, of which only the first character is stripped. As with @Alexandru's submission, it evals the translated code, which is simply mapped one character at a time to corresponding JS.

\$\endgroup\$
2
\$\begingroup\$

C# - 373 349 339 335 chars

using C=System.Console;class P{static void Main(string[] z){try{for(dynamic c,p=z[0],a=new int[30000],s=new int[9],f=1>0,i=0,d=0,t=0;;i=c==51&&f&(f|=s[--t]<0)?s[t]:++i){c=p[i]-42;a[d+=(c-19)*(f&c>17&c<21?1:0)]+=(2-c)*(f&c>0&c<4?1:0);if(f&c==4)C.Write((char)a[d]);if(f&c==2)a[d]=C.Read();if(c==49)s[t++]=f?(f=a[d]!=0)?i:-1:i;}}catch{}}}

And more readable:

using C=System.Console;
class P
{
    static void Main(string[] z)
    {
        try
        {
            for(dynamic c,p=z[0],a=new int[30000],s=new int[9],f=1>0,i=0,d=0,t=0;;i=c==51&&f&(f|=s[--t]<0)?s[t]:++i)
            {
                c=p[i]-42;
                a[d+=(c-19)*(f&c>17&c<21?1:0)]+=(2-c)*(f&c>0&c<4?1:0);
                if(f&c==4)C.Write((char)a[d]);
                if(f&c==2)a[d]=C.Read();
                if(c==49)s[t++]=f?(f=a[d]!=0)?i:-1:i;
            }
        }
        catch{}
    }
}

Limitation is it only handles nested [ up to 9 deep. Can make the s array bigger to handle more.

Edit 373 -> 349: Removed outer loop (was for a different site), character comparisons to integers, moved c declaration into the for loop

Edit 349 -> 339:

  • Combined +/- and >/< into single lines.
  • Reduced integer literal lengths by subtracting 42 from c to allow for some of the integer literals to be a single character (credit @ceilingcat).
  • Moved i=... into the for loop iterator section (credit @ceilingcat).

Edit 339 -> 335:

  • Combined +/- and >/< into a single line (credit @ceilingcat)
  • Removed unnecessary parenthesis in the i=... (credit @ceilingcat)
\$\endgroup\$
3
  • \$\begingroup\$ oooo, very nice with the subtracting from the c to make the number literals smaller. Can't believe I didn't think of putting the i=... in the loop iterator section. \$\endgroup\$
    – tdashroy
    Commented Aug 10, 2020 at 4:23
  • \$\begingroup\$ awesome again! slowly getting closer to the folks at code.golf/brainfuck#c-sharp. Still in disbelief that so many more bytes can be shaved off. So curious how they do it \$\endgroup\$
    – tdashroy
    Commented Aug 10, 2020 at 8:41
  • \$\begingroup\$ Don't need the space between string[] and z \$\endgroup\$
    – ceilingcat
    Commented Aug 10, 2020 at 19:38
2
\$\begingroup\$

Rust, 312 bytes

use std::io::*;macro_rules! b{(@+)=>{A[I]+=1;};(@-)=>{A[I]-=1;};(@>)=>{I+=1;};(@<)=>{I-=1;};(@[$($t:tt)*])=>{while A[I]>0{$(b!(@$t);)*}};(@.)=>{print!("{}",A[I]as char);};(@,)=>{stdin().read(&mut A[I..=I]);};(@$t:tt)=>{};($($t:tt)*)=>{static mut A:[u8;30000]=[0;30000];static mut I:usize=0;unsafe{$(b!(@$t);)*}}}

Try it online! A more readable (and expansionable) version here. A macro that takes in a list of tokens and transforms them into rust code. The code is inputted as rust tokens, so some characters need to have a separator between them, and the most common ones to avoid are the >>, <<, ->, <- and .. operators. If you would like to read the tape after the code's execution the statics generated will still be usable. Also, loops nested 31 or greater deep may run into the recursion limit.

\$\endgroup\$
4
  • \$\begingroup\$ Doesn't the nonstandard behavior of , mean you are not actually interpreting Brainfuck but instead your own Brainfuck derivative and thus invalidate this answer? \$\endgroup\$ Commented Nov 17, 2020 at 1:53
  • \$\begingroup\$ @pppery there isn't really a standard behavior for , but I see what you mean. I'll fix it when I get back to my computer. \$\endgroup\$
    – Aiden4
    Commented Nov 17, 2020 at 14:56
  • \$\begingroup\$ Are you at your computer yet? \$\endgroup\$ Commented Nov 20, 2020 at 14:00
  • \$\begingroup\$ @pppery sorry, it should be fixed now \$\endgroup\$
    – Aiden4
    Commented Nov 20, 2020 at 15:50
2
\$\begingroup\$

Duocentehexaquinquagesimal, 260 bytes

5„-^ñ™[fyΛÈÐ\∍ζ=¦δW€ªвƵиˆóδˆ†¦#Ûø“:#”Ù@θý9îæζJ¯иεhlÎà₂âY&т9zì*qI∍`ç∍Šñí¼GÏ0¦R˜#ðžèLÛüûK;Øî“müƶrηÝ'ç0Œ©₆V²_Δ≠tδ<üC/ï„Õ›0aÜ7H:¡°RF®Õ(:3%Yñβù½Sègæ₁„z¹*ôŒ$Ðεüõ<тD8ʒ: óǝÁ¸33ùçUηïZ熧Ëh/Wαï¹AÑÜ׌ޢÍη.ÓAËΩćUQ¯Óƒ‡`EuÈänÖÎo'²₃ĆÄHн
Á3ÞIœæÃλ≠HΛ8ˆÔ„ö|ÐÛ¸Γ>)W₃âf?ā¯®Ìмv₅—ƶζ

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 3.8 (pre-release), 245 237 247 bytes

-8 bytes thanks to Jo King

+10 bytes because input wasn't handled correctly

from sys import*
i,n,*a=[0]*30002
exec('\n'.join([((i:=i+(v:=s=='[')-(s==']'))-v)*' '+'while(a[n]): 0 n-=1 n+=1 a[n]+=1 a[n]-=1 a[n]=ord(stdin.read(1)) print(end=chr(a[n]))'.split()[u.index(s)]for s in open(argv[1]).read()if s in(u:='[]<>+-,.')]))

Try it online!

Compiles bf source code to python and execs.

\$\endgroup\$
2
  • \$\begingroup\$ You can just do end=chr(a[n]). The initialisation can also be i,n,*a=[0]*30002 \$\endgroup\$
    – Jo King
    Commented Oct 7, 2021 at 21:58
  • \$\begingroup\$ Ahh, meant to do the last one. Thanks for the end=, wouldn't have thought of that. \$\endgroup\$ Commented Oct 8, 2021 at 0:33
2
\$\begingroup\$

Rattle, 234 bytes

\&[0]*199&99&\|!I[g0P4I~n[62P2g+s][60P2g-s][43f6+f5][45f6-f5][46f6,][91f6[0f0]]
[93f6[^0f1]][44g3P5I~nP2f5P5g+s]P4g+sg0I^[~q]g]0;P6g=+s[P4g+f2[91f3]g8[93f4[0f]]]0
;P6g=+s[P4g-f2[93f3]g8[91f4[0f]]]0;sg0I~ns8;P6g+s;P6g-s;r`g1l(~,\);g1P2I~

(without the line breaks)

Try it Online!

This is by far Rattle's most complicated program yet.

This takes Brainf*** code as the first line of input and input for the Brainf*** code as the second line of input. Note that Rattle expects the second line to exist even if there is no input for Brainf***.

Here's a similar example except instead of the classic Hello World!, I've modified it to take ! as input but otherwise still output the same thing.

Explanation

This program is a little lengthy to do a full explanation for but here's a much more human-readable version of the program:

\&[0]*199&99&\|!I

[
  g0 P4 I~n

  [62 g2 + s2]
  [60 g2 - s2]
  [43 g1 P2 I~ + r` g1 l(~,\)]
  [45 g1 P2 I~ - r` g1 l(~,\)]
  [46 g1 P2 I~ ,]
  [91 g1 P2 I~ [0 f0]]
  [93 g1 P2 I~ [^0 f1]]
  [44 g3 P5 I~ n r` g1 P2 l(~,\) g5 + s5]

  g4 + s4
  g0 I^ P4 [~q]
  P4g
]0

;g6 =+ s6 [g4 + s4 g0 P4 I~ n s8 [91 g6 + s6] g8 [93 g6 - s6 [0 f]]]0
;g7 =+ s7 [g4 - s4 g0 P4 I~ n s8 [93 g7 + s7] g8 [91 g7 - s7 [0 f]]]0

:(this line and below is just a comment)
data tape values:
0 - code
1 - code data tape
2 - code pointer
3 - input
4 - code command index
5 - input character index
6 - open loop counter
7 - close loop counter
8 - temp
\$\endgroup\$
2
\$\begingroup\$

nice-expr, 660 bytes

var f is func(str)none func(var C is str)none{var T is list[int]repeat(0,30001);var p is int;var B is map[int]int;var b is list[int];for var i is int0{var c is str C_i;if c="["then{set b+[i];}else if c="]"then{set B@b_-1is i;set B@i is b_-1;set b is b_0..-1;};set i+1;if i>=len(C)then{break;};};for var i is int0{var c is str C_i;if c=">"then{set p+1;}else if c="<"then{set p-1;}else if c="+"then{set T@p is(T_p)+1;}else if c="-"then{set T@p is(T_p)-1;}else if c="."then{print(char(T_p));}else if c=","then{set T@p is ord(inputchar());}else if c="["and(T_p)=0then{set i is B_i;}else if c="]"and(T_p)!=0then{set i is B_i;};set i+1;if i>=len(C)then{break;};};};

This is a function that takes takes in the brainfuck code as a string.

This certainly can be golfed down; half the code in the solution is only dedicated to pairing up brackets to each other.

Ungolfed Explanation

var interpret is func(str)none func(var code is str)none {
    // there are neither 8-bit, nor unsigned, types in nice-expr.
    // a list of ints will have to do.
    var tape is list[int] repeat(0,30000);
    var ptr is int 0; // start on the start of the tape.

    var brackets is map[int]int <||>; // keys and values are indexes of brackets.

    var bracketStack is list[int] []; // stack that holds left bracket indexes
    for var i is int 0 { // first pass: match up brackets
        var c is str code_i;
        if c = "[" then {
            set bracketStack + [i]; // push a left bracket
        } else if c = "]" then {
            // pop a left bracket
            var left is int bracketStack_-1;
            set bracketStack is bracketStack_0..-1;
            var right is int i;
            set brackets@left is right;
            set brackets@right is left;
        };
        set i + 1;
        if i >= len(code) then { break; };
    };

    for var i is int 0 {
        var c is str code_i;
        if c = ">" then {
            set ptr + 1;
        } else if c = "<" then {
            set ptr - 1;
        } else if c = "+" then {
            set tape@ptr is (tape_ptr) + 1;
        } else if c = "-" then {
            set tape@ptr is (tape_ptr) - 1;
        } else if c = "." then {
            print(char(tape_ptr));
        } else if c = "," then {
            set tape@ptr is ord(inputchar());
        } else if c = "[" and (tape_ptr) = 0 then {
            set i is brackets_i; // jump to the matching right bracket
        } else if c = "]" and (tape_ptr) != 0 then {
            set i is brackets_i; // jump to matching left bracket
        };

        set i + 1;
        if i >= len(code) then { break; };
    };
};
\$\endgroup\$
2
\$\begingroup\$

ASCII FALSE, 365 bytes

Takes Brainfuck program and input separated by $ ("end of Brainfuck"); very slow (replacing a cell is a linear time operation with bad constant factors; loops search for the matching bracket each time they are executed). Could be optimized by (1) doing peephole optimizations on most commands, most notably stripping loops, memorizing loop targets and compressing sequences of +/- into single instructions (2) using binary trees as the array representation, giving better O(log n) modification time (much more complex; requires managing binary trees, and basic GC if no memory is to be leaked).

EOF is all ones (255; it's unclear what "no EOF symbol" is supposed to mean). Overflow being undefined behavior is taken advantage of. The pointer not over/underflowing is taken advantage of as well.

Runs "hello world" correctly as well as the prime finder, though it is very inefficient (as expected). I recommend first stripping the prime finder of comments, then appending $<small number>:

>++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,----------[<+>-------------------------------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]++++++++++.[-]
$20

This runs in about 1s for me, producing

Primes up to: 2 3 5 7 11 13 17 19

(Since input is given after the program in stdin, the number "up to" which primes are printed is of course missing from the output; this could be addressed by outputting all read characters (insert $, after ^), if desired.)

Note: This is ASCII FALSE, using O instead of ø (if ø were to be used instead, it would be a couple bytes longer) and B instead of ß (buffering is not relevant here however). Interpreters for ASCII FALSE can be found here.

Golfed

[n;0=$[%%x;0~]?~[$0=$[% % n;1-n:q;!0 0~]?~[$1&\2/\ $[% q;!2*1|0~]?~[q;!2*]?]?]?]q:0c:[^$'$=~][c;1+c:]#%30000$t:[1-$][0\]#0i:0p:[t;c;+i;-1-O]o:[x:p;n:q;!]s:[o;!$'[=[b;1+b:]?']=[b;1-b:]?]j:[c;i;>][o;!k:k;'.=[p;O,]?k;',=[^255&s;!]?k;'>=[p;1+p:]?k;'<=[p;1-p:]?k;'+=[p;O1+s;!]?k;'-=[p;O1-s;!]?k;'[=[p;O0=[1b:[b;][i;1+i:j;!]#]?]?k;']=[p;O[1_b:[b;][i;1-i:j;!]#]?]?i;1+i:]#

There are most probably quite a few more easy golfs possible.

Ungolfed

The core function is q ("shove/splice"), which allows fully using the stack like an array by remembering items on the call stack, then mutating the stack by replacing an element, and then restoring the elements remembered on the call stack. Once we can use the stack as an array, the rest is straightforward.

{
    shove/splice (q):
    pop n elements, remembering them on the call stack,
    then mutate the stack, dropping an item and replacing it with x,
    then restore the popped elements

    invocation: 101x: 42n: q;!
}
[
    n;0=
    $[% %x; 0~]?
    ~[
        $0=
        $[
            % {kill cond}
            % {kill dup'd zero on stack}
            n; 1- n:
            q;!
            0 {this is to be left on the stack}
            0~
        ]?
        ~[
            $ 1& {extract lowest bit}
            \ 2/ \ {>> 1 thing on stack}
            $[
                % q;! 2* 1| 0~
            ]?
            ~[
                q;! 2*
            ]?
        ]?
    ]?
]q:

0c: {# commands}
[^$ '$=~][c;1+c:]# {loop until `$` is encountered, leaves chars on stack}
% {drop '$}

30000$t:[1-$][0\]# {leave 30k 0's on the stack (note: final iteration will leave zeroed counter itself on stack)}

0i: {instruction pointer}
0p: {data pointer (0-based)}
[t;c;+ {depth of stack} i;- 1- O]o: {get (o)p}

[x: p;n: q;!]s: {set item}

[
    o;!
    $'[=[b;1+b:]?
    ']=[b;1-b:]?
]j: {count bracket balance}

[c;i;>][
    o;! k:
    k;'.=[p;O ,]?
    k;',=[^ 255& s;!]?
    k;'>=[
        p;1+p:
    ]?
    k;'<=[
        p;1-p:
    ]?
    k;'+=[p;O 1+ s;!]?
    k;'-=[p;O 1- s;!]?
    k;'[=[
        p;O 0=[
            1b: {balance}
            [b;][
                i;1+i:
                j;!
            ]#
        ]?
    ]?
    k;']=[
        p;O [
            {analogeous with two small changes}
            1_ b: {balance}
            [b;][
                i;1-i:
                j;!
            ]#
        ]?
    ]?
    i;1+i:
]#
```
\$\endgroup\$
2
\$\begingroup\$

Atto-8*, 0 bytes

*with brainfuck frontend

Unfortunately couldn't manage to golf off additional bytes. Open to suggestions if anyone has pointers.

Explanation

The Atto-8 microprocessor, when built with its brainfuck frontend, begins executing ASCII-encoded brainfuck directly from RAM, on bare metal. The microprocessor's machine code is brainfuck source code, and so no interpreter is required.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Golf! Atto-8 looks very cool, thanks for sharing it on this site. I think you would have to change the header of this post to "Atto-8 + BF Frontend, 0 bytes". I'd be interested in seeing some golf submissions written for the Atto-8, maybe in some sort of assembly. \$\endgroup\$ Commented Nov 7, 2023 at 20:58
2
\$\begingroup\$

Julia 1.7, 193 bytes

!x="let a=fill(0,8^5),i=1
"*replace(x*"]",(["><+-.,[]"...].=>[["i" "a[i]"].*["+=1";"-=1"]...
"print('\0'+a[i])"
"a[i:i]=read(stdin,1)"
"while a[i]>0"
"end"].*";")...,r"."s=>"")|>Meta.parse|>eval

Attempt This Online!

Julia 1.7 is needed for replace with multiple patterns

ungolfed code:

!x="let a=fill(0,8^5),i=1
"*replace(x*"]",	# add `end` to close the `let` block
'>' => "i+=1;",
'<' => "i-=1;",
'+' => "a[i]+=1;",
'-' => "a[i]-=1;",
'.' => "print('\0'+a[i]);",
',' => "a[i:i]=read(stdin,1);",
'[' => "while a[i]>0;",
']' => "end;",
r"."s => ""		# remove all other characters
)|>Meta.parse|>eval

Attempt This Online!

This function takes the program as parameter.
Program with the stricter IO (as a file given as argument): 206 bytes

\$\endgroup\$
2
\$\begingroup\$

TI-Basic (TI-84 Plus), 519 bytes

*fixed an error

"................................ !.....'()*+,-./0123456789:.<=>?.ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^..abcdefghijklmnopqrstuvwxyz{.}.→Str2
Prompt Str1
50→dim(L₁
Fill(0,L₁
50→Dim(L₂
Fill(0,L₂
5→P
0→L
0→D
0→X
1→Y
0→S
ClrHome
For(I,1,length(Str1
sub(Str1,I,1→Str3
If not(D
Then
If Str3=",
Then
Input Str4
inString(Str2,Str4→L₁(P
End
If Str3=".
Then
If L₁(P
Output(int(X/16)+1,remainder(X,16)+1,sub(Str2,L₁(P),1
X+1+X
End
L₁(P)+(Str3="+")-(Str3="-→L₁(P
remainder(abs(254(L₁(P)<0)-L₁(P)),256→L₁(P
P+(Str3=">")-(Str3="<→P
End
If Str3="[
Then
If L₁(P
Then
L+1→L
I→L₂(L
Else
S+1→S
1→D
End
End
If Str3="]
Then
S(S>1→S
If D(S=1
Then
0→D
0→S
Else
If L₁(P
Then
L₂(L→I
Else
L-1→L
End
End
End
End

I had to re-create the ASCII code page myself, since the TI-84 plus doesn't have a command that gets a character from its char code. The periods are characters that are not on the TI-84 Plus.

Keep in mind this is extremely slow at just printing Hello World (around 70 seconds to do it) so I couldn't imagine it trying to calculate primes.

It prompts you for code when the program starts, you MUST put a quotation mark (") before your code because of how the TI-84 works.

When prompting you for an input, you also have to put a quotation mark before your input.

There might be an error in the code due to me manually copying it from my calculator to my computer. If there is, please tell me.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ you don't need to initialize variables to zero and fill the lists with zeros, since you can assume a fresh environment \$\endgroup\$
    – MarcMush
    Commented May 17 at 17:32
  • \$\begingroup\$ @MarcMush ah! I didn't know I could do that. I'll try to fix it once my calculator starts working again since its been having temper tantrums as of late and not turning on =c \$\endgroup\$ Commented May 20 at 13:32
2
\$\begingroup\$

Casio BASIC (Casio FX-9750GIII), 532 468 bytes

" !.#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~."→Str 3
255→Dim List 1
{0,-1,1}→List 2
50→Dim List 3
1→L~S
For 1→I To StrLen(Str 1
StrMid(Str 1,I,1→Str 2
If Not D
Then If Not StrCmp(Str 2,"."
Then 1+MOD(Q-1,21→Z
List 1[P]-31→J
J<1⇒15→J
Locate Z,(Int (Q÷22))+2,StrMid(Str 3,J,1)
Isz Q
IfEnd
MOD(List 1[P]+List 2[StrScr("-+",Str 2)+1],255→List 1[P]
1+MOD(P+List 2[StrSrc("12",Str 2)+1]-1,255→P
IfEnd
If Not StrCmp(Str 2,"["
Then If List 1[P]+D
Then I→List 3[L]
Isz L
Else Isz S
1→D
IfEnd
IfEnd
If Not StrCmp(Str 2,"]"
Then S>1⇒Dsz S
If SD
Then 0→D
Dsz S
Else If List 1[P]
Then List 3[L-1]→I
Else Dsz L
IfEnd
IfEnd
IfEnd
Next

this isn't perfect AT ALL. you can't do input.

You have to enter the program into Str 1, and you have to replace < and > with 1 and 2 respectively

its also super slow (but not slower than the TI-84 program I made a while earlier)

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

Lua (to long)

I made some Lua implementation, but I can't get the bracket stuff right. Here it is anyway:

-- >    increment the data pointer (to point to the next cell to the right).
-- <    decrement the data pointer (to point to the next cell to the left).
-- +    increment (increase by one) the byte at the data pointer.
-- -    decrement (decrease by one) the byte at the data pointer.
-- .    output a character, the ASCII value of which being the byte at the data pointer.
-- ,    accept one byte of input, storing its value in the byte at the data pointer.
-- [    if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the
--      command after the matching ] command*.
-- ]    if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the
--      command after the matching [ command*.
s=setmetatable({0},{__index=function() return 0 end})

i=1 -- index array
j=1 -- index input
l=loadstring
t="><+-.,[]"
o=0
fh=arg[1] and io.open(arg[1]) or io.stdin
I=fh:read"*a":gsub("[^><%+%-%.,%[%]]","")
fh:close()
print(I)
for k=1,#I do io.write(k%5==1 and"+"or"-") end
io.write"\n"
for k=1,math.ceil(#I/5) do local n=5*(k-1)+1 local s=(" "):rep(4-math.floor(math.log10(n))) io.write(n,s) end
io.write"\n"
dbg=true
f={
"i=i+1 ",   -- array index ++
"i=i-1 ",   -- array index --
"s[i]=(s[i]+1)%256 ",   -- byte + 1
"s[i]=(s[i]-1)%256 ",   -- byte - 1
"io.write(string.char(s[i])) ", -- put byte
"local c=io.read(1):byte()s[i]=c==10 and s[i] or c",        -- read byte "Newline required!"
[=[if s[i]==0 then
    o=0
    repeat
        if dbg then print(j,"Forward!",o,b) end
        b=I:sub(j,j):match'[%[%]]'
        o= b=='['and o+1 or b==']' and o-1 or o;
        j=j+1
    until b==']' and o == 0
end
]=],    -- jump to matching ]
[=[
if s[i]~=0 then
    o=0
    count=0
    repeat 
        if dbg then print(j,"Backwards",o,b) end
        b=I:sub(j,j):match"[%[%]]"
        o= b=='['and o-1 or b==']' and o+1 or o;
        j=j-1
    until b=='[' and o == 0
end
]=],    -- jump to matching ]
}
for k,v in ipairs(f) do f[t:sub(k,k)],e=l(v) if e then error(e)end end
function run()
j=1
while j<=#I do
    f[I:sub(j,j)]()
    j=j+1
end
end
res,err = pcall(run)
if not res then
    print('error=',err)
    print('Dumping state')
    print('','stack')
    for k,v in pairs(s) do print("",k,v) end
end
if debug then
    print("stack")
    for k,v in pairs(s) do print(k,v) end
end

It doesn't pass the prime test, but acts nicely with Hello World and all echo and reverse examples I tried. So if anyone sees the bug, feel free to catch it.

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

Smalltalk, Squeak 4.x flavour 414 chars

Here is an interpreter which works exclusively with streams and block closures:

b:=[:c :i :o :n |
| v |
v := 1 to: n.
v := (v collect: [:x| | t |
    t := 0.
    Dictionary newFrom: {
        $+ -> [t:=t+1\\256].
        $- -> [t:=t-1\\256].
        $. -> [o nextPut:t].
        $, -> [t:=i next].
        $< -> [v back].
        $> -> [v next].
        $[ -> [t=0 and: [
            [c next=$[
                ifTrue: [(v peek at: $[) value].
             c peek=$]] whileFalse.
            c next]].
        $] -> [t=0 or: [c back.
            [c back=$]
                ifTrue: [(v peek at: c next) value. c back;back].
             c peek=$[] whileFalse.
            c next]].
        }]) readStream.
[c atEnd] whileFalse: [(v peek at: c next ifAbsent: [[]]) value]]
  • c is a readStream on code
  • i is a readStream on input (a ByteArray)
  • o is a writeStream on output (a ByteArray)
  • v is a readStream on interpreters (an Array)
  • n is number of cells

For each cell, we create an interpreter - that is a Dictionary which associate a Block to each BF command (a Character).
Those blocks close over a value t, initialized at zero.
The jump instructions are implemented recursively.
The pointers (code and data) are hidden in streams state.

To use the interpreter, we just have to feed this block with proper streams:

c := 'http://esoteric.sange.fi/brainfuck/bf-source/prog/PRIME.BF' asUrl retrieveContents contents readStream.
i := '15\' withCRs withUnixLineEndings asByteArray readStream.
o := #[] writeStream.
n := 30000.
b valueWithArguments: {c.i.o.n}.
^'',o contents

The interpreter can be golfed to 414 chars, using as:Dictionary which is shorter and by removing overflow and underflow protections (the cell value is then unbound).

b:=[:c :i :o :n||v|v:=1to:n.v:=(v collect:[:x||t|t:=0.{$+->[t:=t+1].$-->[t:=t-1].$.->[o nextPut:t].$,->[t:=i next].$<->[v back].$>->[v next].$[->[t=0and:[[c next=$[ifTrue:[(v peek at:$[)value].c peek=$]]whileFalse.c next]].$]->[t=0or:[c back.[c back=$]ifTrue:[(v peek at:c next)value.c back;back].c peek=$[]whileFalse.c next]]}as:Dictionary])readStream.[c atEnd]whileFalse:[(v peek at:c next ifAbsent:[[]])value]].
\$\endgroup\$
1
\$\begingroup\$

C: 317 characters (reads from a file)

#include <stdio.h>
char t[30000],*p=t,b[30000],c;void r(char*a){while((c=*a++)&&c-93){p+=c==62;p-=c==60;*p+=c==43;*p-=c==45;c^46||putchar(*p);c^44||(*p=getchar());if(c==91){while(*p)r(a);c=1;while(c+=(*a==91)-(*a++==93));}}}int main(int n,char**a){FILE*f;f=fopen(a[1],"r");fread(b,1,30000,f);fclose(f);r(b);return 0;}

This is my brainfuck interpreter that I wrote for a couple of months ago, it's quite a bit longer than it needs to be, but that is because I didn't focus on size when I wrote it, I focused on readability (just the fact that it compiles without error and even includes a library suggest that it is heavily shrinkable).

And expanded:

#include <stdio.h>
char t[30000],*p=t,b[30000],c;
void r(char*a){
    while((c=*a++)&&c-93){
        p+=c==62;
        p-=c==60;
        *p+=c==43;
        *p-=c==45;
        c^46||putchar(*p);
        c^44||(*p=getchar());
        if(c==91){
            while(*p)r(a);
            c=1;
            while(c+=(*a==91)-(*a++==93));
        }
    }
}
int main(int n,char**a){
    FILE*f;
    f=fopen(a[1],"r");
    fread(b,1,30000,f);
    fclose(f);
    r(b);
    return 0;
}

I might return with an actually golfed version.

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

LiveScript evaling JavaScript: 263

Note that this is currently untested.

p='process.std';g=p+'in.read';f='function(x){return';eval "eval('var i=0,m=[#{[0]*3e4*\,}];'+#g().map(#f'[]+-<>,.'.indexOf(x)).filter(#f~-x).map(#f['#{"while(8){,},i++,i--,8++,8--,#{p}out.write(String.fromCharCode(8)),#g(1)"/','*"','"/'8'*'m[i]'}'][x]).join(''))"

Ungolfed:

p='process.std'
g=p+'in.read'
f='function(x){return'
eval """
  eval('
      var i = 0,
          m=[#{[0]*3e4*\,}];' +
    #{g}()
      .map(#{f} '[]+-<>,.'.indexOf(x))
      .filter(#{f} ~-x)
      .map(#{f} ['#{
        "while( 8 ){ 0
         } 0
         i++ 0
         i-- 0
         8++ 0
         8-- 0
         #{p}out.write(String.fromCharCode( 8 )) 0
         #{g}(1)" / '0' * "','" / '8' * 'm[i]'
       }'][x])
       .join(''))
"""
\$\endgroup\$
1
\$\begingroup\$

Simplex v.0.5, 103 bytes

br{j'>=?[v'R;Ru]'<=?[v'L;Ru]'+=?[v'I;Ru]'-=?[v'M;Ru]'.=?[v's;Ru]',=?[v'G;Ru]'[=?[v'{;Ru]']=?[v'};Ru]LL}
b                     ~~ Takes a string input (BF prgm)
 r                    ~~ Reverses the string (pointer is at end)
  {               LL} ~~ Loop until empty cell is found
   j                  ~~ Inserts an empty cell at pointer
    '>                ~~ Sets empty cell to character (>) 
      =               ~~ Sets cell to 1 if > is the current character
       ?[      ]      ~~ Evaluate inside if cell is 1
         v    u       ~~ Goes down, then up
          'R          ~~ Puts the character (R) to the byte
            ;         ~~ Adds the current cell to the outer program
             R        ~~ Goes right (frees up next cell)
    '< =? [v'L;Ru]    ~~ …etc
    '+ =? [v'I;Ru]
    '- =? [v'M;Ru]
    '. =? [v's;Ru]
    ', =? [v'G;Ru]
    '[ =? [v'{;Ru]
    '] =? [v'};Ru]

I used this program to prove that Simplex is Turing-complete, it being reducible to a Turing-complete language. It's simple enough; after evaluation of this program, a second program is evaluated, which contains the BF "transcript". Yeah, it really just compiled BF to Simplex. But hey! I think this is the shortest answer thus posted.

(Note that I implemented a theoretically infinite (unbound) version, as Simplex is thus.)

\$\endgroup\$
3
  • \$\begingroup\$ Is this still accurate? \$\endgroup\$ Commented Feb 28, 2016 at 1:29
  • \$\begingroup\$ @VoteToClose No, I have not yet implemented some of the commands found in this program. \$\endgroup\$ Commented Feb 28, 2016 at 1:31
  • 1
    \$\begingroup\$ ‪:c crosses fingers for Simplex implementation \$\endgroup\$ Commented Feb 28, 2016 at 1:43
1
\$\begingroup\$

SmileBASIC, 258 bytes

C=0DEF B S,K
DIM M[3E4]FOR I=0TO LEN(S)-1C=ASC(S[I])N=M[P]ON!F GOTO@C?CHR$(N)*(C==46);
O=C==91F=!N*O
K=K+CHR$(I)*O*!F
IF C==93THEN I=ASC(POP(K))-1
M[P]=N-N(42)P=P+N(59)IF C==44THEN M[P]=ASC(SHIFT(K))@C:F=F-N(90)
NEXT
END
DEF N(L)RETURN(C-L-2)*(C<L&&C<L+4)END

Call the function as B code,input

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

Python 3, 306 bytes (no eval)

from sys import*
s=open(argv[1]).read()
d=[0]*30000
i=p=a=0
k=[]
j=k+d
for o in s:
 if o==']':j[a]=k.pop();j[j[a]]=a
 k+=[a]*(o=='[');a+=1
while i<a:x,r='[]<>,.+-'.find(s[i]),d[p];d[p],p=(r+(x==6)-(x>6))%256if 4!=x else ord(stdin.read(1)),p+(x==3)-(x==2);i=j[i] if x==(r>0)else 1+i;print(end=chr(r)*(5==x))

Outputs null (0x00) characters though, and times out on prime example but should theoretically finish.
Can still be improved a bit.

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

Go, 377 bytes

I just had to Golf this. Straightforward implementation; leverages constraints (no overflows, no bad instructions), prime finder works as expected. Takes path to Brainfuck program as first argument and input over stdin.

package main
import."os"
func main(){
var t[30000]uint8
d,i,s:=0,0,[]byte{0}
c,_:=ReadFile(Args[1])
for;i<len(c);i++{m:=func(j int){b:=j
for b!=0{i+=j
switch c[i]{case'[':b++
case']':b--}}}
switch c[i]{case',':Stdin.Read(s);t[d]=s[0]
case'.':s[0]=t[d];Stdout.Write(s)
case'<':d--
case'>':d++
case'+':t[d]++
case'-':t[d]--
case '[':if t[d]==0{m(1)}
case ']':if t[d]!=0{m(-1)}}}}
\$\endgroup\$
1
\$\begingroup\$

Lua, 353 bytes

Doesn't beat the other working Lua solution which transpiles the entire source to Lua, then runs that rather than doing the mish-mash this one does; very inefficient due to the use of heavy pattern matching for finding matching brackets concisely.

s=io.open(...):read"*a"f="if(d[p]or 0)%s0 then i=%s end"d={}p=1 i=1 while#s>i do load(({[43]="d[p]=(d[p]or 0)+1",[45]="d[p]=(d[p]or 0)-1",[60]="p=p-1",[62]="p=p+1",[46]="io.write(string.char(d[p]or 0))",[44]="d[p]=io.read(1):byte()",[91]=f:format("==","s:find('^%b[]()',i)-1"),[93]=f:format(">","s:sub(1,i):find('()%b[]$')")})[s:byte(i)]or"")()i=i+1 end

Or with some formatting:

s=io.open(...):read"*a"
f="if(d[p]or 0)%s0 then i=%s end"
g=""d={}p=1
i=1
while#s>i do
    load(({
        [43]="d[p]=(d[p]or 0)+1",
        [45]="d[p]=(d[p]or 0)-1",
        [60]="p=p-1",
        [62]="p=p+1",
        [46]="io.write(string.char(d[p]or 0))",
        [44]="d[p]=io.read(1):byte()",
        [91]=f:format("==","s:find('^%b[]()',i)-1"),
        [93]=f:format(">","s:sub(1,i):find('()%b[]$')")
    })[s:byte(i)]or"")()i=i+1
end
\$\endgroup\$
0
\$\begingroup\$

JavaScript - Partial Solution (241 235)

Does not read from file - does not manage PRIMES.BF, but works for Hello World!

// not included in 235 count, the hello world code from wikipedia
var p="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.",

// partial solution - dies on primes
a=[0,0,0,0,0],b=0
eval(p.replace(/[^\][.,+><-]/g,'').replace(/(.)/g,function(e){return "0while(a[b]){0}0console.log(String.fromCharCode(a[b]))0a[b]=prompt()0++a[b]0--a[b]0++b0--b".split(0)[" [].,+-><".search(new RegExp("\\"+e))]+";"}))

Just copy and paste it into javascript console to see it in action. Works in node.js, or broswer.

I was hoping to get PRIMES.BF to work in node.js, but not been able to emulate STDIN in a synchronous way yet.


With comments

// should read from file - easy with node.js
// this is the `Hello World! ` program from wikipedia
var p="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.",

// declare a and b. If a needs to be longer, can use:
//     a=[];for(0;a.length<30000;a.push(0))b=0
a=[0,0,0,0,0],b=0

// evaluate
eval(
  // the brainfuck code
  p
  // replacing all the non brainfuck commands with nothing 
  .replace(/[^\][.,+><-]/g,'')
  // replacing all commands (captured in parenthesis) with callback
  .replace(/(.)/g,function(e){
     // return swapped commands
     return "0while(a[b]){0}0console.log(String.fromCharCode(a[b]))0a[b]=prompt()0++a[b]0--a[b]0++b0--b"
     // split into array on the 0 (used as seperator - shorter than "|" when
     // called in .split(0) function)
     .split(0)[
       // matching brainfuck commands
       " [].,+-><"
       // searched with escaped, captured command
       .search(new RegExp("\\"+e))
       // add a semicolon to all statements - extra semicolons do not interfere
       // with execution of javascript
     ]+";"
  })
)
\$\endgroup\$
1 2
3

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.