diff --git a/compiler/assembler.ts b/compiler/assembler.ts index 92b17b9..c33af98 100644 --- a/compiler/assembler.ts +++ b/compiler/assembler.ts @@ -1,113 +1,19 @@ import { Ops, opToString } from "./arch.ts"; -export type Line = { - labels?: number[]; -} & LineKind; +export type Line = { labels?: string[]; ins: Ins }; -export type Label = { label: number }; +export type Ins = Lit[]; -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; - } -} - -export type Line2 = { labels?: number[]; ins: Ins2 }; - -export type Ins2 = [Ops, ...Lit[]]; +export type Label = { label: string }; export type Lit = number | string | boolean | Label; -export class Assembler2 { - private lines: Line2[] = []; - private addedLabels: number[] = []; +export class Assembler { + private lines: Line[] = []; + private addedLabels: string[] = []; private labelCounter = 0; - public add(ins: Ins2): Assembler2 { + public add(...ins: Ins): Assembler { if (this.addedLabels.length > 0) { this.lines.push({ ins, labels: this.addedLabels }); this.addedLabels = []; @@ -117,8 +23,19 @@ export class Assembler2 { return this; } + public concat(assembler: Assembler) { + if (assembler.lines.length < 0) { + return; + } + if (assembler.lines[0].labels !== undefined) { + this.addedLabels.push(...assembler.lines[0].labels); + } + this.add(...assembler.lines[0].ins); + this.lines.push(...assembler.lines.slice(1)); + } + public makeLabel(): Label { - return { label: this.labelCounter++ }; + return { label: `.L${(this.labelCounter++).toString()}` }; } public setLabel({ label }: Label) { @@ -128,9 +45,12 @@ export class Assembler2 { public assemble(): number[] { let ip = 0; const output: number[] = []; - const locs: { [key: number]: number } = {}; - const refs: { [key: number]: number } = {}; + const locs: { [key: string]: number } = {}; + const refs: { [key: number]: string } = {}; for (const line of this.lines) { + for (const label of line.labels ?? []) { + locs[label] = ip; + } for (const lit of line.ins as Lit[]) { if (typeof lit === "number") { output.push(lit); @@ -168,12 +88,10 @@ export class Assembler2 { public printProgram() { for (const line of this.lines) { for (const label of line.labels ?? []) { - console.log(`.L${label}:`); + console.log(`${label}:`); } - const op = opToString(line.ins[0] as unknown as number).padEnd( - 13, - " ", - ); + const op = opToString(line.ins[0] as number) + .padEnd(13, " "); const args = (line.ins.slice(1) as Lit[]).map((lit) => { if (typeof lit === "number") { return lit; @@ -186,7 +104,7 @@ export class Assembler2 { .replaceAll("\r", "\\r") + '"'; } else { - return `.L${lit.label}`; + return lit.label; } }).join(", "); console.log(` ${op} ${args}`); diff --git a/compiler/lowerer.ts b/compiler/lowerer.ts index 3a20b09..7381a06 100644 --- a/compiler/lowerer.ts +++ b/compiler/lowerer.ts @@ -8,7 +8,7 @@ import { VType, vtypeToString } from "./vtype.ts"; export class Lowerer { private program = new Assembler(); private locals: Locals = new LocalsFnRoot(); - private fnStmtIdAddrMap: { [key: number]: number } = {}; + private fnStmtIdLabelMap: { [key: number]: string } = {}; private breakStack: Label[] = []; public lower(stmts: Stmt[]) { @@ -51,7 +51,7 @@ export class Lowerer { return this.lowerAssignStmt(stmt); case "expr": this.lowerExpr(stmt.kind.expr); - this.program.push(Ops.Pop); + this.program.add(Ops.Pop); return; } throw new Error(`unhandled stmt '${stmt.kind.type}'`); @@ -65,21 +65,19 @@ export class Lowerer { switch (stmt.kind.subject.kind.type) { case "field": { this.lowerExpr(stmt.kind.subject.kind.subject); - this.addPushStringOp(stmt.kind.subject.kind.value); - this.program.addOp(Ops.Builtin); - this.program.addLit(Builtins.StructSet); + this.program.add(Ops.PushString, stmt.kind.subject.kind.value); + this.program.add(Ops.Builtin, Builtins.StructSet); return; } case "index": { this.lowerExpr(stmt.kind.subject.kind.subject); this.lowerExpr(stmt.kind.subject.kind.value); - this.program.addOp(Ops.Builtin); - this.program.addLit(Builtins.ArraySet); + this.program.add(Ops.Builtin, Builtins.ArraySet); return; } case "sym": { - this.program.addOp(Ops.StoreLocal); - this.program.addLit( + this.program.add( + Ops.StoreLocal, this.locals.symId(stmt.kind.subject.kind.sym.ident), ); return; @@ -96,14 +94,17 @@ export class Lowerer { if (stmt.kind.expr) { this.lowerExpr(stmt.kind.expr); } - this.program.addOp(Ops.Jump); - this.program.addRef(this.breakStack.at(-1)!); + this.program.add(Ops.Jump, this.breakStack.at(-1)!); } private lowerFnStmt(stmt: Stmt) { if (stmt.kind.type !== "fn") { throw new Error(); } + const label = `${stmt.kind.ident}_${stmt.id}`; + this.fnStmtIdLabelMap[stmt.id] = label; + this.program.setLabel({ label }); + const outerLocals = this.locals; this.locals = new LocalsFnRoot(outerLocals); const outerProgram = this.program; @@ -111,13 +112,13 @@ export class Lowerer { for (const { ident } of stmt.kind.params) { this.locals.allocSym(ident); - this.program.push( + this.program.add( Ops.StoreLocal, this.locals.symId(ident), ); } this.lowerExpr(stmt.kind.body); - this.program.push(Ops.Return); + this.program.add(Ops.Return); this.locals = outerLocals; outerProgram.concat(this.program); @@ -129,9 +130,11 @@ export class Lowerer { throw new Error(); } this.lowerExpr(stmt.kind.value); - this.locals.allocSym(stmt.kind.param.ident), - this.program.push(Ops.StoreLocal); - this.program.push(this.locals.symId(stmt.kind.param.ident)); + this.locals.allocSym(stmt.kind.param.ident); + this.program.add( + Ops.StoreLocal, + this.locals.symId(stmt.kind.param.ident), + ); } private lowerExpr(expr: Expr) { @@ -177,22 +180,22 @@ export class Lowerer { throw new Error(); } if (expr.kind.sym.type === "let") { - this.program.push( + this.program.add( Ops.LoadLocal, this.locals.symId(expr.kind.ident), ); return; } if (expr.kind.sym.type === "fn_param") { - this.program.push( + this.program.add( Ops.LoadLocal, this.locals.symId(expr.kind.ident), ); return; } if (expr.kind.sym.type === "fn") { - const addr = this.fnStmtIdAddrMap[expr.kind.sym.stmt.id]; - this.program.push(Ops.PushPtr, addr); + const label = this.fnStmtIdLabelMap[expr.kind.sym.stmt.id]; + this.program.add(Ops.PushPtr, label); return; } throw new Error(`unhandled sym type '${expr.kind.sym.type}'`); @@ -202,21 +205,14 @@ export class Lowerer { if (expr.kind.type !== "int") { throw new Error(); } - this.program.push(Ops.PushInt, expr.kind.value); + this.program.add(Ops.PushInt, expr.kind.value); } private lowerStringExpr(expr: Expr) { if (expr.kind.type !== "string") { throw new Error(); } - this.addPushStringOp(expr.kind.value); - } - - private addPushStringOp(value: string) { - this.program.addOp(Ops.PushString); - for (let i = 0; i < value.length; ++i) { - this.program.addLit(value.charCodeAt(i)); - } + this.program.add(Ops.PushString, expr.kind.value); } private lowerBinaryExpr(expr: Expr) { @@ -229,32 +225,33 @@ export class Lowerer { if (vtype.type === "int") { switch (expr.kind.binaryType) { case "+": - this.program.addOp(Ops.Add); + this.program.add(Ops.Add); return; case "*": - this.program.addOp(Ops.Multiply); + this.program.add(Ops.Multiply); return; case "==": - this.program.addOp(Ops.Equal); + this.program.add(Ops.Equal); return; case ">=": - this.program.addOp(Ops.LessThan); - this.program.addOp(Ops.Not); + this.program.add(Ops.LessThan); + this.program.add(Ops.Not); return; default: } } if (vtype.type === "string") { if (expr.kind.binaryType === "+") { - this.program.push(Ops.Builtin, Builtins.StringConcat); + this.program.add(Ops.Builtin, Builtins.StringConcat); return; } if (expr.kind.binaryType === "==") { - this.program.push(Ops.Builtin, Builtins.StringEqual); + this.program.add(Ops.Builtin, Builtins.StringEqual); return; } if (expr.kind.binaryType === "!=") { - this.program.push(Ops.Builtin, Builtins.StringEqual, Ops.Not); + this.program.add(Ops.Builtin, Builtins.StringEqual); + this.program.add(Ops.Not); return; } } @@ -287,13 +284,12 @@ export class Lowerer { this.lowerExpr(expr.kind.cond); - this.program.push(Ops.Not, Ops.JumpIfTrue); - this.program.addRef(falseLabel); + this.program.add(Ops.Not); + this.program.add(Ops.JumpIfTrue, falseLabel); this.lowerExpr(expr.kind.truthy); - this.program.push(Ops.Jump); - this.program.addRef(doneLabel); + this.program.add(Ops.Jump, doneLabel); this.program.setLabel(falseLabel); @@ -315,11 +311,10 @@ export class Lowerer { this.program.setLabel(contineLabel); this.lowerExpr(expr.kind.body); - this.program.addOp(Ops.Jump); - this.program.addRef(breakLabel); + this.program.add(Ops.Jump, breakLabel); this.program.setLabel(breakLabel); if (expr.vtype!.type === "null") { - this.program.addOp(Ops.PushNull); + this.program.add(Ops.PushNull); } this.breakStack.pop(); @@ -337,7 +332,7 @@ export class Lowerer { if (expr.kind.expr) { this.lowerExpr(expr.kind.expr); } else { - this.program.addOp(Ops.PushNull); + this.program.add(Ops.PushNull); } this.locals = outerLocals; } diff --git a/compiler/main.ts b/compiler/main.ts index f77ae0a..4f1968e 100644 --- a/compiler/main.ts +++ b/compiler/main.ts @@ -17,4 +17,5 @@ const lowerer = new Lowerer(); lowerer.lower(ast); lowerer.printProgram(); const program = lowerer.finish(); -console.log(JSON.stringify(program, null, 4)); +//console.log(JSON.stringify(program, null, 4)); +console.log(JSON.stringify(program));