/
cli.ts
101 lines (86 loc) · 2.54 KB
/
cli.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#! /usr/bin/env node
import { Compiler } from "./compiler.js";
import { Sim } from "./sim.js";
import { Parser } from "./parser.js";
import { Command } from "commander";
import fs from "fs/promises";
import path from "path";
process.on("uncaughtException", (err) => {
console.log(err.message);
});
const parser = new Parser();
const compiler = new Compiler();
const program = new Command();
const inputBuffer: number[] = [];
let simRunning = false;
const sim = new Sim({
outputRawCallback: (n) => {
if (n == 0x7f)
//Backspace
process.stdout.write("\b \b");
else if (n == 0x0d || n == 0x0a)
//CR
process.stdout.write("\n");
else process.stdout.write(String.fromCharCode(n));
},
inputAvailableCallback: () => inputBuffer.length > 0,
inputRawCallback: () => inputBuffer.shift(),
haltCallback: () => {
console.log("\n\nHalting");
simRunning = false;
},
badInsCallback: (adr) => console.warn("Bad instruction at address: ", adr),
});
function stepSim() {
for (let i = 0; i < 1_000_000; i++) {
sim.singleStep();
if (!simRunning) process.exit();
}
setTimeout(stepSim); //Set timeout allows for input handling code to run
}
function runSim() {
process.stdin.setRawMode?.(true);
process.stdin.on("data", (data) => {
for (const d of data) {
if (d == 3) process.exit(); // ctrl-c
else inputBuffer.push(d);
}
});
simRunning = true;
stepSim();
}
program.name("16TTAC-sim").description("Simulator and compiler for the 16TTAC");
program.argument("<source>", "Source file to run").action(async (source) => {
const sourceCode = await fs.readFile(source, { encoding: "utf8" });
sim.initializeMemory(compiler.compile(parser.parse(sourceCode)));
runSim();
});
program
.command("compile")
.argument("<source>", "Source file to compile")
.argument("[binary]", "File to write binary output to")
.action(async (source, output) => {
const sourceCode = await fs.readFile(source, { encoding: "utf8" });
const outputName =
output ||
path.join(
path.dirname(source),
path.basename(source, path.extname(source)) + ".bin"
);
fs.writeFile(outputName, compiler.compile(parser.parse(sourceCode)));
});
program
.command("run")
.argument("<binary>", "Binary file to run")
.action(async (binary) => {
const loadedBuffer = await fs.readFile(binary);
sim.initializeMemory(
new Uint16Array(
loadedBuffer.buffer,
loadedBuffer.byteOffset,
loadedBuffer.length / 2
)
);
runSim();
});
program.parse();