mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 12:46:31 +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 { BinaryType, Expr, Stmt } from "./ast.ts";
|
||||||
import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts";
|
import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts";
|
||||||
import { Ops } from "./mod.ts";
|
import { Ops } from "./mod.ts";
|
||||||
|
import { Assembler } from "./program_builder.ts";
|
||||||
import { VType, vtypeToString } from "./vtypes.ts";
|
import { VType, vtypeToString } from "./vtypes.ts";
|
||||||
|
|
||||||
export class Lowerer {
|
export class Lowerer {
|
||||||
private program: number[] = [];
|
private program = new Assembler();
|
||||||
private locals: Locals = new LocalsFnRoot();
|
private locals: Locals = new LocalsFnRoot();
|
||||||
private fnStmtIdAddrMap: { [key: number]: number } = {};
|
private fnStmtIdAddrMap: { [key: number]: number } = {};
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ export class Lowerer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public finish(): number[] {
|
public finish(): number[] {
|
||||||
return this.program;
|
return this.program.assemble();
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerStaticStmt(stmt: Stmt) {
|
private lowerStaticStmt(stmt: Stmt) {
|
||||||
@ -60,7 +61,7 @@ export class Lowerer {
|
|||||||
const outerLocals = this.locals;
|
const outerLocals = this.locals;
|
||||||
this.locals = new LocalsFnRoot(outerLocals);
|
this.locals = new LocalsFnRoot(outerLocals);
|
||||||
const outerProgram = this.program;
|
const outerProgram = this.program;
|
||||||
this.program = [];
|
this.program = new Assembler();
|
||||||
|
|
||||||
for (const { ident } of stmt.kind.params) {
|
for (const { ident } of stmt.kind.params) {
|
||||||
this.locals.allocSym(ident);
|
this.locals.allocSym(ident);
|
||||||
@ -73,7 +74,7 @@ export class Lowerer {
|
|||||||
this.program.push(Ops.Return);
|
this.program.push(Ops.Return);
|
||||||
|
|
||||||
this.locals = outerLocals;
|
this.locals = outerLocals;
|
||||||
outerProgram.push(...this.program);
|
outerProgram.concat(this.program);
|
||||||
this.program = outerProgram;
|
this.program = outerProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,13 +223,25 @@ export class Lowerer {
|
|||||||
if (expr.kind.type !== "if") {
|
if (expr.kind.type !== "if") {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const falseLabel = this.program.makeLabel();
|
||||||
|
const doneLabel = this.program.makeLabel();
|
||||||
|
|
||||||
this.lowerExpr(expr.kind.cond);
|
this.lowerExpr(expr.kind.cond);
|
||||||
|
|
||||||
|
this.program.push(Ops.Not, Ops.JumpIfTrue);
|
||||||
|
this.program.addRef(falseLabel);
|
||||||
|
|
||||||
this.lowerExpr(expr.kind.truthy);
|
this.lowerExpr(expr.kind.truthy);
|
||||||
const falsyIndex = this.program.length;
|
|
||||||
if (expr.kind.falsy) {
|
this.program.push(Ops.Jump);
|
||||||
this.lowerExpr(expr.kind.falsy);
|
this.program.addRef(doneLabel);
|
||||||
}
|
|
||||||
const doneIndex = this.program.length;
|
this.program.setLabel(falseLabel);
|
||||||
|
|
||||||
|
this.lowerExpr(expr.kind.falsy!);
|
||||||
|
|
||||||
|
this.program.setLabel(doneLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private lowerBlockExpr(expr: Expr) {
|
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