// HACKER NEWS — CYBERSECURITY
I wrote a ray tracer in Brainfuck
As I was preparing for a systems programming competition in C++, I began to relearn CMake, as Cargo had spoilt me too much in the meantime, and I noticed an interesting claim in the tutorial.
Oftentimes the correct answer is to write a tool in a general purpose
programming language which solves the problem, and teach CMake how to invoke
that tool as part of the build process. Code generation, cryptographic
signature utilities, and even ray-tracers have been written in CMake Language,
but this is not a recommended practice.
Having written a raytracer earlier, and re-written it for the GPU, this statement caught my eye and made me wonder what would be an even better language to write a raytracer in.
The last re-write involved writing code which had little of a first-principles based approach and mostly depended on a comparatively more complex set of APIs. So I picked the simplest language I knew, BF, because a simple language obviously results in a very simple codebase. In fact, codebases in BF regularly tend to be only a few lines long. Further, Muller’s comment in the README made me want to show a counter example.
BF is a decidedly simple language, involving only 8 operations and one “data structure”: a one-sided infinite tape of cells, each capable of storing a u8.
On seeing the character >, the data pointer, which points to a cell on the tape, moves rightward, and vice versa on <.
I/O is managed through , and .. The first stores the input byte where the data pointer points and the latter prints it out.
The only primitives other than I/O which allow changing a value are increment and decrement at the data pointer, through + and -.
The limitations should be obvious: there are no n > 1 registers as other machines tend to have, no instruction operating on more than one cell, and no instructions for addition or multiplication.
The last ingredient required to make BF Turing-complete is its loop, written using [ and ]. When the token [ is met, the runtime checks the cell at the data pointer: if it is zero, execution jumps past the matching ], otherwise it enters the loop. At ], it returns to the matching [ if the cell is non-zero and exits the loop otherwise.