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); printf("Access: %.*s\n", (int)node->expr.access.member_len, node->expr.access.member);
print_ast(node->expr.access.expr, depth + 1); print_ast(node->expr.access.expr, depth + 1);
break; 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: case NODE_BINARY:
printf("BinaryOp (%s)\n", get_op_str(node->expr.binary.operator)); printf("BinaryOp (%s)\n", get_op_str(node->expr.binary.operator));
print_ast(node->expr.binary.left, depth + 1); print_ast(node->expr.binary.left, depth + 1);
@ -126,9 +132,6 @@ void print_ast(ast_node *node, int depth) {
case NODE_IF: case NODE_IF:
printf("IfStmt (Fields missing in struct)\n"); printf("IfStmt (Fields missing in struct)\n");
break; break;
case NODE_WHILE:
printf("WhileStmt (Fields missing in struct)\n");
break;
case NODE_VAR_DECL: case NODE_VAR_DECL:
printf("VarDecl (Fields missing in struct)\n"); printf("VarDecl (Fields missing in struct)\n");
break; break;
@ -136,7 +139,8 @@ void print_ast(ast_node *node, int depth) {
printf("FunctionDef (Fields missing in struct)\n"); printf("FunctionDef (Fields missing in struct)\n");
break; break;
case NODE_RETURN: case NODE_RETURN:
printf("Return (Fields missing in struct)\n"); printf("Return:\n");
print_ast(node->expr.ret.value, depth + 1);
break; break;
default: default:
printf("Unknown Node Type: %d\n", node->type); 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, "struct", TOKEN_STRUCT);
trie_insert(keywords, lex->allocator, "enum", TOKEN_ENUM); trie_insert(keywords, lex->allocator, "enum", TOKEN_ENUM);
trie_insert(keywords, lex->allocator, "union", TOKEN_UNION); trie_insert(keywords, lex->allocator, "union", TOKEN_UNION);
trie_insert(keywords, lex->allocator, "while", TOKEN_WHILE); trie_insert(keywords, lex->allocator, "loop", TOKEN_LOOP);
trie_insert(keywords, lex->allocator, "for", TOKEN_FOR);
trie_insert(keywords, lex->allocator, "goto", TOKEN_GOTO); trie_insert(keywords, lex->allocator, "goto", TOKEN_GOTO);
trie_insert(keywords, lex->allocator, "if", TOKEN_IF); trie_insert(keywords, lex->allocator, "if", TOKEN_IF);
trie_insert(keywords, lex->allocator, "else", TOKEN_ELSE); trie_insert(keywords, lex->allocator, "else", TOKEN_ELSE);

View file

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

View file

@ -66,8 +66,7 @@ static void parser_sync(parser *p)
case TOKEN_STRUCT: case TOKEN_STRUCT:
case TOKEN_ENUM: case TOKEN_ENUM:
case TOKEN_IF: case TOKEN_IF:
case TOKEN_WHILE: case TOKEN_LOOP:
case TOKEN_FOR:
case TOKEN_DO: case TOKEN_DO:
case TOKEN_RETURN: case TOKEN_RETURN:
case TOKEN_SWITCH: case TOKEN_SWITCH:
@ -380,7 +379,7 @@ static ast_node *parse_statement(parser *p)
{ {
if (match(p, TOKEN_BREAK)) { if (match(p, TOKEN_BREAK)) {
if (!match(p, TOKEN_SEMICOLON)) { if (!match(p, TOKEN_SEMICOLON)) {
error(p, "expected `;`."); error(p, "expected `;` after `break`.");
return NULL; return NULL;
} }
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); 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); ast_node *expr = parse_expression(p);
if (!expr) { if (!expr) {
error(p, "expected expression."); error(p, "expected expression after `return`.");
return NULL; return NULL;
} }
if (!match(p, TOKEN_SEMICOLON)) { if (!match(p, TOKEN_SEMICOLON)) {
@ -402,13 +401,38 @@ static ast_node *parse_statement(parser *p)
node->type = NODE_RETURN; node->type = NODE_RETURN;
node->expr.ret.value = expr; node->expr.ret.value = expr;
return node; 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 { } else {
ast_node *expr = parse_expression(p); ast_node *expr = parse_expression(p);
if (!expr) { if (!expr) {
return NULL; return NULL;
} }
if (!match(p, TOKEN_SEMICOLON)) { if (!match(p, TOKEN_SEMICOLON)) {
error(p, "expected `;`."); error(p, "expected `;` after expression.");
return NULL; return NULL;
} }
return expr; return expr;

View file

@ -75,9 +75,10 @@ typedef enum {
NODE_POSTFIX, NODE_POSTFIX,
NODE_BREAK, NODE_BREAK,
NODE_RETURN, NODE_RETURN,
NODE_SWITCH, NODE_LABEL,
NODE_FOR, NODE_GOTO,
NODE_DO, NODE_DO,
NODE_FOR,
NODE_WHILE, NODE_WHILE,
NODE_IF, NODE_IF,
NODE_COMPOUND, NODE_COMPOUND,
@ -87,13 +88,17 @@ typedef enum {
NODE_VAR_DECL, NODE_VAR_DECL,
NODE_FUNCTION, NODE_FUNCTION,
NODE_TERNARY, NODE_TERNARY,
NODE_GOTO, NODE_SWITCH,
NODE_UNIT, NODE_UNIT,
} node_type; } node_type;
typedef struct _ast_node { typedef struct _ast_node {
node_type type; node_type type;
union { union {
struct {
char *name;
usize name_len;
} label; // both label and goto
struct { struct {
struct _ast_node *left; struct _ast_node *left;
struct _ast_node *right; struct _ast_node *right;

4
test.c
View file

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