summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-10 22:24:14 -0300
committerCarlos Maniero <carlos@maniero.me>2023-05-10 22:45:31 -0300
commit5042a4ffc1363d6f0f99a3afd79f76cf2da738d6 (patch)
tree90c31d77ddf6b9051669fafdc6dfe0fc3b1f35eb /src/parser.c
parent6f187a71cbe3aa4ebb32ba287c75562d96c7a3f4 (diff)
gas: implement function calls
For now function calls are following the C's calling convention, which means they are using the following registers to pass functions' arguments: rdi, rsi, rdx, rcx, r8, r9 If a function has more then 6 parameters, the compilation will fail. To enable function with more than 6 parameters we will need to save the extra arguments on stack. Naming: parameters: function parameters are the variables a function receives. arguments: Arguments are the values passed to a function when calling it. Calling mechanism: When a function is called, all the expressions passed as argument are evaluated, after the evaluation, the result is stored on the register that represents its argument position, the first argument will be stored on rdi, the second on rsi and so on. Receiving mechanism: When a function starts, the first thing it does is store all the registers onto the stack. So rdi will be stored on -8(rbp), rsi on -16(rbp) and so on. And, a ref_entry is created making the relationship parameter-stack_offset. Signed-off-by: Carlos Maniero <carlos@maniero.me>
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c95
1 files changed, 85 insertions, 10 deletions
diff --git a/src/parser.c b/src/parser.c
index 377ff73..fe2a2f0 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -33,6 +33,9 @@ parser_expression_matches_the_expected_type(parser_t *parser, ast_node_t *expres
static ast_node_t *
parser_parse_block_declarations(parser_t *parser, type_t result_type);
+static bool
+is_next_token_cparen(parser_t *parser);
+
void
parser_init(parser_t *parser, lexer_t *lexer, scope_t *scope)
{
@@ -354,16 +357,40 @@ parser_parse_factor(parser_t *parser)
referenced_node->data.variable_declaration.type);
}
+ // Function parameters are also variables.
+ if (referenced_node->kind == AST_FUNCTION_PARAMETER) {
+ return ast_node_new_variable(&referenced_node->data.function_parameter.identifier,
+ referenced_node->data.function_parameter.type);
+ }
+
// Parse function parameters
if (!drop_expected_token(parser, TOKEN_OPAREN)) {
return NULL;
}
- if (!drop_expected_token(parser, TOKEN_CPAREN)) {
- return NULL;
+
+ vector_t *arguments = vector_new();
+
+ while (!is_next_token_cparen(parser)) {
+ ast_node_t *argument = parser_parse_expression(parser);
+
+ if (argument == NULL) {
+ ast_node_destroy_vector(arguments);
+ return NULL;
+ }
+
+ vector_push_back(arguments, argument);
+
+ if (!is_next_token_cparen(parser) && !drop_expected_token(parser, TOKEN_COMMA)) {
+ ast_node_destroy_vector(arguments);
+ return NULL;
+ }
}
- return ast_node_new_function_call(&referenced_node->data.function.identifier,
- referenced_node->data.function.return_type);
+ drop_expected_token(parser, TOKEN_CPAREN);
+
+ return ast_node_new_function_call(ast_node_function_declaration_identifier(referenced_node),
+ referenced_node->data.function.prototype.return_type,
+ arguments);
}
default: {
parser_error_t error;
@@ -591,6 +618,14 @@ is_next_function_declaration(parser_t *parser)
}
static bool
+is_next_token_cparen(parser_t *parser)
+{
+ token_t token;
+ lexer_peek_next_token(parser->lexer, &token);
+ return token.kind == TOKEN_CPAREN;
+}
+
+static bool
is_next_token_eof(parser_t *parser)
{
token_t token;
@@ -722,10 +757,48 @@ parser_parse_block_declarations(parser_t *parser, type_t result_type)
return ast_node_new_block(body);
}
-static bool
-parser_parse_function_arguments(parser_t *parser)
+static vector_t *
+parser_parse_function_parameters(parser_t *parser)
{
- return drop_expected_token(parser, TOKEN_OPAREN) && drop_expected_token(parser, TOKEN_CPAREN);
+ if (!drop_expected_token(parser, TOKEN_OPAREN)) {
+ return NULL;
+ }
+
+ vector_t *vector = vector_new();
+
+ while (!is_next_token_cparen(parser)) {
+ token_t token_name;
+ type_t type;
+
+ if (!expected_token(&token_name, parser, TOKEN_NAME)) {
+ ast_node_destroy_vector(vector);
+ return NULL;
+ }
+ if (!drop_expected_token(parser, TOKEN_COLON)) {
+ ast_node_destroy_vector(vector);
+ return NULL;
+ }
+
+ if (!parser_parse_type(parser, &type)) {
+ ast_node_destroy_vector(vector);
+ return NULL;
+ }
+
+ ast_node_t *parameter = ast_node_new_function_parameter(token_name.value, type);
+
+ scope_push(parser->scope, &parameter->data.function_parameter.identifier, parameter);
+
+ vector_push_back(vector, parameter);
+
+ if (!is_next_token_cparen(parser) && !drop_expected_token(parser, TOKEN_COMMA)) {
+ ast_node_destroy_vector(vector);
+ return NULL;
+ }
+ }
+
+ drop_expected_token(parser, TOKEN_CPAREN);
+
+ return vector;
}
ast_node_t *
@@ -741,7 +814,9 @@ parser_parse_function_declaration(parser_t *parser)
return NULL;
}
- if (!parser_parse_function_arguments(parser)) {
+ vector_t *parameters = parser_parse_function_parameters(parser);
+
+ if (parameters == NULL) {
return NULL;
}
@@ -766,11 +841,11 @@ parser_parse_function_declaration(parser_t *parser)
return NULL;
}
- ast_node_t *node = ast_node_new_function_declaration(func_name_token.value, return_type, body);
+ ast_node_t *node = ast_node_new_function_declaration(func_name_token.value, return_type, parameters, body);
// TODO: When implementing function calls the scope must be pushed before the
// body to be parsed, otherwise recursion not gonna work.
- scope_push(parser->scope, &node->data.function.identifier, node);
+ scope_push(parser->scope, &node->data.function.prototype.identifier, node);
return node;
}