From 1be3bf06598832b89ec3b46927f17e572f52ef51 Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Mon, 1 Dec 2025 19:54:20 +0100 Subject: [PATCH] added postfix, break and return parsing --- examples/generics.l | 4 +++ examples/hello_world.l | 6 ++++ examples/test.l | 10 ++++++ lc.c | 9 ++++- lexer.c | 2 +- lexer.h | 2 +- parser.c | 80 ++++++++++++++++++++++++++++++++++++++++-- parser.h | 13 +++---- test.c | 2 +- 9 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 examples/generics.l create mode 100644 examples/hello_world.l create mode 100644 examples/test.l diff --git a/examples/generics.l b/examples/generics.l new file mode 100644 index 0000000..770cb5e --- /dev/null +++ b/examples/generics.l @@ -0,0 +1,4 @@ +u32 sum(T x, T y) +{ + return x + y; +} diff --git a/examples/hello_world.l b/examples/hello_world.l new file mode 100644 index 0000000..31e17d4 --- /dev/null +++ b/examples/hello_world.l @@ -0,0 +1,6 @@ +import test; + +i32 main() +{ + print_msg("Hello world!"); +} diff --git a/examples/test.l b/examples/test.l new file mode 100644 index 0000000..7451cda --- /dev/null +++ b/examples/test.l @@ -0,0 +1,10 @@ +import std::io; + +module log { + +void print_msg([u8] msg) +{ + printf("%s\n", msg); +} + +} diff --git a/lc.c b/lc.c index 10abe3e..16f4bf9 100644 --- a/lc.c +++ b/lc.c @@ -90,6 +90,13 @@ void print_ast(ast_node *node, int depth) { printf("UnaryOp (%s)\n", get_uop_str(node->expr.unary.operator)); print_ast(node->expr.unary.right, depth + 1); break; + case NODE_POSTFIX: + printf("Postfix (%s)\n", get_uop_str(node->expr.unary.operator)); + print_ast(node->expr.unary.right, depth + 1); + break; + case NODE_BREAK: + printf("Break\n"); + break; case NODE_TERNARY: printf("Ternary (? :)\n"); print_indent(depth + 1); printf("Condition:\n"); @@ -125,7 +132,7 @@ void print_ast(ast_node *node, int depth) { case NODE_VAR_DECL: printf("VarDecl (Fields missing in struct)\n"); break; - case NODE_FUNCTION_DEF: + case NODE_FUNCTION: printf("FunctionDef (Fields missing in struct)\n"); break; case NODE_RETURN: diff --git a/lexer.c b/lexer.c index 7891cfd..c90899b 100644 --- a/lexer.c +++ b/lexer.c @@ -400,7 +400,7 @@ lexer *lexer_init(char *source, usize size, arena *arena) trie_insert(keywords, lex->allocator, "if", TOKEN_IF); trie_insert(keywords, lex->allocator, "else", TOKEN_ELSE); trie_insert(keywords, lex->allocator, "switch", TOKEN_SWITCH); - trie_insert(keywords, lex->allocator, "case", TOKEN_CASE); + trie_insert(keywords, lex->allocator, "break", TOKEN_BREAK); trie_insert(keywords, lex->allocator, "do", TOKEN_DO); trie_insert(keywords, lex->allocator, "defer", TOKEN_DEFER); trie_insert(keywords, lex->allocator, "return", TOKEN_RETURN); diff --git a/lexer.h b/lexer.h index f3879f4..34f07ad 100644 --- a/lexer.h +++ b/lexer.h @@ -63,7 +63,7 @@ typedef enum { TOKEN_IF, TOKEN_ELSE, TOKEN_SWITCH, - TOKEN_CASE, + TOKEN_BREAK, TOKEN_DO, TOKEN_DEFER, TOKEN_MODULE, diff --git a/parser.c b/parser.c index 05ecb78..7851d5f 100644 --- a/parser.c +++ b/parser.c @@ -1,6 +1,9 @@ #include "parser.h" #include #include +#include + +bool has_errors = false; ast_node *parse_expression(parser *p); @@ -79,6 +82,7 @@ static void parser_sync(parser *p) static void error(parser *p, char *msg) { printf("\x1b[31m\x1b[1merror\x1b[0m\x1b[1m:%ld:%ld:\x1b[0m %s\n", p->previous->position.row, p->previous->position.column, msg); + has_errors = true; parser_sync(p); } @@ -169,6 +173,7 @@ static ast_node *parse_factor(parser *p) if (p->tokens->next && p->tokens->next->type == TOKEN_LPAREN) { return parse_call(p); } + advance(p); ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); node->type = NODE_IDENTIFIER; @@ -343,23 +348,87 @@ ast_node *parse_expression(parser *p) return node; } + /* + * If after parsing an expression a `++` or a `--` + * token is found, it should be a postfix expression. + */ + if (match(p, TOKEN_PLUS_PLUS) | match(p, TOKEN_MINUS_MINUS)) { + unary_op op; + switch (p->previous->type) { + case TOKEN_PLUS_PLUS: + op = UOP_INCR; + break; + case TOKEN_MINUS_MINUS: + op = UOP_DECR; + break; + default: + break; + } + + ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); + node->type = NODE_POSTFIX; + node->expr.unary.operator = op; + node->expr.unary.right = left; + + return node; + } + return left; } +static ast_node *parse_statement(parser *p) +{ + if (match(p, TOKEN_BREAK)) { + if (!match(p, TOKEN_SEMICOLON)) { + error(p, "expected `;`."); + return NULL; + } + ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); + node->type = NODE_BREAK; + return node; + } else if (match(p, TOKEN_RETURN)) { + ast_node *expr = parse_expression(p); + + if (!expr) { + error(p, "expected expression."); + return NULL; + } + if (!match(p, TOKEN_SEMICOLON)) { + error(p, "expected `;`."); + return NULL; + } + + ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); + node->type = NODE_RETURN; + node->expr.ret.value = expr; + return node; + } else { + ast_node *expr = parse_expression(p); + if (!expr) { + return NULL; + } + if (!match(p, TOKEN_SEMICOLON)) { + error(p, "expected `;`."); + return NULL; + } + return expr; + } +} + /* Get a list of expressions to form a full AST. */ static void parse(parser *p) { p->ast = arena_alloc(p->allocator, sizeof(ast_node)); p->ast->type = NODE_UNIT; - p->ast->expr.unit_node.expr = parse_expression(p); + p->ast->expr.unit_node.expr = parse_statement(p); ast_node *tail = p->ast; - ast_node *expr = parse_expression(p); + ast_node *expr = parse_statement(p); while (expr) { tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node)); tail->expr.unit_node.next->expr.unit_node.expr = expr; tail = tail->expr.unit_node.next; tail->type = NODE_UNIT; - expr = parse_expression(p); + expr = parse_statement(p); } } @@ -371,5 +440,10 @@ parser *parser_init(lexer *l, arena *allocator) parse(p); + if (has_errors) { + printf("Compilation failed.\n"); + exit(1); + } + return p; } diff --git a/parser.h b/parser.h index cecc20c..5ce64db 100644 --- a/parser.h +++ b/parser.h @@ -58,7 +58,7 @@ typedef struct { char *name; usize name_len; member *params; -} function_decl; +} function; typedef enum { NODE_IDENTIFIER, @@ -73,23 +73,21 @@ typedef enum { NODE_ACCESS, NODE_CALL, NODE_POSTFIX, - NODE_GOTO, NODE_BREAK, - NODE_CASE, + NODE_RETURN, NODE_SWITCH, NODE_FOR, NODE_DO, NODE_WHILE, NODE_IF, - NODE_RETURN, NODE_COMPOUND, NODE_ENUM, NODE_STRUCT, NODE_UNION, NODE_VAR_DECL, - NODE_FUNCTION_DEF, - NODE_FUNCTION_DECL, + NODE_FUNCTION, NODE_TERNARY, + NODE_GOTO, NODE_UNIT, } node_type; @@ -142,6 +140,9 @@ typedef struct _ast_node { char *name; usize name_len; } call; + struct { + struct _ast_node *value; + } ret; } expr; } ast_node; diff --git a/test.c b/test.c index 116c235..d8a8536 100644 --- a/test.c +++ b/test.c @@ -1 +1 @@ -x(4, 5) +x[3];