-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathtiny_three_pass_compiler.js
More file actions
65 lines (60 loc) · 2.31 KB
/
tiny_three_pass_compiler.js
File metadata and controls
65 lines (60 loc) · 2.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// @ts-nocheck
/* eslint-disable */
// https://www.codewars.com/kata/5265b0885fda8eac5900093b
class Compiler {
compile = program => this.pass3(this.pass2(this.pass1(program)));
tokenize = program => program
.replace(/\s*([-+*/\[\]\(\)]|[A-Za-z]+|\d+)\s*/g, ":$1")
.substring(1)
.split(":")
.map(t => (isNaN(t) ? t : t | 0));
pass1(program){
const tokens = this.tokenize(program);
let pos = 0;
const peek = () => tokens[pos], take = () => tokens[pos++], expect = s => take() !== s;
expect("[");
const argNames = [], argIndex = Object.create(null);
while (peek() !== "]"){
const name = take();
argIndex[name] = argNames.length;
argNames.push(name);
}
expect("]");
const parseFactor = (tok = take()) => {
if (tok === "("){
const node = parseExpression();
expect(")");
return node;
}
return (typeof tok === "number") ? ({ op: "imm", n: tok }) : ({ op: "arg", n: argIndex[tok] });
};
const parseTerm = (node = parseFactor()) => {
while (peek() === "*" || peek() === "/") node = { op: take(), a: node, b: parseFactor() };
return node;
};
const parseExpression = (node = parseTerm()) => {
while (peek() === "+" || peek() === "-") node = { op: take(), a: node, b: parseTerm() };
return node;
};
return parseExpression();
}
pass2(ast){
const fold = node => {
if (node.op === "imm" || node.op === "arg") return node;
const a = fold(node.a), b = fold(node.b);
return (a.op === "imm" && b.op === "imm") ? ({
op: "imm", n: node.op === "+" ? a.n + b.n : node.op === "-" ? a.n - b.n : node.op === "*" ? a.n * b.n : a.n / b.n,
}) : ({ op: node.op, a, b });
};
return fold(ast);
}
pass3(ast){
const ins = { "+": "AD", "-": "SU", "*": "MU", "/": "DI" };
const gen = node => {
if (node.op === "imm") return [`IM ${node.n}`];
if (node.op === "arg") return [`AR ${node.n}`];
return [...gen(node.a), "PU", ...gen(node.b), "SW", "PO", ins[node.op]];
};
return gen(ast);
}
}