diff options
Diffstat (limited to 'src/gas_assembly_generator.c')
-rw-r--r-- | src/gas_assembly_generator.c | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index f09b60d..5091120 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -17,8 +17,10 @@ #include "gas_assembly_generator.h" #include <assert.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> static void gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binary_operation_t *binary_operation); @@ -32,11 +34,41 @@ gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_litera static void gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt); +static void +gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *gen, + ast_variable_declaration_t *variable_declaration); + +static void +gas_assembly_generator_compile_variable(gas_assembly_generator_t *gen, ast_variable_t *variable); + +typedef struct ref_entry_t +{ + ast_identifier_t *id; + int stack_offset; +} ref_entry_t; + +// TODO: We need a destroy function for ref_entry. +static ref_entry_t * +ref_entry_new(void) +{ + ref_entry_t *entry = (ref_entry_t *)malloc(sizeof(ref_entry_t)); + + if (entry == NULL) { + fprintf(stderr, "ref_entry_new: Out of memory: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + return entry; +} + + void gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream) { assert(gen && stream); gen->stream = stream; + gen->refs = vector_new(); + gen->stack_offset = 0; } void @@ -59,10 +91,10 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) assert(false && "TODO: ast identifier not implemented yet"); break; case AST_VARIABLE_DECLARATION: - assert(false && "TODO: ast variable declaration not implemented yet"); + gas_assembly_generator_compile_variable_declaration(gen, &ast->data.variable_declaration); break; case AST_VARIABLE: - assert(false && "TODO: ast variable not implemented yet"); + gas_assembly_generator_compile_variable(gen, &ast->data.variable); break; case AST_UNKOWN_NODE: assert(false && "unreachable"); @@ -82,10 +114,14 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct fprintf(gen->stream, ".global _start\n"); fprintf(gen->stream, ".text\n"); fprintf(gen->stream, "_start:\n"); + fprintf(gen->stream, " push %%rbp\n"); + fprintf(gen->stream, " mov %%rsp, %%rbp\n"); for (size_t i = 0; i < func->body->size; i++) { gas_assembly_generator_compile(gen, vector_at(func->body, i)); } + + fprintf(gen->stream, " pop %%rbp\n"); } static void @@ -95,9 +131,38 @@ gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_re gas_assembly_generator_compile(gen, return_stmt->argument); - fprintf(gen->stream, " mov %%rax, %%rbx\n"); - fprintf(gen->stream, " mov $1, %%al\n"); - fprintf(gen->stream, " int $0x80\n"); + fprintf(gen->stream, " mov %%rax, %%rdi\n"); + fprintf(gen->stream, " mov $60, %%rax\n"); + fprintf(gen->stream, " syscall\n"); +} + +static void +gas_assembly_generator_compile_variable_declaration(gas_assembly_generator_t *gen, + ast_variable_declaration_t *variable_declaration) +{ + gen->stack_offset -= 8; + gas_assembly_generator_compile(gen, variable_declaration->value); + + ref_entry_t *entry = ref_entry_new(); + *entry = (ref_entry_t){ .id = &variable_declaration->identifier, .stack_offset = gen->stack_offset }; + vector_push_back(gen->refs, entry); + + fprintf(gen->stream, " mov %%rax, %d(%%rbp)\n", entry->stack_offset); +} + +static void +gas_assembly_generator_compile_variable(gas_assembly_generator_t *gen, ast_variable_t *variable) +{ + ref_entry_t *entry = NULL; + for (int i = gen->refs->size - 1; i >= 0; --i) { + ref_entry_t *entry_tmp = (ref_entry_t *)vector_at(gen->refs, i); + if (entry_tmp->id == variable->identifier) { + entry = entry_tmp; + break; + } + } + assert(entry && "reference not found"); + fprintf(gen->stream, " mov %d(%%rbp), %%rax\n", entry->stack_offset); } static void @@ -117,11 +182,13 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar { gas_assembly_generator_compile(gen, binary_operation->right); - fprintf(gen->stream, " push %%rax\n"); + gen->stack_offset -= 8; + fprintf(gen->stream, " mov %%rax, %d(%%rbp)\n", gen->stack_offset); gas_assembly_generator_compile(gen, binary_operation->left); - fprintf(gen->stream, " pop %%rcx\n"); + fprintf(gen->stream, " mov %d(%%rbp), %%rcx\n", gen->stack_offset); + gen->stack_offset += 8; if (binary_operation->kind == AST_BINOP_ADITION) { fprintf(gen->stream, " add %%rcx, %%rax\n"); |