{"id":19989772,"url":"https://github.com/inspiaaa/bfinterpreter","last_synced_at":"2026-06-11T10:31:30.489Z","repository":{"id":108959768,"uuid":"424985324","full_name":"Inspiaaa/BfInterpreter","owner":"Inspiaaa","description":"Optimising interpreter for the esoteric Brainf#@% programming language written in Nim.","archived":false,"fork":false,"pushed_at":"2022-01-23T20:12:48.000Z","size":137,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-01T21:52:24.108Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Inspiaaa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-05T14:55:26.000Z","updated_at":"2021-11-20T23:51:19.000Z","dependencies_parsed_at":"2023-08-25T20:16:37.882Z","dependency_job_id":null,"html_url":"https://github.com/Inspiaaa/BfInterpreter","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Inspiaaa/BfInterpreter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inspiaaa%2FBfInterpreter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inspiaaa%2FBfInterpreter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inspiaaa%2FBfInterpreter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inspiaaa%2FBfInterpreter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Inspiaaa","download_url":"https://codeload.github.com/Inspiaaa/BfInterpreter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inspiaaa%2FBfInterpreter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34195112,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T04:50:05.418Z","updated_at":"2026-06-11T10:31:30.464Z","avatar_url":"https://github.com/Inspiaaa.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Nim BFI\n\nOptimising interpreter for the esoteric [Brainf#@%](https://en.wikipedia.org/wiki/Brainfuck) programming language written in Nim.\n\n### CLI Usage:\n\n```shell\nUsage:\n  bfi {SUBCMD}  [sub-command options \u0026 parameters]\nwhere {SUBCMD} is one of:\n  help     print comprehensive or per-cmd help\n  r        Runs the interpreter.\n  inspect  Prints the first n instructions of the optimized code.\n\nUsage:\n  bfi r [optional-params]\nRuns the interpreter.\nOptions:\n  -h, --help                       print this cligen-erated help\n  --help-syntax                    advanced: prepend,plurals,..\n  -f=, --file=      string  \"\"     Path to the file with the BF code\n  -c=, --code=      string  \"\"     Directly enter BF code as a string\n  -n, --noOpt       bool    false  Flag to disable optimizations\n  -i=, --input=     string  \"\"     Path to the input data; Uses stdin if none specified\n  -o=, --output=    string  \"\"     Path to the output file; Uses stdout if none specified\n  -s, --silent      bool    false  Flag that, when provided, prevents the interpreter from outputting any text\n  -t=, --tapeSize=  int     30000  Number of cells in the tape. Dynamically grows the tape for tapeSize=-1\n\nUsage:\n  bfi inspect [optional-params]\nPrints the first n instructions of the optimized code.\nOptions:\n  -h, --help                  print this cligen-erated help\n  --help-syntax               advanced: prepend,plurals,..\n  -f=, --file=    string  \"\"  set file\n  -c=, --code=    string  \"\"  set code\n  -o=, --output=  string  \"\"  set output\n  -n=, --number=  int     -1  set number\n```\n\n### CLI Examples:\n\n```shell\n# Execute code from a file\nbfi r -f examples/mandelbrot.bf\n\n# Write the output to a file\nbfi r -f examples/mandelbrot.bf -o mandelbrot.txt\n\n# Disable optimization\nbfi r -f examples/mandelbrot.bf -n\nbfi r -f examples/mandelbrot.bf --noOpt\n\n# Execute a string directly, prints \"Hello World!\"\nbfi r -c \"-\u003e+\u003e\u003e\u003e+\u003e\u003e-[++++++[\u003e+++++++++\u003e+++++\u003e+\u003c\u003c\u003c-]\u003c+]\u003e\u003e.\u003e--.-\u003e++..\u003e\u003e+.\u003e-[\u003e.\u003c\u003c]\u003e[\u003e]\u003c\u003c+.\"\n\n# Silent: Prevents the program from outputting any text, useful for benchmarking\nbfi r -f examples/hanoi.bf -s\n\n# Set the size of the tape\nbfi r -f examples/hanoi.bf -t 1000\nbfi r -f examples/hanoi.bf -tapeSize 1000\n# Let the tape dynamically grow as it needs more cells\nbfi r -f examples/hanoi.bf -t -1\n\n# Prints the instructions of the optimized code in the console.\nbfi inspect -c \"\u003e\u003e\u003e+++[-\u003e+\u003c]\"\n\n# Prints the first 100 instructions of mandelbrot.bf\nbfi inspect -f examples/mandelbrot.bf -n 100\n```\n\n### Compilation\n\n```batch\nnimble install cligen\nnim c --out:bfi.exe -d:danger --gc:markAndSweep src/cli.nim\n```\n\nThe `-d:danger` flag makes the program run faster at the cost of runtime checks. This flag can of course be omitted when compiling.\n\nIt uses `cligen` for making the command line interface.\n\n### Using the Nim API\n\nSee the `example.nim` file for a full example.\n\n```nim\nimport std/streams\nimport ./src/optimizing_interpreter\n\nlet code = \"\"\"\n\"-\u003e+\u003e\u003e\u003e+\u003e\u003e-[++++++[\u003e+++++++++\u003e+++++\u003e+\u003c\u003c\u003c-]\u003c+]\u003e\u003e.\u003e--.-\u003e++..\u003e\u003e+.\u003e-[\u003e.\u003c\u003c]\u003e[\u003e]\u003c\u003c+.\"\n\"\"\"\n\n# Option A:\nrun(code, newStringStream(\"\"), newFileStream(stdout))\n\n\n# Option B:\nimport ./src/ir\nvar instructions: seq[Instr] = parse(code)\ninstructions = optimize(instructions)\naddJumpInformation(instructions)\n\n# Inspect the optimized instructions\nfor i in instructions[0..\u003clen(instructions)]:\n    echo i\n\nrun(instructions, newStringStream(\"\"), newFileStream(stdout))\n```\n\n# Optimiser\n\nThis project executes BF code with an interpreter.\n\nOne of the tricks to increase the performance of an interpreted language, is to interpret less, i.e. spending less time interpreting instructions and more time actually doing something meaningful. Generally higher-level interpreted languages are faster than lower-level interpreted languages, as they can achieve the same result with fewer instructions, meaning that more of the functionality is implemented in the optimised interpreter code instead of emulated via instructions.\n\nThis is also the fundamental idea of many BF optimisers: To reduce common patterns to single instructions that are efficiently implemented in the underlying language, here: Nim.\n\nFor example, to increment the current cell by 4, in BF you'd write: `++++`. The optimised code is: `Add(4)` (One instruction, not four).\n\n### Normal instructions\n\n| Instruction | Meaning                                                             |\n| ----------- | ------------------------------------------------------------------- |\n| `\u003e`         | Move the pointer to the right by 1 block.                           |\n| `\u003c`         | Move the pointer to the left by 1 block.                            |\n| `+`         | Increment the current block.                                        |\n| `-`         | Decrement the current block.                                        |\n| `[`         | Jump to the corresponding `]` if the current block is `0`.          |\n| `]`         | Jump back to the corresponding `[` if the current block is not `0`. |\n| `.`         | Write the current block as an ASCII character.                      |\n| `,`         | Read one byte from the input stream into the current block.         |\n\n### Expanded instruction set ([ir.nim](https://github.com/Inspiaaa/BfInterpreter/blob/master/src/ir.nim))\n\n| Instruction   | BF Example           | Meaning                                                                  |\n| ------------- | -------------------- | ------------------------------------------------------------------------ |\n| opAdd         | `+`, `+++`           | Performs multiple `+` instructions at once.                              |\n| opSub         | `-`, `---`           | ...                                                                      |\n| opMove        | `\u003e`, `\u003c`, `\u003e\u003e\u003e`      | Performs multiple `\u003e` or `\u003c` instructions at once.                       |\n| opLoopStart   | `[`                  |                                                                          |\n| opLoopEnd     | `]`                  |                                                                          |\n| opWrite       | `.`                  |                                                                          |\n| opRead        | `,`                  |                                                                          |\n| opClear       | `[-]`,`[+]`          | Clears the current cell.                                                 |\n| opSet         | `[-]+++`             | Sets the current cell to a value.                                        |\n| opScan        | `[\u003e]`,`[\u003c]`, `[\u003e\u003e\u003e]` | Moves to the next empty cell by jumping certain increments.              |\n| opCopyAdd     | `[-\u003e+\u003c]`             | Adds the current cell to another cell.                                   |\n| opCopySub     | `[-\u003e-\u003c]`             | Subtracts ...                                                            |\n| opMulAdd      | `[-\u003e+++\u003c]`           | Adds the current cell times a multiplication factor to another cell.     |\n| opMulSub      | `[-\u003e---\u003c]`           | Subtracts ...                                                            |\n| opAddAtOffset | `\u003e\u003e\u003e+`, `\u003c+++`       | Adds the current cell to another cell without changing the cell pointer. |\n| opSubAtOffset | `\u003e\u003e\u003e-`, `\u003c---`       | Subtracts ...                                                            |\n\n### Optimisation phases\n\n1. **Parsing**\n\n   Converts the string instructions into `Instr` objects. Already fuses multiple `+`,`-`, `\u003e` and `\u003c` instructions into one instruction (opAdd, opSub, and opMove, respectively). This makes the subsequent optimisation phase faster and simpler.\n\n2. **Advanced optimisations**\n\n   1. Clear loops\n\n   2. Scan loops\n\n   3. Copy loops\n\n   4. Multiplication loops\n\n   5. \"Lazy movements\" (Operation at an offset)\n\n3. **Jump table creation**\n\n   In order to not have to search for the corresponding bracket of a `[` and `]` instruction, precompute the target jump locations before executing the program. E.g. First `[` instruction jumps to index 10...\n\n4. **Execution**\n\n### Example\n\nStart of mandelbrot.bf (with comments):\n\n```\n+++++++++++++                             # A\n[-\u003e++\u003e\u003e\u003e+++++\u003e++\u003e+\u003c\u003c\u003c\u003c\u003c\u003c]                 # B\n\u003e\u003e\u003e\u003e\u003e++++++\u003e---\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e+++++++++++++++  # C\n[[\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e]                              # D\n# ...\n```\n\nFirst 14 instructions of the optimised code (`bfi inspect -f examples/mandelbrot.bf -n 14`) (with comments):\n\n```\n# A\n(opAdd, value: 13)\n\n# B\n(opLoopStart, pos: 7)\n(opMulAdd, offset: 1, factor: 2)\n(opMulAdd, offset: 4, factor: 5)\n(opMulAdd, offset: 5, factor: 2)\n(opCopyAdd, offset: 6)\n(opClear)\n(opLoopEnd, pos: 1)\n\n# C\n(opAddAtOffset, offset: 5, value: 6)\n(opSubAtOffset, offset: 6, value: 3)\n(opAddAtOffset, offset: 16, value: 15)\n(opMove, offset: 16)\n\n# D\n(opLoopStart, pos: 18)\n(opScan, offset: 9)\n```\n\n---\n\n## Unscientific Benchmarks\n\n`bench/bench.nim` (`nim c -r -d:danger --gc:markAndSweep bench/bench.nim`)\n\nRuns the interpreter in silent mode, i.e. doesn't print anything to the console.\n\n| Input program     | Unoptimised Time / s | Optimised Time / s |\n| ----------------- | -------------------- | ------------------ |\n| **mandelbrot.bf** | 13.081               | **2.722**          |\n| **hanoi.bf**      | 8.123                | **0.138**          |\n\n---\n\n## Further reading\n\nhttps://www.nayuki.io/page/optimizing-brainfuck-compiler\n\nhttp://calmerthanyouare.org/2015/01/07/optimizing-brainfuck.html\n\n[Basics of BrainFuck · GitHub](https://gist.github.com/roachhd/dce54bec8ba55fb17d3a)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finspiaaa%2Fbfinterpreter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finspiaaa%2Fbfinterpreter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finspiaaa%2Fbfinterpreter/lists"}