shithub: scc

Download patch

ref: 3c619b9a7518c458fe6343faab8f566368557080
parent: 6b87a0492cf186510ad71c5b20fa4e90ec4ff050
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Wed Aug 5 04:52:33 EDT 2015

Rewrite decl.c

decl.c had several function that were very similar between them,
basically the different kind of declarations in a C program:

	- externals
	- internals
	- parameters
	- struct/union fields

This version puts all the logic in only one function, dodcl(),
which receives different parameters to adapt to the different
situations. The idea was taken from kencc and lcc.

--- a/cc1/TODO
+++ b/cc1/TODO
@@ -1,8 +1,6 @@
 * Verify correctness in initializators
 * emit initializators
 * emit structures definition
-* Rewrite decl.c and use only one decl function with a function pointer
-  parameter
 * Allow external declarations of incomplete array types
 * Implement bitfields
 * Define data structure shared between cc1 and cc2 with the type
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -306,7 +306,7 @@
 
 /* decl.c */
 extern Type *typename(void);
-extern void extdecl(void), decl(void);
+extern void decl(void);
 
 /* lex.c */
 extern char ahead(void);
@@ -350,6 +350,8 @@
 extern unsigned cppctx;
 extern Input *input;
 extern int lexmode;
+extern unsigned curctx;
+extern Symbol *curfun;
 
 extern Type *voidtype, *pvoidtype, *booltype,
             *uchartype,   *chartype,
--- a/cc1/decl.c
+++ b/cc1/decl.c
@@ -8,12 +8,9 @@
 #include "../inc/cc.h"
 #include "cc1.h"
 
-#define ID_EXPECTED     1
-#define ID_ACCEPTED     2
-#define ID_FORBIDDEN    3
+#define OUTCTX 0
+#define PARCTX 1
 
-/* TODO: check identifiers in enum declaration */
-
 struct dcldata {
 	unsigned char op;
 	unsigned short nelem;
@@ -55,54 +52,16 @@
 	return queue(dp, ARY, n, NULL);
 }
 
-static Symbol *parameter(void);
+static void parlist(Type *);
 
 static struct dcldata *
 fundcl(struct dcldata *dp)
 {
-	size_t siz;
-	unsigned n, i, noname;
-	Type *pars[NR_FUNPARAM], **tp = pars;
-	Symbol *syms[NR_FUNPARAM], **sp = syms, *sym;
+	Type dummy = {.n = {.elem = 0}, .pars = NULL};
 
 	pushctx();
-	expect('(');
-
-	n = noname = 0;
-	if (yytoken != ')') do {
-		if ((sym = parameter()) == NULL) {
-			if (n == 0)
-				break;
-			error("incorrect void parameter");
-		}
-		if (n++ == NR_FUNPARAM)
-			error("too much parameters in function definition");
-		*sp++ = sym;
-		*tp++ = sym->type;
-		noname |= sym->name[0] == '\0';
-	} while (accept(','));
-
-	expect(')');
-	if (n != 0) {
-		siz = sizeof(*tp) * n;
-		tp = memcpy(xmalloc(siz), pars, siz);
-	} else {
-		tp = NULL;
-	}
-
-	if (yytoken != '{') {
-		/* it is only a prototype */
-		popctx();
-	} else {
-		/* it is a function definition */
-		if (noname)
-			error("parameter name omitted");
-		sp = syms;
-		for (i = 0; i < n; ++i)
-			emit(ODECL, *sp++);
-	}
-
-	return queue(dp, FTN, n, tp);
+	parlist(&dummy);
+	return queue(dp, FTN, dummy.n.elem, dummy.pars);
 }
 
 static struct dcldata *declarator0(struct dcldata *dp, unsigned ns);
@@ -154,7 +113,7 @@
 }
 
 static Symbol *
-declarator(Type *tp, int flags, unsigned ns)
+declarator(Type *tp, unsigned ns)
 {
 	struct dcldata data[NR_DECLARATORS+1];
 	struct dcldata *bp;
@@ -167,16 +126,12 @@
 			tp = mktype(tp, bp->op, bp->nelem, bp->data);
 		} else {
 			sym = bp->data;
-			if (flags == ID_EXPECTED && *sym->name == '\0')
-				error("missed identifier in declaration");
-			if (flags == ID_FORBIDDEN && *sym->name != '\0')
-				error("unexpected identifier in type name");
 			break;
 		}
 	}
 
 	/* TODO: deal with external array declarations of []  */
