slige/compiler/assembler.ts

143 lines
4.5 KiB
TypeScript
Raw Normal View History

2024-12-17 02:10:11 +01:00
import { opToString } from "./arch.ts";
2024-12-10 15:45:19 +01:00
2024-12-11 00:03:19 +01:00
export type Line = { labels?: string[]; ins: Ins };
2024-12-10 15:45:19 +01:00
2024-12-11 00:03:19 +01:00
export type Ins = Lit[];
2024-12-10 15:45:19 +01:00
2024-12-11 00:03:19 +01:00
export type Label = { label: string };
export type Lit = number | string | boolean | Label;
2024-12-10 15:45:19 +01:00
2024-12-15 00:07:36 +01:00
export type Locs = { [key: string]: number };
export type Refs = { [key: number]: string };
2024-12-10 15:45:19 +01:00
export class Assembler {
private lines: Line[] = [];
2024-12-11 00:03:19 +01:00
private addedLabels: string[] = [];
2024-12-10 15:45:19 +01:00
2024-12-17 02:10:11 +01:00
private constructor(private labelCounter: number) {}
public static newRoot(): Assembler {
return new Assembler(0);
}
public fork(): Assembler {
return new Assembler(this.labelCounter);
2024-12-10 15:45:19 +01:00
}
2024-12-17 02:10:11 +01:00
public join(assembler: Assembler) {
this.labelCounter = assembler.labelCounter;
2024-12-11 00:03:19 +01:00
if (assembler.lines.length < 0) {
return;
2024-12-10 15:45:19 +01:00
}
2024-12-11 00:03:19 +01:00
if (assembler.lines[0].labels !== undefined) {
this.addedLabels.push(...assembler.lines[0].labels);
2024-12-10 15:45:19 +01:00
}
2024-12-11 00:03:19 +01:00
this.add(...assembler.lines[0].ins);
this.lines.push(...assembler.lines.slice(1));
2024-12-10 23:30:15 +01:00
}
2024-12-17 02:10:11 +01:00
public add(...ins: Ins): Assembler {
if (this.addedLabels.length > 0) {
this.lines.push({ ins, labels: this.addedLabels });
this.addedLabels = [];
return this;
}
this.lines.push({ ins });
return this;
}
2024-12-10 23:30:15 +01:00
public makeLabel(): Label {
2024-12-11 00:03:19 +01:00
return { label: `.L${(this.labelCounter++).toString()}` };
2024-12-10 23:30:15 +01:00
}
public setLabel({ label }: Label) {
this.addedLabels.push(label);
}
2024-12-15 00:07:36 +01:00
public assemble(): { program: number[]; locs: Locs } {
2024-12-10 23:30:15 +01:00
let ip = 0;
2024-12-15 00:07:36 +01:00
const program: number[] = [];
const locs: Locs = {};
const refs: Refs = {};
2024-12-11 03:11:00 +01:00
2024-12-13 09:55:09 +01:00
let selectedLabel = "";
2024-12-10 23:30:15 +01:00
for (const line of this.lines) {
2024-12-11 00:03:19 +01:00
for (const label of line.labels ?? []) {
2024-12-13 09:55:09 +01:00
const isAbsLabel = !label.startsWith(".");
if (isAbsLabel) {
selectedLabel = label;
locs[label] = ip;
} else {
locs[`${selectedLabel}${label}`] = ip;
}
2024-12-11 00:03:19 +01:00
}
2024-12-10 23:30:15 +01:00
for (const lit of line.ins as Lit[]) {
if (typeof lit === "number") {
2024-12-15 00:07:36 +01:00
program.push(lit);
2024-12-10 23:30:15 +01:00
ip += 1;
} else if (typeof lit === "boolean") {
2024-12-15 00:07:36 +01:00
program.push(lit ? 1 : 0);
2024-12-10 23:30:15 +01:00
ip += 1;
} else if (typeof lit === "string") {
2024-12-15 00:07:36 +01:00
program.push(lit.length);
2024-12-11 12:36:19 +01:00
ip += 1;
2024-12-10 23:30:15 +01:00
for (let i = 0; i < lit.length; ++i) {
2024-12-15 00:07:36 +01:00
program.push(lit.charCodeAt(i));
2024-12-10 23:30:15 +01:00
ip += 1;
}
} else {
2024-12-15 00:07:36 +01:00
program.push(0);
2024-12-13 09:55:09 +01:00
refs[ip] = lit.label.startsWith(".")
? `${selectedLabel}${lit.label}`
: refs[ip] = lit.label;
2024-12-10 23:30:15 +01:00
ip += 1;
}
}
}
2024-12-15 00:07:36 +01:00
for (let i = 0; i < program.length; ++i) {
2024-12-10 23:30:15 +01:00
if (!(i in refs)) {
continue;
}
if (!(refs[i] in locs)) {
console.error(
`Assembler: label '${refs[i]}' used at ${i} not defined`,
);
continue;
}
2024-12-15 00:07:36 +01:00
program[i] = locs[refs[i]];
2024-12-10 23:30:15 +01:00
}
2024-12-15 00:07:36 +01:00
return { program, locs };
2024-12-10 23:30:15 +01:00
}
public printProgram() {
2024-12-11 12:36:19 +01:00
let ip = 0;
2024-12-10 23:30:15 +01:00
for (const line of this.lines) {
for (const label of line.labels ?? []) {
2024-12-11 12:36:19 +01:00
console.log(` ${label}:`);
2024-12-10 23:30:15 +01:00
}
2024-12-11 00:03:19 +01:00
const op = opToString(line.ins[0] as number)
.padEnd(13, " ");
2024-12-10 23:30:15 +01:00
const args = (line.ins.slice(1) as Lit[]).map((lit) => {
if (typeof lit === "number") {
return lit;
} else if (typeof lit === "boolean") {
return lit.toString();
} else if (typeof lit === "string") {
return '"' +
lit.replaceAll("\\", "\\\\").replaceAll("\0", "\\0")
.replaceAll("\n", "\\n").replaceAll("\t", "\\t")
.replaceAll("\r", "\\r") +
'"';
} else {
2024-12-11 00:03:19 +01:00
return lit.label;
2024-12-10 23:30:15 +01:00
}
}).join(", ");
2024-12-11 12:36:19 +01:00
console.log(`${ip.toString().padStart(8, " ")}: ${op} ${args}`);
ip += line.ins.map((lit) =>
2024-12-12 16:07:59 +01:00
typeof lit === "string" ? lit.length + 1 : 1
2024-12-11 12:36:19 +01:00
).reduce((acc, curr) => acc + curr, 0);
2024-12-10 23:30:15 +01:00
}
}
}