Skip to content

Commit e6572d1

Browse files
committed
Implement C2y labeled(named) loop/switch
1 parent 24d24ac commit e6572d1

File tree

2 files changed

+117
-68
lines changed

2 files changed

+117
-68
lines changed

parse.c

Lines changed: 85 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ typedef struct {
9999
bool is_volatile;
100100
} EvalContext;
101101

102+
typedef struct JumpContext JumpContext;
103+
struct JumpContext {
104+
JumpContext *next;
105+
char *brk_label;
106+
char *cont_label;
107+
DeferStmt *defr_end;
108+
Token *labels;
109+
Node *switch_node;
110+
};
111+
112+
static JumpContext *jump_ctx;
113+
102114
// Likewise, global variables are accumulated to this list.
103115
static Obj *globals;
104116

@@ -111,17 +123,8 @@ static Obj *current_fn;
111123
static Node *gotos;
112124
static Node *labels;
113125

114-
// Current "goto" and "continue" jump targets.
115-
static char *brk_label;
116-
static char *cont_label;
117-
118-
// Points to a node representing a switch if we are parsing
119-
// a switch statement. Otherwise, NULL.
120-
static Node *current_switch;
121-
122126
static DeferStmt *current_defr;
123-
static DeferStmt *brk_defr;
124-
static DeferStmt *cont_defr;
127+
125128
static bool fn_use_vla;
126129
static bool dont_dealloc_vla;
127130
static bool is_global_init_context;
@@ -143,7 +146,7 @@ static Node *lvar_initializer(Token **rest, Token *tok, Obj *var);
143146
static void gvar_initializer(Token **rest, Token *tok, Obj *var);
144147
static void constexpr_initializer(Token **rest, Token *tok, Obj *init_var, Obj *var);
145148
static Node *compound_stmt(Token **rest, Token *tok, NodeKind kind);
146-
static Node *stmt(Token **rest, Token *tok);
149+
static Node *stmt(Token **rest, Token *tok, Token *label_list);
147150
static Node *expr_stmt(Token **rest, Token *tok);
148151
static Node *expr(Token **rest, Token *tok);
149152
static int64_t eval(Node *node);
@@ -2336,9 +2339,13 @@ static Node *asm_stmt(Token **rest, Token *tok) {
23362339
return node;
23372340
}
23382341

