Created
March 29, 2017 14:44
-
-
Save Chalarangelo/576773ef989ff9229f2befde57c82043 to your computer and use it in GitHub Desktop.
Brainsource - regex-based brainfuck interpreter written in functional Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////////////////////////////////// | |
//* *// | |
// - B R A I N S O U R C E - // | |
// Regex-based brainfuck interpreter written in functional Javascript // | |
// Author: Angelos Chalaris ([email protected]) // | |
// 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