Skip to content

Instantly share code, notes, and snippets.

@dmsnell
Last active June 14, 2017 15:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmsnell/84538226462e7266e664daf8eb2fcb86 to your computer and use it in GitHub Desktop.
Save dmsnell/84538226462e7266e664daf8eb2fcb86 to your computer and use it in GitHub Desktop.
An interpreter for BF in PEGjs
// Brain-Fried Language
// Load document from this GIST for a secret message
// https://gist.githubusercontent.com/dmsnell/b5e9465e97d352556249500c80ae6cbd/raw/bf547f71291e44c890ce9fe80c3c3b5217aae715/rot13.bf
{
const stdin = 'Jbeq Pnzc'.split('').map( c => c.charCodeAt( 0 ) ).concat( 0 );
const incDP = m => Object.assign( {}, m, { dp: m.dp + 1, maxRegister: Math.max( m.maxRegister, m.dp + 1 ) } )
const decDP = m => Object.assign( {}, m, { dp: Math.max( 0, m.dp - 1 ) } )
const incB = m => {
const next = m.data.slice(); next[ m.dp ]++
return Object.assign( {}, m, { data: next } )
}
const decB = m => {
const next = m.data.slice(); next[ m.dp ]--
return Object.assign( {}, m, { data: next } )
}
const out = m => Object.assign( {}, m, { output: m.output + String.fromCharCode( m.data[ m.dp ] ) } )
const in2 = m => {
const next = m.data.slice(); next[ m.dp ] = stdin.shift()
return Object.assign( {}, m, { data: next } );
}
const jz = m => {
if ( m.data[ m.dp ] ) { return m }
// jump to matching ']'
const jump = m.program.slice( m.ip + 1 ).reduce(
( accum, opcode, address ) => {
const keepGoing = accum.keepGoing;
const depth = accum.depth;
if ( ! keepGoing ) { return accum }
if ( '[' === opcode ) { return { keepGoing: true, depth: depth + 1 } }
if ( ']' === opcode && 0 === depth ) { return { keepGoing: false, depth, index: address } }
if ( ']' === opcode ) { return { keepGoing: true, depth: depth - 1 } }
return accum
}
, { keepGoing: true, depth: 0, index: 0 }
).index
return Object.assign( {}, m, { ip: m.ip + jump } )
}
const jnz = m => {
if ( ! m.data[ m.dp ] ) { return m }
// jump to matching '['
const jump = m.program.slice( 0, m.ip ).reverse().reduce(
( accum, opcode, address ) => {
const keepGoing = accum.keepGoing;
const depth = accum.depth;
if ( ! keepGoing ) { return accum }
if ( ']' === opcode ) { return { keepGoing: true, depth: depth + 1 } }
if ( '[' === opcode && 0 === depth ) { return { keepGoing: false, depth, index: address } }
if ( '[' === opcode ) { return { keepGoing: true, depth: depth - 1 } }
return accum
}
, { keepGoing: true, depth: 0, index: 0 }
).index
return Object.assign( {}, m, { ip: m.ip - jump - 1 } )
}
const run = ( op, machine ) => {
switch ( op ) {
case ">": return incDP( machine )
case "<": return decDP( machine )
case "+": return incB( machine )
case "-": return decB( machine )
case ".": return out( machine )
case ",": return in2( machine )
case "[": return jz( machine )
case "]": return jnz( machine )
default: return machine
}
}
}
Program
= ops:OpCode*
{
const size = 10
let machine = {
program: ops,
cycles: 0,
maxRegister: 0,
ip: 0,
dp: 0,
data: new Array(size),
output: ''
};
for ( let i = 0; i < size; i++ ) { machine.data[ i ] = 0 }
const safety = 100000
for ( var i = 0; i < safety && machine.ip < machine.program.length; i++ ) {
machine = run( machine.program[ machine.ip ], machine )
machine.ip++
machine.cycles++
}
return Object.assign( machine, { program: machine.program.join('') } );
}
OpCode
= o:[><+-.,\[\]] _ { return o }
_ = (![><+-.,\[\]] .)*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment