summary refs log tree commit diff
path: root/the_e_programming_language/compiler.ts
diff options
context:
space:
mode:
Diffstat (limited to 'the_e_programming_language/compiler.ts')
-rw-r--r--the_e_programming_language/compiler.ts151
1 files changed, 151 insertions, 0 deletions
diff --git a/the_e_programming_language/compiler.ts b/the_e_programming_language/compiler.ts
new file mode 100644
index 0000000..37538f7
--- /dev/null
+++ b/the_e_programming_language/compiler.ts
@@ -0,0 +1,151 @@
+import { ASTNode, BinaryExpressionNode, FunctionDeclarationNode, NumberNode, VariableDeclarationNode, WhileNode } from "./ast.ts";
+// import { PC } from "../pc.ts";
+// const pc = new PC();
+
+type Opcode = 
+    'mov'  |
+    'swp'  |
+    'ld'   |
+    'str'  |
+    'add'  |
+    'sub'  |
+    'mul'  |
+    'div'  |
+    'mod'  |
+    'shl'  |
+    'shr'  |
+    'cmp'  |
+    'cmr'  |
+    'and'  |
+    'or'   |
+    'xor'  |
+    'not'  |
+    'push' |
+    'pop'  |
+    'halt' |
+    'sys'  |
+    'jmp'  |
+    'jnz'  |
+    'jz'   |
+    'jmr'  |
+    'ret'  |
+    'end';
+type Register = 97 | 98 | 99 | 100
+
+interface Instruction {
+    opcode: Opcode,
+    args: (Register | number)[]
+}
+
+const types: Record<string, number> = {
+    'int' : 1,
+    'bool': 1,
+    'char': 1
+}
+
+const A: Register = 97;
+const B: Register = 98;
+// deno-lint-ignore no-unused-vars
+const C: Register = 99;
+// deno-lint-ignore no-unused-vars
+const D: Register = 100;
+
+export default class Compiler {
+    vars: Record<string, [number, number]> = {};
+    functions: Record<string, number> = {};
+    AST: ASTNode[];
+    lastAddr: number = 0;
+    instructions: Instruction[] = [];
+    constructor (ast: ASTNode[]) {
+        this.AST = ast
+    }
+    compile (node: ASTNode) {
+        if ((node as VariableDeclarationNode).type == 'VariableDeclaration') {
+            const varDeclNode = node as VariableDeclarationNode;
+            if (!types[varDeclNode.vtype]) throw 'unknown type';
+            const addr = this.vars[varDeclNode.identifier] =
+                [this.lastAddr, types[varDeclNode.vtype] * varDeclNode.length];
+            this.lastAddr += types[varDeclNode.vtype] * varDeclNode.length;
+            if (varDeclNode.value.type != 'Number') throw 'a';
+            this.instructions.push({
+                opcode: 'mov',
+                args: [A, (varDeclNode.value as NumberNode).value]
+            })
+            this.instructions.push({
+                opcode: 'mov',
+                args: [B, addr[0]]
+            })
+            this.instructions.push({
+                opcode: 'str',
+                args: [B, A]
+            })
+        } else if ((node as FunctionDeclarationNode).type == 'FunctionDeclaration') {
+            const fnDeclNode = node as FunctionDeclarationNode;
+            this.functions[fnDeclNode.name] = this.instructions
+                .map(k => 1 + k.args.length)
+                .reduce((prev, curr) => {
+                    return prev + curr 
+                }, 0);
+            for (const node of fnDeclNode.body) {
+                this.compile(node)
+            }
+        } else if ((node as BinaryExpressionNode).type == 'BinaryExpression') {
+            const binExpNode = node as BinaryExpressionNode;
+            this.instructions.push({
+                opcode: 'pop',
+                args: [A]
+            })
+            this.instructions.push({
+                opcode: 'pop',
+                args: [B]
+            })
+            switch (binExpNode.operator) {
+                case '+':
+                    this.instructions.push({
+                        opcode: 'add',
+                        args: [A, A, B]
+                    })
+                    break;
+            
+                default:
+                    throw 'oh no'
+            }
+            this.instructions.push({
+                opcode: 'push',
+                args: [A]
+            })
+        } else if ((node as WhileNode).type == 'While') {
+            const whileNode = node as WhileNode;
+            const start = this.instructions
+                .map(k => 1 + k.args.length)
+                .reduce((prev, curr) => {
+                    return prev + curr 
+                }, 0);
+            for (const node of whileNode.branch) {
+                this.compile(node)
+            }
+            this.instructions.push({
+                opcode: 'pop',
+                args: [A]
+            })
+            this.instructions.push({
+                opcode: 'mov',
+                args: [B, 0]
+            })
+            this.instructions.push({
+                opcode: 'cmp',
+                args: [A, B]
+            })
+            this.instructions.push({
+                opcode: 'mov',
+                args: [A, start]
+            })
+            this.instructions.push({
+                opcode: 'jnz',
+                args: [A]
+            })
+        } else {
+            console.error(`!!! UNIMPLEMENTED NODE `, node.type, node)
+        }
+    }
+}
\ No newline at end of file