coed spilt
This commit is contained in:
parent
b2a59de1b2
commit
27e066f5b1
241
compiler.ts
241
compiler.ts
@ -1,241 +0,0 @@
|
||||
import { Expr } from "./parsed";
|
||||
|
||||
export type Register = "acc" | "op";
|
||||
export type Value = number;
|
||||
export type Location = number;
|
||||
|
||||
export type Instruction = ({
|
||||
type: "push" | "pop",
|
||||
register: Register,
|
||||
} | {
|
||||
type: "load",
|
||||
register: Register,
|
||||
value: Value,
|
||||
} | {
|
||||
type: "add" | "mul" | "sub" | "div",
|
||||
left: Register,
|
||||
right: Register,
|
||||
dest: Register,
|
||||
} | {
|
||||
type: "negate",
|
||||
src: Register,
|
||||
dest: Register,
|
||||
} | {
|
||||
type: "jump_zero",
|
||||
register: Register,
|
||||
location: Location,
|
||||
} | {
|
||||
type: "jump",
|
||||
location: Location,
|
||||
}) & ({ jumpedTo: true, label: number } | { jumpedTo?: false });
|
||||
|
||||
export class Compiler {
|
||||
public result: Instruction[] = [];
|
||||
|
||||
public compileExpr(expr: Expr) {
|
||||
switch (expr.exprType) {
|
||||
case "int": {
|
||||
this.result.push({ type: "load", register: "acc", value: expr.value })
|
||||
break;
|
||||
}
|
||||
case "unary": {
|
||||
this.compileExpr(expr.subject);
|
||||
switch (expr.unaryType) {
|
||||
case "plus": {
|
||||
break;
|
||||
}
|
||||
case "negate": {
|
||||
this.result.push({ type: "negate", src: "acc", dest: "acc" })
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "binary": {
|
||||
this.compileExpr(expr.right);
|
||||
this.result.push({ type: "push", register: "acc" })
|
||||
this.compileExpr(expr.left);
|
||||
this.result.push({ type: "pop", register: "op" });
|
||||
let binaryType: "add" | "sub" | "mul" | "div";
|
||||
switch (expr.binaryType) {
|
||||
case "add": {
|
||||
binaryType = "add";
|
||||
break;
|
||||
}
|
||||
case "subtract": {
|
||||
binaryType = "sub";
|
||||
break;
|
||||
}
|
||||
case "multiply": {
|
||||
binaryType = "mul";
|
||||
break;
|
||||
}
|
||||
case "divide": {
|
||||
binaryType = "div";
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.result.push({ type: binaryType, left: "acc", right: "op", dest: "acc" });
|
||||
break;
|
||||
}
|
||||
case "if": {
|
||||
this.compileExpr(expr.condition);
|
||||
|
||||
const jumpToFalsyIndex = this.result.length;
|
||||
this.result.push({ type: "jump_zero", register: "acc", location: 0 });
|
||||
|
||||
this.compileExpr(expr.truthy);
|
||||
|
||||
const skipFalsyIndex = this.result.length;
|
||||
this.result.push({ type: "jump", location: 0 });
|
||||
|
||||
let jumpToFalsyRef = this.result[jumpToFalsyIndex];
|
||||
if (jumpToFalsyRef.type !== "jump_zero") throw new Error("unreachable");
|
||||
jumpToFalsyRef.location = this.result.length;
|
||||
|
||||
this.compileExpr(expr.falsy);
|
||||
|
||||
let skipFalsyRef = this.result[skipFalsyIndex];
|
||||
if (skipFalsyRef.type !== "jump") throw new Error("unreachable");
|
||||
skipFalsyRef.location = this.result.length;
|
||||
|
||||
break;
|
||||
}
|
||||
case "block": {
|
||||
this.compileExpr(expr.expr);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const exhaustiveCheck: never = expr;
|
||||
throw new Error(`Unhandled color case: ${exhaustiveCheck}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function locateAndSetJumpedToInstructions(instructions: Instruction[]) {
|
||||
let nextLabel = 0;
|
||||
for (const ins of instructions) {
|
||||
if (ins.type === "jump_zero" || ins.type === "jump") {
|
||||
instructions[ins.location] = {
|
||||
...instructions[ins.location],
|
||||
jumpedTo: true,
|
||||
label: nextLabel,
|
||||
};
|
||||
nextLabel += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class X86Generator {
|
||||
public generate(instructions: Instruction[]): string {
|
||||
return this.asmWithHeaders(instructions.map((ins) => this.generateInstruction(ins)).join(""));
|
||||
}
|
||||
|
||||
private generateInstruction(ins: Instruction): string {
|
||||
let result = "";
|
||||
if (ins.jumpedTo) {
|
||||
|
||||
}
|
||||
switch (ins.type) {
|
||||
case "load": {
|
||||
result += ` ; load`
|
||||
result += ` mov ${this.reg64(ins.register)}, ${this.value(ins.value)}\n`;
|
||||
break;
|
||||
}
|
||||
case "push": {
|
||||
return `
|
||||
; push
|
||||
push ${this.reg64(ins.register)}
|
||||
`;
|
||||
}
|
||||
case "pop": {
|
||||
return `
|
||||
; pop
|
||||
pop ${this.reg64(ins.register)}
|
||||
`;
|
||||
}
|
||||
case "negate": {
|
||||
return `
|
||||
; neg
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.src)}
|
||||
neg ${this.reg64(ins.dest)}
|
||||
`;
|
||||
}
|
||||
case "add": {
|
||||
return `
|
||||
; add
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.left)}
|
||||
add ${this.reg64(ins.dest)}, ${this.reg64(ins.right)}
|
||||
`;
|
||||
}
|
||||
case "sub": {
|
||||
return `
|
||||
; sub
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.left)}
|
||||
sub ${this.reg64(ins.dest)}, ${this.reg64(ins.right)}
|
||||
`;
|
||||
}
|
||||
case "mul": {
|
||||
return `
|
||||
; mul
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.left)}
|
||||
imul ${this.reg64(ins.dest)}, ${this.reg64(ins.right)}
|
||||
`;
|
||||
}
|
||||
case "div": {
|
||||
return `
|
||||
; div
|
||||
mov rdi, ${this.reg64(ins.right)}
|
||||
mov rax, ${this.reg64(ins.left)}
|
||||
xor rdx, rdx
|
||||
cqo
|
||||
idiv rdi
|
||||
mov ${this.reg64(ins.dest)}, rax
|
||||
`;
|
||||
}
|
||||
case "jump_zero": {
|
||||
return `
|
||||
; jump_zero
|
||||
|
||||
`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private asmWithHeaders(asm: string) {
|
||||
return `
|
||||
bits 64
|
||||
global _start
|
||||
|
||||
_start:
|
||||
${asm}
|
||||
exit:
|
||||
mov rdi, rax
|
||||
mov rax, 60
|
||||
syscall
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
private reg64(reg: Register): string {
|
||||
switch (reg) {
|
||||
case "acc": return "rax";
|
||||
case "op": return "rdx";
|
||||
}
|
||||
}
|
||||
|
||||
private reg32(reg: Register): string {
|
||||
switch (reg) {
|
||||
case "acc": return "eax";
|
||||
case "op": return "edx";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private value(value: Value): string {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
60
grammar.ne
60
grammar.ne
@ -1,60 +0,0 @@
|
||||
@preprocessor typescript
|
||||
|
||||
@{%
|
||||
import { Expr } from "./parsed";
|
||||
%}
|
||||
|
||||
expr -> term {% id %}
|
||||
|
||||
term -> term _ "+" _ factor
|
||||
{% ([left, _0, _1, _2, right]): Expr =>
|
||||
({ exprType: "binary", binaryType: "add", left, right }) %}
|
||||
| term _ "-" _ factor
|
||||
{% ([left, _0, _1, _2, right]): Expr =>
|
||||
({ exprType: "binary", binaryType: "subtract", left, right }) %}
|
||||
| factor {% id %}
|
||||
|
||||
factor -> factor _ "*" _ unary
|
||||
{% ([left, _0, _1, _2, right]): Expr =>
|
||||
({ exprType: "binary", binaryType: "multiply", left, right }) %}
|
||||
| factor _ "/" _ unary
|
||||
{% ([left, _0, _1, _2, right]): Expr =>
|
||||
({ exprType: "binary", binaryType: "divide", left, right }) %}
|
||||
| unary {% id %}
|
||||
|
||||
unary -> "+" _ unary
|
||||
{% ([_0, _1, subject]): Expr =>
|
||||
({ exprType: "unary", unaryType: "plus", subject }) %}
|
||||
| "-" _ unary
|
||||
{% ([_0, _1, subject]): Expr =>
|
||||
({ exprType: "unary", unaryType: "negate", subject }) %}
|
||||
| operand {% id %}
|
||||
|
||||
operand -> int {% id %}
|
||||
| group {% id %}
|
||||
| block {% id %}
|
||||
| if {% id %}
|
||||
|
||||
int -> [0-9]:+
|
||||
{% ([token]): Expr =>
|
||||
({ exprType: "int", value: parseInt(token.join("")) }) %}
|
||||
|
||||
group -> "(" _ expr _ ")" {% (v): Expr => v[2] %}
|
||||
|
||||
block -> "{" _ expr _ "}" {% (v): Expr => ({ exprType: "block", expr: v[2] }) %}
|
||||
|
||||
if -> "if" __ expr _ block _ "else" _ block
|
||||
{%
|
||||
(v): Expr => ({
|
||||
exprType: "if",
|
||||
condition: v[2],
|
||||
truthy: v[4],
|
||||
falsy: v[8]
|
||||
})
|
||||
%}
|
||||
|
||||
_ -> __:?
|
||||
__ -> ws:+
|
||||
|
||||
ws -> [ \t\r\n]
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "npm run build && ts-node main.ts",
|
||||
"build": "nearleyc grammar.ne -o grammar.out.ts"
|
||||
"start": "npm run build && ts-node src/main.ts",
|
||||
"build": "nearleyc src/grammar.ne -o src/grammar.out.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/moo": "^0.5.5",
|
||||
@ -10,6 +11,7 @@
|
||||
"moo": "^0.5.2",
|
||||
"nearley": "^2.20.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"ts-results": "^3.3.0",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
||||
|
103
src/compiler.ts
Normal file
103
src/compiler.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { Instruction } from "./ir";
|
||||
import { Expr } from "./parsed";
|
||||
import { assertExhaustive } from "./utils";
|
||||
|
||||
|
||||
export class Compiler {
|
||||
public result: Instruction[] = [];
|
||||
|
||||
public compileExpr(expr: Expr) {
|
||||
switch (expr.exprType) {
|
||||
case "int": {
|
||||
this.result.push({ type: "load", register: "acc", value: expr.value })
|
||||
break;
|
||||
}
|
||||
case "unary": {
|
||||
this.compileExpr(expr.subject);
|
||||
switch (expr.unaryType) {
|
||||
case "plus": {
|
||||
break;
|
||||
}
|
||||
case "negate": {
|
||||
this.result.push({ type: "negate", src: "acc", dest: "acc" })
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "binary": {
|
||||
this.compileExpr(expr.right);
|
||||
this.result.push({ type: "push", register: "acc" })
|
||||
this.compileExpr(expr.left);
|
||||
this.result.push({ type: "pop", register: "op" });
|
||||
let binaryType: "add" | "sub" | "mul" | "div";
|
||||
switch (expr.binaryType) {
|
||||
case "add": {
|
||||
binaryType = "add";
|
||||
break;
|
||||
}
|
||||
case "subtract": {
|
||||
binaryType = "sub";
|
||||
break;
|
||||
}
|
||||
case "multiply": {
|
||||
binaryType = "mul";
|
||||
break;
|
||||
}
|
||||
case "divide": {
|
||||
binaryType = "div";
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.result.push({ type: binaryType, left: "acc", right: "op", dest: "acc" });
|
||||
break;
|
||||
}
|
||||
case "if": {
|
||||
this.compileExpr(expr.condition);
|
||||
|
||||
const jumpToFalsyIndex = this.result.length;
|
||||
this.result.push({ type: "jump_zero", register: "acc", location: 0 });
|
||||
|
||||
this.compileExpr(expr.truthy);
|
||||
|
||||
const skipFalsyIndex = this.result.length;
|
||||
this.result.push({ type: "jump", location: 0 });
|
||||
|
||||
let jumpToFalsyRef = this.result[jumpToFalsyIndex];
|
||||
if (jumpToFalsyRef.type !== "jump_zero") throw new Error("unreachable");
|
||||
jumpToFalsyRef.location = this.result.length;
|
||||
|
||||
this.compileExpr(expr.falsy);
|
||||
|
||||
let skipFalsyRef = this.result[skipFalsyIndex];
|
||||
if (skipFalsyRef.type !== "jump") throw new Error("unreachable");
|
||||
skipFalsyRef.location = this.result.length;
|
||||
|
||||
break;
|
||||
}
|
||||
case "block": {
|
||||
this.compileExpr(expr.expr);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function locateAndSetJumpedToInstructions(instructions: Instruction[]) {
|
||||
let nextLabel = 0;
|
||||
for (const ins of instructions) {
|
||||
if (ins.type === "jump_zero" || ins.type === "jump") {
|
||||
instructions[ins.location] = {
|
||||
...instructions[ins.location],
|
||||
jumpedTo: true,
|
||||
label: nextLabel,
|
||||
};
|
||||
nextLabel += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
63
src/grammar.ne
Normal file
63
src/grammar.ne
Normal file
@ -0,0 +1,63 @@
|
||||
@preprocessor typescript
|
||||
|
||||
@{%
|
||||
import { Expr } from "./parsed";
|
||||
|
||||
const expr = (e: Expr): Expr => e;
|
||||
|
||||
%}
|
||||
|
||||
expr -> term {% id %}
|
||||
|
||||
term -> term _ "+" _ factor
|
||||
{% ([left, _0, _1, _2, right]) =>
|
||||
expr({ exprType: "binary", binaryType: "add", left, right }) %}
|
||||
| term _ "-" _ factor
|
||||
{% ([left, _0, _1, _2, right]) =>
|
||||
expr({ exprType: "binary", binaryType: "subtract", left, right }) %}
|
||||
| factor {% id %}
|
||||
|
||||
factor -> factor _ "*" _ unary
|
||||
{% ([left, _0, _1, _2, right]) =>
|
||||
expr({ exprType: "binary", binaryType: "multiply", left, right }) %}
|
||||
| factor _ "/" _ unary
|
||||
{% ([left, _0, _1, _2, right]) =>
|
||||
expr({ exprType: "binary", binaryType: "divide", left, right }) %}
|
||||
| unary {% id %}
|
||||
|
||||
unary -> "+" _ unary
|
||||
{% ([_0, _1, subject]) =>
|
||||
expr({ exprType: "unary", unaryType: "plus", subject }) %}
|
||||
| "-" _ unary
|
||||
{% ([_0, _1, subject]) =>
|
||||
expr({ exprType: "unary", unaryType: "negate", subject }) %}
|
||||
| operand {% id %}
|
||||
|
||||
operand -> int {% id %}
|
||||
| group {% id %}
|
||||
| block {% id %}
|
||||
| if {% id %}
|
||||
|
||||
int -> [0-9]:+
|
||||
{% ([token]) =>
|
||||
expr({ exprType: "int", value: parseInt(token.join("")) }) %}
|
||||
|
||||
group -> "(" _ expr _ ")" {% v => expr(v[2]) %}
|
||||
|
||||
block -> "{" _ expr _ "}" {% v => expr({ exprType: "block", expr: v[2] }) %}
|
||||
|
||||
if -> "if" __ expr _ block _ "else" _ block
|
||||
{%
|
||||
v => expr({
|
||||
exprType: "if",
|
||||
condition: v[2],
|
||||
truthy: v[4],
|
||||
falsy: v[8]
|
||||
})
|
||||
%}
|
||||
|
||||
_ -> __:?
|
||||
__ -> ws:+
|
||||
|
||||
ws -> [ \t\r\n]
|
||||
|
28
src/ir.ts
Normal file
28
src/ir.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export type Register = "acc" | "op";
|
||||
export type Value = number;
|
||||
export type Location = number;
|
||||
|
||||
export type Instruction = ({
|
||||
type: "push" | "pop",
|
||||
register: Register,
|
||||
} | {
|
||||
type: "load",
|
||||
register: Register,
|
||||
value: Value,
|
||||
} | {
|
||||
type: "add" | "mul" | "sub" | "div",
|
||||
left: Register,
|
||||
right: Register,
|
||||
dest: Register,
|
||||
} | {
|
||||
type: "negate",
|
||||
src: Register,
|
||||
dest: Register,
|
||||
} | {
|
||||
type: "jump_zero",
|
||||
register: Register,
|
||||
location: Location,
|
||||
} | {
|
||||
type: "jump",
|
||||
location: Location,
|
||||
}) & ({ jumpedTo: true, label: number } | { jumpedTo?: false });
|
@ -1,8 +1,8 @@
|
||||
import { Parser, Grammar } from "nearley"
|
||||
import compiledGrammar from "./grammar.out"
|
||||
import { Compiler, Instruction, Register, Value, X86Generator as X8664Generator, locateAndSetJumpedToInstructions } from "./compiler";
|
||||
import { Compiler, locateAndSetJumpedToInstructions } from "./compiler";
|
||||
import fs from "fs/promises";
|
||||
import { exec } from "child_process";
|
||||
import { parse } from "./parser";
|
||||
import { X8664Generator } from "./x86_64_generator";
|
||||
|
||||
function executeCommand(command: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
@ -22,16 +22,13 @@ function executeCommand(command: string) {
|
||||
}
|
||||
|
||||
async function main(args: string[]) {
|
||||
const parser = new Parser(Grammar.fromCompiled(compiledGrammar));
|
||||
|
||||
const input = args[2];
|
||||
|
||||
if (input === null)
|
||||
throw new Error("input fucked")
|
||||
|
||||
parser.feed(input);
|
||||
|
||||
const ast = parser.results[0];
|
||||
const ast = parse(input).unwrap();
|
||||
|
||||
console.log(JSON.stringify(ast, null, 4))
|
||||
|
20
src/parser.ts
Normal file
20
src/parser.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Grammar, Parser } from "nearley";
|
||||
import { Err, Ok, Result } from "ts-results";
|
||||
import compiledGrammar from "./grammar.out"
|
||||
import { Expr } from "./parsed";
|
||||
|
||||
export function parse(text: string): Result<Expr, string> {
|
||||
const parser = new Parser(Grammar.fromCompiled(compiledGrammar));
|
||||
try {
|
||||
parser.feed(text);
|
||||
} catch (parseError) {
|
||||
console.log(parseError)
|
||||
}
|
||||
const result = parser.results?.at(0);
|
||||
if (!result)
|
||||
return Err("failed to parse");
|
||||
if (parser.results.length > 1)
|
||||
return Err("ambigous parse result");
|
||||
return Ok(result);
|
||||
}
|
||||
|
12
src/utils.ts
Normal file
12
src/utils.ts
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
export function assertExhaustive(matchedItem?: never): never {
|
||||
throw new Error(`unexhaustive match, unmatched value: ${matchedItem}`);
|
||||
}
|
||||
|
||||
export function toString(value: unknown): string {
|
||||
const stringified = String(value);
|
||||
if (stringified === "[object Object]")
|
||||
return JSON.stringify(value, null, 4)
|
||||
return stringified;
|
||||
}
|
||||
|
148
src/x86_64_generator.ts
Normal file
148
src/x86_64_generator.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import { Instruction, Register, Value } from "./ir";
|
||||
import { assertExhaustive } from "./utils";
|
||||
|
||||
export class X8664Generator {
|
||||
private result = "";
|
||||
|
||||
public generate(instructions: Instruction[]): string {
|
||||
this.result = "";
|
||||
for (const ins of instructions) {
|
||||
this.generateInstruction(ins, instructions);
|
||||
}
|
||||
return this.asmWithHeaders(this.result);
|
||||
}
|
||||
|
||||
private generateInstruction(ins: Instruction, instructions: Instruction[]) {
|
||||
let result = "";
|
||||
if (ins.jumpedTo)
|
||||
result += `.L${ins.label}:\n`;
|
||||
switch (ins.type) {
|
||||
case "load":
|
||||
this.add(`
|
||||
; load
|
||||
mov ${this.reg64(ins.register)}, ${this.value(ins.value)}
|
||||
`);
|
||||
break;
|
||||
case "push":
|
||||
this.add(`
|
||||
; push
|
||||
push ${this.reg64(ins.register)}
|
||||
`);
|
||||
case "pop":
|
||||
this.add(`
|
||||
; pop
|
||||
pop ${this.reg64(ins.register)}
|
||||
`);
|
||||
break;
|
||||
case "negate":
|
||||
this.add(`
|
||||
; neg
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.src)}
|
||||
neg ${this.reg64(ins.dest)}
|
||||
`);
|
||||
break;
|
||||
case "add":
|
||||
this.add(`
|
||||
; add
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.left)}
|
||||
add ${this.reg64(ins.dest)}, ${this.reg64(ins.right)}
|
||||
`);
|
||||
break;
|
||||
case "sub":
|
||||
this.add(`
|
||||
; sub
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.left)}
|
||||
sub ${this.reg64(ins.dest)}, ${this.reg64(ins.right)}
|
||||
`);
|
||||
break;
|
||||
case "mul":
|
||||
this.add(`
|
||||
; mul
|
||||
mov ${this.reg64(ins.dest)}, ${this.reg64(ins.left)}
|
||||
imul ${this.reg64(ins.dest)}, ${this.reg64(ins.right)}
|
||||
`);
|
||||
break;
|
||||
case "div":
|
||||
this.add(`
|
||||
; div
|
||||
mov rdi, ${this.reg64(ins.right)}
|
||||
mov rax, ${this.reg64(ins.left)}
|
||||
xor rdx, rdx
|
||||
cqo
|
||||
idiv rdi
|
||||
mov ${this.reg64(ins.dest)}, rax
|
||||
`);
|
||||
break;
|
||||
case "jump_zero":
|
||||
this.add(`
|
||||
; jump_zero
|
||||
cmp ${ins.register}
|
||||
jz .L${(() => {
|
||||
const dest = instructions[ins.location];
|
||||
if (!dest.jumpedTo)
|
||||
throw new Error("impossible");
|
||||
return dest.label;
|
||||
})()}
|
||||
`);
|
||||
break;
|
||||
case "jump":
|
||||
this.add(`
|
||||
; jump
|
||||
jz .L${(() => {
|
||||
const dest = instructions[ins.location];
|
||||
if (!dest.jumpedTo)
|
||||
throw new Error("impossible");
|
||||
return dest.label;
|
||||
})()}
|
||||
`);
|
||||
break;
|
||||
default:
|
||||
assertExhaustive(ins);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private add(lines: string) {
|
||||
this.result += lines
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map(s => s.replace(/^( )+/, " "))
|
||||
.join("\n")
|
||||
+ "\n";
|
||||
}
|
||||
|
||||
private asmWithHeaders(asm: string) {
|
||||
return `
|
||||
bits 64
|
||||
global _start
|
||||
|
||||
_start:
|
||||
\t${asm}
|
||||
exit:
|
||||
\tmov rdi, rax
|
||||
\tmov rax, 60
|
||||
\tsyscall
|
||||
|
||||
`.replace(/ /g, "").replace(/\t/g, " ");
|
||||
}
|
||||
|
||||
private reg64(reg: Register): string {
|
||||
switch (reg) {
|
||||
case "acc": return "rax";
|
||||
case "op": return "rdx";
|
||||
}
|
||||
}
|
||||
|
||||
private reg32(reg: Register): string {
|
||||
switch (reg) {
|
||||
case "acc": return "eax";
|
||||
case "op": return "edx";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private value(value: Value): string {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
Arguments:
|
||||
/usr/bin/node /usr/bin/yarn add ts-done
|
||||
|
||||
PATH:
|
||||
/home/pieter/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/home/pieter/.cargo/bin:/home/pieter/.yarn/bin:/home/pieter/.cabal/bin:/home/pieter/.ghcup/bin
|
||||
|
||||
Yarn version:
|
||||
1.22.19
|
||||
|
||||
Node version:
|
||||
20.4.0
|
||||
|
||||
Platform:
|
||||
linux x64
|
||||
|
||||
Trace:
|
||||
Error: https://registry.yarnpkg.com/ts-done: Not found
|
||||
at params.callback [as _callback] (/usr/lib/node_modules/yarn/lib/cli.js:66145:18)
|
||||
at self.callback (/usr/lib/node_modules/yarn/lib/cli.js:140890:22)
|
||||
at Request.emit (node:events:512:28)
|
||||
at Request.<anonymous> (/usr/lib/node_modules/yarn/lib/cli.js:141862:10)
|
||||
at Request.emit (node:events:512:28)
|
||||
at IncomingMessage.<anonymous> (/usr/lib/node_modules/yarn/lib/cli.js:141784:12)
|
||||
at Object.onceWrapper (node:events:626:28)
|
||||
at IncomingMessage.emit (node:events:524:35)
|
||||
at endReadableNT (node:internal/streams/readable:1378:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
|
||||
|
||||
npm manifest:
|
||||
{
|
||||
"scripts": {
|
||||
"build": "nearleyc grammar.ne -o grammar.out.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"moo": "^0.5.2",
|
||||
"nearley": "^2.20.1"
|
||||
}
|
||||
}
|
||||
|
||||
yarn manifest:
|
||||
No manifest
|
||||
|
||||
Lockfile:
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
commander@^2.19.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
discontinuous-range@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
|
||||
integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==
|
||||
|
||||
moo@^0.5.0, moo@^0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"
|
||||
integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
|
||||
|
||||
nearley@^2.20.1:
|
||||
version "2.20.1"
|
||||
resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474"
|
||||
integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==
|
||||
dependencies:
|
||||
commander "^2.19.0"
|
||||
moo "^0.5.0"
|
||||
railroad-diagrams "^1.0.0"
|
||||
randexp "0.4.6"
|
||||
|
||||
railroad-diagrams@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
|
||||
integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==
|
||||
|
||||
randexp@0.4.6:
|
||||
version "0.4.6"
|
||||
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
|
||||
integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==
|
||||
dependencies:
|
||||
discontinuous-range "1.0.0"
|
||||
ret "~0.1.10"
|
||||
|
||||
ret@~0.1.10:
|
||||
version "0.1.15"
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
@ -154,6 +154,11 @@ ts-node@^10.9.1:
|
||||
v8-compile-cache-lib "^3.0.1"
|
||||
yn "3.1.1"
|
||||
|
||||
ts-results@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-results/-/ts-results-3.3.0.tgz#68623a6c18e65556287222dab76498a28154922f"
|
||||
integrity sha512-FWqxGX2NHp5oCyaMd96o2y2uMQmSu8Dey6kvyuFdRJ2AzfmWo3kWa4UsPlCGlfQ/qu03m09ZZtppMoY8EMHuiA==
|
||||
|
||||
typescript@^5.1.6:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
|
||||
|
Loading…
Reference in New Issue
Block a user