summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2023-04-21 15:11:17 +0200
committerCarlos Maniero <carlosmaniero@gmail.com>2023-04-21 10:29:41 -0300
commitd86d70fc7c6751713a6b9f02d9f77814e2f75718 (patch)
tree15340e4f421628fa79461374c39407997f928d93 /src/parser.c
parent562fa8785f9bc3074e8b2acf524f4120add22752 (diff)
parser: Parse integers arithmetic expression
This patch implements the AST creation for arithmetic expressions. NOTE: The implementation works only for integer numbers. Signed-off-by: Johnny Richard <johnny@johnnyrichard.com> Reviewed-by: Carlos Maniero <carlosmaniero@gmail.com>
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/src/parser.c b/src/parser.c
index 176a4a8..ad38125 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -109,16 +109,20 @@ parser_literal_integer_node(ast_node_t *node, token_t *token)
}
bool
-parser_parse_next_expression(parser_t *parser, ast_node_t *node)
+parser_parse_factor(parser_t *parser, ast_node_t *node)
{
token_t token;
lexer_next_token(parser->lexer, &token);
- if (token.kind == TOKEN_NUMBER)
- {
+ if (token.kind == TOKEN_NUMBER) {
return parser_literal_integer_node(node, &token);
+ } else if (token.kind == TOKEN_OPAREN) {
+ parser_parse_expression(parser, node);
+ if (!drop_expected_token(parser, TOKEN_CPAREN)) return false;
+ return true;
}
+ // FIXME: Extract this erros logic to a function
parser_error_t error;
error.token = token;
sprintf(
@@ -128,10 +132,76 @@ parser_parse_next_expression(parser_t *parser, ast_node_t *node)
SVARG(&token.value)
);
parser->errors[parser->errors_len++] = error;
+
return false;
}
bool
+parser_parse_term(parser_t *parser, ast_node_t *node)
+{
+ if (!parser_parse_factor(parser, node)) return false;
+
+ token_t token;
+ lexer_next_token(parser->lexer, &token);
+
+ while (token.kind == TOKEN_OP && (string_view_eq(token.value, string_view_from_str("*")) || string_view_eq(token.value, string_view_from_str("/")))) {
+ ast_node_t *binary_op = ast_node_new();
+ binary_op->kind = AST_BINARY_OPERATION;
+ binary_op->data.binary_operation.op = token.value;
+
+ binary_op->data.binary_operation.left = ast_node_new();
+ *binary_op->data.binary_operation.left = *node;
+
+ binary_op->data.binary_operation.right = ast_node_new();
+ if (!parser_parse_factor(parser, binary_op->data.binary_operation.right)) return false;
+
+ *node = *binary_op;
+
+ lexer_next_token(parser->lexer, &token);
+ }
+
+ lexer_step_back_to(parser->lexer, &token);
+
+ return true;
+}
+
+/**
+ *
+ * <expression> ::= <term> (('+' | '-') term)*
+ * <term> ::= <factor> (('*' | '/') factor)*
+ * <factor> ::= <integer> | '(' <expression> ')'
+ *
+ */
+bool
+parser_parse_expression(parser_t *parser, ast_node_t *node)
+{
+ if (!parser_parse_term(parser, node)) return false;
+
+ token_t token;
+ lexer_next_token(parser->lexer, &token);
+
+ while (token.kind == TOKEN_OP && (string_view_eq(token.value, string_view_from_str("+")) || string_view_eq(token.value, string_view_from_str("-")))) {
+
+ ast_node_t *binary_op = ast_node_new();
+ binary_op->kind = AST_BINARY_OPERATION;
+ binary_op->data.binary_operation.op = token.value;
+
+ binary_op->data.binary_operation.left = ast_node_new();
+ *binary_op->data.binary_operation.left = *node;
+
+ binary_op->data.binary_operation.right = ast_node_new();
+ if (!parser_parse_term(parser, binary_op->data.binary_operation.right)) return false;
+
+ *node = *binary_op;
+ lexer_next_token(parser->lexer, &token);
+ }
+
+ lexer_step_back_to(parser->lexer, &token);
+
+ return true;
+}
+
+bool
parser_parse_return_stmt(parser_t *parser, ast_node_t *node)
{
token_t return_keyword_token;
@@ -155,7 +225,7 @@ parser_parse_return_stmt(parser_t *parser, ast_node_t *node)
}
ast_node_t *argument_token = ast_node_new();
- if (!parser_parse_next_expression(parser, argument_token)) return false;
+ if (!parser_parse_expression(parser, argument_token)) return false;
if (!drop_expected_token(parser, TOKEN_SEMICOLON)) return false;
if (!drop_expected_token(parser, TOKEN_CCURLY)) return false;