diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | src/compiler.h | 115 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/x86_64/postlude.asm | 8 | ||||
-rw-r--r-- | src/x86_64/prelude.asm | 56 |
6 files changed, 191 insertions, 2 deletions
@@ -52,6 +52,12 @@ tests: $(BIN) | |||
52 | # ./$(BIN) examples/types.bdl | diff tests/types_expected.txt - | 52 | # ./$(BIN) examples/types.bdl | diff tests/types_expected.txt - |
53 | # ./$(BIN) examples/variables.bdl | diff tests/variables_expected.txt - | 53 | # ./$(BIN) examples/variables.bdl | diff tests/variables_expected.txt - |
54 | 54 | ||
55 | run: $(BIN) | ||
56 | $(BIN) example.bdl > build/example.asm | ||
57 | nasm -felf64 build/example.asm -o build/example.o | ||
58 | ld build/example.o -o build/example | ||
59 | @./build/example | ||
60 | |||
55 | # Remove build directory. | 61 | # Remove build directory. |
56 | clean: | 62 | clean: |
57 | rm -rf $(BUILD_DIR) | 63 | rm -rf $(BUILD_DIR) |
@@ -75,6 +75,7 @@ program : <statement>* EOF | |||
75 | - [An Incremental Approach to Compiler Construction][ghuloum11] | 75 | - [An Incremental Approach to Compiler Construction][ghuloum11] |
76 | - [Make-A-Lisp Guide][mal] | 76 | - [Make-A-Lisp Guide][mal] |
77 | - [An Introduction to Scheme and its Implementation][intro-to-scheme-and-imp] | 77 | - [An Introduction to Scheme and its Implementation][intro-to-scheme-and-imp] |
78 | - [Scheme to C][scheme-to-c] | ||
78 | 79 | ||
79 | [sicp]: https://mitpress.mit.edu/sites/default/files/sicp/index.html | 80 | [sicp]: https://mitpress.mit.edu/sites/default/files/sicp/index.html |
80 | [crafting-interpreters]: https://craftinginterpreters.com/ | 81 | [crafting-interpreters]: https://craftinginterpreters.com/ |
@@ -83,3 +84,4 @@ program : <statement>* EOF | |||
83 | [ghuloum11]: http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf | 84 | [ghuloum11]: http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf |
84 | [mal]: https://github.com/kanaka/mal/blob/master/process/guide.md | 85 | [mal]: https://github.com/kanaka/mal/blob/master/process/guide.md |
85 | [intro-to-scheme-and-imp]: https://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_toc.html#SEC271 | 86 | [intro-to-scheme-and-imp]: https://www.cs.utexas.edu/ftp/garbage/cs345/schintro-v14/schintro_toc.html#SEC271 |
87 | [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 @@ | |||
1 | #ifndef BDL_COMPILER_H | ||
2 | #define BDL_COMPILER_H | ||
3 | |||
4 | |||
5 | #define PRELUDE_FILE "src/x86_64/prelude.asm" | ||
6 | #define POSTLUDE_FILE "src/x86_64/postlude.asm" | ||
7 | |||
8 | void compile_object(Object *obj); | ||
9 | void compile_fixnum(Object *obj); | ||
10 | void compile_proc_call(Object *obj); | ||
11 | void compile(Root *roots); | ||
12 | |||
13 | void | ||
14 | emit_file(char *file_name) { | ||
15 | FILE *file = fopen(file_name, "r"); | ||
16 | if (!file) { | ||
17 | fprintf(stderr, "error: couldn't open input file: %s\n", file_name); | ||
18 | exit(EXIT_FAILURE); | ||
19 | } | ||
20 | char buf[1024]; | ||
21 | size_t n = 0; | ||
22 | while ((n = fread(&buf, 1, 1024, file)) > 0) { | ||
23 | fwrite(buf, 1, n, stdout); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | void | ||
28 | compile_fixnum(Object *obj) { | ||
29 | printf(" ;; -- compile_fixnum --\n"); | ||
30 | printf(" mov rax, %ld\n", obj->fixnum); | ||
31 | printf(" push rax\n"); | ||
32 | printf(" ;; --------------------\n"); | ||
33 | } | ||
34 | |||
35 | typedef enum OpType { | ||
36 | OP_ADD, | ||
37 | OP_SUB, | ||
38 | OP_MUL, | ||
39 | OP_DIV, | ||
40 | OP_MOD, | ||
41 | } OpType; | ||
42 | |||
43 | void | ||
44 | arithmetic_op(OpType type) { | ||
45 | printf(" ;; -- arithmetic_op --\n"); | ||
46 | printf(" pop rcx\n"); | ||
47 | printf(" pop rax\n"); | ||
48 | switch (type) { | ||
49 | case OP_ADD: { | ||
50 | printf(" add rax, rcx\n"); | ||
51 | } break; | ||
52 | case OP_SUB: { | ||
53 | printf(" sub rax, rcx\n"); | ||
54 | } break; | ||
55 | case OP_MUL: { | ||
56 | printf(" mul rcx\n"); | ||
57 | } break; | ||
58 | case OP_DIV: { | ||
59 | printf(" mov rdx, 0\n"); | ||
60 | printf(" div rcx\n"); | ||
61 | } break; | ||
62 | case OP_MOD: { | ||
63 | printf(" mov rdx, 0\n"); | ||
64 | printf(" div rcx\n"); | ||
65 | printf(" mov rax, rdx\n"); | ||
66 | } break; | ||
67 | } | ||
68 | printf(" push rax\n"); | ||
69 | printf(" ;; -------------------\n"); | ||
70 | } | ||
71 | |||
72 | void | ||
73 | compile_proc_call(Object *obj) { | ||
74 | printf(" ;; -- compile_proc_call --\n"); | ||
75 | OpType op; | ||
76 | if (sv_equal(&obj->head->text, &STRING("+"))) { op = OP_ADD;} | ||
77 | if (sv_equal(&obj->head->text, &STRING("-"))) { op = OP_SUB;} | ||
78 | if (sv_equal(&obj->head->text, &STRING("*"))) { op = OP_MUL;} | ||
79 | if (sv_equal(&obj->head->text, &STRING("/"))) { op = OP_DIV;} | ||
80 | if (sv_equal(&obj->head->text, &STRING("%"))) { op = OP_MOD;} | ||
81 | // TODO: Resolve function call. | ||
82 | Object *args = obj->tail; | ||
83 | // TODO: capture first operand in the accumulator. Number of arguments | ||
84 | // checking should have been handled in the parser. | ||
85 | compile_object(args->head); | ||
86 | args = args->tail; | ||
87 | while (args != NULL) { | ||
88 | compile_object(args->head); | ||
89 | args = args->tail; | ||
90 | arithmetic_op(op); | ||
91 | } | ||
92 | printf(" ;; -----------------------\n"); | ||
93 | } | ||
94 | |||
95 | void | ||
96 | compile_object(Object *obj) { | ||
97 | switch (obj->type) { | ||
98 | case OBJ_TYPE_FIXNUM: { compile_fixnum(obj); } break; | ||
99 | case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; | ||
100 | default: break; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | void | ||
105 | compile(Root *roots) { | ||
106 | emit_file(PRELUDE_FILE); | ||
107 | for (size_t i = 0; i < array_size(roots); i++) { | ||
108 | Object *root = roots[i]; | ||
109 | compile_object(root); | ||
110 | // OBJ_PRINT(root); | ||
111 | } | ||
112 | emit_file(POSTLUDE_FILE); | ||
113 | } | ||
114 | |||
115 | #endif // BDL_COMPILER_H | ||
@@ -8,6 +8,7 @@ | |||
8 | #include "errors.c" | 8 | #include "errors.c" |
9 | #include "lexer.c" | 9 | #include "lexer.c" |
10 | #include "parser.c" | 10 | #include "parser.c" |
11 | #include "compiler.h" | ||
11 | 12 | ||
12 | void | 13 | void |
13 | init(void) { | 14 | init(void) { |
@@ -41,9 +42,10 @@ process_source(const StringView *source, const char *file_name) { | |||
41 | } | 42 | } |
42 | array_free(tokens); | 43 | array_free(tokens); |
43 | 44 | ||
44 | // TODO: Semantic analysis. | ||
45 | // TODO: Optimization. | 45 | // TODO: Optimization. |
46 | // TODO: Compilation. | 46 | |
47 | // Compilation. | ||
48 | compile(roots); | ||
47 | 49 | ||
48 | // Free resources. | 50 | // Free resources. |
49 | free_objects(); | 51 | 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 @@ | |||
1 | ;; return the last value in the stack | ||
2 | pop rdi | ||
3 | call printdln | ||
4 | |||
5 | ; exit syscall | ||
6 | mov rax, 60 | ||
7 | xor rdi, rdi | ||
8 | 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 @@ | |||
1 | printdln: | ||
2 | sub rsp, 40 | ||
3 | mov BYTE [rsp+31], 10 | ||
4 | test rdi, rdi | ||
5 | jne .L2 | ||
6 | mov BYTE [rsp+30], 48 | ||
7 | mov eax, 30 | ||
8 | mov r8d, 2 | ||
9 | .L3: | ||
10 | lea rsi, [rsp+rax] | ||
11 | mov rdx, r8 | ||
12 | ;; write syscall (Linux) | ||
13 | mov rdi, 1 | ||
14 | mov rax, 1 | ||
15 | syscall | ||
16 | add rsp, 40 | ||
17 | ret | ||
18 | .L2: | ||
19 | mov r10d, 1 | ||
20 | js .L12 | ||
21 | .L4: | ||
22 | mov r8d, 1 | ||
23 | lea r9, [rsp+31] | ||
24 | mov rsi, -3689348814741910323 | ||
25 | .L5: | ||
26 | mov rax, rdi | ||
27 | mov rcx, r9 | ||
28 | mul rsi | ||
29 | sub rcx, r8 | ||
30 | shr rdx, 3 | ||
31 | lea rax, [rdx+rdx*4] | ||
32 | add rax, rax | ||
33 | sub rdi, rax | ||
34 | mov rax, r8 | ||
35 | add r8, 1 | ||
36 | add edi, 48 | ||
37 | mov BYTE [rcx], dil | ||
38 | mov rdi, rdx | ||
39 | test rdx, rdx | ||
40 | jne .L5 | ||
41 | cmp r10d, -1 | ||
42 | jne .L10 | ||
43 | not r8 | ||
44 | mov BYTE [rsp+32+r8], 45 | ||
45 | lea r8, [rax+2] | ||
46 | .L10: | ||
47 | mov eax, 32 | ||
48 | sub rax, r8 | ||
49 | jmp .L3 | ||
50 | .L12: | ||
51 | neg rdi | ||
52 | mov r10d, -1 | ||
53 | jmp .L4 | ||
54 | |||
55 | global _start | ||
56 | _start: | ||