Contains code from the presentation "How to make a simple virtual machine".
The accompanying slides are available at https://speakerdeck.com/csl/how-to-make-a-simple-virtual-machine
In the talk, I showed how to build several Brainfuck virtual machines. The aim is to teach virtual machine interpretation and compilation topics. For instance, in the first interpreter, we need a runtime stack to manage loops. In the JIT-compiler, we only use a stack during compile-time: The finished code will use addresses for jumps.
The pure Python interpreter should work on both Python 2 and 3. The
JIT-to-CPython bytecode version requires the byteplay
module, available
through pip (but only for Python 2.7):
$ pip install byteplay
Note that we use some bytecode instructions only available to Python 2.7.
Finally, the C++ JIT-compiler to machine code requires GNU Lightning. I had trouble compiling this on Linux, and I had to disable shared libraries:
$ # download GNU Lightning source code
$ ./configure --disable-shared
$ make -j
$ make check
$ make install
To build the C++ Brainfuck VM, you should now simply do
$ g++ -W -Wall -g bfloo.cpp -obfloo.cpp -llightning
For your convenience, you can also probably just do:
$ make -j
If you compiled with debug symbols, as shown above, you can disassemble the JIT-ed code with gdb or lldb:
$ gdb ./bfloo
(gdb) break Machine::run
(gdb) run examples/hello.bf
...
(gdb) print *this
{ ... { code = 0xDEADBEEF... }}
(gdb) x/i 0xDEADBEEF...
If you don't like AT&T assembly syntax, do
(gdb) set disassembly-flavor intel
Type make check
to quickly see if the VMs work. Note that the byteplay
module uses some Python instructions only available on the Python 2.7 branch.
So to run with python2.7, do
$ PYTHON=python2.7 make -e check
The Brainfuck examples were taken from the net. You can view their sources to see who made them.
Most programs take the program name as the first option. The pure Python interpreter:
$ python bf.py examples/hello.bf
To-Python bytecode JIT:
$ python bfc.py examples/hello.bf
Same, but with some optimizations:
$ python bfo.py examples/hello.bf
The Python versions take some options:
-u8 Use 8-bit memory cells
-u16 Use 16-bit memory cells
-u32 Use 32-bit memory cells
Some programs, in particular bottles.bf
, require 8-bit cells. You can also
use the option -b
to buffer output (i.e., not run flush()
for every printed
item).
The C++ VM only takes the Brainfuck files as input:
$ ./bfloo examples/hello.bf
Note that some of the optimizations in the code may be incorrect, and thus some demos may not work for the different VMs.
Also, if you like this, be sure to check out my blog post on how to write simple stack machines: https://csl.name/post/vm/
Finally, there are a lot of really cool Brainfuck interpreters, optimizers and JIT-ers on the net.
The file examples/brainfuck.bf
contains a Brainfuck interpreter written in
Brainfuck. You need to send both the program code and user input to standard
input, separated with a !
, for example:
$ echo `cat examples/primes.bf`'!40' | ./bfloo examples/brainfuck.bf
Type make profile
to time the running time of the different VMs on some
particular Brainfuck programs. If your default python version is 2.6 or lower,
this won't work; you need 2.7. You can choose another version like so:
$ PYTHON=python2.7 make -e check
Copyright (C) 2015 Christian Stigen Larsen
Distributed under the LGPL v2.1 or later. You are allowed to change the license on a particular copy to the LGPL 3.0, the GPL 2.0 or GPL 3.0.