diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lexer.c | 27 | ||||
-rw-r--r-- | src/lexer.h | 2 | ||||
-rw-r--r-- | src/parser.c | 102 | ||||
-rw-r--r-- | src/parser.h | 45 | ||||
-rw-r--r-- | src/pipac.c | 7 |
5 files changed, 182 insertions, 1 deletions
diff --git a/src/lexer.c b/src/lexer.c index 14165ae..0327ad5 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -198,3 +198,30 @@ lexer_current_char(lexer_t *lexer) return lexer->src[lexer->cur]; } +char * +token_kind_to_str(token_kind_t kind) +{ + switch (kind) { + case TOKEN_NAME: + return "TOKEN_NAME"; + case TOKEN_OPAREN: + return "("; + case TOKEN_CPAREN: + return ")"; + case TOKEN_COLON: + return ":"; + case TOKEN_SEMICOLON: + return ";"; + case TOKEN_OCURLY: + return "{"; + case TOKEN_CCURLY: + return "}"; + case TOKEN_NUMBER: + return "TOKEN_NUMBER"; + case TOKEN_EOF: + return "TOKEN_EOF"; + default: + return "UNKNOW_TOKEN"; + } +} + diff --git a/src/lexer.h b/src/lexer.h index 29cfc11..f5333a0 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -64,5 +64,7 @@ bool lexer_is_not_eof(lexer_t *lexer); void lexer_drop_char(lexer_t *lexer); +char * token_kind_to_str(token_kind_t kind); + #endif /* LEXER_H */ 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 <https://www.gnu.org/licenses/>. +*/ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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) + }; +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..e9a1cb7 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,45 @@ +/* +* 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 <https://www.gnu.org/licenses/>. +*/ +#ifndef PARSER_H +#define PARSER_H + +#include "lexer.h" + +typedef struct parser_t { + lexer_t *lexer; +} parser_t; + +typedef enum { + TYPE_I32 +} type_t; + +typedef struct ast_return_stmt_t { + uint32_t number; +} ast_return_stmt_t; + +typedef struct ast_function_t { + char *name; + type_t return_type; + ast_return_stmt_t body; +} ast_function_t; + +void parser_init(parser_t *parser, lexer_t *lexer); + +ast_function_t parser_parse_function(parser_t *parser); + +#endif /* PARSER_H */ + diff --git a/src/pipac.c b/src/pipac.c index f1e5865..0df4a08 100644 --- a/src/pipac.c +++ b/src/pipac.c @@ -17,6 +17,7 @@ #include <stdio.h> #include <stdlib.h> #include "lexer.h" +#include "parser.h" void print_usage() @@ -46,8 +47,12 @@ main(int argc, char **argv) lexer_init(&lexer, filepath); printf("[INFO]: %ld bytes loaded [filename='%s']\n", lexer.srclen, lexer.filepath); + + parser_t parser; + parser_init(&parser, &lexer); + ast_function_t func = parser_parse_function(&parser); - print_tokens(&lexer); + printf("function name='%s' and return type '%d' with value %d\n", func.name, func.return_type, func.body.number); return EXIT_SUCCESS; } |