aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-11-15 22:32:02 +0100
committerBad Diode <bd@badd10de.dev>2021-11-15 22:32:02 +0100
commit26f1b9c35d337c0814158077fdc8f56b817e0b14 (patch)
treee0b20f3e6e843a3df45400f713eae1242ce8db65
parentdf4d884edb9b3a29d498d6852d0e8e077d9350df (diff)
downloadbdl-26f1b9c35d337c0814158077fdc8f56b817e0b14.tar.gz
bdl-26f1b9c35d337c0814158077fdc8f56b817e0b14.zip
Fix stack on procedure call return
-rw-r--r--Makefile5
-rw-r--r--src/compiler.h80
-rw-r--r--src/parser.c4
3 files changed, 65 insertions, 24 deletions
diff --git a/Makefile b/Makefile
index 581dc1a..cdb8c93 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,7 @@ BIN := $(BUILD_DIR)/$(TARGET)
17CC := cc 17CC := cc
18CFLAGS := -Wall -Wextra -pedantic -DBIN_NAME=\"$(TARGET)\" 18CFLAGS := -Wall -Wextra -pedantic -DBIN_NAME=\"$(TARGET)\"
19CFLAGS += $(INC_FLAGS) 19CFLAGS += $(INC_FLAGS)
20NASM_FLAGS ?= -felf64
20LDFLAGS := 21LDFLAGS :=
21LDLIBS := 22LDLIBS :=
22RELEASE_CFLAGS := -DNDEBUG -O2 -static 23RELEASE_CFLAGS := -DNDEBUG -O2 -static
@@ -30,8 +31,10 @@ DEBUG_CFLAGS := -DDEBUG -O0 -g
30DEBUG ?= 0 31DEBUG ?= 0
31ifeq ($(DEBUG), 1) 32ifeq ($(DEBUG), 1)
32 CFLAGS += $(DEBUG_CFLAGS) 33 CFLAGS += $(DEBUG_CFLAGS)
34 NASM_FLAGS += -g -F dwarf
33else ifeq ($(DEBUG), 2) 35else ifeq ($(DEBUG), 2)
34 CFLAGS += $(DEBUG_CFLAGS) -fsanitize=address 36 CFLAGS += $(DEBUG_CFLAGS) -fsanitize=address
37 NASM_FLAGS += -g -F dwarf
35else 38else
36 CFLAGS += $(RELEASE_CFLAGS) 39 CFLAGS += $(RELEASE_CFLAGS)
37endif 40endif
@@ -54,7 +57,7 @@ tests: $(BIN)
54 57
55run: $(BIN) 58run: $(BIN)
56 $(BIN) example.bdl > build/example.asm 59 $(BIN) example.bdl > build/example.asm
57 nasm -felf64 build/example.asm -o build/example.o 60 nasm $(NASM_FLAGS) build/example.asm -o build/example.o
58 ld build/example.o -o build/example 61 ld build/example.o -o build/example
59 @./build/example 62 @./build/example
60 63
diff --git a/src/compiler.h b/src/compiler.h
index 2a44220..1312d99 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -28,6 +28,8 @@ static Environment *current_env = NULL;
28// TODO: Separate c/h files 28// TODO: Separate c/h files
29// TODO: Create a "driver.c" file with the (display) function for external 29// TODO: Create a "driver.c" file with the (display) function for external
30// linkage or assembly inlining. 30// linkage or assembly inlining.
31// TODO: Ensure we don't compile a function multiple times (for example with
32// a function that contains internal functions).
31 33
32// Immediate constants. 34// Immediate constants.
33#define NIL_VAL 47LU 35#define NIL_VAL 47LU
@@ -339,6 +341,30 @@ compile_cdr(Object *obj) {
339} 341}
340 342
341void 343void
344compile_call(Object *obj) {
345 context_printf(" ;; --> compile_call\n");
346 compile_object(obj->head);
347 size_t n_args = 0;
348 while (obj->tail != NULL) {
349 obj = obj->tail;
350 compile_object(obj->head);
351 n_args++;
352 }
353 context_printf(" mov rax, [rsp + %zu]\n", 8 * n_args);
354 context_printf(" mov rcx, PTR_MASK\n");
355 context_printf(" and rcx, rax\n");
356 context_printf(" mov rax, [rcx]\n");
357 context_printf(" call rax\n");
358
359 // Restore stack to previous location and store the result on top.
360 context_printf(" add rsp, %zu\n", 8 * (n_args + 1));
361 // TODO: Handle the case where the function doesn't return anything, for
362 // example if the last parameter is (display ...) or (def ...).
363 context_printf(" push rax\n");
364 context_printf(" ;; <-- compile_call\n");
365}
366
367void
342compile_proc_call(Object *obj) { 368compile_proc_call(Object *obj) {
343 // TODO: Probably we want to use a hash table for these lookups that is 369 // TODO: Probably we want to use a hash table for these lookups that is
344 // initialized at the start of the compilation procedure. 370 // initialized at the start of the compilation procedure.
@@ -364,7 +390,6 @@ compile_proc_call(Object *obj) {
364 compile_object(obj->tail->head); 390 compile_object(obj->tail->head);
365 context_printf(" pop rdi\n"); 391 context_printf(" pop rdi\n");
366 context_printf(" call display\n"); 392 context_printf(" call display\n");
367 compile_nil();
368 } else if (sv_equal(&obj->head->text, &STRING("not"))) { 393 } else if (sv_equal(&obj->head->text, &STRING("not"))) {
369 compile_not(obj->tail); 394 compile_not(obj->tail);
370 } else if (sv_equal(&obj->head->text, &STRING("and"))) { 395 } else if (sv_equal(&obj->head->text, &STRING("and"))) {
@@ -388,19 +413,7 @@ compile_proc_call(Object *obj) {
388 } else if (sv_equal(&obj->head->text, &STRING("cdr"))) { 413 } else if (sv_equal(&obj->head->text, &STRING("cdr"))) {
389 compile_cdr(obj->tail); 414 compile_cdr(obj->tail);
390 } else { 415 } else {
391 compile_object(obj->head); 416 compile_call(obj);
392 size_t n_args = 0;
393 while (obj->tail != NULL) {
394 obj = obj->tail;
395 compile_object(obj->head);
396 n_args++;
397 }
398 context_printf(" mov rax, [rsp + %zu]\n", 8 * n_args);
399 context_printf(" mov rcx, PTR_MASK\n");
400 context_printf(" and rcx, rax\n");
401 context_printf(" mov rax, [rcx]\n");
402 context_printf(" call rax\n");
403 context_printf(" push rax\n");
404 } 417 }
405} 418}
406 419
@@ -518,28 +531,51 @@ compile_def(Object *obj) {
518 ssize_t idx = find_var_index(current_env->locals, obj->var_name); 531 ssize_t idx = find_var_index(current_env->locals, obj->var_name);
519 context_printf(" pop rax\n"); 532 context_printf(" pop rax\n");
520 context_printf(" mov [rbp + %ld], rax\n", 8 * idx); 533 context_printf(" mov [rbp + %ld], rax\n", 8 * idx);
521 compile_nil();
522 context_printf(" ;; <-- compile_def\n"); 534 context_printf(" ;; <-- compile_def\n");
523} 535}
524 536
525void 537void
526compile_symbol(Object *obj) { 538compile_symbol(Object *obj) {
527 context_printf(" ;; --> compile_symbol\n"); 539 context_printf(" ;; --> compile_symbol\n");
528 ssize_t idx = find_var_index(current_env->locals, obj); 540 ssize_t idx = -1;
541
542 // TODO: Is a captured variable?
543 // FIXME: Order might be an issue, for example if the variable was initially
544 // captured but then declared as a local?
545 // (def a 40)
546 // (fun ext ()
547 // (display a)
548 // (def a 10)
549 // (display a))
550 idx = find_var_index(current_env->captured, obj);
551 if (idx != -1) {
552 // TODO: not implemented.
553 context_printf(" ;; <-- compile_symbol\n");
554 return;
555 }
556
557 // Is a local variable?
558 idx = find_var_index(current_env->locals, obj);
529 if (idx != -1) { 559 if (idx != -1) {
530 context_printf(" mov rax, [rbp + %ld]\n", 8 * idx); 560 context_printf(" mov rax, [rbp + %ld]\n", 8 * idx);
531 context_printf(" push rax\n"); 561 context_printf(" push rax\n");
532 context_printf(" ;; <-- compile_symbol\n"); 562 context_printf(" ;; <-- compile_symbol\n");
533 return; 563 return;
534 } 564 }
565
566 // Is a function parameter?
535 idx = find_var_index(current_env->params, obj); 567 idx = find_var_index(current_env->params, obj);
568 if (idx != -1) {
569 size_t n_locals = array_size(current_env->locals);
570 size_t n_params = array_size(current_env->params);
571 size_t offset = 8 * (n_locals + n_params - idx + 1);
572 context_printf(" mov rax, [rbp + %ld]\n", offset);
573 context_printf(" push rax\n");
574 context_printf(" ;; <-- compile_symbol\n");
575 return;
576 }
577
536 assert(idx != -1 && "unexpected index"); 578 assert(idx != -1 && "unexpected index");
537 size_t n_locals = array_size(current_env->locals);
538 size_t n_params = array_size(current_env->params);
539 size_t offset = 8 * (n_locals + n_params - idx + 1);
540 context_printf(" mov rax, [rbp + %ld]\n", offset);
541 context_printf(" push rax\n");
542 context_printf(" ;; <-- compile_symbol\n");
543} 579}
544 580
545void 581void
diff --git a/src/parser.c b/src/parser.c
index 64bd22d..0968ccd 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -456,7 +456,9 @@ symbol_in_env(Environment *env, Object *symbol) {
456 456
457void 457void
458insert_local(Environment *env, Object *symbol, Object *value) { 458insert_local(Environment *env, Object *symbol, Object *value) {
459 if (find_var_index(env->locals, symbol) != -1) { 459 ssize_t idx = find_var_index(env->locals, symbol);
460 if (idx != -1) {
461 env->local_values[idx] = value;
460 return; 462 return;
461 } 463 }
462 array_push(env->locals, symbol); 464 array_push(env->locals, symbol);