scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 1c759c3cd3d169a1c58fd40b3b95d5766747accf
parent 64d12d9252d124d68ac2455a83db8bbd20dfd914
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Thu, 24 Apr 2014 15:32:15 +0200

Detect when a label used in a goto is not defined

We cannot know that a goto label is not defined until the
end of a function, so the best place for this check is in
the free stage, where we can be sure that the label is
not going to be defined.

Diffstat:
Mcc1.h | 1+
Mstmt.c | 39+++++++++++++++++++++++++++++----------
Msymbol.c | 2++
3 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/cc1.h b/cc1.h @@ -100,6 +100,7 @@ struct symbol { bool isstatic : 1; bool isauto : 1; bool isregister : 1; + bool isdefined : 1; } s; union { int i; diff --git a/stmt.c b/stmt.c @@ -12,14 +12,25 @@ extern Node * iszero(Node *np); static void stmt(Symbol *lbreak, Symbol *lcont, Symbol *lswitch); static Symbol * -label(char *s) +label(char *s, char define) { - if (!s) + Symbol *sym; + + if (s) { + if ((sym = lookup(s, NS_LABEL)) != NULL) { + if (define && sym->s.isdefined) + error("label '%s' already defined", s); + else + sym->s.isdefined = 1; + return sym; + } + } else { s = ""; - else if (lookup(s, NS_LABEL)) - error("label '%s' already defined", s); + } - return install(s, NS_LABEL); + sym = install(s, NS_LABEL); + sym->s.isdefined = define; + return sym; } static void @@ -45,9 +56,13 @@ condition(void) static void While(Symbol *lswitch) { - Symbol *begin= label(NULL), *cond = label(NULL), *end = label(NULL); + Symbol *begin, *cond, *end; Node *np; + begin = label(NULL, 1); + end = label(NULL, 1); + cond = label(NULL, 1); + expect(WHILE); np = condition(); emitjump(cond, NULL); @@ -63,9 +78,13 @@ While(Symbol *lswitch) static void For(Symbol *lswitch) { - Symbol *begin= label(NULL), *cond = label(NULL), *end = label(NULL); + Symbol *begin, *cond, *end; Node *econd = NULL, *einc = NULL; + begin = label(NULL, 1); + end = label(NULL, 1); + cond = label(NULL, 1); + expect(FOR); expect('('); stmtexp(); @@ -92,7 +111,7 @@ For(Symbol *lswitch) static void Dowhile(Symbol *lswitch) { - Symbol *begin= label(NULL), *end = label(NULL); + Symbol *begin= label(NULL, 1), *end = label(NULL, 1); expect(DO); @@ -137,7 +156,7 @@ Break(Symbol *lbreak) static void Label(void) { - emitlabel(label(yytext)); + emitlabel(label(yytext, 1)); expect(IDEN); expect(':'); @@ -160,7 +179,7 @@ Goto(void) if (yytoken != IDEN) error("unexpected '%s'", yytext); - emitjump(label(yytext), NULL); + emitjump(label(yytext, 0), NULL); next(); expect(';'); } diff --git a/symbol.c b/symbol.c @@ -37,6 +37,8 @@ freesyms(uint8_t ns) for (sym = tbl->head; sym; sym = next) { if (sym->ctx <= curctx) break; + if (ns == NS_LABEL && !sym->s.isdefined) + error("label '%s' is not defined", sym->name); tbl->htab[hash(sym->name)] = sym->hash; next = tbl->head = sym->next; free(sym->name);