aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-11-09 10:15:26 +0100
committerBad Diode <bd@badd10de.dev>2021-11-09 10:15:26 +0100
commit701369bfb490596a7336415d01142fdee52d5415 (patch)
tree64455f8def9c65bc82d58b9054bde5f1d8b15e3a
parent7b3b52e6307ceda963bd1a6c481baeb720c2beb3 (diff)
downloadbdl-701369bfb490596a7336415d01142fdee52d5415.tar.gz
bdl-701369bfb490596a7336415d01142fdee52d5415.zip
Add support for compiling string literals
-rw-r--r--src/compiler.h130
-rw-r--r--src/x86_64/postlude.asm5
-rw-r--r--src/x86_64/prelude.asm23
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
9typedef struct Constant {
10 Object *obj;
11 char *label;
12} Constant;
13
14static Constant *constants = NULL;
15static 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);
30void compile(Root *roots); 42void compile(Root *roots);
31 43
32char * 44char *
33generate_label(void) { 45generate_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) {
60void 71void
61compile_fixnum(Object *obj) { 72compile_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) {
149void 160void
150compile_and(Object *args) { 161compile_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
173void 182void
174compile_or(Object *args) { 183compile_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
198compile_cmp_list(OpType op, Object* args) { 205compile_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
377void 382void
378compile_if(Object *obj) { 383compile_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
401void
402compile_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
398void 431void
@@ -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
411void 445void
446emit_bss_section(void) {
447 printf("section .bss\n");
448 printf("bdl_heap:\n");
449 printf(" resb HEAP_SIZE\n");
450 printf("\n");
451}
452
453void
454emit_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
476void
412compile(Root *roots) { 477compile(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
7exit: 7exit:
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
13section .bss
14bdl_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
74true_str: 74printstring:
75 db "true", 10 75 mov rsi, rdi
76false_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
79display: 85display:
80 ;; is nil? 86 ;; is nil?
@@ -91,6 +97,15 @@ display:
91 ret 97 ret
92not_bool: 98not_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
107not_string:
108
94 ;; is fixnum? 109 ;; is fixnum?
95 mov rax, rdi 110 mov rax, rdi
96 call printdln 111 call printdln