Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bfjit

bfjit is a Brainfuck JIT compiler written in Zig. It reads a Brainfuck file, folds runs of simple commands together, emits x86-64 machine code, and runs that code in the same process.

The code is small enough to study without much compiler background. The machine-code emitter is handwritten, so there is no LLVM or other compiler framework involved.

Requirements

Building and running

Build the executable:

zig build

Run the included Hello World program:

zig build run -- hello_world.bf

You can also run the installed binary directly:

./zig-out/bin/bfjit hello_world.bf

bfjit expects one source file. If the program uses ,, it reads raw bytes from standard input. For example, save ,. in a file named echo.bf, then run:

printf 'A' | zig build run -- echo.bf

The program prints A.

Language behavior

All eight Brainfuck commands work:

Commands What they do
+ / - Increment or decrement the current cell
> / < Move the tape pointer right or left
. Write the current byte to standard output
, Read one byte from standard input into the current cell
[ / ] Loop while the current cell is nonzero

The tape has 30,000 u8 cells, all initialized to zero. Cell arithmetic wraps at 0 and 255. Reading at EOF stores zero in the current cell. The parser ignores non-command bytes, so comments and whitespace are fine.

The parser reports unmatched brackets with their byte offset. Moving outside the 30,000-cell tape stops the program with an error. Source files may be up to 1 MiB.

What happens when a program runs

Brainfuck source
      -> compact IR
      -> x86-64 machine bytes
      -> executable memory
      -> native function call

The parser combines adjacent cell changes and pointer moves. For example, +++++-- becomes one add 3 operation. The x86-64 backend turns those operations into machine-code bytes and turns loops into conditional jumps.

Input and output go through C ABI callbacks into Zig. This keeps Zig's buffered standard streams out of the generated code. The generated memory starts out writable so the compiler can fill it, then changes to read-execute before the function call.

Note

This version only supports the Linux x86-64 System V ABI. It has no interpreter mode or advanced optimization passes.

About

A JIT compiler for brainf**k, implemented in zig (original idea by @tsoding)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages