diff options
author | Johnny Richard <johnny@johnnyrichard.com> | 2023-04-29 20:49:51 +0200 |
---|---|---|
committer | Carlos Maniero <carlosmaniero@gmail.com> | 2023-04-29 15:57:15 -0300 |
commit | 3bc44f85de340c8da88d74b561b75716162d84d0 (patch) | |
tree | aba9d34bdbfb199a705bb0d15e7185ca7fe83a8c /src | |
parent | cd77ac7997fa956c1d67ef91cde056e817aa16c7 (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')
-rw-r--r-- | src/ast.c | 42 | ||||
-rw-r--r-- | src/ast.h | 15 | ||||
-rw-r--r-- | src/gas_assembly_generator.c | 102 | ||||
-rw-r--r-- | src/gas_assembly_generator.h | 7 | ||||
-rw-r--r-- | src/pipac.c | 3 |
5 files changed, 65 insertions, 104 deletions
@@ -19,42 +19,6 @@ #include <stdio.h> #include <stdlib.h> -void -ast_node_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) -{ - assert(node); - assert(node->accept_visitor); - node->accept_visitor(node, visitor); -} - -static void -ast_node_function_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) -{ - assert(visitor->visit_function && "unimplemented visit_function"); - visitor->visit_function(visitor, &node->data.function); -} - -static void -ast_node_return_stmt_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) -{ - assert(visitor->visit_return_stmt && "unimplemented visit_return_stmt"); - visitor->visit_return_stmt(visitor, &node->data.return_stmt); -} - -static void -ast_node_literal_visitor(ast_node_t *node, ast_visitor_t *visitor) -{ - assert(visitor->visit_literal && "unimplemented visit_literal"); - visitor->visit_literal(visitor, &node->data.literal); -} - -static void -ast_node_binary_operation_visitor(ast_node_t *node, ast_visitor_t *visitor) -{ - assert(visitor->visit_binary_operation && "unimplemented visit_binary_operation"); - visitor->visit_binary_operation(visitor, &node->data.binary_operation); -} - ast_node_t * ast_node_new() { @@ -108,7 +72,6 @@ ast_node_destroy(ast_node_t *node) void ast_node_init_return_stmt(ast_node_t *node, ast_node_t *argument) { - node->accept_visitor = &ast_node_return_stmt_accept_visitor; node->kind = AST_RETURN_STMT; node->data.return_stmt = (ast_return_stmt_t){ .argument = argument }; } @@ -116,7 +79,6 @@ ast_node_init_return_stmt(ast_node_t *node, ast_node_t *argument) void ast_node_init_function_declaration(ast_node_t *node, string_view_t name, type_t return_type, vector_t *body) { - node->accept_visitor = &ast_node_function_accept_visitor; node->kind = AST_FUNCTION_DECLARATION; node->data = (ast_node_data_t){ .function = { .name = name, .return_type = return_type, .body = body } }; } @@ -124,7 +86,6 @@ ast_node_init_function_declaration(ast_node_t *node, string_view_t name, type_t void ast_literal_integer_create(ast_node_t *node, uint32_t number) { - node->accept_visitor = &ast_node_literal_visitor; node->kind = AST_LITERAL; node->data.literal = (ast_literal_t){ .kind = AST_LITERAL_INTEGER, .value = { .integer = number } }; } @@ -132,7 +93,6 @@ ast_literal_integer_create(ast_node_t *node, uint32_t number) void ast_node_init_binary_operation(ast_node_t *node, ast_binary_operation_kind_t kind, ast_node_t *left, ast_node_t *right) { - node->accept_visitor = &ast_node_binary_operation_visitor; node->kind = AST_BINARY_OPERATION; node->data = (ast_node_data_t){ .binary_operation = { .kind = kind, .left = left, .right = right } }; } @@ -140,7 +100,6 @@ ast_node_init_binary_operation(ast_node_t *node, ast_binary_operation_kind_t kin void ast_node_init_variable_declaration(ast_node_t *node, string_view_t variable_name, type_t type, ast_node_t *value) { - // FIXME: define the visitor strategy node->kind = AST_VARIABLE_DECLARATION; node->data = (ast_node_data_t){ .variable = { .name = variable_name, .type = type, .value = value } }; } @@ -148,7 +107,6 @@ ast_node_init_variable_declaration(ast_node_t *node, string_view_t variable_name void ast_node_init_identifier(ast_node_t *node, string_view_t name) { - // FIXME: define the visitor strategy node->kind = AST_IDENTIFIER; node->data.identifier = (ast_identifier_t){ .name = name }; } @@ -20,14 +20,11 @@ #include "vector.h" #include <stdint.h> -#define ast_visitor_visit(visitor, node) ast_node_accept_visitor(node, (ast_visitor_t *)visitor); - typedef enum { TYPE_I32 } type_t; -typedef struct ast_visitor_t ast_visitor_t; typedef struct ast_node_t ast_node_t; typedef struct ast_return_stmt_t @@ -85,14 +82,6 @@ typedef struct ast_variable_declaration_t ast_node_t *value; } ast_variable_declaration_t; -typedef struct ast_visitor_t -{ - void (*visit_function)(struct ast_visitor_t *, ast_function_declaration_t *); - void (*visit_return_stmt)(struct ast_visitor_t *, ast_return_stmt_t *); - void (*visit_literal)(struct ast_visitor_t *, ast_literal_t *); - void (*visit_binary_operation)(struct ast_visitor_t *, ast_binary_operation_t *); -} ast_visitor_t; - typedef enum { AST_BINARY_OPERATION, @@ -116,14 +105,10 @@ typedef union typedef struct ast_node_t { - void (*accept_visitor)(ast_node_t *, ast_visitor_t *); ast_node_kind_t kind; ast_node_data_t data; } ast_node_t; -void -ast_node_accept_visitor(ast_node_t *node, ast_visitor_t *visitor); - ast_node_t * ast_node_new(); void 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; } diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h index c3192b7..4d4b28e 100644 --- a/src/gas_assembly_generator.h +++ b/src/gas_assembly_generator.h @@ -22,14 +22,13 @@ typedef struct gas_assembly_generator_t { - ast_visitor_t super; - FILE *out; + FILE *stream; } gas_assembly_generator_t; void -gas_assembly_generator_init(gas_assembly_generator_t *, FILE *); +gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream); void -gas_assembly_generator_visit(gas_assembly_generator_t *gen, ast_node_t *ast); +gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast); #endif /* GAS_ASSEMBLY_GENERATOR_H */ diff --git a/src/pipac.c b/src/pipac.c index 1acb4b6..d5781a5 100644 --- a/src/pipac.c +++ b/src/pipac.c @@ -29,8 +29,7 @@ generate_gas_x86_64_linux(ast_node_t *func) { gas_assembly_generator_t gen; gas_assembly_generator_init(&gen, stdout); - - ast_visitor_visit(&gen, func); + gas_assembly_generator_compile(&gen, func); } void |