57 lines
2.0 KiB
Markdown
57 lines
2.0 KiB
Markdown
# Brainfuck2Scheme
|
|
|
|
A simple compiler from Brainfuck to R5RS. The compiler will output a Scheme
|
|
list that is a lambda with three arguments:
|
|
|
|
* `data`: The data vector.
|
|
* `dptr`: The initial data pointer.
|
|
* `debugger`: Debugger function
|
|
|
|
To turn the list into an executable Scheme function, just give it to
|
|
`eval`. `(execute scheme len)` will run the Scheme code in `scheme`
|
|
with a data vector of length `len`.
|
|
|
|
This dialect of Brainfuck supports `#` to call the `debugger` procedure
|
|
with `data` and `dptr` as arguments.
|
|
|
|
Since Brainfuck programs become Scheme procedures, you can modularize
|
|
Brainfuck code and (ab)use the debugger for things like procedure calls
|
|
and foreign libraries.
|
|
|
|
## 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))`
|
|
* `#` -> `(debugger data dptr)`
|
|
|
|
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.
|