type BFError = string; type Token = string; type Node = string | NodeArray; interface NodeArray extends Array {} const error = (message: BFError) => { console.error(message); process.exit(1); }; const scan = (source: string): Token[] => { return source.split('').filter((c) => "+-<>[].,".includes(c)); }; const parse = (tokens: Token[]): Node[] | undefined => { let position = 0; let tree: Node[] = []; const parseNode = (token: string): Node | undefined => { if ("+-<>.,".includes(token)) { position++; return token; } else if (token === '[') { position++; const body: Node[] = []; while (position < tokens.length && tokens[position] !== ']') { const subnode = parseNode(tokens[position]); if (subnode) body.push(subnode); } if (tokens[position] === ']') { position++; } else if (position === tokens.length) { error('Expected ], got EOF'); } return body; } else { error(`Unrecognized token ${token}`); } }; while (position < tokens.length) { const node = parseNode(tokens[position]); if (node) tree.push(node); } return tree; }; const interpret = (tree: Node[]) => { let position = 0; let pointer = 0; let stack = Array.from({ length: 30_000 }, () => 0); const interpretNode = (node: Node) => { switch (node) { case '+': stack[pointer]++; break; case '-': stack[pointer]--; break; case '>': pointer++; break; case '<': pointer--; break; case '.': process.stdout.write(stack[pointer].toString()); break; case ',': throw('Unimplemented'); default: while (stack[pointer] > 0) { let subposition = 0; while (subposition < node.length) { console.log(subposition); interpretNode(node[subposition]); subposition++; } } } position++; }; while (position < tree.length) interpretNode(tree[position]); }; const tree = parse(scan(process.argv[2])); if (tree) interpret(tree);