Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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