2339-
static void label_stmt(Node **cur, Token **rest, Token *tok) {
2342+
static Token *label_stmt(Node **cur, Token **rest, Token *tok) {
2343+
Token *label_list = NULL;
2344+
Node *active_switch = NULL;
23402345
for (;;) {
23412346
if (tok->kind == TK_IDENT && equal(tok->next, ":")) {
2347+
if (!label_list)
2348+
label_list = tok;
23422349
Node *node = new_node(ND_LABEL, tok);
23432350
node->label = strndup(tok->loc, tok->len);
23442351
node->unique_label = new_unique_name();
@@ -2350,17 +2357,26 @@ static void label_stmt(Node **cur, Token **rest, Token *tok) {
23502357
}
23512358

23522359
if (equal(tok, "case") || equal(tok, "default")) {
2353-
if (!current_switch)
2354-
error_tok(tok, "stray case");
2355-
if (current_defr != brk_defr)
2356-
error_tok(tok, "illegal jump");
2360+
label_list = NULL;
2361+
2362+
if (!active_switch) {
2363+
JumpContext *ctx = jump_ctx;
2364+
for (; ctx; ctx = ctx->next)
2365+
if (ctx->switch_node)
2366+
break;
2367+
if (!ctx)
2368+
error_tok(tok, "stray case");
2369+
if (jump_ctx->defr_end != current_defr)
2370+
error_tok(tok, "illegal jump");
2371+
active_switch = ctx->switch_node;
2372+
}
23572373

23582374
Node *node = new_node(ND_CASE, tok);
23592375
node->label = new_unique_name();
23602376

23612377
if (equal(tok, "default")) {
23622378
tok = skip(tok->next, ":");
2363-
current_switch->default_case = node;
2379+
active_switch->default_case = node;
23642380
(*cur) = (*cur)->next = node;
23652381
continue;
23662382
}
@@ -2374,7 +2390,7 @@ static void label_stmt(Node **cur, Token **rest, Token *tok) {
23742390
else
23752391
end = begin;
23762392

2377-
Type *cond_ty = current_switch->cond->ty;
2393+
Type *cond_ty = active_switch->cond->ty;
23782394
if (cond_ty->size <= 4) {
23792395
if (!cond_ty->is_unsigned)
23802396
begin = (int32_t)begin, end = (int32_t)end;
@@ -2388,14 +2404,14 @@ static void label_stmt(Node **cur, Token **rest, Token *tok) {
23882404
tok = skip(tok, ":");
23892405
node->begin = begin;
23902406
node->end = end;
2391-
node->case_next = current_switch->case_next;
2392-
current_switch->case_next = node;
2407+
node->case_next = active_switch->case_next;
2408+
active_switch->case_next = node;
23932409
(*cur) = (*cur)->next = node;
23942410
continue;
23952411
}
23962412

23972413
*rest = tok;
2398-
return;
2414+
return label_list;
23992415
}
24002416
}
24012417

@@ -2406,27 +2422,43 @@ static Node *secondary_block(Token **rest, Token *tok) {
24062422
DeferStmt *dfr = new_block_scope();
24072423
Node head = {0};
24082424
Node *cur = &head;
2409-
label_stmt(&cur, &tok, tok);
2410-
cur->next = stmt(rest, tok);
2425+
Token *label_list = label_stmt(&cur, &tok, tok);
2426+
cur->next = stmt(rest, tok, label_list);
24112427
return leave_block_scope(dfr, head.next);
24122428
}
24132429

2414-
static void loop_body(Token **rest, Token *tok, Node *node) {
2415-
char *brk = brk_label;
2416-
char *cont = cont_label;
2417-
brk_label = node->brk_label = new_unique_name();
2418-
cont_label = node->cont_label = new_unique_name();
2430+
static void loop_body(Token **rest, Token *tok, Node *node, Token *label_list) {
2431+
JumpContext ctx = {.next = jump_ctx};
2432+
jump_ctx = &ctx;
24192433

2420-
DeferStmt *brkdefr = brk_defr;
2421-
DeferStmt *contdefr = cont_defr;
2422-
brk_defr = cont_defr = current_defr;
2434+
ctx.labels = label_list;
2435+
ctx.brk_label = node->brk_label = new_unique_name();
2436+
ctx.cont_label = node->cont_label = new_unique_name();
2437+
ctx.defr_end = current_defr;
24232438

24242439
node->then = secondary_block(rest, tok);
24252440

2426-
brk_label = brk;
2427-
cont_label = cont;
2428-
brk_defr = brkdefr;
2429-
cont_defr = contdefr;
2441+
jump_ctx = ctx.next;
2442+
}
2443+
2444+
static JumpContext *resolve_labeled_jump(Token **rest, Token *tok, bool is_cont) {
2445+
Token *name = NULL;
2446+
if (tok->next->kind == TK_IDENT)
2447+
name = tok = tok->next;
2448+
*rest = skip(tok->next, ";");
2449+
2450+
for (JumpContext *ctx = jump_ctx; ctx; ctx = ctx->next) {
2451+
if (is_cont && ctx->switch_node)
2452+
continue;
2453+
if (!name)
2454+
return ctx;
2455+
for (Token *t = ctx->labels; t && t->kind == TK_IDENT && equal(t->next, ":");) {
2456+
if (name->len == t->len && !memcmp(name->loc, t->loc, t->len))
2457+
return ctx;
2458+
t = t->next->next;
2459+
}
2460+
}
2461+
error_tok(tok, "cannot resolve jump");
24302462
}
24312463

24322464
// stmt = "return" expr? ";"
@@ -2444,7 +2476,7 @@ static void loop_body(Token **rest, Token *tok, Node *node) {
24442476
// | ident ":" stmt
24452477
// | "{" compound-stmt
24462478
// | expr-stmt
2447-
static Node *stmt(Token **rest, Token *tok) {
2479+
static Node *stmt(Token **rest, Token *tok, Token *label_list) {
24482480
if (equal(tok, "return")) {
24492481
Node *node = new_node(ND_RETURN, tok);
24502482
node->defr_start = current_defr;
@@ -2485,21 +2517,16 @@ static Node *stmt(Token **rest, Token *tok) {
24852517
if (!is_integer(node->cond->ty))
24862518
error_tok(tok, "controlling expression not integer");
24872519

2488-
Node *sw = current_switch;
2489-
current_switch = node;
2490-
2491-
char *brk = brk_label;
2492-
brk_label = node->brk_label = new_unique_name();
2520+
JumpContext ctx = {.next = jump_ctx, .switch_node = node};
2521+
jump_ctx = &ctx;
24932522

2494-
DeferStmt *defr = brk_defr;
2495-
brk_defr = current_defr;
2523+
ctx.labels = label_list;
2524+
ctx.brk_label = node->brk_label = new_unique_name();
2525+
ctx.defr_end = current_defr;
24962526

24972527
node->then = secondary_block(rest, tok);
24982528

2499-
current_switch = sw;
2500-
brk_label = brk;
2501-
brk_defr = defr;
2502-
2529+
jump_ctx = ctx.next;
25032530
return leave_block_scope(dfr, node);
25042531
}
25052532

@@ -2531,7 +2558,7 @@ static Node *stmt(Token **rest, Token *tok) {
25312558
node->inc = expr(&tok, tok);
25322559
tok = skip(tok, ")");
25332560

2534-
loop_body(rest, tok, node);
2561+
loop_body(rest, tok, node, label_list);
25352562

25362563
return leave_block_scope(dfr, node);
25372564
}
@@ -2544,15 +2571,15 @@ static Node *stmt(Token **rest, Token *tok) {
25442571
node->cond = to_bool(cond_declaration(&tok, skip(tok->next, "("), ")", 1));
25452572
node->defr_start = current_defr;
25462573

2547-
loop_body(rest, tok, node);
2574+
loop_body(rest, tok, node, label_list);
25482575

25492576
return leave_block_scope(dfr, node);
25502577
}
25512578

25522579
if (equal(tok, "do")) {
25532580
Node *node = new_node(ND_DO, tok);
25542581

2555-
loop_body(&tok, tok->next, node);
2582+
loop_body(&tok, tok->next, node, label_list);
25562583

25572584
tok = skip(tok, "while");
25582585
tok = skip(tok, "(");
@@ -2591,25 +2618,15 @@ static Node *stmt(Token **rest, Token *tok) {
25912618
return node;
25922619
}
25932620

2594-
if (equal(tok, "break")) {
2595-
if (!brk_label)
2596-
error_tok(tok, "stray break");
2621+
if (equal(tok, "break") || equal(tok, "continue")) {
25972622
Node *node = new_node(ND_GOTO, tok);
2598-
node->unique_label = brk_label;
2599-
node->defr_end = brk_defr;
2600-
node->defr_start = current_defr;
2601-
*rest = skip(tok->next, ";");
2602-
return node;
2603-
}
26042623

2605-
if (equal(tok, "continue")) {
2606-
if (!cont_label)
2607-
error_tok(tok, "stray continue");
2608-
Node *node = new_node(ND_GOTO, tok);
2609-
node->unique_label = cont_label;
2610-
node->defr_end = cont_defr;
2624+
bool is_cont = equal(tok, "continue");
2625+
JumpContext *ctx = resolve_labeled_jump(rest, tok, is_cont);
2626+
2627+
node->unique_label = is_cont ? ctx->cont_label : ctx->brk_label;
2628+
node->defr_end = ctx->defr_end;
26112629
node->defr_start = current_defr;
2612-
*rest = skip(tok->next, ";");
26132630
return node;
26142631
}
26152632

@@ -2636,7 +2653,7 @@ static Node *compound_stmt(Token **rest, Token *tok, NodeKind kind) {
26362653
Node *cur = &head;
26372654

26382655
for (;;) {
2639-
label_stmt(&cur, &tok, tok);
2656+
Token *label_list = label_stmt(&cur, &tok, tok);
26402657

26412658
if (equal(tok, "}"))
26422659
break;
@@ -2647,7 +2664,7 @@ static Node *compound_stmt(Token **rest, Token *tok, NodeKind kind) {
26472664
}
26482665

26492666
if (!is_typename(tok)) {
2650-
cur = cur->next = stmt(&tok, tok);
2667+
cur = cur->next = stmt(&tok, tok, label_list);
26512668
add_type(cur);
26522669
continue;
26532670
}

test/labeled_loop_sw.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "test.h"
2+
3+
int fn(int i) {
4+
F:
5+
for (;; i += 1) {
6+
S1:
7+
S2:
8+
switch (i)
9+
F1:
10+
case 11:
11+
F2:
12+
for (;; i += 7) {
13+
switch (i)
14+
case 10:
15+
continue F;
16+
break S2;
17+
case 3:
18+
continue F2;
19+
default:
20+
break F;
21+
case 0:
22+
break S1;
23+
}
24+
i += 2;
25+
}
26+
return i;
27+
}
28+
29+
int main(void) {
30+
ASSERT(14, fn(0));
31+
printf("OK\n");
32+
}

0 commit comments

Comments
 (0)