-	if (!tp->defined && *sym->name)
+	if (!tp->defined && sym->name)
 		error("declared variable '%s' of incomplete type", sym->name);
 	sym->type = tp;
 	return sym;
@@ -326,63 +281,26 @@
 
 /* TODO: bitfields */
 
+static void fieldlist(Type *tp);
+
 static Type *
 structdcl(void)
 {
-	Type *tagtype, *buff[NR_MAXSTRUCTS], **bp = &buff[0];
-	Symbol *tagsym, *sym;
-	unsigned n;
-	size_t siz;
+	Symbol *sym;
+	Type *tp;
 
-	tagsym = newtag();
-	tagtype = tagsym->type;
+	sym = newtag();
+	tp = sym->type;
 	if (!accept('{'))
-		return tagtype;
+		return tp;
 
-	if (tagtype->defined)
-		error("redefinition of struct/union '%s'", yytext);
-	tagtype->defined = 1;
+	if (tp->defined)
+		error("redefinition of struct/union '%s'", sym->name);
+	tp->defined = 1;
 
-	while (!accept('}')) {
-		Type *base, *tp;
-
-		switch (yytoken) {
-		case SCLASS:
-			error("storage class '%s' in struct/union field",
-			      yytext);
-		case IDEN: case TYPE: case TYPEIDEN: case TQUALIFIER:
-			base = specifier(NULL);
-			break;
-		case ';':
-			next();
-			continue;
-		default:
-			unexpected();
-		}
-
-		if (accept(';'))
-			error("identifier expected");
-
-		do {
-			sym = declarator(base, ID_EXPECTED, tagtype->ns);
-			sym->flags |= ISFIELD;
-			tp = sym->type;
-			if (tp->op == FTN)
-				error("invalid type in struct/union");
-			if (bp == &buff[NR_MAXSTRUCTS])
-				error("too much fields in struct/union");
-			*bp++ = sym->type;
-			emit(ODECL, sym);
-		} while (accept(','));
-		expect(';');
-	}
-
-	if ((n = bp - buff) != 0) {
-		siz = sizeof(Type *) * n;
-		tagtype->n.elem = n;
-		tagtype->pars = memcpy(xmalloc(siz), buff, siz);
-	}
-	return tagtype;
+	while (!accept('}'))
+		fieldlist(tp);
+	return tp;
 }
 
 static Type *
@@ -427,60 +345,168 @@
 	return tp;
 }
 
-static Symbol *
-parameter(void)
+Type *
+typename(void)
 {
-	Symbol *sym;
 	unsigned sclass;
 	Type *tp;
+	Symbol *sym;
 
-	if ((tp = specifier(&sclass)) == voidtype)
-		return NULL;
-	sym = declarator(tp, ID_ACCEPTED, NS_IDEN);
-	sym->flags |= ISPARAM;
+	tp = specifier(&sclass);
+	if (sclass)
+		error("class storage in type name");
+	sym = declarator(tp, NS_IDEN);
+
+	if (!sym->name)
+		error("unexpected identifier in type name");
+
+	return  sym->type;
+}
+
+static void
+field(Symbol *sym, unsigned sclass, Type *data)
+{
+	Type *tp = sym->type, *funtp = data;
+	size_t n = funtp->n.elem;
+
+	if (sclass)
+		error("storage class in struct/union field");
+	if (!sym->name)
+		error("missed identifier in field declaration");
+	if (tp->op == FTN)
+		error("invalid type in struct/union");
+	sym->flags |= ISFIELD;
+	if (n++ == NR_FUNPARAM)
+		error("too much fields in struct/union");
+	funtp->pars = xrealloc(funtp->pars, n);
+	funtp->pars[n-1] = tp;
+	funtp->n.elem = n;
+}
+
+static void
+parameter(Symbol *sym, unsigned sclass, Type *data)
+{
+	Type *tp = sym->type, *funtp = data;
+	size_t n = funtp->n.elem;
+
+	if (tp == voidtype) {
+		if (n != 0)
+			error("incorrect void parameter");
+		funtp->n.elem = -1;
+		return;
+	}
+
+	if (n == -1)
+		error("'void' must be the only parameter");
 	tp = sym->type;
 	if (tp->op == FTN)
 		error("incorrect function type for a function parameter");
 	if (tp->op == ARY)
 		tp = mktype(tp->type, PTR, 0, NULL);
-	switch (sclass) {
-	case REGISTER:
-		sym->flags |= ISREGISTER;
-		break;
-	case 0:
+	if (!sclass)
 		sym->flags |= ISAUTO;
-		break;
-	default:
+	if (sym->flags & (ISSTATIC|ISEXTERN))
 		error("bad storage class in function parameter");
-	}
-	return sym;
+	if (n++ == NR_FUNPARAM)
+		error("too much parameters in function definition");
+	funtp->pars = xrealloc(funtp->pars, n);
+	funtp->pars[n-1] = tp;
+	funtp->n.elem = n;
 }
 
-void
-decl(void)
+static void
+internal(Symbol *sym, unsigned sclass, Type *data)
 {
-	Type *tp;
-	Symbol *sym;
-	unsigned sclass, isfun;
-	extern jmp_buf recover;
 
-	setsafe(END_DECL);
-	if (setjmp(recover))
+	if (!sym->name) {
+		warn("empty declaration");
 		return;
-	tp = specifier(&sclass);
-	if (accept(';'))
+	}
+	if (!sclass)
+		sym->flags |= ISAUTO;
+	if (accept('='))
+		initializer(sym);
+	/* TODO: check if the variable is extern and has initializer */
+	emit(ODECL, sym);
+}
+
+static void
+external(Symbol *sym, unsigned sclass, Type *data)
+{
+	if (!sym->name) {
+		warn("empty declaration");
 		return;
+	}
+	sym->flags |= ISSTATIC|ISGLOBAL;
 
+	if (sym->flags & (ISREGISTER|ISAUTO))
+		error("incorrect storage class for file-scope declaration");
+	if (accept('='))
+		initializer(sym);
+	/* TODO: check if the variable is extern and has initializer */
+	emit(ODECL, sym);
+}
+
+static int
+prototype(Symbol *sym)
+{
+	int r = 1;
+
+	/* TODO: check type of the function */
+	/* TODO: check function is not redefined */
+
+	if (sym->flags & (ISREGISTER|ISAUTO))
+		error("invalid storage class for function '%s'", sym->name);
+
+	if (curctx == PARCTX && yytoken == '{') {
+		if (sym->token == TYPEIDEN)
+			error("function definition declared 'typedef'");
+
+		/* TODO: emit parameters emit(ODECL, *sp++); */
+		sym->flags |= ISDEFINED;
+		curfun = sym;
+		emit(OFUN, sym);
+		compound(NULL, NULL, NULL);
+		emit(OEFUN, NULL);
+		r = 0;
+	}
+
+	/*
+	 * fundcl() creates a new context for the parameters
+	 * and in this point we have to destroy the context
+	 */
+	popctx();
+	return r;
+}
+
+static bool
+dodcl(int rep, void (*fun)(Symbol *, unsigned, Type *), uint8_t ns, Type *type)
+{
+	Type *base, *tp = NULL;
+	unsigned sclass = 0;
+	Symbol *sym = NULL;
+
+	/* FIXME: curctx == PARCTX is incorrect. Structs also
+	 * create new contexts
+	 */
+	/* FIXME: in arguments base can be NULL */
+	base = specifier(&sclass);
+	if (!base && curctx == OUTCTX) {
+		warn("type defaults to 'int' in declaration");
+		tp = inttype;
+	}
+
 	do {
-		setsafe(END_LDECL);
-		setjmp(recover);
-		sym = declarator(tp, ID_EXPECTED, NS_IDEN);
-		isfun = sym->type->op == FTN;
+		sym = declarator(base, ns);
+		tp = sym->type;
 
 		switch (sclass) {
-		case TYPEDEF:
-			sym->token = TYPEIDEN;
-			continue;
+		case REGISTER:
+			sym->flags |= ISREGISTER;
+			break;
+		case AUTO:
+			sym->flags |= ISAUTO;
+			break;
 		case STATIC:
 			sym->flags |= ISSTATIC;
 			break;
@@ -487,105 +513,49 @@
 		case EXTERN:
 			sym->flags |= ISEXTERN;
 			break;
-		case REGISTER:
-			sym->flags = ISREGISTER;
-			if (isfun)
-				goto bad_function;
+		case TYPEDEF:
+			sym->token = TYPEIDEN;
 			break;
-		case AUTO:
-			if (isfun)
-				goto bad_function;
-			/* passtrough */
-		default:
-			sym->flags |= ISAUTO;
-			break;
 		}
-		if (accept('='))
-			initializer(sym);
-		emit(ODECL, sym);
-	} while (accept(','));
 
-	expect(';');
-	return;
+		if (tp->op == FTN && !prototype(sym))
+			return 0;
+		(*fun)(sym, sclass, type);
+	} while (rep && accept(','));
 
-bad_function:
-	error("invalid storage class for function '%s'", sym->name);
+	return 1;
 }
 
-Type *
-typename(void)
+void
+decl(void)
 {
-	unsigned sclass;
-	Type *tp;
-	Symbol *sym;
-
-	tp = specifier(&sclass);
-	if (sclass)
-		error("class storage in type name");
-	sym = declarator(tp, ID_FORBIDDEN, NS_IDEN);
-	return  sym->type;
+	if (accept(';'))
+		return;
+	if (!dodcl(1, curctx == OUTCTX ? external : internal, NS_IDEN, NULL))
+		return;
+	expect(';');
 }
 
-void
-extdecl(void)
+static void
+parlist(Type *tp)
 {
-	Type *base, *tp;
-	unsigned sclass;
-	Symbol *sym;
-	extern Symbol *curfun;
-	extern jmp_buf recover;
+	expect('(');
 
-	setsafe(END_DECL);
-	if (setjmp(recover))
+	if (accept(')')) {
+		/* TODO: implement k&r functions */
 		return;
-
-	switch (yytoken) {
-	case IDEN: case TYPE: case TYPEIDEN: case SCLASS: case TQUALIFIER:
-		base = specifier(&sclass);
-		if (accept(';'))
-			return;
-		do {
-			/* FIX: we cannot put a setjmp here because
-			   base was already assigned, and we were having
-			   problems with EOF */
-			sym = declarator(base, ID_EXPECTED, NS_IDEN);
-			tp = sym->type;
-			sym->flags |= ISSTATIC;
-			sym->flags |= ISGLOBAL;
-
-			switch (sclass) {
-			case REGISTER: case AUTO:
-				error("incorrect storage class for file-scope declaration");
-			case STATIC:
-				sym->flags |= ISSTATIC;
-				break;
-			case EXTERN:
-				sym->flags |= ISEXTERN;
-				break;
-			case TYPEDEF:
-				sym->token = TYPEIDEN;
-				continue;
-			}
-
-			if (tp->op != FTN) {
-				if (accept('='))
-					initializer(sym);
-				emit(ODECL, sym);
-			} else if (yytoken == '{') {
-				curfun = sym;
-				emit(OFUN, sym);
-				compound(NULL, NULL, NULL);
-				emit(OEFUN, NULL);
-				popctx();
-				return;
-			}
-		} while (accept(','));
-		/* PASSTHROUGH */
-	case ';':
-		expect(';');
-		return;
-	default:
-		unexpected();
 	}
+	do
+		dodcl(0, parameter, NS_IDEN, tp);
+	while (accept(','));
+
+	expect(')');
 }
 
+static void
+fieldlist(Type *tp)
+{
+	if (yytoken != ';')
+		dodcl(1, field, tp->ns, tp);
+	expect(';');
+}
--- a/cc1/main.c
+++ b/cc1/main.c
@@ -67,7 +67,7 @@
 	ikeywords();
 	ilex(*argv);
 
-	for (next(); yytoken != EOFTOK; extdecl())
+	for (next(); yytoken != EOFTOK; decl())
 		/* nothing */;
 
 	return 0;
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
@@ -10,7 +10,7 @@
 
 #define NR_SYM_HASH 64
 
-static unsigned curctx;
+unsigned curctx;
 static short localcnt;
 static short globalcnt;