diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | src/compiler.h | 80 | ||||
-rw-r--r-- | src/parser.c | 4 |
3 files changed, 65 insertions, 24 deletions
@@ -17,6 +17,7 @@ BIN := $(BUILD_DIR)/$(TARGET) | |||
17 | CC := cc | 17 | CC := cc |
18 | CFLAGS := -Wall -Wextra -pedantic -DBIN_NAME=\"$(TARGET)\" | 18 | CFLAGS := -Wall -Wextra -pedantic -DBIN_NAME=\"$(TARGET)\" |
19 | CFLAGS += $(INC_FLAGS) | 19 | CFLAGS += $(INC_FLAGS) |
20 | NASM_FLAGS ?= -felf64 | ||
20 | LDFLAGS := | 21 | LDFLAGS := |
21 | LDLIBS := | 22 | LDLIBS := |
22 | RELEASE_CFLAGS := -DNDEBUG -O2 -static | 23 | RELEASE_CFLAGS := -DNDEBUG -O2 -static |
@@ -30,8 +31,10 @@ DEBUG_CFLAGS := -DDEBUG -O0 -g | |||
30 | DEBUG ?= 0 | 31 | DEBUG ?= 0 |
31 | ifeq ($(DEBUG), 1) | 32 | ifeq ($(DEBUG), 1) |
32 | CFLAGS += $(DEBUG_CFLAGS) | 33 | CFLAGS += $(DEBUG_CFLAGS) |
34 | NASM_FLAGS += -g -F dwarf | ||
33 | else ifeq ($(DEBUG), 2) | 35 | else ifeq ($(DEBUG), 2) |
34 | CFLAGS += $(DEBUG_CFLAGS) -fsanitize=address | 36 | CFLAGS += $(DEBUG_CFLAGS) -fsanitize=address |
37 | NASM_FLAGS += -g -F dwarf | ||
35 | else | 38 | else |
36 | CFLAGS += $(RELEASE_CFLAGS) | 39 | CFLAGS += $(RELEASE_CFLAGS) |
37 | endif | 40 | endif |
@@ -54,7 +57,7 @@ tests: $(BIN) | |||
54 | 57 | ||
55 | run: $(BIN) | 58 | run: $(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 | ||
341 | void | 343 | void |
344 | compile_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 | |||
367 | void | ||
342 | compile_proc_call(Object *obj) { | 368 | compile_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 | ||
525 | void | 537 | void |
526 | compile_symbol(Object *obj) { | 538 | compile_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 | ||
545 | void | 581 | void |
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 | ||
457 | void | 457 | void |
458 | insert_local(Environment *env, Object *symbol, Object *value) { | 458 | insert_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); |