impl
This commit is contained in:
		
							parent
							
								
									204e71acc7
								
							
						
					
					
						commit
						27ec81441b
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,4 @@ | ||||
| 
 | ||||
| node_modules | ||||
| *.out.* | ||||
| a.out | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										182
									
								
								compiler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								compiler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,182 @@ | ||||
| import { Expr } from "./parsed"; | ||||
| 
 | ||||
| export type Register = "acc" | "op"; | ||||
| export type Value = 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, | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|             } | ||||
|             default: { | ||||
|                 const exhaustiveCheck: never = expr; | ||||
|                 throw new Error(`Unhandled color case: ${exhaustiveCheck}`); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export class X86Generator { | ||||
|     public generate(instructions: Instruction[]): string { | ||||
|         return this.asmWithHeaders(instructions.map((ins) => this.generateInstruction(ins)).join("")); | ||||
|     } | ||||
| 
 | ||||
|     private generateInstruction(ins: Instruction): string { | ||||
|         switch (ins.type) { | ||||
|             case "load": { | ||||
|                 return ` | ||||
|                     mov ${this.reg64(ins.register)}, ${this.value(ins.value)} | ||||
|                 `;
 | ||||
|             } | ||||
|             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 | ||||
|                 `;
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										35
									
								
								grammar.ne
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								grammar.ne
									
									
									
									
									
								
							| @ -6,32 +6,37 @@ import { Expr } from "./parsed"; | ||||
| 
 | ||||
| expr -> term {% id %} | ||||
| 
 | ||||
| term -> term "+" factor | ||||
| 		{% ([left, _, right]): Expr => | ||||
| term -> term _ "+" _ factor | ||||
| 		{% ([left, _0, _1, _2, right]): Expr => | ||||
| 			({ exprType: "binary", binaryType: "add", left, right }) %} | ||||
| 	| term "-" factor | ||||
| 		{% ([left, _, right]): Expr => | ||||
| 	| term _ "-" _ factor | ||||
| 		{% ([left, _0, _1, _2, right]): Expr => | ||||
| 			({ exprType: "binary", binaryType: "subtract", left, right }) %} | ||||
| 	| factor {% id %} | ||||
| 
 | ||||
| factor -> factor "*" unary | ||||
| 		{% ([left, _, right]): Expr => | ||||
| factor -> factor _ "*" _ unary | ||||
| 		{% ([left, _0, _1, _2, right]): Expr => | ||||
| 			({ exprType: "binary", binaryType: "multiply", left, right }) %} | ||||
| 	| factor "/" unary | ||||
| 		{% ([left, _, right]): Expr => | ||||
| 	| factor _ "/" _ unary | ||||
| 		{% ([left, _0, _1, _2, right]): Expr => | ||||
| 			({ exprType: "binary", binaryType: "divide", left, right }) %} | ||||
| 	| unary {% id %} | ||||
| 
 | ||||
| unary -> "+" unary | ||||
| 		{% ([_, subject]): Expr => | ||||
| unary -> "+" _ unary | ||||
| 		{% ([_0, _1, subject]): Expr => | ||||
| 			({ exprType: "unary", unaryType: "plus", subject }) %} | ||||
| 	| "-" unary | ||||
| 		{% ([_, subject]): Expr => | ||||
| 	| "-" _ unary | ||||
| 		{% ([_0, _1, subject]): Expr => | ||||
| 			({ exprType: "unary", unaryType: "negate", subject }) %} | ||||
| 	| operand {% id %} | ||||
| 
 | ||||
| operand -> "(" expr ")" {% ([_, expr]): Expr => expr %} | ||||
| 	| ("0" | [1-9][0-9]:*) {% ([token]): Expr => ({ exprType: "int", value: parseInt(token.value) }) %} | ||||
| operand -> "(" _ expr _ ")" {% ([_0, _1, expr]): Expr => expr %} | ||||
| 	| [0-9]:+ | ||||
| 		{% ([token]): Expr => | ||||
| 			({ exprType: "int", value: parseInt(token.join("")) }) %} | ||||
| 
 | ||||
| _ -> __:? | ||||
| __ -> [ \t\r\n]:+ | ||||
| __ -> ws:+ | ||||
| 
 | ||||
| ws -> [ \t\r\n] | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										53
									
								
								main.ts
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								main.ts
									
									
									
									
									
								
							| @ -1,16 +1,55 @@ | ||||
| import { Parser, Grammar } from "nearley" | ||||
| import compiledGrammar from "./grammar.out" | ||||
| import { Compiler, Instruction, Register, Value, X86Generator as X8664Generator } from "./compiler"; | ||||
| import fs from "fs/promises"; | ||||
| import { exec } from "child_process"; | ||||
| 
 | ||||
| const parser = new Parser(Grammar.fromCompiled(compiledGrammar)); | ||||
| function executeCommand(command: string) { | ||||
|     return new Promise<void>((resolve, reject) => { | ||||
|         exec(command, {}, (error, stdout, stderr) => { | ||||
|             if (stdout) console.log(stdout); | ||||
|             if (stderr) console.error(stderr); | ||||
| 
 | ||||
| const input = "1 + 2"; | ||||
|             if (error) { | ||||
|                 console.error(error); | ||||
|                 reject(); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
| if (input === null) | ||||
|     throw new Error("input fucked") | ||||
|             resolve(); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| parser.feed(input); | ||||
| async function main(args: string[]) { | ||||
|     const parser = new Parser(Grammar.fromCompiled(compiledGrammar)); | ||||
| 
 | ||||
| const ast = parser.results; | ||||
|     const input = args[2]; | ||||
| 
 | ||||
| console.log(JSON.stringify(ast, null, 4)) | ||||
|     if (input === null) | ||||
|         throw new Error("input fucked") | ||||
| 
 | ||||
|     parser.feed(input); | ||||
| 
 | ||||
|     const ast = parser.results[0]; | ||||
| 
 | ||||
|     console.log(JSON.stringify(ast, null, 4)) | ||||
| 
 | ||||
|     const compiler = new Compiler(); | ||||
|     compiler.compileExpr(ast); | ||||
|     const ir = compiler.result; | ||||
|     console.log(ir); | ||||
| 
 | ||||
|     const generator = new X8664Generator(); | ||||
|     const asm = generator.generate(ir); | ||||
|     console.log(asm); | ||||
| 
 | ||||
|     await fs.writeFile("generated.out.asm", asm); | ||||
| 
 | ||||
|     await executeCommand("nasm -f elf64 -o generated.out.o generated.out.asm"); | ||||
| 
 | ||||
|     await executeCommand("ld generated.out.o -o a.out"); | ||||
| } | ||||
| 
 | ||||
| main(process.argv); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user