From 8adccb7b65f96818781e236e17aca55d1083af24 Mon Sep 17 00:00:00 2001 From: Neon Date: Tue, 22 Feb 2022 03:39:07 -0500 Subject: [PATCH] FIRST STUFF --- .gitignore | 3 ++ disco.asm | 52 +++++++++++++++++++ disco.disco | 3 ++ disco.js | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++ out.asm | 33 ++++++++++++ package.json | 11 ++++ 6 files changed, 242 insertions(+) create mode 100644 .gitignore create mode 100644 disco.asm create mode 100644 disco.disco create mode 100755 disco.js create mode 100644 out.asm create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7764e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +disco +out +*.o \ No newline at end of file diff --git a/disco.asm b/disco.asm new file mode 100644 index 0000000..bae15c7 --- /dev/null +++ b/disco.asm @@ -0,0 +1,52 @@ + + +section .data + text db "abc",10,0 + +section .bss + stackArguments resb 64 + trip resb 8 ; temporary return instruction pointer (for stack manipulation) + ; tem resb 64 + +section .text + global _start + +_start: + push text + call _print + call _exit + +_print: + ; first we remove the params from the stack + ; remembering to not fuck up our return pointer + pop qword [trip] ; pop old instruction pointer, save for later. + pop rax ; pop first argument + push qword [trip] ; push the old execution pointer back + + ; reset base stack to here. + push rbp + mov rbp, rsp + + ; push in our arguments + push rax + ; rbp+0 => old base pointer + ; rbp+8 => old instruction pointer + ; rbp+16 => last param + ; rbp+24 => first param + + mov rax, 1 + mov rdi, 1 + mov rsi, [rbp - 8] + mov rdx, 4 + syscall + + ; pop variables (arguments) off stack + add rsp, 8 + pop rbp + ret + +_exit: + mov rax, 60 + mov rdi, 0 + syscall + ret \ No newline at end of file diff --git a/disco.disco b/disco.disco new file mode 100644 index 0000000..1372c42 --- /dev/null +++ b/disco.disco @@ -0,0 +1,3 @@ + +link log +log("hello\n") \ No newline at end of file diff --git a/disco.js b/disco.js new file mode 100755 index 0000000..da29ca5 --- /dev/null +++ b/disco.js @@ -0,0 +1,140 @@ +#!/usr/bin/env node + +const AST = { + Body(statements) { return { type: 'body', value: statements } }, + Identifier(name) { return { type: 'iden', value: name } }, + Link(identifier) { return { type: 'link', value: identifier } }, + Const(name, value) { return { type: 'const', name, value } }, + Int(n) { return { type: 'int', value: n } }, + String(s) { return { type: 'string', value: s } }, + Invocation(identifier, ...args) { return { type: 'invo', value: identifier, args } } +} + +const linkables = { + log: { + asmName: '_log', + asm: `\ + push rax + mov rbx, 0 +_log_loop: + mov cl, [rax] + cmp cl, 0 + je _log_loop_end + inc rax + inc rbx + jmp _log_loop +_log_loop_end: + mov rdx, rbx + mov rax, 1 + mov rdi, 1 + pop rsi + syscall + ret` + } +} + +function compile(body) { + const linkedFunctions = {} + + // add linked functions + // add static literals + // add main statments + const rname = () => (new Array(8).fill('')).map(() => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[Math.floor(Math.random() * 26)]).join(''); + const literals = { + + } + let mainStatements = ''; + + const parseLink = (identifier) => { + console.assert(identifier.type === 'iden', 'EXPECTED IDENTIFIER AFTER LINK'); + console.assert(identifier.value in linkables, 'CANNOT FIND LINK ' + identifier.value); + linkedFunctions[identifier.value] = linkables[identifier.value]; + } + + const parseString = (string) => { + const name = rname(); + literals[name] = string.value + return name; + } + + const parseInvocation = (invocation) => { + console.assert(invocation.value.value in linkedFunctions, 'UNKNOWN FUNCTION ' + invocation.value); + + const stuffIdk = []; + + for(const arg of invocation.args) { + switch(arg.type) { + case 'string': { + const asmName = parseString(arg); + stuffIdk.push(asmName); + break; + } + } + } + + mainStatements += `\ + mov rax, ${stuffIdk[0]} + call ${linkedFunctions[invocation.value.value].asmName} +` + + } + + const parseBody = (body) => { + for(const node of body.value) { + switch(node.type) { + case 'link': { + parseLink(node.value); + break; + } + case 'invo': { + parseInvocation(node); + break; + } + } + } + } + + parseBody(body); + + return `\ +section .data +${Object.entries(literals).map(([name, string]) => { + return " " + name + " db \"" + string + "\",10,0"; +})} +section .text + global _start + +_start: +${mainStatements} + call _exit + +_exit: + mov rax, 60 + mov rdi, 0 + syscall + +${Object.values(linkedFunctions).map(({asmName, asm}) => { + return `${asmName}:\n${asm}` +}).join('\n\n')}` +} + + +require('fs').writeFileSync('out.asm', compile(AST.Body([ + AST.Link(AST.Identifier('log')), + AST.Invocation( + AST.Identifier('log'), + AST.String('Hello World') + ) +]))); + + +try { + require('child_process').execSync('nasm -f elf64 out.asm -o out.o'); + require('child_process').execSync('ld out.o -o out'); + require('child_process').execSync('./out', { stdio: 'inherit' }); +} catch (e) { + +} + + + diff --git a/out.asm b/out.asm new file mode 100644 index 0000000..c5e317b --- /dev/null +++ b/out.asm @@ -0,0 +1,33 @@ +section .data + YMYJYNCD db "Hello World",10,0 +section .text + global _start + +_start: + mov rax, YMYJYNCD + call _log + + call _exit + +_exit: + mov rax, 60 + mov rdi, 0 + syscall + +_log: + push rax + mov rbx, 0 +_log_loop: + mov cl, [rax] + cmp cl, 0 + je _log_loop_end + inc rax + inc rbx + jmp _log_loop +_log_loop_end: + mov rdx, rbx + mov rax, 1 + mov rdi, 1 + pop rsi + syscall + ret \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..f50ff1a --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "disco", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "build": "nasm -f elf64 disco.asm -o disco.o && ld disco.o -o disco", + "start": "./disco", + "dev": "yarn build && yarn start" + } +}