This is the companion code repository for the article Learn Assembly with Entirely Too Many Brainfuck Compilers. The code is 100% safe Rust and dependency-free.
Quick links:
- interpreter source
- x86 compiler source
- ARM compiler source
- WebAssembly compiler source
- LLVM compiler source
To run all the code in this repo you need the following: an x86_64 host machine, Rust installed, and Docker installed. I can't help you with the first requirement but for the latter two requirements:
- if you don't have Rust installed the preferred way to install and manage the Rust toolchain on your machine is to install rustup
- if you don't have Docker installed you can find the installation instructions on the Docker website
Once you have completed the above requirements the next step is to use Rust's package manager, Cargo, to install the Just command runner with cargo install just
. Make sure you have $HOME/.cargo/bin
in your PATH
.
The final setup step is to run just build-env
which builds a Docker image on your machine from this Dockerfile. Running this command may take a few minutes. The Docker image contains all the necessary dependencies to build and run all the examples in this repo.
All examples are in the ./examples/
directory of this repo. All of the commands below only work if you've already run just build-env
as instructed above.
carx
is short for "compile and run x86_64 example" and {{name}}
is the name of the x86_64 source file (without .s
extension) in the ./examples/x86_64/
directory. This command also automatically appends Exit code: <code>
to the end of the program's output which logs which code it exited with.
Example
> just carx hello_world
Hello world!
Exit Code: 0
cara
is short for "compile and run aarch64 example" and {{name}}
is the name of the aarch64 source file (without .s
extension) in the ./examples/aarch64/
directory. This command also automatically appends Exit code: <code>
to the end of the program's output which logs which code it exited with.
Example
> just cara hello_world
Hello world!
Exit Code: 0
carw
is short for "compile and run WebAssembly example" and {{name}}
is the name of the WebAssembly source file (without .wat
extension) in the ./examples/wasm32_wasi/
directory. This command also automatically appends Exit code: <code>
to the end of the program's output which logs which code it exited with.
Example
> just carw hello_world
Hello world!
Exit Code: 0
carl
is short for "compile and run LLVM IR example" and {{name}}
is the name of the LLVM IR source file (without .ll
extension) in the ./examples/llvm_ir/
directory. This command also automatically appends Exit code: <code>
to the end of the program's output which logs which code it exited with.
Example
> just carl hello_world
Hello world!
Exit Code: 0
All of the brainfuck source files are in the ./input
directory.
{{name}}
is the name of the brainfuck source file (without .b
extension) in the ./input/
directory.
Example
> just interpret hello_world
Hello world!
All of the brainfuck source files are in the ./input
directory. All of the commands below only work if you've already run just build-env
as instructed above.
carbx
is short for "compile and run brainfuck to x86_64" and {{name}}
is the name of the brainfuck source file (without .b
extension) in the ./input/
directory. The output x86_64 source file is written to ./output/x86_64/{{name}}.s
and then assembled and run immediately.
Example
> just carbx hello_world
Hello world!
carba
is short for "compile and run brainfuck to aarch64" and {{name}}
is the name of the brainfuck source file (without .b
extension) in the ./input/
directory. The output aarch64 source file is written to ./output/aarch64/{{name}}.s
and then assembled and run immediately.
Example
> just carba hello_world
Hello world!
carbw
is short for "compile and run brainfuck to WebAssembly" and {{name}}
is the name of the brainfuck source file (without .b
extension) in the ./input/
directory. The output WebAssembly source file is written to ./output/wasm32_wasi/{{name}}.wat
and then run immediately.
Example
> just carbw hello_world
Hello world!
carbl
is short for "compile and run brainfuck to LLVM IR" and {{name}}
is the name of the brainfuck source file (without .b
extension) in the ./input/
directory. The output LLVM IR source file is written to ./output/llvm_ir/{{name}}.ll
and then assembled and run immediately.
Example
> just carbl hello_world
Hello world!
cbat
is short for "compile brainfuck to all targets" and {{name}}
is the name of the brainfuck source file (without .b
extension) in the ./input/
directory. The output files are written to the ./output/
directory in their relevant subdirectories.
Example
> just cbat hello_world
Times how long it takes to interpret and run the compiled versions of {{name}}
where name is the name of the brainfuck source file (without .b
extension) in the ./input/
directory. If this command doesn't work for whatever reason it's because you should run just cbat {{name}}
first.
> just cbat mandelbrot
> just benchmark mandelbrot
# program outputs omitted
# interpreted mandelbrot.b
4.95s user 0.01s system 99% cpu 4.960 total
# x86_64 compiled mandelbrot.b
real 0m1.214s
user 0m1.149s
sys 0m0.041s
# aarch64 compiled mandelbrot.b
real 0m4.206s
user 0m4.103s
sys 0m0.083s
# wasm32-wasi compiled mandelbrot.b
real 0m1.480s
user 0m1.429s
sys 0m0.046s
# llvm-ir compiled mandelbrot.b
real 0m0.896s
user 0m0.887s
sys 0m0.001s
To be compatible with Rust, all code in this repository (unless otherwise stated in the source file) is licensed under Apache License Version 2.0 or MIT License, at your option.