aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-10-21 15:10:19 -0700
committerMichael Forney <mforney@mforney.org>2021-10-21 17:23:35 -0700
commit8b3c7cbd735d959e8bbe9fd6a382a946d3cbfb63 (patch)
treecc0a183301e328e2fb16eedcc08bdd17ecb490ae
parent5d319bcb003033a2ed9ecf2b58426e1d64455f98 (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.c84
1 files changed, 46 insertions, 38 deletions
diff --git a/stmt.c b/stmt.c
index 3bb09cf..9ae0039 100644
--- a/stmt.c
+++ b/stmt.c
@@ -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]);