Brainsource - regex-based brainfuck interpreter written in functional Javascript
//////////////////////////////////////////////////////////////////////////////// | |
//* *// | |
// - B R A I N S O U R C E - // | |
// Regex-based brainfuck interpreter written in functional Javascript // | |
// Author: Angelos Chalaris (chalarangelo@gmail.com) // | |
// License: MIT License - https://opensource.org/licenses/MIT // | |
// Note: Certain parts might be slow, buggy or even not work at all. Use at // | |
// your own risk. // | |
//* *// | |
//////////////////////////////////////////////////////////////////////////////// | |
// Replaces 'regex' with 'replacement' in 'str' | |
// Curry function, usage: replaceRegex(regexVar, replacementVar) (strVar) | |
const replaceRegex = function(regex, replacement){ | |
return function(str){ | |
return str.replace(regex, replacement); | |
} | |
} | |
// Regular expressions that parse brainfuck | |
const parseProgram = replaceRegex(/[^\>\<\[\]\+\-\.\,]/g, ''); | |
const tokenizeNumericIncrements = replaceRegex(/\+{1,9}/g, function(m){return '+'+m.length;}); | |
const tokenizeNumericDecrements = replaceRegex(/\-{1,9}/g, function(m){return '-'+m.length;}); | |
const tokenizePointerIncrements = replaceRegex(/\>{1,9}/g, function(m){return '>'+m.length;}); | |
const tokenizePointerDecrements = replaceRegex(/\<{1,9}/g, function(m){return '<'+m.length;}); | |
const tokenizeOutputs = replaceRegex(/\.{1,9}/g, function(m){return '.'+m.length;}); | |
const tokenizeInputs = replaceRegex(/\,{1,9}/g, function(m){return ','+m.length;}); | |
const tokenizeLoopStarts = replaceRegex(/\[/g, function(m){return '[:';}); | |
const tokenizeLoopEnds = replaceRegex(/\]/g, function(m){return ';]';}); | |
// Parses and tokenizes brainfuck source code | |
const parseAndTokenize = function(str) { | |
return tokenizeLoopEnds(tokenizeLoopStarts(tokenizeInputs( | |
tokenizeOutputs(tokenizePointerDecrements(tokenizePointerIncrements( | |
tokenizeNumericDecrements(tokenizeNumericIncrements( | |
parseProgram(str) | |
)) | |
))) | |
))); | |
} | |
// Produces a bracket map from a given brainfuck source | |
const buildBracketMap = function(str){ | |
var leftBrackets = [], rightBrackets = [], bracketMap = {}; | |
for (var i = 0; i< str.length; i+=2){ | |
if(str[i] == '[') leftBrackets.push(i); | |
else if (str[i] == ';') { | |
var l = leftBrackets.pop(), r = i; | |
bracketMap[l] = r; | |
bracketMap[r] = l; | |
} | |
} | |
return bracketMap; | |
} | |
// Executes the given brainfuck code with the relative bracket map and input | |
const runCode = function(code, bracketMap, input){ | |
const tapeLength = 30000; | |
var tape = new Array(tapeLength).fill(0); | |
var tapePointer = 0; | |
var output = ''; var inputPointer = 0; input += String.fromCharCode(0); | |
for (var i =0; i< code.length; i+=2){ | |
if(code[i+1] == ']' && tape[tapePointer] !== 0) i = bracketMap[i]; | |
else if(code[i+1] == ':' && tape[tapePointer] === 0) i = bracketMap[i]-2; | |
else { | |
let amount = parseInt(code[i+1]); | |
if(code[i] == '+') tape[tapePointer] += amount; | |
else if (code[i] == '-') tape[tapePointer] -= amount; | |
else if (code[i] == '<') tapePointer -= amount; | |
else if (code[i] == '>') tapePointer += amount; | |
else if (code[i] == '.') for(let j = 0; j<amount; j++) output += String.fromCharCode(tape[tapePointer]); | |
else if (code[i] == ',') for(let j = 0; j<amount; j++) tape[tapePointer] = input.charCodeAt(inputPointer++); | |
} | |
while(tape[tapePointer] > 255) tape[tapePointer] -=255; | |
while(tape[tapePointer] < 0) tape[tapePointer] += 255; | |
} | |
return output; | |
} | |
// Takes a brainfuck source and input and produces an output | |
const executeBF = function(sourceCode, input) { | |
var parsedCode = parseAndTokenize(sourceCode); | |
var bracketMap = buildBracketMap(parsedCode); | |
return runCode(parsedCode, bracketMap, input); | |
} | |
// Sample usage of the above code (hello world program): | |
// console.log(executeBF('++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.' , '')); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment