Brainlite

Interpreter

This document describes how the interpreter works internally.

The interpreter directly executes brainfuck source code. It is not involved in brainlite compilation. If you are using brainlite, the compiler outputs a file with brainfuck code in it which can be executed anywhere needed but can be fed into this interpreter as well.

Memory

The interpreter allocates a flat 38000-byte array at startup using malloc. This is the entire memory available to a running program.

A single integer runtime_pointer tracks the current position in this array. It starts at 0.

Memory is freed when the interpreter shuts down, or immediately before any error-triggered exit.

Startup

The interpreter() function takes a source file path. It:

  1. Checks if the file exists at the current working directory. Exits with an error if not.
  2. Opens the file and reads it line by line into source_code (a std::vector<std::string>).
  3. Iterates over each line and calls parse().

Parsing

parse() walks each character in a line one at a time. Each character is treated as a token.

If a token is not in validTokens, the interpreter prints an error and exits immediately. If valid, the corresponding function from execTokens is dispatched via exec_func(). The variable validTokens is an unordered set and execTokens is unordered map.

collectedArgsLength is used to skip characters consumed by instructions like [...] so the outer loop does not re-process them.

Valid Tokens

Token Instruction
+ Increment current cell
- Decrement current cell
> Move pointer right
< Move pointer left
[ Start loop
] End loop
. Print current cell as ASCII
, Read one character from stdin into current cell

Any character not in this set is an invalid token and causes an immediate exit.

Pointer Movement

right() increments runtime_pointer. If it exceeds 37999, it prints a runtime overflow error and exits.

left() decrements runtime_pointer. If it goes below 0, it prints a runtime underflow error and exits.

Loop Handling

Loops are the most complex part of the interpreter.

When [ is encountered, the interpreter:

  1. Scans the rest of the current line to find the matching ], tracking nested brackets with a counter.
  2. If no matching ] is found on the same line, it exits with a loop-not-terminated error.
  3. Extracts the substring between [ and ].
  4. Runs that substring repeatedly via exec_func() while the current cell is non-zero.

Assumption: The closing ] must be on the same line as the opening [. This is a known design constraint.

When ] is encountered outside of a loop dispatch (i.e., as a standalone token), it decrements isLooping. If isLooping is already 0, it exits with an invalid loop termination error.

The reason for this decrement logic is to support multi-layer looping.

Error Codes

The interpreter uses integer exit codes defined elsewhere. The ones triggered here are:

End of Document

That covers the interpreter’s internal behavior. It is deliberately simple and makes no attempt at optimization.