scc

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

commit fb10d4864465bf9398705011026ff12cd19da2a6
parent 4e770c4791211178f97399cb864a99e319eccbdf
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Thu, 31 Oct 2013 18:58:49 +0100

Split storage specifier and type qualifier

They means very different things, and having different data structures
for them, makes the code easier and avoid a lot of comparisions.

Diffstat:
Mdecl.c | 35+++++++++++++++++++++++++----------
Msymbol.h | 11+++++++++--
Mtypes.c | 84+++++++++++++++++++++++++++++++++++--------------------------------------------
3 files changed, 71 insertions(+), 59 deletions(-)

diff --git a/decl.c b/decl.c @@ -82,18 +82,21 @@ aggregate(register struct ctype *tp) tp->sym = sym; } -static bool specifier(struct ctype *, struct storage *); +static bool +specifier(register struct ctype *, struct storage *, struct qualifier *); static struct ctype * fielddcl(unsigned char ns) { struct ctype base; struct storage store; + struct qualifier qlf; register struct ctype *tp; initctype(&base); initstore(&store); - specifier(&base, &store); + initqlf(&qlf); + specifier(&base, &store, &qlf); if (store.defined) error("storage specifier in a struct/union field declaration"); @@ -114,6 +117,7 @@ fielddcl(unsigned char ns) } } cursym->ctype = tp; + cursym->qlf = qlf; } while (accept(',')); expect(';'); @@ -173,12 +177,16 @@ enumdcl(struct ctype *base) } bool -specifier(register struct ctype *tp, register struct storage *store) +specifier(register struct ctype *tp, + struct storage *store, struct qualifier *qlf) { for (;; next()) { switch (yytoken) { - case TYPEDEF: case EXTERN: case STATIC: case AUTO: - case REGISTER: case CONST: case VOLATILE: + case CONST: case VOLATILE: + qlf = qualifier(qlf, yytoken); + break; + case TYPEDEF: case EXTERN: case STATIC: + case AUTO: case REGISTER: store = storage(store, yytoken); break; case UNSIGNED: case SIGNED: @@ -197,7 +205,7 @@ specifier(register struct ctype *tp, register struct storage *store) next(); return structdcl(tp); case IDEN: - if (!tp->defined && !store->defined) { + if (!tp->defined && !store->defined && !qlf->defined) { register struct symbol *sym; sym = lookup(yytext, NS_IDEN); @@ -211,7 +219,7 @@ specifier(register struct ctype *tp, register struct storage *store) default: check_type: /* TODO: simplify this checks */ - if (!tp->defined && !store->defined) { + if (!tp->defined && !store->defined && !qlf->defined) { /* TODO: Allow no type in structs and union */ if (curctx != CTX_OUTER || yytoken != IDEN) return false; @@ -294,7 +302,7 @@ initializer(register struct ctype *tp) } static struct node * -listdcl(struct ctype *base, struct storage *store) +listdcl(struct ctype *base, struct storage *store, struct qualifier *qlf) { struct compound c; char fun; @@ -307,6 +315,7 @@ listdcl(struct ctype *base, struct storage *store) declarator(base, NS_IDEN); cursym->store = *store; + cursym->qlf = *qlf; tp = cursym->ctype = decl_type(base); if ((tp->type == STRUCT || tp->type == UNION) && tp->forward) error("declaration of variable with incomplete type"); @@ -328,12 +337,14 @@ decl(void) { struct ctype base; struct storage store; + struct qualifier qlf; struct node *np; repeat: initctype(&base); initstore(&store); + initqlf(&qlf); - if (!specifier(&base, &store)) + if (!specifier(&base, &store, &qlf)) return NULL; if (accept(';')) { @@ -345,6 +356,10 @@ repeat: initctype(&base); warn(options.useless, "useless storage class specifier in empty declaration"); } + if (qlf.defined) { + warn(options.useless, + "useless type qualifier in empty declaration"); + } if (base.sym && type != ENUM) { warn(options.useless, "unnamed struct/union that defines no instances"); @@ -355,7 +370,7 @@ repeat: initctype(&base); } goto repeat; } - np = listdcl(&base, &store); + np = listdcl(&base, &store, &qlf); return np; } diff --git a/symbol.h b/symbol.h @@ -17,14 +17,18 @@ enum { NS_TAG }; +struct qualifier { + bool c_const : 1; + bool c_volatile : 1; + bool defined: 1; +}; + struct storage { bool c_typedef : 1; bool c_extern : 1; bool c_static : 1; bool c_auto : 1; bool c_register : 1; - bool c_const : 1; - bool c_volatile : 1; bool defined: 1; }; @@ -50,6 +54,7 @@ struct ctype { struct symbol { struct ctype *ctype; struct storage store; + struct qualifier qlf; unsigned char ctx; unsigned char ns; char *name; @@ -77,10 +82,12 @@ extern void freesyms(void); extern struct symbol *lookup(const char *s, signed char ns); extern void insert(struct symbol *sym, unsigned char ctx); extern struct storage *storage(struct storage *tp, unsigned char mod); +extern struct qualifier *qualifier(register struct qualifier *, unsigned char); extern void delctype(struct ctype *tp); extern unsigned char hash(register const char *s); extern struct ctype *initctype(register struct ctype *tp); extern struct storage *initstore(register struct storage *store); +extern struct qualifier * initqlf(struct qualifier *qlf); #ifndef NDEBUG extern void ptype(register struct ctype *t); diff --git a/types.c b/types.c @@ -12,6 +12,13 @@ static unsigned char stack[NR_DECLARATORS]; static unsigned char *stackp = stack; +struct qualifier * +initqlf(struct qualifier *qlf) +{ + memset(qlf, 0, sizeof(*qlf)); + return qlf; +} + struct ctype * initctype(register struct ctype *tp) { @@ -198,85 +205,68 @@ two_or_more: error("two or more basic types"); } -struct storage* +struct qualifier * +qualifier(register struct qualifier *qlf, unsigned char mod) +{ + switch (mod) { + case CONST: + if (options.repeat && qlf->c_const) + goto duplicated; + qlf->c_const = 1; + break; + case VOLATILE: + if (options.repeat && qlf->c_volatile) + goto duplicated; + qlf->c_volatile = 1; + break; + default: + assert(0); + } + + qlf->defined = 1; + return qlf; +duplicated: + error("duplicated '%s'", yytext); +} + +struct storage * storage(register struct storage *sp, unsigned char mod) { extern unsigned char curctx; - if (!sp->defined) { + if (!sp->defined) sp->c_auto = 0; - sp->defined = 1; - } + else + error("Two or more storage specifier"); switch (mod) { case TYPEDEF: - if (sp->c_typedef) - goto duplicated; - if (sp->c_extern | sp->c_auto | sp->c_register | sp->c_static) - goto two_storage; - if (sp->c_const || sp->c_volatile) - goto bad_typedef; sp->c_typedef = 1; break; case EXTERN: - if (sp->c_extern) - goto duplicated; - if (sp->c_typedef | sp->c_auto | sp->c_register | sp->c_static) - goto two_storage; sp->c_extern = 1; break; case STATIC: - if (sp->c_static) - goto duplicated; - if (sp->c_typedef | sp->c_extern | sp->c_auto | sp->c_register) - goto two_storage; sp->c_static = 1; break; case AUTO: if (curctx == CTX_OUTER) goto bad_file_scope_storage; - if (sp->c_typedef | sp->c_extern | sp->c_static |sp->c_register) - goto two_storage; - if (sp->c_auto) - goto duplicated; - sp->c_static = 1; + sp->c_auto = 1; break; case REGISTER: if (curctx == CTX_OUTER) goto bad_file_scope_storage; - if (sp->c_typedef | sp->c_extern | sp->c_auto | sp->c_static) - goto two_storage; - if (sp->c_register) - goto duplicated; sp->c_register = 1; break; - case CONST: - if (options.repeat && sp->c_const) - goto duplicated; - if (sp->c_typedef) - goto bad_typedef; - sp->c_const = 1; - break; - case VOLATILE: - if (options.repeat && sp->c_volatile) - goto duplicated; - if (sp->c_typedef) - goto bad_typedef; - sp->c_volatile = 1; - break; default: assert(0); } + sp->defined = 1; return sp; -bad_typedef: - error("typedef specifies type qualifier"); bad_file_scope_storage: error("file-scope declaration specifies '%s'", yytext); -two_storage: - error("Two or more storage specifier"); -duplicated: - error("duplicated '%s'", yytext); } #ifndef NDEBUG