shithub: scc

Download patch

ref: fb10d4864465bf9398705011026ff12cd19da2a6
parent: 4e770c4791211178f97399cb864a99e319eccbdf
author: Roberto E. Vargas Caballero <[email protected]>
date: Thu Oct 31 14:58:49 EDT 2013

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.

--- a/decl.c
+++ b/decl.c
@@ -82,7 +82,8 @@
 	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)
@@ -89,11 +90,13 @@
 {
 	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 @@
 			}
 		}
 		cursym->ctype = tp;
+		cursym->qlf = qlf;
 	} while (accept(','));
 
 	expect(';');
@@ -173,12 +177,16 @@
 }
 
 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 @@
 			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 @@
 		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 @@
 }
 
 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 @@
 
 		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 @@
 {
 	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 @@
 				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 @@
 		}
 		goto repeat;
 	}
-	np = listdcl(&base, &store);
+	np = listdcl(&base, &store, &qlf);
 	return np;
 }
 
--- a/symbol.h
+++ b/symbol.h
@@ -17,6 +17,12 @@
 	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;
@@ -23,8 +29,6 @@
 	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 symbol {
 	struct ctype *ctype;
 	struct storage store;
+	struct qualifier qlf;
 	unsigned char ctx;
 	unsigned char ns;
 	char *name;
@@ -77,10 +82,12 @@
 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);
--- 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 @@
 	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