mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 08:24:05 +02:00
136 lines
3.8 KiB
TypeScript
136 lines
3.8 KiB
TypeScript
import * as mir from "./mir.ts";
|
|
|
|
export type Program = {
|
|
strings: Map<number, string>;
|
|
fns: Fn[];
|
|
};
|
|
|
|
export type Fn = {
|
|
id: number;
|
|
label: string;
|
|
mir: mir.Fn;
|
|
lines: Line[];
|
|
|
|
localRegs: Map<number, Reg>;
|
|
};
|
|
|
|
export type Line = {
|
|
labels: Label[];
|
|
ins: Ins;
|
|
};
|
|
|
|
export type Ins =
|
|
| { tag: "error" }
|
|
| { tag: "nop" }
|
|
| { tag: "alloc_param"; reg: Reg; size: number }
|
|
| { tag: "alloc_local"; reg: Reg; size: number }
|
|
| { tag: "mov_int"; reg: Reg; val: number }
|
|
| { tag: "mov_string"; reg: Reg; stringId: number }
|
|
| { tag: "mov_fn"; reg: Reg; fn: Fn }
|
|
| { tag: "push"; reg: Reg }
|
|
| { tag: "pop"; reg: Reg }
|
|
| { tag: "load"; reg: Reg; sReg: Reg }
|
|
| { tag: "store_reg"; sReg: Reg; reg: Reg }
|
|
| { tag: "store_imm"; sReg: Reg; val: number }
|
|
| { tag: "call_reg"; reg: Reg; args: number }
|
|
| { tag: "call_imm"; fn: Fn; args: number }
|
|
| { tag: "jmp"; target: Label }
|
|
| { tag: "jnz_reg"; reg: Reg; target: Label }
|
|
| { tag: "ret" }
|
|
| { tag: BinaryOp; dst: Reg; src: Reg }
|
|
| { tag: "kill"; reg: Reg };
|
|
|
|
export type BinaryOp =
|
|
| "lt"
|
|
| "gt"
|
|
| "le"
|
|
| "ge"
|
|
| "eq"
|
|
| "ne"
|
|
| "add"
|
|
| "sub"
|
|
| "mul"
|
|
| "div"
|
|
| "mod";
|
|
|
|
export type Reg = number;
|
|
export type Label = number;
|
|
|
|
export class ProgramStringifyer {
|
|
public constructor(
|
|
private program: Program,
|
|
) {}
|
|
|
|
public stringify(): string {
|
|
return this.program.fns
|
|
.map((fn) =>
|
|
`${fn.label}:\n${
|
|
fn.lines
|
|
.map((label) =>
|
|
`${
|
|
label.labels
|
|
.map((label) => `.L${label}:\n`)
|
|
.join()
|
|
} ${this.ins(label.ins)}\n`
|
|
)
|
|
.join("")
|
|
}`
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
private ins(ins: Ins): string {
|
|
switch (ins.tag) {
|
|
case "error":
|
|
return "<error>";
|
|
case "nop":
|
|
return "nop";
|
|
case "alloc_param":
|
|
return `alloc_param %${ins.reg}, ${ins.size}`;
|
|
case "alloc_local":
|
|
return `alloc_local %${ins.reg}, ${ins.size}`;
|
|
case "mov_int":
|
|
return `mov_int %${ins.reg}, ${ins.val}`;
|
|
case "mov_string":
|
|
return `mov_string %${ins.reg}, string+${ins.stringId}`;
|
|
case "mov_fn":
|
|
return `mov_fn %${ins.reg}, ${ins.fn.label}`;
|
|
case "push":
|
|
return `push %${ins.reg}`;
|
|
case "pop":
|
|
return `pop %${ins.reg}`;
|
|
case "load":
|
|
return `load %${ins.reg}, [%${ins.sReg}]`;
|
|
case "store_reg":
|
|
return `store_reg [%${ins.sReg}], %${ins.reg}`;
|
|
case "store_imm":
|
|
return `store_val [%${ins.sReg}], ${ins.val}`;
|
|
case "call_reg":
|
|
return `call_reg %${ins.reg}, ${ins.args}`;
|
|
case "call_imm":
|
|
return `call_fn ${ins.fn.label}, ${ins.args}`;
|
|
case "jmp":
|
|
return `jmp .L${ins.target}`;
|
|
case "jnz_reg":
|
|
return `jnz_reg %${ins.reg}, .L${ins.target}`;
|
|
case "ret":
|
|
return "ret";
|
|
case "lt":
|
|
case "gt":
|
|
case "le":
|
|
case "ge":
|
|
case "eq":
|
|
case "ne":
|
|
case "add":
|
|
case "sub":
|
|
case "div":
|
|
case "mul":
|
|
case "mod":
|
|
return `${ins.tag} %${ins.dst}, %${ins.src}`;
|
|
case "kill":
|
|
return `kill %${ins.reg}`;
|
|
}
|
|
const _: never = ins;
|
|
}
|
|
}
|