aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.h2
-rw-r--r--src/codegen.c13
-rw-r--r--src/parse.c18
3 files changed, 33 insertions, 0 deletions
diff --git a/src/ast.h b/src/ast.h
index c5171d7..4ca2e1b 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -106,10 +106,12 @@ typedef enum {
AstNodeKind_func_call,
AstNodeKind_func_decl,
AstNodeKind_func_def,
+ AstNodeKind_goto_stmt,
AstNodeKind_gvar,
AstNodeKind_gvar_decl,
AstNodeKind_if_stmt,
AstNodeKind_int_expr,
+ AstNodeKind_label_stmt,
AstNodeKind_list,
AstNodeKind_logical_expr,
AstNodeKind_lvar,
diff --git a/src/codegen.c b/src/codegen.c
index f02a38c..4387449 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -578,6 +578,15 @@ static void codegen_continue_stmt(CodeGen* g, AstNode* ast) {
fprintf(g->out, " jmp .Lcontinue%d\n", label);
}
+static void codegen_goto_stmt(CodeGen* g, AstNode* ast) {
+ fprintf(g->out, " jmp .L%s__%s\n", g->current_func->name, ast->name);
+}
+
+static void codegen_label_stmt(CodeGen* g, AstNode* ast) {
+ fprintf(g->out, ".L%s__%s:\n", g->current_func->name, ast->name);
+ codegen_stmt(g, ast->node_body);
+}
+
// Helper to collect case values from the switch body
static void collect_cases(AstNode* stmt, int* case_values, int* case_labels, int* n_cases) {
if (!stmt)
@@ -694,6 +703,10 @@ static void codegen_stmt(CodeGen* g, AstNode* ast) {
codegen_break_stmt(g, ast);
} else if (ast->kind == AstNodeKind_continue_stmt) {
codegen_continue_stmt(g, ast);
+ } else if (ast->kind == AstNodeKind_goto_stmt) {
+ codegen_goto_stmt(g, ast);
+ } else if (ast->kind == AstNodeKind_label_stmt) {
+ codegen_label_stmt(g, ast);
} else if (ast->kind == AstNodeKind_expr_stmt) {
codegen_expr_stmt(g, ast);
} else if (ast->kind == AstNodeKind_lvar_decl) {
diff --git a/src/parse.c b/src/parse.c
index b82c45d..1ad11bd 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1331,12 +1331,30 @@ static AstNode* parse_stmt(Parser* p) {
return parse_break_stmt(p);
} else if (t->kind == TokenKind_keyword_continue) {
return parse_continue_stmt(p);
+ } else if (t->kind == TokenKind_keyword_goto) {
+ expect(p, TokenKind_keyword_goto);
+ Token* label_token = expect(p, TokenKind_ident);
+ expect(p, TokenKind_semicolon);
+
+ AstNode* goto_stmt = ast_new(AstNodeKind_goto_stmt);
+ goto_stmt->name = label_token->value.string;
+ return goto_stmt;
} else if (t->kind == TokenKind_brace_l) {
return parse_block_stmt(p);
} else if (t->kind == TokenKind_semicolon) {
return parse_empty_stmt(p);
} else if (is_type_token(p, t)) {
return parse_var_decl(p);
+ } else if (t->kind == TokenKind_ident && peek_token2(p)->kind == TokenKind_colon) {
+ // Label statement
+ Token* label_token = expect(p, TokenKind_ident);
+ expect(p, TokenKind_colon);
+ AstNode* stmt = parse_stmt(p);
+
+ AstNode* label_stmt = ast_new(AstNodeKind_label_stmt);
+ label_stmt->name = label_token->value.string;
+ label_stmt->node_body = stmt;
+ return label_stmt;
} else {
return parse_expr_stmt(p);
}