From e927a4b22115e0461db6feeee891256b10650c0e Mon Sep 17 00:00:00 2001 From: Johnny Richard Date: Fri, 14 Apr 2023 23:10:25 +0200 Subject: parser: Create parser for function with return statements This is a very limited parser implementation which parses a single function with return type i32 and body containing a return number statement. The parser doesn't show the 'filepath:row:col' when it fails, a future improvement would be display it to easy find where the compilation problem is located. The ast_nodes are taking the token.value ownership (which is a really bad design since not all token.value ownership has been taken causing memory leaking) but we never free them. For a future fix we could use a string_view instead since we never change the original source code. The string_view will also improve the performance a lot avoiding unnecessary heap memory allocation. Signed-off-by: Johnny Richard --- src/parser.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/parser.c (limited to 'src/parser.c') diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..5d2a734 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,102 @@ +/* +* Copyright (C) 2023 Johnny Richard +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include +#include +#include +#include + +#include "lexer.h" +#include "parser.h" + +void +parser_init(parser_t *parser, lexer_t *lexer) +{ + assert(parser && "parser must be defined"); + assert(lexer && "lexer must be defined"); + parser->lexer = lexer; +} + +static token_t +expected_token(parser_t *parser, token_kind_t kind) +{ + token_t token; + lexer_next_token(parser->lexer, &token); + + if (token.kind == TOKEN_EOF) { + fprintf(stderr, "[ERROR]: expected '%s' but got end of file\n", token_kind_to_str(kind)); + exit(EXIT_FAILURE); + } + + if (token.kind != kind) { + fprintf(stderr, "[ERROR]: expected '%s' but got '%s'\n", token_kind_to_str(kind), token_kind_to_str(token.kind)); + exit(EXIT_FAILURE); + } + + return token; +} + +static type_t +parser_parse_type(parser_t *parser) +{ + token_t token = expected_token(parser, TOKEN_NAME); + + if (strcmp(token.value, "i32") == 0) { + return TYPE_I32; + } + + fprintf(stderr, "[ERROR]: expected type 'i32' but got '%s'\n", token.value); + exit(EXIT_FAILURE); +} + +static ast_return_stmt_t +parser_parse_return_stmt(parser_t *parser) +{ + expected_token(parser, TOKEN_OCURLY); + token_t return_keyword_token = expected_token(parser, TOKEN_NAME); + + if (strcmp(return_keyword_token.value, "return") != 0) { + // TODO: Add filename:row:col prefix to expected token exceptions + fprintf(stderr, "[ERROR]: expected 'return' keyword but got '%s'\n", return_keyword_token.value); + exit(EXIT_FAILURE); + } + + token_t number_token = expected_token(parser, TOKEN_NUMBER); + expected_token(parser, TOKEN_SEMICOLON); + expected_token(parser, TOKEN_CCURLY); + + return (ast_return_stmt_t) { + .number = atoi(number_token.value) + }; +} + +ast_function_t +parser_parse_function(parser_t *parser) +{ + token_t func_name_token = expected_token(parser, TOKEN_NAME); + expected_token(parser, TOKEN_OPAREN); + expected_token(parser, TOKEN_CPAREN); + expected_token(parser, TOKEN_COLON); + type_t return_type = parser_parse_type(parser); + + return (ast_function_t) { + // FIXME: alloc memory for the ast_function.name, it's not a good idea to use the token.value + .name = func_name_token.value, + .return_type = return_type, + .body = parser_parse_return_stmt(parser) + }; +} -- cgit v1.2.3