diff options
| author | 2022-08-08 08:48:21 +0200 | |
|---|---|---|
| committer | 2022-08-08 08:50:18 +0200 | |
| commit | 215c18ebc86b116827d3af19ca0779316e1a0e15 (patch) | |
| tree | 472683c87148646856b73c0af09e64768aa550af /bootstrap/parse.c | |
| parent | 8e94bb58ca91b26c0916210a179157b1280489be (diff) | |
break & continue
Diffstat (limited to 'bootstrap/parse.c')
| -rw-r--r-- | bootstrap/parse.c | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 02980cc..631d007 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -373,6 +373,9 @@ lex(struct parser *P) { tok.t = '#len'; } else if (!strcmp(s, "#?")) { tok.t = '#?'; + } else if (!strncmp(s, "#:", 2)) { + tok.t = TKlabel; + tok.str = xstrdup(s); } else { fatal(P, P->tokspan, "invalid #keyword"); } @@ -1860,7 +1863,7 @@ pstforletyield(struct stmt *st, void *arg) { } static struct stmt -pstfor(struct parser *P) { +pstfor(struct parser *P, const char *label) { struct stmt st = {Sfor}; struct tok tok; @@ -1895,7 +1898,16 @@ pstfor(struct parser *P) { st.loop.next = exprdup(parseexpr(P)); lexexpect(P, '{'); } - st.loop.body = parseblock(P).block; + st.loop.id = P->loopid++; + struct env env = {P->curenv}; + if (label) { + pushenv(P, &env); + putdecl(P, tok.span, &(struct decl) { Dlabel, label, .loopid = st.loop.id }); + } + WITH_TMPCHANGE(int, P->curloop, st.loop.id) + st.loop.body = parseblock(P).block; + if (label) + popenv(P); return st; } @@ -2158,6 +2170,7 @@ static void parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) { struct stmt st = {0}; struct tok tok; + const char *label = NULL; if (lexmatch(P, &tok, '{')) { st.span = tok.span; @@ -2168,7 +2181,16 @@ parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) { } else if (lexmatch(P, &tok, TKkw_if)) { st.span = tok.span; st = pstifelse(P); + } else if (lexmatch(P, &tok, TKlabel)) { + label = tok.str; + if (lexmatch(P, &tok, TKkw_while)) + goto whilel; + else if (lexmatch(P, &tok, TKkw_for)) + goto forl; + else + fatal(P, tok.span, "cannot use label for this statement"); } else if (lexmatch(P, &tok, TKkw_while)) { + whilel: st.t = Swhile; st.span = tok.span; st.loop.test = parseexpr(P); @@ -2177,10 +2199,20 @@ parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) { "while statement condition must be bool or pointer (%t)", st.loop.test.ty); lexexpect(P, '{'); - st.loop.body = parseblock(P).block; + st.loop.id = P->loopid++; + struct env env = { P->curenv }; + if (label) { + pushenv(P, &env); + putdecl(P, tok.span, &(struct decl) { Dlabel, label, .loopid = st.loop.id }); + } + WITH_TMPCHANGE(int, P->curloop, st.loop.id) + st.loop.body = parseblock(P).block; + if (label) + popenv(P); } else if (lexmatch(P, &tok, TKkw_for)) { + forl: st.span = tok.span; - st = pstfor(P); + st = pstfor(P, label); } else if (lexmatch(P, &tok, TKkw_switch)) { st = pstswitch(P); st.span = tok.span; @@ -2201,6 +2233,32 @@ parsestmt(stmt_yielder_t yield, void *yarg, struct parser *P) { fatal(P, tok.span, "return statement in non-void function must return a value"); } + } else if (lexmatch(P, &tok, TKkw_break)) { + if (P->curloop < 0) + fatal(P, tok.span, "break outside loop"); + st.t = Sbreak; + st.brkcon.id = P->curloop; + if (lexmatch(P, &tok, TKlabel)) { + const struct decl *decl = finddecl(P, tok.str); + if (!decl) + fatal(P, tok.span, "no such label %T", tok); + assert(decl->t == Dlabel); + st.brkcon.id = decl->loopid; + } + lexexpect(P, ';'); + } else if (lexmatch(P, &tok, TKkw_continue)) { + if (P->curloop < 0) + fatal(P, tok.span, "continue outside loop"); + st.t = Scontinue; + st.brkcon.id = P->curloop; + if (lexmatch(P, &tok, TKlabel)) { + const struct decl *decl = finddecl(P, tok.str); + if (!decl) + fatal(P, tok.span, "no such label %T", tok); + assert(decl->t == Dlabel); + st.brkcon.id = decl->loopid; + } + lexexpect(P, ';'); } else if (isdecltokt((tok = lexpeek(P)).t)) { st.t = Sdecl; st.span = tok.span; @@ -2327,8 +2385,9 @@ parsefn(struct decl *decl, struct parser *P) { putdecl(P, tok.span, &decl); } fn->body = xcalloc(1, sizeof *fn->body); - WITH_TMPCHANGE(int, P->varid, 0) - *fn->body = parseblock(P); + WITH_TMPCHANGE(int, P->curloop, -1) WITH_TMPCHANGE(int, P->loopid, 0) + WITH_TMPCHANGE(int, P->varid, 0) + *fn->body = parseblock(P); popenv(P); } } |