Compile Brainfuck to R5RS
Go to file
Peter McGoron 9cf01c72c8 brainfuck->scheme 2024-11-18 18:19:10 -05:00
COPYING brainfuck->scheme 2024-11-18 18:19:10 -05:00
README.md brainfuck->scheme 2024-11-18 18:19:10 -05:00
bf2s.scm brainfuck->scheme 2024-11-18 18:19:10 -05:00

README.md

Brainfuck2Scheme

A simple compiler from Brainfuck to R5RS. The compiler will output a Scheme list that is a lambda with two arguments:

  • data: The data vector.
  • dptr: The initial data pointer.

To turn the list into an executable Scheme function, just give it to eval.

How It Works

Brainfuck is a very simple Harvard architecture computer. The data is stored as a vector data and the data pointer is an integer dptr. The big idea is that all the code is compiled to a big lambda form, but there are some wrinkles due to jumps.

Data access brainfuck instructions are translated like

  • + -> (vector-set! data dptr (+ 1 (vector-ref data dptr)))
  • - -> (vector-set! data dptr (+ -1 (vector-ref data dptr)))
  • > -> (set! dptr (+ dptr 1))
  • < -> (set! dptr (- dptr 1))
  • . -> (display (vector-ref data dptr))
  • , -> (vector-set! data dptr (read-char))

Branches are trickier. Basically, all code that will be executed in a block is in a lambda. Given [code...], the code... will be compiled to a lambda in a letrec, with a conditional at the end that will tail-call the lambda if the current data pointer is not zero.

The transformation then goes like

[ CODE ... ] REST ...] ->

(letrec ((between (lambda ()
                    (TRANSLATE CODE ...)
                    (if (not (zero? vector-ref data dptr)
                        (between))))))
  (if (not (zero? (vector-ref data dptr)))
      (between)))
(TRANSLATE REST ...)

where (TRANSLATE CODE ...) translates CODE to Scheme instructions like above.