From 7418a5042471a3a7f05283d36e45b6b422d9785b Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Mon, 1 Nov 2021 14:30:30 +0100 Subject: Add x86_64 compilation for arithmetic expressions --- Makefile | 6 +++ README.md | 2 + src/compiler.h | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 6 ++- src/x86_64/postlude.asm | 8 ++++ src/x86_64/prelude.asm | 56 +++++++++++++++++++++++ 6 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 src/compiler.h create mode 100644 src/x86_64/postlude.asm create mode 100644 src/x86_64/prelude.asm diff --git a/Makefile b/Makefile index b1d8597..581dc1a 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,12 @@ tests: $(BIN) # ./$(BIN) examples/types.bdl | diff tests/types_expected.txt - # ./$(BIN) examples/variables.bdl | diff tests/variables_expected.txt - +run: $(BIN) + $(BIN) example.bdl > build/example.asm + nasm -felf64 build/example.asm -o build/example.o + ld build/example.o -o build/example + @./build/example + # Remove build directory. clean: rm -rf $(BUILD_DIR) diff --git a/README.md b/README.md index cdb30a8..b5681c8 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ program : * EOF - [An Incremental Approach to Compiler Construction][ghuloum11] - [Make-A-Lisp Guide][mal] - [An Introduction to Scheme and its Implementation][intro-to-scheme-and-imp] +- [Scheme to C][scheme-to-c] [sicp]: https://mitpress.mit.edu/sites/default/files/sicp/index.html [crafting-interpreters]: https://craftinginterpreters.com/ @@ -83,3 +84,4 @@ program : * EOF [ghuloum11]: http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf [mal]: https://github.com/kanaka/mal/blob/master/process/guide.md [intro-to-scheme-and-imp]: https://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_toc.html#SEC271 +[scheme-to-c]: https://github.com/akeep/scheme-to-c diff --git a/src/compiler.h b/src/compiler.h new file mode 100644 index 0000000..3fed075 --- /dev/null +++ b/src/compiler.h @@ -0,0 +1,115 @@ +#ifndef BDL_COMPILER_H +#define BDL_COMPILER_H + + +#define PRELUDE_FILE "src/x86_64/prelude.asm" +#define POSTLUDE_FILE "src/x86_64/postlude.asm" + +void compile_object(Object *obj); +void compile_fixnum(Object *obj); +void compile_proc_call(Object *obj); +void compile(Root *roots); + +void +emit_file(char *file_name) { + FILE *file = fopen(file_name, "r"); + if (!file) { + fprintf(stderr, "error: couldn't open input file: %s\n", file_name); + exit(EXIT_FAILURE); + } + char buf[1024]; + size_t n = 0; + while ((n = fread(&buf, 1, 1024, file)) > 0) { + fwrite(buf, 1, n, stdout); + } +} + +void +compile_fixnum(Object *obj) { + printf(" ;; -- compile_fixnum --\n"); + printf(" mov rax, %ld\n", obj->fixnum); + printf(" push rax\n"); + printf(" ;; --------------------\n"); +} + +typedef enum OpType { + OP_ADD, + OP_SUB, + OP_MUL, + OP_DIV, + OP_MOD, +} OpType; + +void +arithmetic_op(OpType type) { + printf(" ;; -- arithmetic_op --\n"); + printf(" pop rcx\n"); + printf(" pop rax\n"); + switch (type) { + case OP_ADD: { + printf(" add rax, rcx\n"); + } break; + case OP_SUB: { + printf(" sub rax, rcx\n"); + } break; + case OP_MUL: { + printf(" mul rcx\n"); + } break; + case OP_DIV: { + printf(" mov rdx, 0\n"); + printf(" div rcx\n"); + } break; + case OP_MOD: { + printf(" mov rdx, 0\n"); + printf(" div rcx\n"); + printf(" mov rax, rdx\n"); + } break; + } + printf(" push rax\n"); + printf(" ;; -------------------\n"); +} + +void +compile_proc_call(Object *obj) { + printf(" ;; -- compile_proc_call --\n"); + OpType op; + if (sv_equal(&obj->head->text, &STRING("+"))) { op = OP_ADD;} + if (sv_equal(&obj->head->text, &STRING("-"))) { op = OP_SUB;} + if (sv_equal(&obj->head->text, &STRING("*"))) { op = OP_MUL;} + if (sv_equal(&obj->head->text, &STRING("/"))) { op = OP_DIV;} + if (sv_equal(&obj->head->text, &STRING("%"))) { op = OP_MOD;} + // TODO: Resolve function call. + Object *args = obj->tail; + // TODO: capture first operand in the accumulator. Number of arguments + // checking should have been handled in the parser. + compile_object(args->head); + args = args->tail; + while (args != NULL) { + compile_object(args->head); + args = args->tail; + arithmetic_op(op); + } + printf(" ;; -----------------------\n"); +} + +void +compile_object(Object *obj) { + switch (obj->type) { + case OBJ_TYPE_FIXNUM: { compile_fixnum(obj); } break; + case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; + default: break; + } +} + +void +compile(Root *roots) { + emit_file(PRELUDE_FILE); + for (size_t i = 0; i < array_size(roots); i++) { + Object *root = roots[i]; + compile_object(root); + // OBJ_PRINT(root); + } + emit_file(POSTLUDE_FILE); +} + +#endif // BDL_COMPILER_H diff --git a/src/main.c b/src/main.c index 6a683a7..cf4bfa4 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include "errors.c" #include "lexer.c" #include "parser.c" +#include "compiler.h" void init(void) { @@ -41,9 +42,10 @@ process_source(const StringView *source, const char *file_name) { } array_free(tokens); - // TODO: Semantic analysis. // TODO: Optimization. - // TODO: Compilation. + + // Compilation. + compile(roots); // Free resources. free_objects(); diff --git a/src/x86_64/postlude.asm b/src/x86_64/postlude.asm new file mode 100644 index 0000000..139c4e1 --- /dev/null +++ b/src/x86_64/postlude.asm @@ -0,0 +1,8 @@ + ;; return the last value in the stack + pop rdi + call printdln + + ; exit syscall + mov rax, 60 + xor rdi, rdi + syscall diff --git a/src/x86_64/prelude.asm b/src/x86_64/prelude.asm new file mode 100644 index 0000000..788b8e9 --- /dev/null +++ b/src/x86_64/prelude.asm @@ -0,0 +1,56 @@ +printdln: + sub rsp, 40 + mov BYTE [rsp+31], 10 + test rdi, rdi + jne .L2 + mov BYTE [rsp+30], 48 + mov eax, 30 + mov r8d, 2 +.L3: + lea rsi, [rsp+rax] + mov rdx, r8 + ;; write syscall (Linux) + mov rdi, 1 + mov rax, 1 + syscall + add rsp, 40 + ret +.L2: + mov r10d, 1 + js .L12 +.L4: + mov r8d, 1 + lea r9, [rsp+31] + mov rsi, -3689348814741910323 +.L5: + mov rax, rdi + mov rcx, r9 + mul rsi + sub rcx, r8 + shr rdx, 3 + lea rax, [rdx+rdx*4] + add rax, rax + sub rdi, rax + mov rax, r8 + add r8, 1 + add edi, 48 + mov BYTE [rcx], dil + mov rdi, rdx + test rdx, rdx + jne .L5 + cmp r10d, -1 + jne .L10 + not r8 + mov BYTE [rsp+32+r8], 45 + lea r8, [rax+2] +.L10: + mov eax, 32 + sub rax, r8 + jmp .L3 +.L12: + neg rdi + mov r10d, -1 + jmp .L4 + +global _start +_start: -- cgit v1.2.1