diff --git a/README.md b/README.md index dc384b3..28e6907 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,4 @@ Gir can parse and prettyprint to Javascript console programs in brainfuck. Gir supports following optimizations: * Turn runs of +- or <> into one command +* Turn [-] or [+] into one command diff --git a/gir.js b/gir.js index a755267..4e58a69 100644 --- a/gir.js +++ b/gir.js @@ -18,6 +18,9 @@ const readByte = Symbol('readByte'); // [-] → {type: loop, contents: [{type: add, value: -1}]} const loop = Symbol('loop'); +// [-] → {type: clear} +const clear = Symbol('clear'); + // TODO: Add extensions from Eldis // ------------------------------------------------------------------ @@ -78,7 +81,10 @@ function parse(program) { } } - commands.push({type: add, value: value}); + // Only add the command is value is not 0 + if(value != 0) { + commands.push({type: add, value: value}); + } // i is not incremented, since it already // points to a location containig a char we // have not yet handled @@ -97,7 +103,10 @@ function parse(program) { } } - commands.push({type: moveHead, value: value}); + // Only add the command is value is not 0 + if(value != 0) { + commands.push({type: moveHead, value: value}); + } // see +/- for why we don't increment i } else if(program[i] == '.') { @@ -162,6 +171,9 @@ function prettyPrint(parsed) { line += 'loop'; console.log(line); printIndented(command.contents, indent + ' '); + } else if(command.type == clear) { + line += 'clear'; + console.log(line); } else { line += `unknown ${command.type}`; console.log(line); @@ -219,6 +231,33 @@ function joinAdjacentOps(parsed) { } // ([commandObjects]) → [commandObjects] -function optimize(parsed) { - return joinAdjacentOps(parsed); +function transformClearLoops(parsed) { + let optimized = []; + + for(let command of parsed) { + // Only match loops like [-] or [+] + let isClearLoop = command.type == loop && + command.contents.length == 1 && + command.contents[0].type == add && + (command.contents[0].value == 1 || + command.contents[0].value == -1); + if(isClearLoop) { + optimized.push({type: clear}); + } else if(command.type == loop) { + // Run for inner loops + optimized.push({type: loop, + contents: transformClearLoops(command.contents)}); + } else { + optimized.push(command); + } + } + + return optimized; +} + +// ([commandObjects]) → [commandObjects] +function optimize(parsed) { + const optimizations = [joinAdjacentOps, transformClearLoops]; + return optimizations.reduce((IR, optimization) => + optimization(IR), parsed); }