Brainfuck compiler
by mcsf
JavaScript
// h e l l o !
// [104, 101, 108, 108, 111, 33]
SOURCE = `
++++++++++
[ > ++++++++++ < - ]
> ++++ .
--- .
< ++ [ > ++++ < - ]
> - ..
+++ .
< ++++++++
[ > ---------- < - ]
> ++ .
`
DATA_SIZE = 3
function compile(source) {
let pc = 0
const program = [], stack = [];
[].slice.call(source).forEach((char) => {
switch (char) {
case '+':
case '-':
case '>':
case '<':
case '.':
case ',':
program.push([char])
break
case '[':
program.push([char])
stack.push(pc)
break
case ']': {
if (! stack.length) throw new Error('Unexpected "]": empty stack.')
const jmpPc = stack.pop()
program.push([char, jmpPc])
program[jmpPc][1] = pc
break
}
case '\n':
case ' ':
pc--
break
default:
throw new Error('Illegal character.')
}
pc++
})
if (stack.length) throw new Error('Unexpected end of program: stack not empty.')
program.push(['END'])
return program
}
function execute(program) {
let pc = 0, ptr = 0
const data = new Array(DATA_SIZE), output = []
for (let i = 0; i < data.length; i++) data[i] = 0
let time = 2000
while (program[pc][0] !== 'END' && ptr < DATA_SIZE) {
if (time-- < 0) throw new Error('Aborted.')
const [operator, operand] = program[pc]
switch (operator) {
case '+': data[ptr]++; break
case '-': data[ptr]--; break
case '>': ptr++; break;
case '<': ptr--; break
case '.': output.push(data[ptr]); break
case ',': data[ptr] = prompt(); break
case '[': if (! data[ptr]) pc = operand; break
case ']': if (data[ptr]) pc = operand; break
case 'END': return
}
pc++
}
return [data, output]
}
{
const program = compile(SOURCE)
console.log('program', program)
const [data, output] = execute(program)
console.log('execute', data, output)
const string = output.map(c =>...