diff options
author | Michael Forney <mforney@mforney.org> | 2021-10-21 15:10:19 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2021-10-21 17:23:35 -0700 |
commit | 8b3c7cbd735d959e8bbe9fd6a382a946d3cbfb63 (patch) | |
tree | cc0a183301e328e2fb16eedcc08bdd17ecb490ae | |
parent | 5d319bcb003033a2ed9ecf2b58426e1d64455f98 (diff) |
stmt: Allow labels intermixed with declarations in compound statements
C23 relaxes the restriction that labels must always be followed by
statements in N2508[0].
[0] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf
-rw-r--r-- | stmt.c | 84 |
1 files changed, 46 insertions, 38 deletions
@@ -7,49 +7,25 @@ #include "util.h" #include "cc.h" +/* 6.8.1 Labeled statements */ static bool -gotolabel(struct func *f) +label(struct func *f, struct scope *s) { char *name; struct gotolabel *g; - - if (tok.kind != TIDENT) - return false; - name = tok.lit; - if (!peek(TCOLON)) - return false; - g = funcgoto(f, name); - g->defined = true; - funclabel(f, g->label); - return true; -} - -/* 6.8 Statements and blocks */ -void -stmt(struct func *f, struct scope *s) -{ - char *name; - struct expr *e; - struct type *t; - struct value *v; - struct block *b[4]; - struct switchcases swtch; + struct block *b; uint64_t i; - while (gotolabel(f)) - ; switch (tok.kind) { - /* 6.8.1 Labeled statements */ case TCASE: next(); if (!s->switchcases) error(&tok.loc, "'case' label must be in switch"); - b[0] = mkblock("switch_case"); - funclabel(f, b[0]); + b = mkblock("switch_case"); + funclabel(f, b); i = intconstexpr(s, true); - switchcase(s->switchcases, i, b[0]); + switchcase(s->switchcases, i, b); expect(TCOLON, "after case expression"); - stmt(f, s); break; case TDEFAULT: next(); @@ -60,15 +36,47 @@ stmt(struct func *f, struct scope *s) expect(TCOLON, "after 'default'"); s->switchcases->defaultlabel = mkblock("switch_default"); funclabel(f, s->switchcases->defaultlabel); - stmt(f, s); break; + case TIDENT: + name = tok.lit; + if (!peek(TCOLON)) + return false; + g = funcgoto(f, name); + g->defined = true; + funclabel(f, g->label); + break; + default: + return false; + } + return true; +} + +static void +labelstmt(struct func *f, struct scope *s) +{ + while (label(f, s)) + ; + stmt(f, s); +} + +/* 6.8 Statements and blocks */ +void +stmt(struct func *f, struct scope *s) +{ + char *name; + struct expr *e; + struct type *t; + struct value *v; + struct block *b[4]; + struct switchcases swtch; + switch (tok.kind) { /* 6.8.2 Compound statement */ case TLBRACE: next(); s = mkscope(s); while (tok.kind != TRBRACE) { - if (gotolabel(f) || !decl(s, f)) + if (!label(f, s) && !decl(s, f)) stmt(f, s); } s = delscope(s); @@ -105,7 +113,7 @@ stmt(struct func *f, struct scope *s) funclabel(f, b[0]); s = mkscope(s); - stmt(f, s); + labelstmt(f, s); s = delscope(s); if (consume(TELSE)) { @@ -113,7 +121,7 @@ stmt(struct func *f, struct scope *s) funcjmp(f, b[2]); funclabel(f, b[1]); s = mkscope(s); - stmt(f, s); + labelstmt(f, s); s = delscope(s); funclabel(f, b[2]); } else { @@ -145,7 +153,7 @@ stmt(struct func *f, struct scope *s) s = mkscope(s); s->breaklabel = b[1]; s->switchcases = &swtch; - stmt(f, s); + labelstmt(f, s); funcjmp(f, b[1]); funclabel(f, b[0]); @@ -178,7 +186,7 @@ stmt(struct func *f, struct scope *s) s = mkscope(s); s->continuelabel = b[0]; s->breaklabel = b[2]; - stmt(f, s); + labelstmt(f, s); s = delscope(s); funcjmp(f, b[0]); funclabel(f, b[2]); @@ -196,7 +204,7 @@ stmt(struct func *f, struct scope *s) s->continuelabel = b[1]; s->breaklabel = b[2]; funclabel(f, b[0]); - stmt(f, s); + labelstmt(f, s); s = delscope(s); expect(TWHILE, "after 'do' statement"); @@ -250,7 +258,7 @@ stmt(struct func *f, struct scope *s) s = mkscope(s); s->breaklabel = b[3]; s->continuelabel = b[2]; - stmt(f, s); + labelstmt(f, s); s = delscope(s); funclabel(f, b[2]); |