aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-08 08:48:21 +0200
committerlemon <lsof@mailbox.org>2022-08-08 08:50:18 +0200
commit215c18ebc86b116827d3af19ca0779316e1a0e15 (patch)
tree472683c87148646856b73c0af09e64768aa550af /bootstrap/parse.c
parent8e94bb58ca91b26c0916210a179157b1280489be (diff)
break & continue
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c71
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);
}
}