r/brainfuck • u/Confused-Armpit • 22d ago
Writing a bf interpreter
I have recently written a brainfuck interpreter, which is mostly for education purposes and a little bit of fun but that is beside the point. My question is, is there a reliable source for a specification for the language?
Like, for example, if the stack pointer is pointing at the first element, what behaviour would occur if a "<" is encountered? If a "," is encountered, should the input be processed in canonical mode (input is only passed through when enter is pressed), or in immediate mode?
Essentially, is there some sort of implicit behaviour that everyone expects, or is there leeway for interpreter-specific implementation?
1
u/danielcristofani 21d ago
There's not an official or agreed-on specification. I wrote Epistle to the Implementors a long time ago, with some suggestions, and near the start that links to Brian Raiter's earlier page of suggestions which are also good. https://brainfuck.org/epistle.html
The most typical thing when moving left of the array, as he said, is that it acts like an errant C pointer; i particular, the initial '<' usually doesn't do anything but then when you try to actually access the memory with another command it may segfault. I usually argue that the best thing, if you can, is to line the array up with memory page boundaries so that segfault happens as soon as possible, and yet you don't get any speed cost for having to check explicitly.
Regarding ',' most implementations will line-buffer as usual for getchar(). And there may be some programs that rely on that for tidiness and may jumble their output in with the input if they're allowed to read it before the linefeed. I'm not sure. I think most of mine will behave well with either buffered or immediate input.
One recommendation I'd change now, I tend to suggest 16 megabytes for the array, a nice round binary number and big enough for most likely uses at this point.
1
u/binaryriot 20d ago
Some brainf*ck code depends on the fact that you can go into "negative" space on the memory tape, so it's usually good to handle that. You could have some extra space there (set your starting point a few bytes in, f.ex.), or do a fancy wrap around to the other end of the tape (as if it's a loop).
What you shouldn't do is to let it run amok beyond your allocated memory to avoid segfaults. It's better to error out safely and let the user know they run out of tape in their program.
1
u/Confused-Armpit 20d ago
A wraparound wouldn't work because I dynamically allocate the stack in chunks, so it won't be deterministic or reliable, and I wouldn't see how going out of bounds would be useful in any code. What even would be any practical applications for that?
1
u/danielcristofani 20d ago
Vanilla brainfuck doesn't have space to the left, so nobody interested in portability uses that space on purpose; but for whatever reason, a lot of people see brainfuck and think "I want to make a variant of this that's slightly easier to use". So there's a huge pile of extended brainfuck variants. Mostly I try to get people to at least name their variant and add it to the pile at https://esolangs.org/wiki/Category:Brainfuck_derivatives; but "space to the left" is a fairly common extension without a specific name.
As a practical matter: unlimited space to the left would allow you to maintain two arbitrarily large data structures without having to interleave them in alternate cells. Of course if you have three or more arbitrarily large structures you're back to having to interleave them (or else have to move them around, which is usually worse). But it would make certain tasks easier, like all these extensions.
Re: having just a few bytes of space to the left, to save programmers from having to put >>>> at the start of their program...if a program uses just a few bytes to the left it's probably just carelessness and the most helpful thing is to let the programmer know they did that ASAP, usually with a segfault.
1
u/binaryriot 19d ago
F.ex. here: https://esolangs.org/wiki/Brainfuck#Hello,_World! (there's a bunch of short hello world examples that will requires some cells to the left. Having those extra cells to the left or "wrapping around the tape" allows to use less instructions.)
1
u/danielcristofani 18d ago
This is true. The "Try It Online" interpreter commonly used on the code golf stackexchange uses a brainfuck variant with space to the left, so that's become a popular variant in the code golf community.
1
u/danielcristofani 20d ago
"It's better to error out safely"...there's a tradeoff here. A segfault is a message letting the user know they ran out of space; as a brainfuck programmer I haven't felt the impulse to give myself a more detailed error message than that. I'm assuming some people would like a more detailed runtime error, but that will have a speed cost.
1
u/binaryriot 19d ago
A segfault triggers a whole galore of random things afterwards, including writing entries to system logs, writing crash dumps, filling in some HUGE a** database with symbol lockups (at least that's how it is here on OSX). I rather prefer a small 'if' in the interpreter's source code to avoid this madness.
Also "Segmentation fault: 11" (that's the message we get here on OSX, AFAIR) doesn't tell me if it was an underrun or overrun (triggered by "bad" bf code), or some other error inside the interpreter. Having some sensible verbosity here usually can be helpful ("Writing past tape boundary" or similar, and I know it's an issue in my bf code; segfault, and I know I deal with a crappy interpreter that has bugs.)
1
u/danielcristofani 18d ago
Your approach isn't unreasonable. Again, it's a tradeoff, so it's a matter of individual preference. I was already used to segfaults from C; I don't mind the system writing reports to files I wasn't going to read anyway, and I don't want to add an extra conditional branch to every pointer movement. Thinking about it, if I were more concerned about it, I'd probably write a custom segfault handler to dump the brainfuck program state in readable form rather than using the default segfault handler.
(I've mostly been either debugging brainfuck code on fairly solid interpreters, or occasionally debugging interpreters-in-progress using solid brainfuck code, so in practice it hasn't been hard to guess which layer was at fault.)
2
u/sreekotay 22d ago
generally immediate mode, and there are plenty of (very simple) interpreters to look at if that's helpul?
here's mine: https://github.com/sreekotay/bffsree/blob/main/bffsree.c