From 219dfdfdc98529ce173f894b79d88919a65c2808 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Thu, 20 Apr 2023 13:42:10 -0300 Subject: parser: Create the literal node type Since we want to extend our code to support multiple kind of expression it does not make sense that the return statement always return a number. For now on, return statement has an ast_node_t as argument, meaning that it could be anything. The literal_node_t was also implemented in order to keep the application behavior. Following the C's calling convention the literal values are stored at %eax and the return takes this argument to do anything it is needed. Signed-off-by: Carlos Maniero Reviewed-by: Johnny Richard --- src/ast.c | 26 ++++++++++++++++++++++++-- src/ast.h | 25 +++++++++++++++++++++---- src/gas_assembly_generator.c | 19 ++++++++++++++++++- src/parser.c | 43 ++++++++++++++++++++++++++++++++++++------- test/parser_test.c | 8 ++++++-- 5 files changed, 105 insertions(+), 16 deletions(-) diff --git a/src/ast.c b/src/ast.c index 50f6a2e..7f3af9e 100644 --- a/src/ast.c +++ b/src/ast.c @@ -39,6 +39,12 @@ ast_node_return_stmt_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) visitor->visit_return_stmt(visitor, &node->data.return_stmt); } +static void +ast_node_literal_visitor(ast_node_t *node, ast_visitor_t *visitor) +{ + visitor->visit_literal(visitor, &node->data.literal); +} + ast_node_t* ast_node_new() { @@ -62,6 +68,8 @@ ast_node_destroy(ast_node_t *node) break; case AST_UNKOWN_NODE: break; + case AST_LITERAL: + break; default: assert(false && "unmapped free strategy"); } @@ -69,13 +77,13 @@ ast_node_destroy(ast_node_t *node) } void -ast_node_init_return_stmt(ast_node_t *node, uint32_t number) +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 = (ast_node_data_t) { .return_stmt = { - .number = number + .argument = argument } }; } @@ -94,3 +102,17 @@ 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 = (ast_node_data_t) { + .literal = { + .kind = AST_LITERAL_INTEGER, + .value = { + .integer = number + } + } + }; +} diff --git a/src/ast.h b/src/ast.h index fab90c1..1c4bbb8 100644 --- a/src/ast.h +++ b/src/ast.h @@ -29,7 +29,7 @@ typedef struct ast_visitor_t ast_visitor_t; typedef struct ast_node_t ast_node_t; typedef struct ast_return_stmt_t { - uint32_t number; + ast_node_t* argument; } ast_return_stmt_t; typedef struct ast_function_declaration_t { @@ -38,19 +38,35 @@ typedef struct ast_function_declaration_t { ast_node_t* body; } ast_function_declaration_t; +typedef enum { + AST_LITERAL_INTEGER +} ast_literal_kind_t; + +typedef union { + uint32_t integer; +} ast_literal_value_t; + +typedef struct ast_literal_t { + ast_literal_kind_t kind; + ast_literal_value_t value; +} ast_literal_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 *); } ast_visitor_t; typedef enum { - AST_UNKOWN_NODE, AST_FUNCTION_DECLARATION, - AST_RETURN_STMT + AST_LITERAL, + AST_RETURN_STMT, + AST_UNKOWN_NODE } ast_node_kind_t; typedef union { ast_function_declaration_t function; + ast_literal_t literal; ast_return_stmt_t return_stmt; } ast_node_data_t; @@ -66,7 +82,8 @@ ast_node_t* ast_node_new(); void ast_node_destroy(ast_node_t *node); void ast_node_init_function_declaration(ast_node_t* node, string_view_t name, type_t return_type, ast_node_t *body); -void ast_node_init_return_stmt(ast_node_t* node, uint32_t number); +void ast_node_init_return_stmt(ast_node_t* node, ast_node_t *argument); +void ast_literal_integer_create(ast_node_t* node, uint32_t number); #endif /* AST_H */ diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index afbfebd..755b0be 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -22,6 +22,7 @@ static void gas_assembly_generator_visit_function(ast_visitor_t *visitor, ast_function_declaration_t *func); static void gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt_t *return_stmt); +static void gas_assembly_generator_visit_literal(ast_visitor_t *visitor, ast_literal_t *return_stmt); void gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *out) @@ -29,6 +30,7 @@ gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *out) 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 }; gen->out = out; @@ -59,8 +61,23 @@ gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt assert(visitor && return_stmt); gas_assembly_generator_t *gen = (gas_assembly_generator_t *) visitor; + ast_visitor_visit(visitor, return_stmt->argument); + + fprintf(gen->out, " mov %%eax, %%ebx\n"); + fprintf(gen->out, " mov $1, %%al\n"); fprintf(gen->out, " mov $1, %%al\n"); - fprintf(gen->out, " mov $%d, %%ebx\n", return_stmt->number); fprintf(gen->out, " int $0x80\n"); } +static void +gas_assembly_generator_visit_literal(ast_visitor_t *visitor, 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, %%eax\n", literal->value.integer); + return; + default: + assert(false && "No code generation strategy."); + } +} diff --git a/src/parser.c b/src/parser.c index 4646de0..176a4a8 100644 --- a/src/parser.c +++ b/src/parser.c @@ -98,6 +98,39 @@ parser_parse_type(type_t *type, parser_t *parser) return false; } +bool +parser_literal_integer_node(ast_node_t *node, token_t *token) +{ + char number_as_str[token->value.size]; + string_view_to_str(&token->value, number_as_str); + + ast_literal_integer_create(node, atoi(number_as_str)); + return true; +} + +bool +parser_parse_next_expression(parser_t *parser, ast_node_t *node) +{ + token_t token; + lexer_next_token(parser->lexer, &token); + + if (token.kind == TOKEN_NUMBER) + { + return parser_literal_integer_node(node, &token); + } + + parser_error_t error; + error.token = token; + sprintf( + error.message, + "unexpected '%s ("SVFMT")' token", + token_kind_to_str(token.kind), + SVARG(&token.value) + ); + parser->errors[parser->errors_len++] = error; + return false; +} + bool parser_parse_return_stmt(parser_t *parser, ast_node_t *node) { @@ -121,17 +154,13 @@ parser_parse_return_stmt(parser_t *parser, ast_node_t *node) return false; } - token_t number_token; - - if (!expected_token(&number_token, parser, TOKEN_NUMBER)) return false; + ast_node_t *argument_token = ast_node_new(); + if (!parser_parse_next_expression(parser, argument_token)) return false; if (!drop_expected_token(parser, TOKEN_SEMICOLON)) return false; if (!drop_expected_token(parser, TOKEN_CCURLY)) return false; - char number_as_str[number_token.value.size]; - string_view_to_str(&number_token.value, number_as_str); - - ast_node_init_return_stmt(node, atoi(number_as_str)); + ast_node_init_return_stmt(node, argument_token); return true; } diff --git a/test/parser_test.c b/test/parser_test.c index d1b8881..573296f 100644 --- a/test/parser_test.c +++ b/test/parser_test.c @@ -71,7 +71,11 @@ test_parse_function(const MunitParameter params[], ast_node_t *ast_return = ast_function->data.function.body; assert_int(AST_RETURN_STMT, ==, ast_return->kind); - assert_int(42, ==, ast_return->data.return_stmt.number); + + ast_node_t *ast_literal = ast_return->data.return_stmt.argument; + + assert_int(AST_LITERAL, ==, ast_literal->kind); + assert_int(42, ==, ast_literal->data.literal.value.integer); ast_node_destroy(ast_function); @@ -89,7 +93,7 @@ test_parse_basic_syntax_errors(const MunitParameter params[], assert_parser_error("main(): { return 42; }" , "expected 'TOKEN_NAME' but got '{'"); assert_parser_error("main(): i32 return 42; }" , "expected '{' but got 'TOKEN_NAME'"); assert_parser_error("main(): i32 { 42; }" , "expected 'TOKEN_NAME' but got 'TOKEN_NUMBER'"); - assert_parser_error("main(): i32 { return; }" , "expected 'TOKEN_NUMBER' but got ';'"); + 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 { oxi 42; }" , "expected 'return' keyword but got 'oxi'"); -- cgit v1.2.3