diff options
-rw-r--r-- | src/ast.c | 7 | ||||
-rw-r--r-- | src/ast.h | 11 | ||||
-rw-r--r-- | src/gas_assembly_generator.c | 3 | ||||
-rw-r--r-- | src/parser.c | 27 | ||||
-rw-r--r-- | src/parser.h | 4 | ||||
-rw-r--r-- | src/pipac.c | 5 | ||||
-rw-r--r-- | src/scope.c | 6 | ||||
-rw-r--r-- | src/scope.h | 7 | ||||
-rw-r--r-- | test/Makefile | 2 | ||||
-rw-r--r-- | test/parser_test.c | 18 | ||||
-rw-r--r-- | test/scope_test.c | 14 |
11 files changed, 80 insertions, 24 deletions
@@ -108,6 +108,13 @@ ast_node_init_variable_declaration(ast_node_t *node, string_view_t variable_name } void +ast_node_init_variable(ast_node_t *node, ast_identifier_t *identifier) +{ + node->kind = AST_VARIABLE; + node->data = (ast_node_data_t){ .variable_ex = { .identifier = identifier } }; +} + +void ast_node_init_identifier(ast_node_t *node, string_view_t name) { node->kind = AST_IDENTIFIER; @@ -37,6 +37,11 @@ typedef struct ast_identifier_t string_view_t name; } ast_identifier_t; +typedef struct ast_variable_t +{ + ast_identifier_t *identifier; +} ast_variable_t; + typedef struct ast_function_declaration_t { ast_identifier_t identifier; @@ -91,6 +96,7 @@ typedef enum AST_RETURN_STMT, AST_UNKOWN_NODE, AST_VARIABLE_DECLARATION, + AST_VARIABLE } ast_node_kind_t; typedef union @@ -99,8 +105,9 @@ typedef union ast_function_declaration_t function; ast_literal_t literal; ast_return_stmt_t return_stmt; - ast_variable_declaration_t variable; + ast_variable_declaration_t variable; // FIXME: Rename to variable_declaration ast_identifier_t identifier; + ast_variable_t variable_ex; // FIXME: Rename to variable } ast_node_data_t; typedef struct ast_node_t @@ -127,5 +134,7 @@ ast_node_init_variable_declaration(ast_node_t *node, string_view_t variable_name // FIXME: use the naming convention void ast_literal_integer_create(ast_node_t *node, uint32_t number); +void +ast_node_init_variable(ast_node_t *node, ast_identifier_t *identifier); #endif /* AST_H */ diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index ea76c5f..f09b60d 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -61,6 +61,9 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) case AST_VARIABLE_DECLARATION: assert(false && "TODO: ast variable declaration not implemented yet"); break; + case AST_VARIABLE: + assert(false && "TODO: ast variable not implemented yet"); + break; case AST_UNKOWN_NODE: assert(false && "unreachable"); } diff --git a/src/parser.c b/src/parser.c index 6b954c2..469fa99 100644 --- a/src/parser.c +++ b/src/parser.c @@ -24,14 +24,16 @@ #include "ast.h" #include "lexer.h" #include "parser.h" +#include "scope.h" #include "vector.h" void -parser_init(parser_t *parser, lexer_t *lexer) +parser_init(parser_t *parser, lexer_t *lexer, scope_t *scope) { assert(parser && "parser must be defined"); assert(lexer && "lexer must be defined"); parser->lexer = lexer; + parser->scope = scope; parser->errors_len = 0; } @@ -134,8 +136,16 @@ parser_parse_factor(parser_t *parser, ast_node_t *node) return false; return true; case TOKEN_NAME: - /// FIXME: Check if the identifier is defined ast_node_init_identifier(node, token.value); + // TODO: Check node kind, today accepts only variables + if (scope_get(parser->scope, token.value) == NULL) { + parser_error_t error; + error.token = token; + sprintf(error.message, "identifier '" SVFMT "' not defined", SVARG(&token.value)); + parser->errors[parser->errors_len++] = error; + return false; + } + return true; default: { parser_error_t error; @@ -143,7 +153,7 @@ parser_parse_factor(parser_t *parser, ast_node_t *node) sprintf(error.message, "unexpected '%s (" SVFMT ")' token", token_kind_to_str(token.kind), SVARG(&token.value)); parser->errors[parser->errors_len++] = error; return false; - } + } } } @@ -247,6 +257,7 @@ parser_parse_variable_definition(parser_t *parser, string_view_t variable_name, } ast_node_init_variable_declaration(node, variable_name, type, expression); + scope_push(parser->scope, &node->data.variable.identifier, node); return true; } @@ -333,11 +344,17 @@ parser_parse_function_declaration(parser_t *parser, ast_node_t *node) return false; vector_t *body = vector_new(); + ast_node_init_function_declaration(node, func_name_token.value, return_type, body); + scope_push(parser->scope, &node->data.function.identifier, node); + + scope_enter(parser->scope); - if (!parser_parse_block_declarations(parser, body)) + if (!parser_parse_block_declarations(parser, body)) { + scope_leave(parser->scope); return false; + } - ast_node_init_function_declaration(node, func_name_token.value, return_type, body); + scope_leave(parser->scope); return true; } diff --git a/src/parser.h b/src/parser.h index bdf0c5a..d3e1431 100644 --- a/src/parser.h +++ b/src/parser.h @@ -19,6 +19,7 @@ #include "ast.h" #include "lexer.h" +#include "scope.h" #include "string_view.h" typedef struct parser_error_t @@ -30,13 +31,14 @@ typedef struct parser_error_t typedef struct parser_t { lexer_t *lexer; + scope_t *scope; int errors_len; // FIXME: replace with vector parser_error_t errors[1]; } parser_t; void -parser_init(parser_t *parser, lexer_t *lexer); +parser_init(parser_t *parser, lexer_t *lexer, scope_t *scope); bool parser_parse_function_declaration(parser_t *parser, ast_node_t *node); diff --git a/src/pipac.c b/src/pipac.c index b31b8b5..2041218 100644 --- a/src/pipac.c +++ b/src/pipac.c @@ -22,6 +22,7 @@ #include "gas_assembly_generator.h" #include "lexer.h" #include "parser.h" +#include "scope.h" #include "string_view.h" static void @@ -62,8 +63,9 @@ main(int argc, char **argv) lexer_t lexer; lexer_init(&lexer, filepath); + scope_t *scope = scope_new(); parser_t parser; - parser_init(&parser, &lexer); + parser_init(&parser, &lexer, scope); ast_node_t *func = ast_node_new(); @@ -74,6 +76,7 @@ main(int argc, char **argv) generate_gas_x86_64_linux(func); + scope_destroy(scope); ast_node_destroy(func); return EXIT_SUCCESS; } diff --git a/src/scope.c b/src/scope.c index 5b696ad..662e59c 100644 --- a/src/scope.c +++ b/src/scope.c @@ -54,7 +54,7 @@ scope_new(void) void scope_destroy(scope_t *scope) { - if (scope->stack->size) { + if (scope->stack->size != 1) { fprintf(stderr, "Stack not cleaned before destroying. This may lead to memory leaks.\n" "Please make sure to call the leave function before destroying it."); @@ -97,7 +97,7 @@ scope_leave(scope_t *scope) } ast_node_t * -scope_get(scope_t *scope, ast_identifier_t *identifier) +scope_get(scope_t *scope, string_view_t name) { for (size_t i = scope->stack->size; i > 0; i--) { vector_t *current_level = vector_at(scope->stack, i - 1); @@ -105,7 +105,7 @@ scope_get(scope_t *scope, ast_identifier_t *identifier) for (size_t j = 0; j < current_level->size; j++) { scope_item_t *item = vector_at(current_level, j); - if (string_view_eq(identifier->name, item->identifier->name)) { + if (string_view_eq(name, item->identifier->name)) { return item->node; } } diff --git a/src/scope.h b/src/scope.h index c221703..2636990 100644 --- a/src/scope.h +++ b/src/scope.h @@ -14,6 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#ifndef SCOPE_H +#define SCOPE_H + #include "ast.h" #include "string_view.h" #include "vector.h" @@ -41,6 +44,8 @@ void scope_leave(scope_t *scope); ast_node_t * -scope_get(scope_t *scope, ast_identifier_t *identifier); +scope_get(scope_t *scope, string_view_t name); void scope_push(scope_t *scope, ast_identifier_t *identifier, ast_node_t *node); + +#endif /* SCOPE_H */ diff --git a/test/Makefile b/test/Makefile index 6d8bfb7..9572d0f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -27,7 +27,7 @@ vector_test: munit.o ../build/vector.o vector_test.o lexer_test: munit.o ../build/string_view.o ../build/lexer.o lexer_test.o $(CC) $? $(CFLAGS) -o $@ -parser_test: munit.o ../build/string_view.o ../build/vector.o ../build/lexer.o ../build/ast.o ../build/parser.o parser_test.o +parser_test: munit.o ../build/string_view.o ../build/scope.o ../build/vector.o ../build/lexer.o ../build/ast.o ../build/parser.o parser_test.o $(CC) $? $(CFLAGS) -o $@ scope_test: munit.o ../build/string_view.o ../build/vector.o ../build/ast.o ../build/scope.o scope_test.o diff --git a/test/parser_test.c b/test/parser_test.c index 40c0198..0c54e50 100644 --- a/test/parser_test.c +++ b/test/parser_test.c @@ -19,6 +19,7 @@ #include "lexer.h" #include "munit.h" #include "parser.h" +#include "scope.h" #include "string.h" #include "vector.h" @@ -43,8 +44,9 @@ assert_parser_error(char *src, char *error_msg) parser_t parser; lexer_t lexer; + scope_t *scope = scope_new(); make_lexer_from_static_src(&lexer, src); - parser_init(&parser, &lexer); + parser_init(&parser, &lexer, scope); ast_node_t *ast_function = ast_node_new(); @@ -54,6 +56,7 @@ assert_parser_error(char *src, char *error_msg) assert_string_equal(error_msg, parser.errors[0].message); ast_node_destroy(ast_function); + scope_destroy(scope); } static MunitResult @@ -61,9 +64,10 @@ test_parse_function(const MunitParameter params[], void *user_data_or_fixture) { parser_t parser; lexer_t lexer; + scope_t *scope = scope_new(); make_lexer_from_static_src(&lexer, "main(): i32 { \nreturn 42;\n }"); - parser_init(&parser, &lexer); + parser_init(&parser, &lexer, scope); ast_node_t *ast_function = ast_node_new(); bool parsed = parser_parse_function_declaration(&parser, ast_function); @@ -85,6 +89,7 @@ test_parse_function(const MunitParameter params[], void *user_data_or_fixture) assert_int(42, ==, ast_literal->data.literal.value.integer); ast_node_destroy(ast_function); + scope_destroy(scope); return MUNIT_OK; } @@ -94,9 +99,10 @@ test_parse_variable_definition(const MunitParameter params[], void *user_data_or { parser_t parser; lexer_t lexer; + scope_t *scope = scope_new(); make_lexer_from_static_src(&lexer, "main(): i32 { \nvariable : i32 = 42; \nreturn variable;\n }"); - parser_init(&parser, &lexer); + parser_init(&parser, &lexer, scope); ast_node_t *ast_function = ast_node_new(); bool parsed = parser_parse_function_declaration(&parser, ast_function); @@ -124,6 +130,7 @@ test_parse_variable_definition(const MunitParameter params[], void *user_data_or assert_string_view_equal("variable", ast_literal->data.identifier.name); ast_node_destroy(ast_function); + scope_destroy(scope); return MUNIT_OK; } @@ -133,9 +140,10 @@ test_parse_arithmetic_expression(const MunitParameter params[], void *user_data_ { parser_t parser; lexer_t lexer; + scope_t *scope = scope_new(); make_lexer_from_static_src(&lexer, "1 + 3 * 3 / 2 - 1"); - parser_init(&parser, &lexer); + parser_init(&parser, &lexer, scope); ast_node_t *ast_expression = ast_node_new(); bool parsed = parser_parse_expression(&parser, ast_expression); @@ -185,6 +193,7 @@ test_parse_arithmetic_expression(const MunitParameter params[], void *user_data_ } ast_node_destroy(ast_expression); + scope_destroy(scope); return MUNIT_OK; } @@ -210,6 +219,7 @@ test_parse_basic_syntax_errors(const MunitParameter params[], void *user_data_or assert_parser_error("main(): i32 { return; }", "unexpected '; (;)' token"); assert_parser_error("main(): i32 { return 42;", "expected '}' but got end of file"); assert_parser_error("main(): beff { return 42; }", "type 'beff' is not defined"); + assert_parser_error("main(): i32 { return b; }", "identifier 'b' not defined"); // FIXME: once function calls are implemented, this error should inform that // neither a variable or function call was found. assert_parser_error("main(): i32 { oxi 42; }", "expected ':' but got 'TOKEN_NUMBER'"); diff --git a/test/scope_test.c b/test/scope_test.c index b8ee30e..c71a38f 100644 --- a/test/scope_test.c +++ b/test/scope_test.c @@ -31,24 +31,24 @@ test_scope(const MunitParameter params[], void *user_data_or_fixture) scope_t *scope = scope_new(); - assert_null(scope_get(scope, &first_id)); - assert_null(scope_get(scope, &second_id)); + assert_null(scope_get(scope, first_id.name)); + assert_null(scope_get(scope, second_id.name)); scope_push(scope, &first_id, &first_id_node_1); scope_push(scope, &second_id, &second_id_node); - assert_ptr_equal((void *)scope_get(scope, &first_id), (void *)&first_id_node_1); - assert_ptr_equal((void *)scope_get(scope, &second_id), (void *)&second_id_node); + assert_ptr_equal((void *)scope_get(scope, first_id.name), (void *)&first_id_node_1); + assert_ptr_equal((void *)scope_get(scope, second_id.name), (void *)&second_id_node); scope_enter(scope); scope_push(scope, &first_id, &first_id_node_2); - assert_ptr_equal((void *)scope_get(scope, &first_id), (void *)&first_id_node_2); - assert_ptr_equal((void *)scope_get(scope, &second_id), (void *)&second_id_node); + assert_ptr_equal((void *)scope_get(scope, first_id.name), (void *)&first_id_node_2); + assert_ptr_equal((void *)scope_get(scope, second_id.name), (void *)&second_id_node); scope_leave(scope); - assert_ptr_equal((void *)scope_get(scope, &first_id), (void *)&first_id_node_1); + assert_ptr_equal((void *)scope_get(scope, first_id.name), (void *)&first_id_node_1); scope_destroy(scope); |