Skip to content

Instantly share code, notes, and snippets.

@meenie
Last active May 3, 2020 15:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meenie/6b9bdce4e6b12cf8362ce9deb8f82ed4 to your computer and use it in GitHub Desktop.
Save meenie/6b9bdce4e6b12cf8362ce9deb8f82ed4 to your computer and use it in GitHub Desktop.
A Brainfuck interpreter written in TypeScript
class Brainfuck {
ptr: number = 0
cmdPtr: number = 0
data: number[] = [0]
output: any[] = []
loops: number[] = []
input: string;
arg: string;
argPtr: number = 0;
go(input: string, arg?: string) {
this.input = input;
this.arg = arg;
this.output = [];
while (this.cmdPtr < this.input.length) {
this.command(this.input[this.cmdPtr]);
this.cmdPtr++;
}
return this.output.join('');
}
private command(cmd: string) {
switch(cmd) {
case ',':
this.data[this.ptr] = (this.arg.charCodeAt(this.argPtr) || -1);
this.argPtr++;
break;
case '.':
this.output.push(String.fromCharCode(this.data[this.ptr]))
break;
case '+':
this.data[this.ptr]++;
break;
case '-':
this.data[this.ptr]--;
break;
case '>':
this.ptr++;
if (typeof this.data[this.ptr] === 'undefined') {
this.data[this.ptr] = 0;
}
break;
case '<':
if (this.ptr > 0) {
this.ptr--;
}
break;
case '[':
if (this.data[this.ptr] === 0) {
let loopDepth = 0;
for (let i = this.cmdPtr; i < this.input.length; i++) {
if (this.input[i] === ']') {
if (--loopDepth === 0) {
this.cmdPtr = i;
break;
}
} else if (this.input[i] === '[') {
loopDepth++;
}
}
} else {
this.loops.push(this.cmdPtr);
}
break;
case ']':
if (this.data[this.ptr] === 0) {
this.loops.pop();
} else {
this.cmdPtr = this.loops[this.loops.length - 1];
}
break;
}
}
}
let bf = new Brainfuck()
console.log(bf.go(`
[
ROT13 Program written in Brainfuck -- https://en.wikipedia.org/wiki/Brainfuck#ROT13
]
-,+[ Read first character and start outer character reading loop
-[ Skip forward if character is 0
>>++++[>++++++++<-] Set up divisor (32) for division loop
(MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
<+<-[ Set up dividend (x minus 1) and enter division loop
>+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward
<[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient
<<<<<- Decrement dividend
] End division loop
]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag
>--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag
++++++++++++<[ If flag then set up divisor (13) for second division loop
(MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
>-[>+>>] Reduce divisor; Normal case: increase remainder
>[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient
<<<<<- Decrease dividend
] End division loop
>>[<+>-] Add remainder back to divisor to get a useful 13
>[ Skip forward if quotient was 0
-[ Decrement quotient and skip forward if quotient was 1
-<<[-]>> Zero quotient and divisor if quotient was 2
]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1
]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
<[-] Clear remainder from first division if second division was skipped
<.[-] Output ROT13ed character from copy and clear it
<-,+ Read next character
] End character reading loop
`, 'Qbrf guvf jbex?'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment