diff options
author | Johnny Richard <johnny@johnnyrichard.com> | 2023-04-21 15:11:17 +0200 |
---|---|---|
committer | Carlos Maniero <carlosmaniero@gmail.com> | 2023-04-21 10:29:41 -0300 |
commit | d86d70fc7c6751713a6b9f02d9f77814e2f75718 (patch) | |
tree | 15340e4f421628fa79461374c39407997f928d93 /src/parser.c | |
parent | 562fa8785f9bc3074e8b2acf524f4120add22752 (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.c | 78 |
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; |