rest
This commit is contained in:
parent
27ec81441b
commit
b2a59de1b2
69
compiler.ts
69
compiler.ts
@ -2,8 +2,9 @@ import { Expr } from "./parsed";
|
|||||||
|
|
||||||
export type Register = "acc" | "op";
|
export type Register = "acc" | "op";
|
||||||
export type Value = number;
|
export type Value = number;
|
||||||
|
export type Location = number;
|
||||||
|
|
||||||
export type Instruction = {
|
export type Instruction = ({
|
||||||
type: "push" | "pop",
|
type: "push" | "pop",
|
||||||
register: Register,
|
register: Register,
|
||||||
} | {
|
} | {
|
||||||
@ -19,7 +20,14 @@ export type Instruction = {
|
|||||||
type: "negate",
|
type: "negate",
|
||||||
src: Register,
|
src: Register,
|
||||||
dest: Register,
|
dest: Register,
|
||||||
}
|
} | {
|
||||||
|
type: "jump_zero",
|
||||||
|
register: Register,
|
||||||
|
location: Location,
|
||||||
|
} | {
|
||||||
|
type: "jump",
|
||||||
|
location: Location,
|
||||||
|
}) & ({ jumpedTo: true, label: number } | { jumpedTo?: false });
|
||||||
|
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
public result: Instruction[] = [];
|
public result: Instruction[] = [];
|
||||||
@ -70,6 +78,33 @@ export class Compiler {
|
|||||||
this.result.push({ type: binaryType, left: "acc", right: "op", dest: "acc" });
|
this.result.push({ type: binaryType, left: "acc", right: "op", dest: "acc" });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "if": {
|
||||||
|
this.compileExpr(expr.condition);
|
||||||
|
|
||||||
|
const jumpToFalsyIndex = this.result.length;
|
||||||
|
this.result.push({ type: "jump_zero", register: "acc", location: 0 });
|
||||||
|
|
||||||
|
this.compileExpr(expr.truthy);
|
||||||
|
|
||||||
|
const skipFalsyIndex = this.result.length;
|
||||||
|
this.result.push({ type: "jump", location: 0 });
|
||||||
|
|
||||||
|
let jumpToFalsyRef = this.result[jumpToFalsyIndex];
|
||||||
|
if (jumpToFalsyRef.type !== "jump_zero") throw new Error("unreachable");
|
||||||
|
jumpToFalsyRef.location = this.result.length;
|
||||||
|
|
||||||
|
this.compileExpr(expr.falsy);
|
||||||
|
|
||||||
|
let skipFalsyRef = this.result[skipFalsyIndex];
|
||||||
|
if (skipFalsyRef.type !== "jump") throw new Error("unreachable");
|
||||||
|
skipFalsyRef.location = this.result.length;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "block": {
|
||||||
|
this.compileExpr(expr.expr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
const exhaustiveCheck: never = expr;
|
const exhaustiveCheck: never = expr;
|
||||||
throw new Error(`Unhandled color case: ${exhaustiveCheck}`);
|
throw new Error(`Unhandled color case: ${exhaustiveCheck}`);
|
||||||
@ -78,17 +113,35 @@ export class Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function locateAndSetJumpedToInstructions(instructions: Instruction[]) {
|
||||||
|
let nextLabel = 0;
|
||||||
|
for (const ins of instructions) {
|
||||||
|
if (ins.type === "jump_zero" || ins.type === "jump") {
|
||||||
|
instructions[ins.location] = {
|
||||||
|
...instructions[ins.location],
|
||||||
|
jumpedTo: true,
|
||||||
|
label: nextLabel,
|
||||||
|
};
|
||||||
|
nextLabel += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class X86Generator {
|
export class X86Generator {
|
||||||
public generate(instructions: Instruction[]): string {
|
public generate(instructions: Instruction[]): string {
|
||||||
return this.asmWithHeaders(instructions.map((ins) => this.generateInstruction(ins)).join(""));
|
return this.asmWithHeaders(instructions.map((ins) => this.generateInstruction(ins)).join(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateInstruction(ins: Instruction): string {
|
private generateInstruction(ins: Instruction): string {
|
||||||
|
let result = "";
|
||||||
|
if (ins.jumpedTo) {
|
||||||
|
|
||||||
|
}
|
||||||
switch (ins.type) {
|
switch (ins.type) {
|
||||||
case "load": {
|
case "load": {
|
||||||
return `
|
result += ` ; load`
|
||||||
mov ${this.reg64(ins.register)}, ${this.value(ins.value)}
|
result += ` mov ${this.reg64(ins.register)}, ${this.value(ins.value)}\n`;
|
||||||
`;
|
break;
|
||||||
}
|
}
|
||||||
case "push": {
|
case "push": {
|
||||||
return `
|
return `
|
||||||
@ -141,6 +194,12 @@ export class X86Generator {
|
|||||||
mov ${this.reg64(ins.dest)}, rax
|
mov ${this.reg64(ins.dest)}, rax
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
case "jump_zero": {
|
||||||
|
return `
|
||||||
|
; jump_zero
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
grammar.ne
22
grammar.ne
@ -30,11 +30,29 @@ unary -> "+" _ unary
|
|||||||
({ exprType: "unary", unaryType: "negate", subject }) %}
|
({ exprType: "unary", unaryType: "negate", subject }) %}
|
||||||
| operand {% id %}
|
| operand {% id %}
|
||||||
|
|
||||||
operand -> "(" _ expr _ ")" {% ([_0, _1, expr]): Expr => expr %}
|
operand -> int {% id %}
|
||||||
| [0-9]:+
|
| group {% id %}
|
||||||
|
| block {% id %}
|
||||||
|
| if {% id %}
|
||||||
|
|
||||||
|
int -> [0-9]:+
|
||||||
{% ([token]): Expr =>
|
{% ([token]): Expr =>
|
||||||
({ exprType: "int", value: parseInt(token.join("")) }) %}
|
({ exprType: "int", value: parseInt(token.join("")) }) %}
|
||||||
|
|
||||||
|
group -> "(" _ expr _ ")" {% (v): Expr => v[2] %}
|
||||||
|
|
||||||
|
block -> "{" _ expr _ "}" {% (v): Expr => ({ exprType: "block", expr: v[2] }) %}
|
||||||
|
|
||||||
|
if -> "if" __ expr _ block _ "else" _ block
|
||||||
|
{%
|
||||||
|
(v): Expr => ({
|
||||||
|
exprType: "if",
|
||||||
|
condition: v[2],
|
||||||
|
truthy: v[4],
|
||||||
|
falsy: v[8]
|
||||||
|
})
|
||||||
|
%}
|
||||||
|
|
||||||
_ -> __:?
|
_ -> __:?
|
||||||
__ -> ws:+
|
__ -> ws:+
|
||||||
|
|
||||||
|
6
main.ts
6
main.ts
@ -1,6 +1,6 @@
|
|||||||
import { Parser, Grammar } from "nearley"
|
import { Parser, Grammar } from "nearley"
|
||||||
import compiledGrammar from "./grammar.out"
|
import compiledGrammar from "./grammar.out"
|
||||||
import { Compiler, Instruction, Register, Value, X86Generator as X8664Generator } from "./compiler";
|
import { Compiler, Instruction, Register, Value, X86Generator as X8664Generator, locateAndSetJumpedToInstructions } from "./compiler";
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
|
|
||||||
@ -37,7 +37,9 @@ async function main(args: string[]) {
|
|||||||
|
|
||||||
const compiler = new Compiler();
|
const compiler = new Compiler();
|
||||||
compiler.compileExpr(ast);
|
compiler.compileExpr(ast);
|
||||||
const ir = compiler.result;
|
let ir = compiler.result;
|
||||||
|
console.log(ir);
|
||||||
|
locateAndSetJumpedToInstructions(ir);
|
||||||
console.log(ir);
|
console.log(ir);
|
||||||
|
|
||||||
const generator = new X8664Generator();
|
const generator = new X8664Generator();
|
||||||
|
@ -13,6 +13,14 @@ export type Expr = {
|
|||||||
binaryType: "add" | "subtract" | "multiply" | "divide",
|
binaryType: "add" | "subtract" | "multiply" | "divide",
|
||||||
left: Expr,
|
left: Expr,
|
||||||
right: Expr,
|
right: Expr,
|
||||||
|
} | {
|
||||||
|
exprType: "if",
|
||||||
|
condition: Expr,
|
||||||
|
truthy: Expr,
|
||||||
|
falsy: Expr,
|
||||||
|
} | {
|
||||||
|
exprType: "block",
|
||||||
|
expr: Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user