← Back to all projects

bj-jit

Just In Time BrainFuck Compiler

Mao syntax failing

Hello world in BrainFuck

Motivation

Ever since learning to create an interpreter, I had been increasingly interested in going deepr. I wanted to learn compilation, optimization and just in time compilation. I knew this was going to be a very heavy set of content to go in blindly, so I knew I wanted to implement all of this on a smaller scale to start. BrainFuck, being a very very simple turing-complete language, was the perfect target for this exactly

bf-jit provides every step of this process as independent runtime targets that can be swapped out: a basic interpreter, an assembler, an ELF64 compiler and finally a Just In Time x86-64 compiler

Implementation

Architecture Overview

The bf-jit system follows a modular architecture with a unified frontend that can target multiple backends:

Brainfuck Source -> Tokenizer -> Intermediate Representation
                                          |
                                          v
              +----------------+----------------+-----------------+
              |                |                |                 |
         Interpreter      Assembler        ELF Compiler      JIT Compiler
              |                |                |                 |
         treewalk        x86 assembly    Standalone binary   Native execution
                    

Tokenizer and Parser

The system begins with a generic tokenizer that processes Brainfuck source code into tokens representing the eight Brainfuck commands: >, <, +, -, ., ,, [, and ]. Repeated operations of the same type are compressed into a single token with repeated metadata (aside from loop boundaries)

1. Interpreter

The interpreter is the simplest backend, executing Brainfuck commands directly:

2. Assembler

The assembler backend generates x86-64 assembly code from the Brainfuck IR:

3. ELF64 Compiler

The most complex static compilation backend generates complete ELF64 executables:

4. JIT Compiler

The JIT compiler provides the speed of the compiler at the convenience level of the interpreter: