From 1ca6f024ee39034759bccdbeeb012f3e70113d98 Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Mon, 1 Dec 2025 21:05:06 +0100 Subject: [PATCH] implemented labels and goto parsing --- examples/for.l | 21 +++++++++++++++++++++ lc.c | 12 ++++++++---- lexer.c | 3 +-- lexer.h | 3 +-- parser.c | 34 +++++++++++++++++++++++++++++----- parser.h | 11 ++++++++--- test.c | 4 +++- 7 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 examples/for.l diff --git a/examples/for.l b/examples/for.l new file mode 100644 index 0000000..68942a8 --- /dev/null +++ b/examples/for.l @@ -0,0 +1,21 @@ +import std::io; + +i32 main() +{ + [u32] list = [1, 2, 3, 4, 5]; + + // iterative loop + loop (0.., list) |i, v| { + printf("%d\n", i); + } + + // conditional loop + loop a == 3 { + + } + + // infinite loop + loop { + + } +} diff --git a/lc.c b/lc.c index 16f4bf9..2daad74 100644 --- a/lc.c +++ b/lc.c @@ -76,6 +76,12 @@ void print_ast(ast_node *node, int depth) { printf("Access: %.*s\n", (int)node->expr.access.member_len, node->expr.access.member); print_ast(node->expr.access.expr, depth + 1); break; + case NODE_LABEL: + printf("Label: %.*s\n", (int)node->expr.label.name_len, node->expr.label.name); + break; + case NODE_GOTO: + printf("Goto: %.*s\n", (int)node->expr.label.name_len, node->expr.label.name); + break; case NODE_BINARY: printf("BinaryOp (%s)\n", get_op_str(node->expr.binary.operator)); print_ast(node->expr.binary.left, depth + 1); @@ -126,9 +132,6 @@ void print_ast(ast_node *node, int depth) { case NODE_IF: printf("IfStmt (Fields missing in struct)\n"); break; - case NODE_WHILE: - printf("WhileStmt (Fields missing in struct)\n"); - break; case NODE_VAR_DECL: printf("VarDecl (Fields missing in struct)\n"); break; @@ -136,7 +139,8 @@ void print_ast(ast_node *node, int depth) { printf("FunctionDef (Fields missing in struct)\n"); break; case NODE_RETURN: - printf("Return (Fields missing in struct)\n"); + printf("Return:\n"); + print_ast(node->expr.ret.value, depth + 1); break; default: printf("Unknown Node Type: %d\n", node->type); diff --git a/lexer.c b/lexer.c index c90899b..de0d099 100644 --- a/lexer.c +++ b/lexer.c @@ -394,8 +394,7 @@ lexer *lexer_init(char *source, usize size, arena *arena) trie_insert(keywords, lex->allocator, "struct", TOKEN_STRUCT); trie_insert(keywords, lex->allocator, "enum", TOKEN_ENUM); trie_insert(keywords, lex->allocator, "union", TOKEN_UNION); - trie_insert(keywords, lex->allocator, "while", TOKEN_WHILE); - trie_insert(keywords, lex->allocator, "for", TOKEN_FOR); + trie_insert(keywords, lex->allocator, "loop", TOKEN_LOOP); trie_insert(keywords, lex->allocator, "goto", TOKEN_GOTO); trie_insert(keywords, lex->allocator, "if", TOKEN_IF); trie_insert(keywords, lex->allocator, "else", TOKEN_ELSE); diff --git a/lexer.h b/lexer.h index 34f07ad..b9b67ac 100644 --- a/lexer.h +++ b/lexer.h @@ -57,9 +57,8 @@ typedef enum { TOKEN_STRING, TOKEN_CHAR, - TOKEN_WHILE, - TOKEN_FOR, TOKEN_GOTO, + TOKEN_LOOP, TOKEN_IF, TOKEN_ELSE, TOKEN_SWITCH, diff --git a/parser.c b/parser.c index 7851d5f..9b0dec5 100644 --- a/parser.c +++ b/parser.c @@ -66,8 +66,7 @@ static void parser_sync(parser *p) case TOKEN_STRUCT: case TOKEN_ENUM: case TOKEN_IF: - case TOKEN_WHILE: - case TOKEN_FOR: + case TOKEN_LOOP: case TOKEN_DO: case TOKEN_RETURN: case TOKEN_SWITCH: @@ -380,7 +379,7 @@ static ast_node *parse_statement(parser *p) { if (match(p, TOKEN_BREAK)) { if (!match(p, TOKEN_SEMICOLON)) { - error(p, "expected `;`."); + error(p, "expected `;` after `break`."); return NULL; } ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); @@ -390,7 +389,7 @@ static ast_node *parse_statement(parser *p) ast_node *expr = parse_expression(p); if (!expr) { - error(p, "expected expression."); + error(p, "expected expression after `return`."); return NULL; } if (!match(p, TOKEN_SEMICOLON)) { @@ -402,13 +401,38 @@ static ast_node *parse_statement(parser *p) node->type = NODE_RETURN; node->expr.ret.value = expr; return node; + } else if (match_peek(p, TOKEN_IDENTIFIER) && p->tokens->next && p->tokens->next->type == TOKEN_COLON) { + /* In this case, this is a label. */ + ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); + node->type = NODE_LABEL; + node->expr.label.name = p->tokens->lexeme; + node->expr.label.name_len = p->tokens->lexeme_len; + advance(p); + /* Consume `:` */ + advance(p); + return node; + } else if (match(p, TOKEN_GOTO)) { + if (!match_peek(p, TOKEN_IDENTIFIER)) { + error(p, "expected label identifier after `goto`."); + return NULL; + } + ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); + node->type = NODE_GOTO; + node->expr.label.name = p->tokens->lexeme; + node->expr.label.name_len = p->tokens->lexeme_len; + advance(p); + if (!match(p, TOKEN_SEMICOLON)) { + error(p, "expected `;` after `goto`."); + return NULL; + } + return node; } else { ast_node *expr = parse_expression(p); if (!expr) { return NULL; } if (!match(p, TOKEN_SEMICOLON)) { - error(p, "expected `;`."); + error(p, "expected `;` after expression."); return NULL; } return expr; diff --git a/parser.h b/parser.h index 5ce64db..665b305 100644 --- a/parser.h +++ b/parser.h @@ -75,9 +75,10 @@ typedef enum { NODE_POSTFIX, NODE_BREAK, NODE_RETURN, - NODE_SWITCH, - NODE_FOR, + NODE_LABEL, + NODE_GOTO, NODE_DO, + NODE_FOR, NODE_WHILE, NODE_IF, NODE_COMPOUND, @@ -87,13 +88,17 @@ typedef enum { NODE_VAR_DECL, NODE_FUNCTION, NODE_TERNARY, - NODE_GOTO, + NODE_SWITCH, NODE_UNIT, } node_type; typedef struct _ast_node { node_type type; union { + struct { + char *name; + usize name_len; + } label; // both label and goto struct { struct _ast_node *left; struct _ast_node *right; diff --git a/test.c b/test.c index d8a8536..8893ebc 100644 --- a/test.c +++ b/test.c @@ -1 +1,3 @@ -x[3]; +test: +goto test; +return 5;