diff options
author | Bad Diode <bd@badd10de.dev> | 2021-11-09 10:15:26 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-11-09 10:15:26 +0100 |
commit | 701369bfb490596a7336415d01142fdee52d5415 (patch) | |
tree | 64455f8def9c65bc82d58b9054bde5f1d8b15e3a | |
parent | 7b3b52e6307ceda963bd1a6c481baeb720c2beb3 (diff) | |
download | bdl-701369bfb490596a7336415d01142fdee52d5415.tar.gz bdl-701369bfb490596a7336415d01142fdee52d5415.zip |
Add support for compiling string literals
-rw-r--r-- | src/compiler.h | 130 | ||||
-rw-r--r-- | src/x86_64/postlude.asm | 5 | ||||
-rw-r--r-- | src/x86_64/prelude.asm | 23 |
3 files changed, 128 insertions, 30 deletions
diff --git a/src/compiler.h b/src/compiler.h index 5e1bf7d..3227eba 100644 --- a/src/compiler.h +++ b/src/compiler.h | |||
@@ -1,12 +1,23 @@ | |||
1 | #ifndef BDL_COMPILER_H | 1 | #ifndef BDL_COMPILER_H |
2 | #define BDL_COMPILER_H | 2 | #define BDL_COMPILER_H |
3 | 3 | ||
4 | |||
5 | #define PRELUDE_FILE "src/x86_64/prelude.asm" | 4 | #define PRELUDE_FILE "src/x86_64/prelude.asm" |
6 | #define POSTLUDE_FILE "src/x86_64/postlude.asm" | 5 | #define POSTLUDE_FILE "src/x86_64/postlude.asm" |
7 | 6 | ||
8 | #define HEAP_SIZE MB(32) | 7 | #define HEAP_SIZE MB(32) |
9 | 8 | ||
9 | typedef struct Constant { | ||
10 | Object *obj; | ||
11 | char *label; | ||
12 | } Constant; | ||
13 | |||
14 | static Constant *constants = NULL; | ||
15 | static char **labels = NULL; | ||
16 | |||
17 | // TODO: Separate c/h files | ||
18 | // TODO: Create a "driver.c" file with the (display) function for external | ||
19 | // linkage or assembly inlining. | ||
20 | |||
10 | // Immediate constants. | 21 | // Immediate constants. |
11 | #define NIL_VAL 47LU | 22 | #define NIL_VAL 47LU |
12 | #define BOOL_MASK 127LU | 23 | #define BOOL_MASK 127LU |
@@ -19,6 +30,7 @@ | |||
19 | #define FIXNUM_SHIFT 2LU | 30 | #define FIXNUM_SHIFT 2LU |
20 | 31 | ||
21 | // Heap allocated objects. | 32 | // Heap allocated objects. |
33 | #define STRING_INV_MASK ~7LU | ||
22 | #define STRING_MASK 7LU | 34 | #define STRING_MASK 7LU |
23 | #define STRING_TAG 3LU | 35 | #define STRING_TAG 3LU |
24 | #define PAIR_MASK 7LU | 36 | #define PAIR_MASK 7LU |
@@ -30,16 +42,15 @@ void compile_proc_call(Object *obj); | |||
30 | void compile(Root *roots); | 42 | void compile(Root *roots); |
31 | 43 | ||
32 | char * | 44 | char * |
33 | generate_label(void) { | 45 | generate_label(char *prefix) { |
34 | // Generate a unique label allocated on the heap. The caller is responsible | ||
35 | // for freeing the memory. | ||
36 | static size_t label_counter = 0; | 46 | static size_t label_counter = 0; |
37 | char buf[32]; | 47 | char buf[32]; |
38 | sprintf(buf, ".BDLL%ld", label_counter++); | 48 | sprintf(buf, "%s%zu", prefix, label_counter++); |
39 | size_t len = strlen(buf); | 49 | size_t len = strlen(buf); |
40 | char * ret = malloc(len + 1); | 50 | char * ret = malloc(len + 1); |
41 | memcpy(ret, buf, len); | 51 | memcpy(ret, buf, len); |
42 | ret[len] = 0; | 52 | ret[len] = 0; |
53 | array_push(labels, ret); | ||
43 | return ret; | 54 | return ret; |
44 | } | 55 | } |
45 | 56 | ||
@@ -60,7 +71,7 @@ emit_file(char *file_name) { | |||
60 | void | 71 | void |
61 | compile_fixnum(Object *obj) { | 72 | compile_fixnum(Object *obj) { |
62 | printf(" ;; --> compile_fixnum\n"); | 73 | printf(" ;; --> compile_fixnum\n"); |
63 | printf(" mov rax, %ld\n", (obj->fixnum << FIXNUM_SHIFT) | FIXNUM_TAG); | 74 | printf(" mov rax, %zu\n", (obj->fixnum << FIXNUM_SHIFT) | FIXNUM_TAG); |
64 | printf(" push rax\n"); | 75 | printf(" push rax\n"); |
65 | printf(" ;; <-- compile_fixnum\n"); | 76 | printf(" ;; <-- compile_fixnum\n"); |
66 | } | 77 | } |
@@ -149,8 +160,8 @@ compile_not(Object* args) { | |||
149 | void | 160 | void |
150 | compile_and(Object *args) { | 161 | compile_and(Object *args) { |
151 | printf(" ;; --> compile_and\n"); | 162 | printf(" ;; --> compile_and\n"); |
152 | char *lab_false = generate_label(); | 163 | char *lab_false = generate_label("BDLL"); |
153 | char *lab_exit = generate_label(); | 164 | char *lab_exit = generate_label("BDLL"); |
154 | while (args != NULL) { | 165 | while (args != NULL) { |
155 | compile_object(args->head); | 166 | compile_object(args->head); |
156 | args = args->tail; | 167 | args = args->tail; |
@@ -165,16 +176,14 @@ compile_and(Object *args) { | |||
165 | printf(" mov rax, FALSE_VAL\n"); | 176 | printf(" mov rax, FALSE_VAL\n"); |
166 | printf(" push rax\n"); | 177 | printf(" push rax\n"); |
167 | printf("%s:\n", lab_exit); | 178 | printf("%s:\n", lab_exit); |
168 | free(lab_false); | ||
169 | free(lab_exit); | ||
170 | printf(" ;; <-- compile_and\n"); | 179 | printf(" ;; <-- compile_and\n"); |
171 | } | 180 | } |
172 | 181 | ||
173 | void | 182 | void |
174 | compile_or(Object *args) { | 183 | compile_or(Object *args) { |
175 | printf(" ;; --> compile_or\n"); | 184 | printf(" ;; --> compile_or\n"); |
176 | char *lab_true = generate_label(); | 185 | char *lab_true = generate_label("BDLL"); |
177 | char *lab_exit = generate_label(); | 186 | char *lab_exit = generate_label("BDLL"); |
178 | while (args != NULL) { | 187 | while (args != NULL) { |
179 | compile_object(args->head); | 188 | compile_object(args->head); |
180 | args = args->tail; | 189 | args = args->tail; |
@@ -189,8 +198,6 @@ compile_or(Object *args) { | |||
189 | printf(" mov rax, TRUE_VAL\n"); | 198 | printf(" mov rax, TRUE_VAL\n"); |
190 | printf(" push rax\n"); | 199 | printf(" push rax\n"); |
191 | printf("%s:\n", lab_exit); | 200 | printf("%s:\n", lab_exit); |
192 | free(lab_true); | ||
193 | free(lab_exit); | ||
194 | printf(" ;; <-- compile_or\n"); | 201 | printf(" ;; <-- compile_or\n"); |
195 | } | 202 | } |
196 | 203 | ||
@@ -198,8 +205,8 @@ void | |||
198 | compile_cmp_list(OpType op, Object* args) { | 205 | compile_cmp_list(OpType op, Object* args) { |
199 | printf(" ;; --> compile_cmp_list\n"); | 206 | printf(" ;; --> compile_cmp_list\n"); |
200 | compile_object(args->head); | 207 | compile_object(args->head); |
201 | char *lab_false = generate_label(); | 208 | char *lab_false = generate_label("BDLL"); |
202 | char *lab_exit = generate_label(); | 209 | char *lab_exit = generate_label("BDLL"); |
203 | args = args->tail; | 210 | args = args->tail; |
204 | while (args != NULL) { | 211 | while (args != NULL) { |
205 | compile_object(args->head); | 212 | compile_object(args->head); |
@@ -231,8 +238,6 @@ compile_cmp_list(OpType op, Object* args) { | |||
231 | printf(" mov rax, FALSE_VAL\n"); | 238 | printf(" mov rax, FALSE_VAL\n"); |
232 | printf(" push rax\n"); | 239 | printf(" push rax\n"); |
233 | printf("%s:\n", lab_exit); | 240 | printf("%s:\n", lab_exit); |
234 | free(lab_false); | ||
235 | free(lab_exit); | ||
236 | printf(" ;; <-- compile_cmp_list\n"); | 241 | printf(" ;; <-- compile_cmp_list\n"); |
237 | } | 242 | } |
238 | 243 | ||
@@ -376,23 +381,51 @@ compile_proc_call(Object *obj) { | |||
376 | 381 | ||
377 | void | 382 | void |
378 | compile_if(Object *obj) { | 383 | compile_if(Object *obj) { |
379 | char *lab_false = generate_label(); | 384 | char *lab_false = generate_label("BDLL"); |
380 | compile_object(obj->condition); | 385 | compile_object(obj->condition); |
381 | printf(" pop rax\n"); | 386 | printf(" pop rax\n"); |
382 | printf(" cmp rax, FALSE_VAL\n"); | 387 | printf(" cmp rax, FALSE_VAL\n"); |
383 | printf(" je %s\n", lab_false); | 388 | printf(" je %s\n", lab_false); |
384 | compile_object(obj->expr_true); | 389 | compile_object(obj->expr_true); |
385 | if (obj->expr_false != NULL) { | 390 | if (obj->expr_false != NULL) { |
386 | char *lab_exit = generate_label(); | 391 | char *lab_exit = generate_label("BDLL"); |
387 | printf(" jmp %s\n", lab_exit); | 392 | printf(" jmp %s\n", lab_exit); |
388 | printf("%s:\n", lab_false); | 393 | printf("%s:\n", lab_false); |
389 | compile_object(obj->expr_false); | 394 | compile_object(obj->expr_false); |
390 | printf("%s:\n", lab_exit); | 395 | printf("%s:\n", lab_exit); |
391 | free(lab_exit); | ||
392 | } else { | 396 | } else { |
393 | printf("%s:\n", lab_false); | 397 | printf("%s:\n", lab_false); |
394 | } | 398 | } |
395 | free(lab_false); | 399 | } |
400 | |||
401 | void | ||
402 | compile_string(Object *obj) { | ||
403 | printf(" ;; --> compile_string\n"); | ||
404 | Constant c; | ||
405 | |||
406 | // Check if the string is already stored as a constant. | ||
407 | ssize_t idx = -1; | ||
408 | for (size_t i = 0; i < array_size(constants); i++) { | ||
409 | c = constants[i]; | ||
410 | if (object_equal(c.obj, obj)) { | ||
411 | idx = i; | ||
412 | break; | ||
413 | } | ||
414 | } | ||
415 | if (idx < 0) { | ||
416 | idx = array_size(constants); | ||
417 | c = (Constant){ | ||
418 | .obj = obj, | ||
419 | .label = generate_label("BDLC"), | ||
420 | }; | ||
421 | array_push(constants, c); | ||
422 | } | ||
423 | |||
424 | // Create a tagged pointer to the label. | ||
425 | printf(" mov rax, %s\n", c.label); | ||
426 | printf(" or rax, STRING_TAG\n"); | ||
427 | printf(" push rax\n"); | ||
428 | printf(" ;; <-- compile_string\n"); | ||
396 | } | 429 | } |
397 | 430 | ||
398 | void | 431 | void |
@@ -403,14 +436,53 @@ compile_object(Object *obj) { | |||
403 | case OBJ_TYPE_FALSE: { compile_boolean(obj); } break; | 436 | case OBJ_TYPE_FALSE: { compile_boolean(obj); } break; |
404 | case OBJ_TYPE_FIXNUM: { compile_fixnum(obj); } break; | 437 | case OBJ_TYPE_FIXNUM: { compile_fixnum(obj); } break; |
405 | case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; | 438 | case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; |
439 | case OBJ_TYPE_STRING: { compile_string(obj); } break; | ||
406 | case OBJ_TYPE_IF: { compile_if(obj); } break; | 440 | case OBJ_TYPE_IF: { compile_if(obj); } break; |
407 | default: break; | 441 | default: break; |
408 | } | 442 | } |
409 | } | 443 | } |
410 | 444 | ||
411 | void | 445 | void |
446 | emit_bss_section(void) { | ||
447 | printf("section .bss\n"); | ||
448 | printf("bdl_heap:\n"); | ||
449 | printf(" resb HEAP_SIZE\n"); | ||
450 | printf("\n"); | ||
451 | } | ||
452 | |||
453 | void | ||
454 | emit_data_section(void) { | ||
455 | printf("section .data\n"); | ||
456 | printf("true_str: db \"true\", 10, 0, 0, 0\n"); | ||
457 | printf("false_str: db \"false\", 10, 0, 0\n"); | ||
458 | for (size_t i = 0; i < array_size(constants); i++) { | ||
459 | // NOTE: Only supporting string constants for now. | ||
460 | Constant c = constants[i]; | ||
461 | int n = c.obj->text.n; | ||
462 | // TODO: escape characters maybe? | ||
463 | // TODO: quote all strings maybe? | ||
464 | printf("%s:\n", c.label); | ||
465 | printf(" dq %d\n", n + 1); | ||
466 | printf(" db \"%.*s\", 10\n", n, c.obj->text.start); | ||
467 | // Ensure alignment to 8 bytes. | ||
468 | int remainder = (n + 1) % 8; | ||
469 | if (remainder != 0) { | ||
470 | printf(" times %d db 0\n", 8 - (n + 1) % 8); | ||
471 | } | ||
472 | } | ||
473 | printf("\n"); | ||
474 | } | ||
475 | |||
476 | void | ||
412 | compile(Root *roots) { | 477 | compile(Root *roots) { |
478 | // Prepare compilation variables. | ||
479 | array_init(constants, 0); | ||
480 | array_init(labels, 0); | ||
481 | |||
482 | // Prelude. | ||
413 | printf("%%define NIL_VAL %zu\n", NIL_VAL); | 483 | printf("%%define NIL_VAL %zu\n", NIL_VAL); |
484 | printf("%%define TRUE_VAL %zu\n", TRUE_VAL); | ||
485 | printf("%%define FALSE_VAL %zu\n", FALSE_VAL); | ||
414 | printf("%%define BOOL_MASK %zu\n", BOOL_MASK); | 486 | printf("%%define BOOL_MASK %zu\n", BOOL_MASK); |
415 | printf("%%define BOOL_TAG %zu\n", BOOL_TAG); | 487 | printf("%%define BOOL_TAG %zu\n", BOOL_TAG); |
416 | printf("%%define BOOL_SHIFT %zu\n", BOOL_SHIFT); | 488 | printf("%%define BOOL_SHIFT %zu\n", BOOL_SHIFT); |
@@ -419,16 +491,30 @@ compile(Root *roots) { | |||
419 | printf("%%define FIXNUM_SHIFT %zu\n", FIXNUM_SHIFT); | 491 | printf("%%define FIXNUM_SHIFT %zu\n", FIXNUM_SHIFT); |
420 | printf("%%define PAIR_MASK %zu\n", PAIR_MASK); | 492 | printf("%%define PAIR_MASK %zu\n", PAIR_MASK); |
421 | printf("%%define PAIR_TAG %zu\n", PAIR_TAG); | 493 | printf("%%define PAIR_TAG %zu\n", PAIR_TAG); |
494 | printf("%%define STRING_INV_MASK %zu\n", STRING_INV_MASK); | ||
422 | printf("%%define STRING_MASK %zu\n", STRING_MASK); | 495 | printf("%%define STRING_MASK %zu\n", STRING_MASK); |
423 | printf("%%define STRING_TAG %zu\n", STRING_TAG); | 496 | printf("%%define STRING_TAG %zu\n", STRING_TAG); |
424 | printf("%%define HEAP_SIZE %zu\n", HEAP_SIZE); | 497 | printf("%%define HEAP_SIZE %zu\n", HEAP_SIZE); |
425 | printf("\n"); | 498 | printf("\n"); |
426 | emit_file(PRELUDE_FILE); | 499 | emit_file(PRELUDE_FILE); |
500 | |||
501 | // Compile program. | ||
427 | for (size_t i = 0; i < array_size(roots); i++) { | 502 | for (size_t i = 0; i < array_size(roots); i++) { |
428 | Object *root = roots[i]; | 503 | Object *root = roots[i]; |
429 | compile_object(root); | 504 | compile_object(root); |
430 | } | 505 | } |
506 | |||
507 | // Postlude. | ||
431 | emit_file(POSTLUDE_FILE); | 508 | emit_file(POSTLUDE_FILE); |
509 | emit_data_section(); | ||
510 | emit_bss_section(); | ||
511 | |||
512 | // Clean resources. | ||
513 | array_free(constants); | ||
514 | for (size_t i = 0; i < array_size(labels); i++) { | ||
515 | free(labels[i]); | ||
516 | } | ||
517 | array_free(labels); | ||
432 | } | 518 | } |
433 | 519 | ||
434 | #endif // BDL_COMPILER_H | 520 | #endif // BDL_COMPILER_H |
diff --git a/src/x86_64/postlude.asm b/src/x86_64/postlude.asm index 37f9df1..45be7ee 100644 --- a/src/x86_64/postlude.asm +++ b/src/x86_64/postlude.asm | |||
@@ -5,11 +5,8 @@ _start_return: | |||
5 | call display | 5 | call display |
6 | 6 | ||
7 | exit: | 7 | exit: |
8 | ; exit syscall | 8 | ;; exit syscall |
9 | mov rax, 60 | 9 | mov rax, 60 |
10 | xor rdi, rdi | 10 | xor rdi, rdi |
11 | syscall | 11 | syscall |
12 | 12 | ||
13 | section .bss | ||
14 | bdl_heap: | ||
15 | resb HEAP_SIZE | ||
diff --git a/src/x86_64/prelude.asm b/src/x86_64/prelude.asm index 3ad33f7..c9ef823 100644 --- a/src/x86_64/prelude.asm +++ b/src/x86_64/prelude.asm | |||
@@ -71,10 +71,16 @@ bool_write: | |||
71 | syscall | 71 | syscall |
72 | ret | 72 | ret |
73 | 73 | ||
74 | true_str: | 74 | printstring: |
75 | db "true", 10 | 75 | mov rsi, rdi |
76 | false_str: | 76 | mov rax, STRING_INV_MASK |
77 | db "false", 10 | 77 | and rsi, rax |
78 | mov rdx, [rsi] | ||
79 | add rsi, 8 | ||
80 | mov rax, 1 | ||
81 | mov rdi, 1 | ||
82 | syscall | ||
83 | ret | ||
78 | 84 | ||
79 | display: | 85 | display: |
80 | ;; is nil? | 86 | ;; is nil? |
@@ -91,6 +97,15 @@ display: | |||
91 | ret | 97 | ret |
92 | not_bool: | 98 | not_bool: |
93 | 99 | ||
100 | ;; is string? | ||
101 | mov rax, rdi | ||
102 | and rax, STRING_MASK | ||
103 | cmp rax, STRING_TAG | ||
104 | jne not_string | ||
105 | call printstring | ||
106 | ret | ||
107 | not_string: | ||
108 | |||
94 | ;; is fixnum? | 109 | ;; is fixnum? |
95 | mov rax, rdi | 110 | mov rax, rdi |
96 | call printdln | 111 | call printdln |