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:
M | decl.c | | | 35 | +++++++++++++++++++++++++---------- |
M | symbol.h | | | 11 | +++++++++-- |
M | types.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