Skip to content

Instantly share code, notes, and snippets.

@WinslowJosiah
Created February 7, 2025 11:15
Show Gist options
  • Save WinslowJosiah/75dcdc22a85601c876d151b06a5e6b0a to your computer and use it in GitHub Desktop.
Save WinslowJosiah/75dcdc22a85601c876d151b06a5e6b0a to your computer and use it in GitHub Desktop.
A brainfuck interpreter in the esolang Bespoke.
# Bespoke software for brainfuck (the esolang)
An okay interpreter that interprets commands of program in line.
- end of input = nothing is changed
- `[]` pair isn't match = `unmatched [` / `]`
- 8 bits, wrapped numbers
- the tape infinitely extends solely forward
(but, go back a lot = `out of bounds`)
- `!` in commands = input starting
I confirm (if it really succeeds) Bespoke is Turing complete. Esolangs like
brainfuck operate Turing-machine-ish, so when a program can be made for machines
which simulate a program in _that_, it is _equal_ to that.
----
A brainfuck compiler written one day by Urban Müller targeted Amiga's OS, having
a tiny filesize equaling only 240 bytes. However, coding Bespoke got _my_ code a
bit big. So let's ignore filesize (which, actually, I believe is _fine_).
It is often categorized "Turing tarpit" -- denoting language with small command
amount. Because it's so tiny, implementations can be very easy, handling eight
commands (`+`, `-`, `<`, `>`, `.`, `,`, `[`, `]`). A listing of bytes go on some
"tape", triggering commands to initiate a process of:
- `+` = add one to value
- `-` = single subtract
- `<` = travel back one
- `>` = go ahead
- `[` = a loop, if byte != 0
- `]` = looping end
- `.` = do a printing
- `,` = entering byte input
(Perhaps worded weirdly, but it fits approximately.)
----
Now to list short programs.
First program's a classic: it says "Hi!"
(It works _so_ slow -- a minor nuisance.)
>---[[<+>->->>>>-<<<<<]>]>.<<<.<.
Secondly, the "cat"; it shows inputs directly copied to output.
(A note: initiate inputted text with `!`.)
,[.[-],]
Finally, _highly_ amazing one is `dbfi.b`, and it's by Daniel Cristofani.
Requires input matching a program in BF; neatly executes programs in _itself_.
(Also, we do input with `!`.)
>>>+[[-]>>[-]++>+>+++++++[<++++>>++<-]++>>+>+>+++++[>++>++++++<<-]+>>>,<++[[>[
->>]<[>>]<<-]<[<]<+>>[>]>[<+>-[[<+>-]>]<[[[-]<]++<-[<+++++++++>[<->-]>>]>>]]<<
]<]<[[<]>[[>]>>[>>]+[<<]<[<]<+>>-]>[>]+[->>]<<<<[[<<]<[<]+<<[+>+<<-[>-->+<<-[>
+<[>>+<<-]]]>[<+>-]<]++>>-->[>]>>[>>]]<<[>>+<[[<]<]>[[<<]<[<]+[-<+>>-[<<+>++>-
[<->[<<+>>-]]]<[>+<-]>]>[>]>]>[>>]>>]<<[>>+>>+>>]<<[->>>>>>>>]<<[>.>>>>>>>]<<[
>->>>>>]<<[>,>>>]<<[>+>]<<[+<<]<]
Everything software is capable of, however, well-done input can do. Simple
puzzles for computer geniuses will interest several people (perhaps you?).
----
In this interpreter for BF (brainfuck), I consider _these_ concerns.
A number's on **heap**, or on **stack**; I did storage of programs covering
**heap**. All of program commands utilize heap, via an address with negative
numbers (-1 begins program, and then -2, -3, -4, ...). I decided numbers in
memory belonged together on heap also, but if it's _nonnegative_ at this area.
(Preserving commands, my pointed-to address won't ever reach negatives. This,
perhaps, somehow can be made not so confining; I probably _could_ generate a
formula so, when I go, it controls _endless_ numbers.)
Execution of loop has it recording the brackets level. Whenever a program is at
a singular starting bracket, _increment_; at a closing/end bracket, you go
_down_ instead. And if a bracket's position gets invalid somehow, broken program
has to send a message for it (`unmatched [` / `]`) and shouldn't still continue.
(A bracket is good if it forms a bracket grouping: a bracket at _starting_
position, then one at _closing_ position. Brackets also can be _between_ each
end of pairs.)
With brainfuck's capacity of numbers, if numbers vary past 0-255 range,
brainfuck wraps numbers between the ends. That's because values express one
byte; a typical storage of memory consists largely of this type, and an 8-bit
(or "byte") size altogether contains 0 to 255. Whenever a pointed-to address
upon plus/minus surpasses range, number's written mod 256.
(Unfortunately, it won't _for_ us; moduloing a specific value involves a command
to do a specific division, getting remainder.)
It will not be efficient, and probably fully deserves a rewrite. It is a
valuable program, however; brainfuck is a classic (old) esolang, and it will
roughly act as a workable argument that a regular Turing machine can evaluate
formulas just like Bespoke can.
## Message printing with number codepoints using Bespoke
At each nonzero stack number, remove it, then display (but as a Unicode chr).
----
Unicode messages (not really "strings", precisely) have codepoints, but it may
be odd for a programmer unschooled in this. Unicode's complex if you'd ever use
anything more than two or three typeface elements (but not a counterintuitive
idea -- by no means! -- just an annoying thing).
This is in ASCII code, however; anything ASCII is more painless overall. All the
interpreter outputs are of a relatively concise, tiny word length, containing
ASCII numbers nearing one hundred eighteen -- some times, decidedly less!
Pushing numbers near the stack's topmost locations all in sequences, a simple
function outputs characters stating the message.
----
Messages here aren't unusually large, stating useless junk. One output message
brainfuck has is `unmatched [` / `]` -- the output if bracket alignment's
invalid. And another function will print `out of bounds` when surpassing the far
limitations along the tape -- preventing a (presumably) _disastrous_
self-modification while it's in a programmed-commands area.
Now, the interpreter message has use, undoubtedly a lot -- it describes mistakes
put in the BF code -- though we still need to describe that with _lots_ of words
(one of the, if not _the_, predominant issues for one programming Bespoke). Each
word in there may be a meaningful segment, each word chosen skillfully while
keeping meaning (remarkably closely, too!).
## Read characters inputted, stopping without passing input completion or `!`
This is very much elementary.
Commands up to input's end (or `!`) are put together, going wherever a negative
heap address is. If I stop eventually, program's ultimate ending's a -1.
Keeping all that as an input, I initialize integers pointing into the program
and at memory. I also then initialize an item as zero: brackets leveling.
----
Finally, Bespoke program runs the brainfuck, and (perhaps) reaches end.
COMMENTARY INITIALIZE
Parameters: [... 0 {c ...}]
c = character codepoint
Result: [...]
COMMENTARY TERMINATED
CONTROL FUNCTION XXXX:OUTPUT CHARACTERS WHILE NONZERO
DO COPY
CONTROL WHILE
OUTPUT CH
DO COPY
CONTROL END
DO P
CONTROL END
CONTROL FUNCTION XXX:OUTPUT NEWLINE UNMATCHED
COMMENTARY INITIALIZE
Print a newline and "unmatched ".
COMMENTARY TERMINATED
PUSH NUMBERZERO
PUT XX:TRI BI
PUT XXX:I NUMBERZERO NUMBERZERO
PUT XXX:I NUMBERZERO I
PUT XXX:I NUMBERZERO FOUR
PUT XX:DIGITNINE DIGITNINE
PUT XXX:I I SEXTET
PUT XX:DIGITNINE SEVENTH
PUT XXX:I NUMBERZERO DIGITNINE
PUT XXX:I I NUMBERZERO
PUT XXX:I I SEVENTH
PUT XX:I NUMBERZERO
CONTROL CALL XXXX:OUTPUT CHARACTERS WHILE NONZERO
CONTROL END
CONTROL FUNCTION XXXX:ERROR UNMATCHED OPEN BRACKET
COMMENTARY INITIALIZE
Print a newline and "unmatched [",
and end the program.
COMMENTARY TERMINATED
CONTROL CALL XXX:OUTPUT NEWLINE UNMATCHED
PUT XX:DIGITNINE I;OUTPUT CH
CONTROL ENDPROGRAM
CONTROL END
CONTROL FUNCTION XXXX:ERROR UNMATCHED CLOSE BRACKET
COMMENTARY INITIALIZE
Print a newline and "unmatched ]",
and end the program.
COMMENTARY TERMINATED
CONTROL CALL XXX:OUTPUT NEWLINE UNMATCHED
PUT XX:DIGITNINE TRI;OUTPUT CH
CONTROL ENDPROGRAM
CONTROL END
CONTROL FUNCTION XXXX:ERROR OUT OF BOUNDS
COMMENTARY INITIALIZE
Print a newline and "out of bounds",
and end the program.
COMMENTARY TERMINATED
PUSH NUMBERZERO
PUT XXX:I I FIFTH
PUT XXX:I NUMBERZERO NUMBERZERO
PUT XXX:I I NUMBERZERO
PUT XXX:I I SEVENTH
PUT XXX:I I I
PUT XX:DIGITNINE INTEIGHT
PUT XX:TRI BI
PUT XXX:I NUMBERZERO BI
PUT XXX:I I I
PUT XX:TRI BI
PUT XXX:I I SEXTET
PUT XXX:I I SEVENTH
PUT XXX:I I I
PUT XX:I NUMBERZERO
CONTROL CALL XXXX:OUTPUT CHARACTERS WHILE NONZERO
CONTROL ENDPROGRAM
CONTROL END
COMMENTARY INITIALIZE
Parameters: [... lvl tp ip]
lvl = nesting level
tp = tape pointer
ip = instruction pointer
Result: [... lvl_ tp_ ip_ continue]
lvl_ = new nesting level
tp_ = new tape pointer
ip_ = new instruction pointer pointer
continue = 0 if at end of program, nonzero otherwise
COMMENTARY TERMINATED
CONTROL FUNCTION XXX:INTERPRET ONE COMMAND
COMMENTARY INITIALIZE
If the instruction is less than 0 (EOF)...
COMMENTARY TERMINATED
DO COPY
H V
PUSH NUMBERZERO STACKTOP LT
CONTROL IF
COMMENTARY INITIALIZE
...check the nesting level.
If it's nonzero, there was an unmatched "[".
COMMENTARY TERMINATED
PUSH TRI DO COPYN
CONTROL IF
CONTROL CALL XXXX:ERROR UNMATCHED OPEN BRACKET
CONTROL END
COMMENTARY INITIALIZE
Otherwise, end this program here.
COMMENTARY TERMINATED
PUSH NUMBERZERO
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 43 ("+")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:FOUR TRI;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...replace this tape value N
with (N+1) % 256.
COMMENTARY TERMINATED
PUSH BI DO COPYN
DO COPY
H V
STACKTOP PLUSONE
PUT XXX:BI FIFTH SEXTET;STACKTOP MODULO
DO SWITCH
H SV
COMMENTARY INITIALIZE
Move on to the next instruction.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 44 (",")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:FOUR FOUR;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...replace this tape value
with an inputted character,
if it's not less than 0 (EOF).
COMMENTARY TERMINATED
INPUT CH
DO COPY
PUSH NUMBERZERO STACKTOP LT
STACKTOP F
CONTROL IF
PUT XXX:BI FIFTH SEXTET;STACKTOP MODULO
PUSH TRI DO COPYN
H SV
DO COPY
CONTROL END
DO P
COMMENTARY INITIALIZE
Move on to the next instruction.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 45 ("-")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:FOUR FIFTH;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...replace this tape value N
with (N-1) % 256.
COMMENTARY TERMINATED
PUSH BI DO COPYN
DO COPY
H V
STACKTOP MINUSONE
PUT XXX:BI FIFTH SEXTET;STACKTOP MODULO
DO SWITCH
H SV
COMMENTARY INITIALIZE
Move on to the next instruction.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 46 (".")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:FOUR SEXTET;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...output this tape value
as a character.
COMMENTARY TERMINATED
PUSH BI DO COPYN
H V
OUTPUT CH
COMMENTARY INITIALIZE
Move on to the next instruction.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 60 ("<")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:SEXTET NUMBERZERO;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...replace the tape pointer N
with N-1.
COMMENTARY TERMINATED
DO SWITCH
STACKTOP MINUSONE
DO SWITCH
COMMENTARY INITIALIZE
If the tape pointer is less than 0,
the tape pointer is out of bounds.
COMMENTARY TERMINATED
PUSH BI DO COPYN
PUSH NUMBERZERO STACKTOP LT
CONTROL IF
CONTROL CALL XXXX:ERROR OUT OF BOUNDS
CONTROL END
COMMENTARY INITIALIZE
Move on to the next instruction.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 62 (">")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:SEXTET BI;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...replace the tape pointer N
with N+1.
COMMENTARY TERMINATED
DO SWITCH
STACKTOP PLUSONE
DO SWITCH
COMMENTARY INITIALIZE
Move on to the next instruction.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 91 ("[")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:DIGITNINE I;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...check this tape value N.
If N is nonzero,
nest and move on to the next instruction.
COMMENTARY TERMINATED
PUSH BI DO COPYN
H V
CONTROL IF
STACKTOP MINUSONE
PUSH TRI DO SWITCHN
STACKTOP PLUSONE
PUSH TRI DO SWITCHN
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
Otherwise, start a "bracket counter" at 1,
trying to find a matching 93 ("]") going forwards.
COMMENTARY TERMINATED
PUSH I
CONTROL DOWHILE
DO SWITCH
STACKTOP MINUSONE
DO COPY
PUSH TRI DO ROT
H V
COMMENTARY INITIALIZE
If this instruction is less than 0 (EOF),
there was an unmatched "[".
COMMENTARY TERMINATED
DO COPY
PUSH NUMBERZERO STACKTOP LT
CONTROL IF
CONTROL CALL XXXX:ERROR UNMATCHED OPEN BRACKET
CONTROL END
COMMENTARY INITIALIZE
If this instruction is 91 ("["),
add one to the bracket counter;
otherwise, if this instruction is 93 ("]"),
subtract one from the bracket counter.
COMMENTARY TERMINATED
DO COPY
PUT XX:DIGITNINE I;STACKTOP MINUS
STACKTOP F
CONTROL IF
DO P
STACKTOP PLUSONE
CONTROL OTHERWISE
DO COPY
PUT XX:DIGITNINE TRI;STACKTOP MINUS
STACKTOP F
CONTROL IF
DO P
STACKTOP MINUSONE
CONTROL OTHERWISE
DO P
CONTROL END
CONTROL END
COMMENTARY INITIALIZE
Stop looping if the bracket counter is 0.
COMMENTARY TERMINATED
DO COPY
CONTROL END
COMMENTARY INITIALIZE
Clean up the bracket counter,
and move just past the bracket.
COMMENTARY TERMINATED
DO P
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If the instruction is 93 ("]")...
COMMENTARY TERMINATED
DO COPY
H V
PUT XX:DIGITNINE TRI;STACKTOP MINUS
STACKTOP F
CONTROL IF
COMMENTARY INITIALIZE
...check this tape value N.
If N is zero,
denest and move on to the next instruction.
COMMENTARY TERMINATED
PUSH BI DO COPYN
H V
STACKTOP F
CONTROL IF
STACKTOP MINUSONE
PUSH TRI DO SWITCHN
STACKTOP MINUSONE
PUSH TRI DO SWITCHN
COMMENTARY INITIALIZE
If the nesting level is less than 0,
there was an unmatched "]".
COMMENTARY TERMINATED
PUSH TRI DO COPYN
PUSH NUMBERZERO STACKTOP LT
CONTROL IF
CONTROL CALL XXXX:ERROR UNMATCHED CLOSE BRACKET
CONTROL END
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
Otherwise, start a "bracket counter" at 1,
trying to find a matching 91 ("[") going backwards.
COMMENTARY TERMINATED
PUSH I
CONTROL DOWHILE
DO SWITCH
STACKTOP PLUSONE
DO COPY
PUSH TRI DO ROT
COMMENTARY INITIALIZE
If the instruction pointer is not less than 0,
there was an unmatched "]".
COMMENTARY TERMINATED
DO COPY
PUSH NUMBERZERO STACKTOP LT
STACKTOP F
CONTROL IF
CONTROL CALL XXXX:ERROR UNMATCHED CLOSE BRACKET
CONTROL END
COMMENTARY INITIALIZE
If this instruction is 91 ("["),
subtract one from the bracket counter;
otherwise, if this instruction is 93 ("]"),
add one to the bracket counter.
COMMENTARY TERMINATED
H V
DO COPY
PUT XX:DIGITNINE I;STACKTOP MINUS
STACKTOP F
CONTROL IF
DO P
STACKTOP MINUSONE
CONTROL OTHERWISE
DO COPY
PUT XX:DIGITNINE TRI;STACKTOP MINUS
STACKTOP F
CONTROL IF
DO P
STACKTOP PLUSONE
CONTROL OTHERWISE
DO P
CONTROL END
CONTROL END
COMMENTARY INITIALIZE
Stop looping if the bracket counter is 0.
COMMENTARY TERMINATED
DO COPY
CONTROL END
COMMENTARY INITIALIZE
Clean up the bracket counter,
and move just past the bracket.
COMMENTARY TERMINATED
DO P
STACKTOP MINUSONE
PUSH I
CONTROL RETURN
CONTROL END
COMMENTARY INITIALIZE
If we're here, the instruction did nothing;
move on to the next instruction anyway.
COMMENTARY TERMINATED
STACKTOP MINUSONE
PUSH I
CONTROL END
COMMENTARY INITIALIZE
First, read the program from input,
and store its characters on the heap
from address -1 downward.
COMMENTARY TERMINATED
PUSH NUMBERZERO
STACKTOP MINUSONE
CONTROL DOWHILE
INPUT CH
COMMENTARY INITIALIZE
If this character is less than 0 (EOF),
or if this character is equal to 33 ("!")...
COMMENTARY TERMINATED
DO COPY
DO COPY
PUSH NUMBERZERO STACKTOP LT
DO SWITCH
PUT XX:TRI TRI;STACKTOP MINUS
STACKTOP F
STACKTOP PLUS
CONTROL IF
COMMENTARY INITIALIZE
...replace the value with -1,
and stop processing input.
COMMENTARY TERMINATED
DO P
PUSH NUMBERZERO
STACKTOP MINUSONE
CONTROL B
CONTROL END
PUSH BI DO COPYN
H SV
STACKTOP MINUSONE
PUSH I
CONTROL END
DO SWITCH
H SV
COMMENTARY INITIALIZE
Initialize the nesting level to 0,
the tape pointer to 0,
and the instruction pointer to -1.
COMMENTARY TERMINATED
PUSH NUMBERZERO
DO COPY
DO COPY
STACKTOP MINUSONE
COMMENTARY INITIALIZE
Finally, interpret the program
one instruction at a time.
COMMENTARY TERMINATED
CONTROL DOWHILE
CONTROL CALL XXX:INTERPRET ONE COMMAND
CONTROL END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment