Skip to main content

brainfuck.js

unfinshed brainfuck interpreter in js. Still need to do [ and ].

gist link


console.group('helloWorld');
var helloWorldScript = 'this is hello world: ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.';
var helloWorld = new BrainFuck(helloWorldScript);
console.log('script:', helloWorldScript);
console.log('validate:', helloWorld.validate());
console.log('execute:', helloWorld.execute());
console.groupEnd('helloWorld');


function BrainFuck(str, cells) {
    var script = str.replace(/[^<>\-\+\[\]\.\,]/g, '');
    var MAX_CELLS = cells || 30000;

    this.validate = function () {
        return validate();
    };
    this.execute = function (stdin) {
        return execute(stdin || '');
    };

    function checkBrackets() {
        var stack = [];
        var arr = script.replace(/[^\[\]]/g, '').split('');
        var openers = [],
            closers = [];
        if (arr.length === 0) {
            return true;
        }
        if (arr[0] !== '[') {
            return false;
        }
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] === '[') {
                stack.push(arr[i]);
                openers.push(arr[i]);
            } else if (arr[i] === ']') {
                stack.pop();
                closers.push(arr[i]);
            }
        }
        if (stack.length > 0 || openers.length !== closers.length) {
            return false;
        }
        return true;
    }

    function bracketsPc() {
        var stack = [];
        var brackets = {};
        var arr = script.split('');
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] === '[') {
                stack.push(i);
                brackets[i] = {
                    '[': i,
                    ']': -1
                };
            } else if (arr[i] === ']') {
                var pc = stack.pop();
                brackets[pc][']'] = i;
                brackets[i] = {
                    '[': pc,
                    ']': i
                };
            }
        }
        return brackets;
    }

    function validate() {
        var matchingBrackets = checkBrackets();
        return matchingBrackets;
    }

    function execute(stdin) {
        if (!validate()) {
            throw new Error("Invalid Syntax");
        }

        var index = 0;
        var arr = new Array(MAX_CELLS + 1).join('a').split('');
        var stdin_arr = stdin.split('');
        var stdout = [];
        var pc_stack = [];
        var brackets = bracketsPc();

        arr = arr.map(function () {
            return 0;
        });

        var opcodes = {};
        opcodes['<'] = function (pc) {
            index -= 1;
            return pc;
        };
        opcodes['>'] = function (pc) {
            index += 1;
            return pc;
        };
        opcodes['+'] = function (pc) {
            arr[index] += 1;
            return pc;
        };
        opcodes['-'] = function (pc) {
            arr[index] -= 1;
            return pc;
        };
        opcodes['['] = function (pc) {
            if (arr[index] === 0) {
                pc = brackets[pc][']'];
            }
            return pc;
        };
        opcodes[']'] = function (pc) {
            if (arr[index] !== 0) {
                pc = brackets[pc]['['];
            }
            return pc;
        };
        opcodes[','] = function (pc) {
            var chr = stdin_arr.shift();
            arr[index] = chr.charCodeAt(0);
            return pc;
        };
        opcodes['.'] = function (pc) {
            stdout.push(String.fromCharCode(arr[index]));
            return pc;
        };

        var ops = script.split('');
        for (var pc = 0; pc < ops.length; pc++) {
            var op = ops[pc];
            pc = opcodes[op](pc);
        }

        return stdout.join('');
    }
}