implemented labels and goto parsing

This commit is contained in:
Lorenzo Torres 2025-12-01 21:05:06 +01:00
parent 1be3bf0659
commit 1ca6f024ee
7 changed files with 71 additions and 17 deletions

21
examples/for.l Normal file
View file

@ -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 {
}
}

12
lc.c
View file

@ -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);

View file

@ -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);

View file

@ -57,9 +57,8 @@ typedef enum {
TOKEN_STRING,
TOKEN_CHAR,
TOKEN_WHILE,
TOKEN_FOR,
TOKEN_GOTO,
TOKEN_LOOP,
TOKEN_IF,
TOKEN_ELSE,
TOKEN_SWITCH,

View file

@ -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;

View file

@ -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;

4
test.c
View file

@ -1 +1,3 @@
x[3];
test:
goto test;
return 5;