summaryrefslogtreecommitdiff
path: root/src/gas_assembly_generator.c
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2023-04-29 20:49:51 +0200
committerCarlos Maniero <carlosmaniero@gmail.com>2023-04-29 15:57:15 -0300
commit3bc44f85de340c8da88d74b561b75716162d84d0 (patch)
treeaba9d34bdbfb199a705bb0d15e7185ca7fe83a8c /src/gas_assembly_generator.c
parentcd77ac7997fa956c1d67ef91cde056e817aa16c7 (diff)
ast: Remove ast visitor pattern to simplify the code
I decided to remove the visitor pattern due to the lack of Object Oriented Programming support for C. Now if you want to navigate through the AST, you should do it with switch case and recursion. The code looks way simpler without visitor pattern. I have added a CFLAG -Werror which validates if the switch statement covers all branches for a given enum at compile time. Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
Diffstat (limited to 'src/gas_assembly_generator.c')
-rw-r--r--src/gas_assembly_generator.c102
1 files changed, 61 insertions, 41 deletions
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c
index bf98255..34864dd 100644
--- a/src/gas_assembly_generator.c
+++ b/src/gas_assembly_generator.c
@@ -21,66 +21,88 @@
#include <stdlib.h>
static void
-gas_assembly_generator_visit_function(ast_visitor_t *visitor, ast_function_declaration_t *func);
+gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binary_operation_t *binary_operation);
+
static void
-gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt_t *return_stmt);
+gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func);
+
static void
-gas_assembly_generator_visit_literal(ast_visitor_t *visitor, ast_literal_t *literal);
+gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_literal_t *literal);
+
static void
-gas_assembly_generator_binary_operation(ast_visitor_t *visitor, ast_binary_operation_t *binary_operation);
+gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt);
+
+void
+gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream)
+{
+ assert(gen && stream);
+ gen->stream = stream;
+}
void
-gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *out)
+gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast)
{
- assert(gen && out);
- gen->super = (ast_visitor_t){ .visit_function = &gas_assembly_generator_visit_function,
- .visit_literal = &gas_assembly_generator_visit_literal,
- .visit_return_stmt = &gas_assembly_generator_visit_return_stmt,
- .visit_binary_operation = &gas_assembly_generator_binary_operation };
- gen->out = out;
+ switch (ast->kind) {
+ case AST_BINARY_OPERATION:
+ gas_assembly_generator_binary_operation(gen, &ast->data.binary_operation);
+ break;
+ case AST_FUNCTION_DECLARATION:
+ gas_assembly_generator_compile_function(gen, &ast->data.function);
+ break;
+ case AST_LITERAL:
+ gas_assembly_generator_compile_literal(gen, &ast->data.literal);
+ break;
+ case AST_RETURN_STMT:
+ gas_assembly_generator_compile_return_stmt(gen, &ast->data.return_stmt);
+ break;
+ case AST_IDENTIFIER:
+ assert(false && "TODO: ast identifier not implemented yet");
+ break;
+ case AST_VARIABLE_DECLARATION:
+ assert(false && "TODO: ast variable declaration not implemented yet");
+ break;
+ case AST_UNKOWN_NODE:
+ assert(false && "unreachable");
+ }
}
static void
-gas_assembly_generator_visit_function(ast_visitor_t *visitor, ast_function_declaration_t *func)
+gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func)
{
- assert(visitor && func);
+ assert(func);
if (!string_view_eq(func->name, string_view_from_str("main"))) {
fprintf(stderr, "[ERROR]: no main function has been defined!\n");
exit(EXIT_FAILURE);
}
- gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor;
-
- fprintf(gen->out, ".global _start\n");
- fprintf(gen->out, ".text\n");
- fprintf(gen->out, "_start:\n");
+ fprintf(gen->stream, ".global _start\n");
+ fprintf(gen->stream, ".text\n");
+ fprintf(gen->stream, "_start:\n");
for (size_t i = 0; i < func->body->size; i++) {
- ast_visitor_visit(visitor, vector_at(func->body, i));
+ gas_assembly_generator_compile(gen, vector_at(func->body, i));
}
}
static void
-gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt_t *return_stmt)
+gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt)
{
- assert(visitor && return_stmt);
- gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor;
+ assert(gen && return_stmt);
- ast_visitor_visit(visitor, return_stmt->argument);
+ gas_assembly_generator_compile(gen, return_stmt->argument);
- fprintf(gen->out, " mov %%rax, %%rbx\n");
- fprintf(gen->out, " mov $1, %%al\n");
- fprintf(gen->out, " int $0x80\n");
+ fprintf(gen->stream, " mov %%rax, %%rbx\n");
+ fprintf(gen->stream, " mov $1, %%al\n");
+ fprintf(gen->stream, " int $0x80\n");
}
static void
-gas_assembly_generator_visit_literal(ast_visitor_t *visitor, ast_literal_t *literal)
+gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_literal_t *literal)
{
- gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor;
switch (literal->kind) {
case AST_LITERAL_INTEGER:
- fprintf(gen->out, " mov $%d, %%rax\n", literal->value.integer);
+ fprintf(gen->stream, " mov $%d, %%rax\n", literal->value.integer);
return;
default:
assert(false && "no code generation strategy.");
@@ -88,36 +110,34 @@ gas_assembly_generator_visit_literal(ast_visitor_t *visitor, ast_literal_t *lite
}
static void
-gas_assembly_generator_binary_operation(ast_visitor_t *visitor, ast_binary_operation_t *binary_operation)
+gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binary_operation_t *binary_operation)
{
- gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor;
-
- ast_visitor_visit(visitor, binary_operation->right);
+ gas_assembly_generator_compile(gen, binary_operation->right);
- fprintf(gen->out, " push %%rax\n");
+ fprintf(gen->stream, " push %%rax\n");
- ast_visitor_visit(visitor, binary_operation->left);
+ gas_assembly_generator_compile(gen, binary_operation->left);
- fprintf(gen->out, " pop %%rcx\n");
+ fprintf(gen->stream, " pop %%rcx\n");
if (binary_operation->kind == AST_BINOP_ADITION) {
- fprintf(gen->out, " add %%rcx, %%rax\n");
+ fprintf(gen->stream, " add %%rcx, %%rax\n");
return;
}
if (binary_operation->kind == AST_BINOP_SUBTRACTION) {
- fprintf(gen->out, " sub %%rcx, %%rax\n");
+ fprintf(gen->stream, " sub %%rcx, %%rax\n");
return;
}
if (binary_operation->kind == AST_BINOP_MULTIPLICATION) {
- fprintf(gen->out, " mul %%rcx\n");
+ fprintf(gen->stream, " mul %%rcx\n");
return;
}
if (binary_operation->kind == AST_BINOP_DIVISION) {
- fprintf(gen->out, " xor %%rdx, %%rdx\n");
- fprintf(gen->out, " div %%rcx\n");
+ fprintf(gen->stream, " xor %%rdx, %%rdx\n");
+ fprintf(gen->stream, " div %%rcx\n");
return;
}