Skip to content

Instantly share code, notes, and snippets.

@pandaninjas
Last active April 8, 2023 01:25
Show Gist options
  • Save pandaninjas/a0a0f5c237ecc7e27dda114d81568687 to your computer and use it in GitHub Desktop.
Save pandaninjas/a0a0f5c237ecc7e27dda114d81568687 to your computer and use it in GitHub Desktop.
import { parse } from "https://deno.land/[email protected]/flags/mod.ts";
interface Indexable {
[index: number]: number;
length: number;
}
const args = parse(Deno.args);
if (args.help || args.program === undefined) {
const scriptName =
(await Deno.permissions.query({ name: "read" })).state === "granted"
? Deno.mainModule.split("/").at(-1)
: "brainfuck.ts";
console.log(scriptName + " - a brainfuck runner");
console.log(`Usage: deno run ${scriptName} [OPTIONS]`);
console.log("Options:");
console.log("--program <program>: The brainfuck program to run");
console.log(
"--cellLength <length>: The number of the cells. If -1 or not specified, infinite cells"
);
console.log(
"--disallowComments: Disallow any character in the program which isn't +-<>[],."
);
console.log(
"--check <runtime or start>: When to check the program. Defaults to runtime"
);
console.log(
"--size <uint8 or unlimited>: size of each cell, default unlimited"
);
Deno.exit(1);
}
const prog = args.program as string;
const runtimeChecking = !(args.check && args.check === "start");
const bracketMap = new Map<number, number>();
if (!runtimeChecking) {
const openBracketStack = [];
for (let i = 0; i < prog.length; i++) {
const char = args.program[i];
if (char === "[") {
openBracketStack.push(i);
} else if (char === "]") {
if (openBracketStack.length === 0) {
console.log("Unmatched close bracket at " + i);
Deno.exit(1);
}
const value = openBracketStack.pop()!;
bracketMap.set(value, i);
bracketMap.set(i, value);
}
}
if (openBracketStack.length > 0) {
console.log("Umatched open bracket at " + openBracketStack.pop());
Deno.exit(1);
}
} else if (args.check && args.check !== "runtime") {
console.log(`Unsupported check type ${args.check}`);
Deno.exit(1);
}
const cellSize = (args.cellLength as number) ?? -1;
if (cellSize === 0) {
console.log("Cell size cannot be 0");
Deno.exit(1);
}
const isUint8 = args.size === "uint8";
if (!isUint8 && args.size && args.size !== "unlimited") {
console.log(`Unsupported size type ${args.size}`);
Deno.exit(1);
}
const state: Indexable =
isUint8 && cellSize !== -1 ? new Uint8Array(cellSize) : [0];
let pointer = 0;
let curCommand = 0;
const disallowComments = args.disallowComments;
while (true) {
const command = prog[curCommand];
switch (command) {
case ">":
pointer++;
if (pointer == state.length) {
if (cellSize == -1 || (state.length < cellSize && !isUint8)) {
(state as number[]).push(0);
} else {
console.log("new pointer > cell size");
Deno.exit(1);
}
}
break;
case "<":
pointer--;
if (pointer < 0) {
console.log("pointer < 0");
Deno.exit(1);
}
break;
case "+":
state[pointer]++;
break;
case "-":
state[pointer]--;
break;
case ".":
await Deno.stdout.write(new Uint8Array([state[pointer]]));
break;
case ",":
const buf = new Uint8Array(1);
let read = await Deno.stdin.read(buf);
if (read != 1) {
console.log("IO error");
Deno.exit(1);
}
state[pointer] = buf[0];
break;
case "[":
if (state[pointer] == 0) {
if (runtimeChecking) {
const oldCurCommand = curCommand;
let openBracketCount = 0;
while (true) {
curCommand++;
if (runtimeChecking && curCommand === prog.length) {
console.log(
"Unmatched open bracket at " + oldCurCommand
);
Deno.exit(1);
}
if (prog[curCommand] == "]" && openBracketCount == 0) {
break;
} else if (prog[curCommand] == "]") {
openBracketCount--;
} else if (prog[curCommand] == "[") {
openBracketCount++;
}
}
} else {
// not runtime checking implies that the bracketMap is populated
curCommand = bracketMap.get(curCommand)!;
}
}
break;
case "]":
if (state[pointer] != 0) {
if (runtimeChecking) {
let closeBracketCount = 0;
const oldCurCommand = curCommand;
while (true) {
curCommand--;
if (runtimeChecking && curCommand === -1) {
console.log(
"Unmatched close bracket at " + oldCurCommand
);
Deno.exit(1);
}
if (prog[curCommand] == "[" && closeBracketCount === 0) {
break;
} else if (prog[curCommand] == "[") {
closeBracketCount--;
} else if (prog[curCommand] == "]") {
closeBracketCount++;
}
}
} else {
curCommand = bracketMap.get(curCommand)!;
}
}
break;
default:
if (disallowComments) {
console.log(
"comment at char " +
curCommand +
" not allowed due to --disallowComments"
);
Deno.exit(0);
}
}
curCommand++;
if (curCommand == prog.length) {
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment