mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 09:46:30 +00:00
add assembler
This commit is contained in:
parent
bf9c0aa866
commit
501cd997e9
@ -2,10 +2,11 @@ import { Builtins } from "./arch.ts";
|
||||
import { BinaryType, Expr, Stmt } from "./ast.ts";
|
||||
import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts";
|
||||
import { Ops } from "./mod.ts";
|
||||
import { Assembler } from "./program_builder.ts";
|
||||
import { VType, vtypeToString } from "./vtypes.ts";
|
||||
|
||||
export class Lowerer {
|
||||
private program: number[] = [];
|
||||
private program = new Assembler();
|
||||
private locals: Locals = new LocalsFnRoot();
|
||||
private fnStmtIdAddrMap: { [key: number]: number } = {};
|
||||
|
||||
@ -16,7 +17,7 @@ export class Lowerer {
|
||||
}
|
||||
|
||||
public finish(): number[] {
|
||||
return this.program;
|
||||
return this.program.assemble();
|
||||
}
|
||||
|
||||
private lowerStaticStmt(stmt: Stmt) {
|
||||
@ -60,7 +61,7 @@ export class Lowerer {
|
||||
const outerLocals = this.locals;
|
||||
this.locals = new LocalsFnRoot(outerLocals);
|
||||
const outerProgram = this.program;
|
||||
this.program = [];
|
||||
this.program = new Assembler();
|
||||
|
||||
for (const { ident } of stmt.kind.params) {
|
||||
this.locals.allocSym(ident);
|
||||
@ -73,7 +74,7 @@ export class Lowerer {
|
||||
this.program.push(Ops.Return);
|
||||
|
||||
this.locals = outerLocals;
|
||||
outerProgram.push(...this.program);
|
||||
outerProgram.concat(this.program);
|
||||
this.program = outerProgram;
|
||||
}
|
||||
|
||||
@ -222,13 +223,25 @@ export class Lowerer {
|
||||
if (expr.kind.type !== "if") {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const falseLabel = this.program.makeLabel();
|
||||
const doneLabel = this.program.makeLabel();
|
||||
|
||||
this.lowerExpr(expr.kind.cond);
|
||||
|
||||
this.program.push(Ops.Not, Ops.JumpIfTrue);
|
||||
this.program.addRef(falseLabel);
|
||||
|
||||
this.lowerExpr(expr.kind.truthy);
|
||||
const falsyIndex = this.program.length;
|
||||
if (expr.kind.falsy) {
|
||||
this.lowerExpr(expr.kind.falsy);
|
||||
}
|
||||
const doneIndex = this.program.length;
|
||||
|
||||
this.program.push(Ops.Jump);
|
||||
this.program.addRef(doneLabel);
|
||||
|
||||
this.program.setLabel(falseLabel);
|
||||
|
||||
this.lowerExpr(expr.kind.falsy!);
|
||||
|
||||
this.program.setLabel(doneLabel);
|
||||
}
|
||||
|
||||
private lowerBlockExpr(expr: Expr) {
|
||||
|
97
compiler/program_builder.ts
Normal file
97
compiler/program_builder.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { Ops } from "./arch.ts";
|
||||
|
||||
export type Line = {
|
||||
labels?: number[];
|
||||
} & LineKind;
|
||||
|
||||
export type Label = { label: number };
|
||||
|
||||
export type LineKind =
|
||||
| { type: "op"; op: number }
|
||||
| { type: "lit"; val: number }
|
||||
| { type: "ref"; label: number };
|
||||
|
||||
export class Assembler {
|
||||
private lines: Line[] = [];
|
||||
private labelCounter = 0;
|
||||
|
||||
public push(...values: number[]) {
|
||||
for (const value of values) {
|
||||
this.addLit(value);
|
||||
}
|
||||
}
|
||||
|
||||
public addOp(op: number): Assembler {
|
||||
this.lines.push({ type: "op", op });
|
||||
return this;
|
||||
}
|
||||
|
||||
public addLit(val: number): Assembler {
|
||||
this.lines.push({ type: "lit", val });
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRef({ label }: Label): Assembler {
|
||||
this.lines.push({ type: "ref", label });
|
||||
return this;
|
||||
}
|
||||
|
||||
public setLabel({ label }: Label): Assembler {
|
||||
const line = this.lines.at(-1);
|
||||
if (line === undefined) {
|
||||
return this;
|
||||
}
|
||||
if (line.labels === undefined) {
|
||||
line.labels = [];
|
||||
}
|
||||
line.labels.push(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
public makeLabel(): Label {
|
||||
const label = this.labelCounter;
|
||||
this.labelCounter += 1;
|
||||
return { label };
|
||||
}
|
||||
|
||||
public concat(assembler: Assembler) {
|
||||
this.lines.push(...assembler.lines);
|
||||
}
|
||||
|
||||
public assemble(): number[] {
|
||||
let ip = 0;
|
||||
const output: number[] = [];
|
||||
const locs: { [key: number]: number } = {};
|
||||
const refs: { [key: number]: number } = {};
|
||||
for (const line of this.lines) {
|
||||
switch (line.type) {
|
||||
case "op":
|
||||
output.push(line.op);
|
||||
ip += 1;
|
||||
break;
|
||||
case "lit":
|
||||
output.push(line.val);
|
||||
ip += 1;
|
||||
break;
|
||||
case "ref":
|
||||
output.push(0);
|
||||
refs[ip] = line.label;
|
||||
ip += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < output.length; ++i) {
|
||||
if (!(i in refs)) {
|
||||
continue;
|
||||
}
|
||||
if (!(refs[i] in locs)) {
|
||||
console.error(
|
||||
`Assembler: label '${refs[i]}' used at ${i} not defined`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
output[i] = locs[refs[i]];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user