Brainfuck
October 4, 2011
A commented version of the hello world program from the previous page is given below:
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set the next four cells to 70/100/30/10
> +++++ ++ add 7 to cell #1
> +++++ +++++ add 10 to cell #2
> +++ add 3 to cell #3
> + add 1 to cell #4
<<<< - decrement counter (cell #0)
]
> ++ . print 'H'
> + . print 'e'
+++++ ++ . print 'l'
. print 'l'
+++ . print 'o'
> ++ . print ' '
<< +++++ +++++ +++++ . print 'W'
> . print 'o'
+++ . print 'r'
----- - . print 'l'
----- --- . print 'd'
> + . print '!'
> . print '\n'
That program comes from the Wikipedia page on brainfuck, as does the rot13 program below; beware that, depending on your operating system and compiler, there may be input buffering issues when running rot13:
-,+[ Read first character and start outer character reading loop
-[ Skip forward if character is 0
>>++++[>++++++++<-] Set up divisor (32) for division loop
(MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
<+<-[ Set up dividend (x minus 1) and enter division loop
>+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward
<[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient
<<<<<- Decrement dividend
] End division loop
]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag
>--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag
++++++++++++<[ If flag then set up divisor (13) for second division loop
(MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
>-[>+>>] Reduce divisor; Normal case: increase remainder
>[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient
<<<<<- Decrease dividend
] End division loop
>>[<+>-] Add remainder back to divisor to get a useful 13
>[ Skip forward if quotient was 0
-[ Decrement quotient and skip forward if quotient was 1
-<<[-]>> Zero quotient and divisor if quotient was 2
]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1
]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
<[-] Clear remainder from first division if second division was skipped
<.[-] Output ROT13ed character from copy and clear it
<-,+ Read next character
] End character reading loop
Daniel B. Cristofani gives this program to print the fibonacci numbers, noting that you will have to kill the program because it doesn’t terminate:
>++++++++++>+>+[
[+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[
[-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
[>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>
]<<<
]
It looks like that the above brainfuck code is slightly wrong. It should be:
++++++++++[>+++++++>++++++++++>+++>+<<<++.>+.+++++++..+++.>++.<.+++.——.——–.>+.>.
You replaced <<<< by >>. The correct code is on page 2.
My last post does not print well. For the correct code see http://en.wikipedia.org/wiki/Brainfuck
I think this works.
This was my first prolog program…
This works on the Hello World! program.
Paul: Fixed. Thanks.
My earlier code did not work for nested loops. This code is slow, but it works. It is better to compile the function for speed.
[…] today’s Programming Praxis exercise, our goal is to implement a Brainfuck interpreter. Let’s get […]
My Haskell solution (see http://bonsaicode.wordpress.com/2011/10/04/programming-praxis-brainfuck/ for a version with comments):
Here’s my python 3 version. It is essentially the same as other’s above.
A minor optimization is to implement looping using a loop stack. When ‘[‘ is encountered, ip (the instruction pointer)
is pushed on the loop stack (ls)(at this point ip points to the instruction after the ‘[‘). When a ‘]’ is encounterd,
d[dp] is tested. If d[dp] is non-zero a jump to the top of the loop is done by loading ip from the top of the loop stack.
If d[dp] is zero, the loop stack is popped and execution continues after the ‘]’.
Just because, here is a bf-to-python cross-compiler.
It optimizes runs of ‘+’, ‘-‘, ” to single statements. E.g., ‘+++’ is translated to ‘d[dp] += 3’.
Well, a loop is just a subroutine, so getting in/out of it should be handled by the evaluator.
Parse the string into a tree, then eval the tree. Loops are then just subtrees that need to be evaluated before we can continue.
My slightly larger than necessary version. Note that I got the idea of using a loop stack from Mike, my first idea was similar to Paul Hofstra’s first answer, and wouldn’t have worked properly.
(* Brainfuck “compiler” in OCaml *)
let src = open_in Sys.argv.(1)
let right (f, i) = f, i + 1
let left (f, i) = f, i – 1
let set f i x j = if j = i then x else f j
let inc (f, i) = set f i (f i + 1), i
let dec (f, i) = set f i (f i – 1), i
let inp (f, i) = set f i (try input_byte stdin with End_of_file -> 0), i
let cur (f, i) = f i
let out s = output_byte stdout (cur s); s
let rec loop p s = if cur s 0 then loop p (p s) else s
let id x = x
let (>>) f g x = g (f x)
let rec compile () =
let emit q = q >> compile () in
try match (input_char src) with
| ‘>’ -> emit right
| ‘ emit left
| ‘+’ -> emit inc
| ‘-‘ -> emit dec
| ‘.’ -> emit out
| ‘,’ -> emit inp
| ‘[‘ -> emit (loop (compile ()))
| ‘]’ -> id
| _ -> compile ()
with End_of_file -> id
let const c x = c
let _ = (compile ()) (const 0, 0)
In ruby (I believe it handles everything) …
October 4th, 2011.cpp:
The interpreter is known to run on an Apple Power Mac G4 (AGP Graphics) (450MHz processor, 1GB memory) on both Mac OS 9.2.2 (International English) (the program interpreted using Leonardo IDE 3.4.1) and Mac OS X 10.4.11 (the program compiled using Xcode 2.2.1).
The description of the problem fails to specify whether the bytes of the data store are unsigned or signed; therefore, I’ve provided the option to specify, when compiling the interpreter, whether the bytes of the data store are unsigned (by leaving line 17 commented out) or signed (by reinstating the aforementioned line).
Similarly, the description of the problem fails to specify the behaviour of the interpreter if the data pointer is decremented beyond the leftmost- or incremented beyond the rightmost- end of the data store; therefore, I’ve provided the option to specify, when compiling the interpreter, whether the interpreter quits with an error message (by leaving line 27 commented out) or whether the data pointer “wraps around” to the opposite end of the data store (by reinstating the aforementioned line).
The description of the problem specifies that the instruction pointer is incremented after unconditional jump (‘
]
’) instructions; this is incorrect, as if the instruction pointer were to be incremented after unconditional jump instructions the conditional jump instructions (‘[
’) jumped to would not be evaluated and any loop entered would never be exited.(I’ve just completed a gig at London South Bank University and so I’m again just trying to solve the problems posed by this ‘site whilst I try to get a job (and I’ve solved this problem in particular to test my
seal_Stack
template class I might use in the fourth version of my SDL2 joystick interrogator utility); I’m well-aware that my solutions are far from the best – but, in my defence, I don’t have any traditional qualifications in computer science :/ )sigh * Where I wrote
I meant to write