shithub: scc

Download patch

ref: 2fae9d998da0050e988c600e6581a076441382ef
parent: 9adea1257259dd445efff48073917cc5a6b3f230
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Jan 11 05:10:40 EST 2016

Add support for k&r functions

I know that this was the most expected feature of scc. You guys
can begin to work with scc after this commit.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -45,6 +45,7 @@
 	bool integer : 1;           /* this type is INT or enum */
 	bool arith : 1;             /* this type is INT, ENUM, FLOAT */
 	bool aggreg : 1;            /* this type is struct or union */
+	bool k_r : 1;               /* This is a k&r function */
 	size_t size;                /* sizeof the type */
 	size_t align;               /* align of the type */
 	Type *type;                 /* base type */
@@ -134,7 +135,8 @@
 enum {
 	FTN = 1,
 	PTR,
-	ARY
+	ARY,
+	KRFTN
 };
 
 /* namespaces */
--- a/cc1/code.c
+++ b/cc1/code.c
@@ -355,20 +355,15 @@
 emitfun(unsigned op, void *arg)
 {
 	Symbol *sym = arg, **sp;
-	TINT n;
 
 	emitdcl(op, arg);
 	puts("\n{");
 
-	n = sym->type->n.elem;
-	for (sp = sym->u.pars; n-- > 0; ++sp) {
-		if ((sym = *sp) == NULL)
-			continue;
-		/* enable non used warnings in parameters */
-		sym->flags &= ~ISUSED;
-		emit(ODECL, sym);
-	}
+	for (sp = sym->u.pars; sp && *sp; ++sp)
+		emit(ODECL, *sp);
 	puts("\\");
+	free(sym->u.pars);
+	sym->u.pars = NULL;
 }
 
 static void
--- a/cc1/decl.c
+++ b/cc1/decl.c
@@ -52,6 +52,7 @@
 	case ARY:
 		p->nelem = va_arg(va, TINT);
 		break;
+	case KRFTN:
 	case FTN:
 		p->nelem = va_arg(va, TINT);
 		p->tpars = va_arg(va, Type **);
@@ -87,7 +88,7 @@
 		popctx();
 		dcl->pars = NULL;
 	}
-	if (p->op == FTN)
+	if (p->op == FTN || p->op == KRFTN)
 		dcl->pars = p->pars;
 	dcl->type = mktype(dcl->type, p->op, p->nelem, p->tpars);
 	return 1;
@@ -159,7 +160,7 @@
 
 	switch (tp->op) {
 	case VOID:
-		if (n != 0) {
+		if (n != 0 || funtp->k_r) {
 			errorp("incorrect void parameter");
 			return NULL;
 		}
@@ -175,13 +176,22 @@
 		return NULL;
 	}
 	if (!empty(sym, tp)) {
-		if ((sym = install(NS_IDEN, sym)) == NULL) {
+		Symbol *p = install(NS_IDEN, sym);
+		if (!p && !funtp->k_r) {
 			errorp("redefinition of parameter '%s'", name);
 			return NULL;
 		}
+		if (p && funtp->k_r) {
+			errorp("declaration for parameter ‘%s’ but no such parameter",
+			       sym->name);
+			return NULL;
+		}
+		if (p)
+			sym = p;
 	}
 
 	sym->type = tp;
+	sym->flags &= ~(ISAUTO|ISREGISTER);
 	sym->flags |= flags;
 	return sym;
 }
@@ -192,66 +202,114 @@
                      Type *type);
 
 static void
-fundcl(struct declarators *dp)
+krfun(Type *tp, Type *types[], Symbol *syms[], int *ntypes, int *nsyms)
 {
-	Type type, *types[NR_FUNPARAM], *tp;
-	Symbol *syms[NR_FUNPARAM], *sym;
-	TINT size;
-	Symbol *pars;
-	int toomany = 0, toovoid = 0;
+	int n = 0;
+	Symbol *sym;
+	int toomany = 0;
 
-	pushctx();
-	expect('(');
-	type.n.elem = 0;
-
-	if (yytoken == ')') {
-		++type.n.elem;
-		syms[0] = NULL;
-		types[0] = ellipsistype;
-		goto end_params;
+	if (yytoken != ')') {
+		do {
+			sym = yylval.sym;
+			expect(IDEN);
+			sym->type = inttype;
+			sym->flags |= ISAUTO;
+			if ((sym = install(NS_IDEN, sym)) == NULL) {
+				errorp("redefinition of parameter '%s'",
+				       sym->name);
+				continue;
+			}
+			if (n < NR_FUNPARAM) {
+				++n;
+				*syms++ = sym;
+				continue;
+			}
+			if (!toomany)
+				errorp("too much parameters in function definition");
+			toomany = 1;
+		} while (accept(','));
 	}
+
+	*nsyms = n;
+	*ntypes = 1;
+	types[0] = ellipsistype;
+}
+
+static void
+ansifun(Type *tp, Type *types[], Symbol *syms[], int *ntypes, int *nsyms)
+{
+	int n = 0;
+	Symbol *sym;
+	int toomany = 0, toovoid = 0;
+
 	do {
-		if (type.n.elem == -1) {
+		if (n == -1) {
 			if (!toovoid)
 				errorp("'void' must be the only parameter");
 			toovoid = 1;
 		}
-		if (!accept(ELLIPSIS)) {
-			sym = dodcl(0, parameter, NS_IDEN, &type);
-			if (!sym)
-				continue;
-			tp = sym->type;
-		} else {
-			if (type.n.elem == 0)
+		if (accept(ELLIPSIS)) {
+			if (n == 0)
 				errorp("a named argument is requiered before '...'");
-			tp = ellipsistype;
-			sym = NULL;
+			++n;
+			*syms = NULL;
+			*types++ = ellipsistype;
+			break;
 		}
-		if (type.n.elem == NR_FUNPARAM) {
-			if (toomany)
-				continue;
-			errorp("too much parameters in function definition");
-			toomany = 1;
-		} else if (type.n.elem >= 0) {
-			syms[type.n.elem] = sym;
-			types[type.n.elem] = tp;
-			++type.n.elem;
+		if ((sym = dodcl(0, parameter, NS_IDEN, tp)) == NULL)
+			continue;
+		if (tp->n.elem == -1) {
+			n = -1;
+			continue;
 		}
-	} while (tp != ellipsistype && accept(','));
+		if (n < NR_FUNPARAM) {
+			*syms++ = sym;
+			*types++ = sym->type;
+			++n;
+			continue;
+		}
+		if (!toomany)
+			errorp("too much parameters in function definition");
+		toomany = 1;
+	} while (accept(','));
 
-end_params:
+	*nsyms = n;
+	*ntypes = n;
+}
+
+static void
+fundcl(struct declarators *dp)
+{
+	Type *types[NR_FUNPARAM], type;
+	Symbol *syms[NR_FUNPARAM+1], **pars;
+	int k_r, ntypes, nsyms;
+	size_t size;
+	void (*fp)(Type **, Symbol **, int *, int *);
+
+	pushctx();
+	expect('(');
+	type.n.elem = 0;
+	type.k_r = 0;
+
+	k_r = (yytoken == ')' || yytoken == IDEN);
+	(*(k_r ? krfun : ansifun))(&type, types, syms, &ntypes, &nsyms);
 	expect(')');
 
-	if (type.n.elem > 0) {
-		size = type.n.elem * sizeof(Symbol *);
-		pars = memcpy(xmalloc(size), syms, size);
-		size = type.n.elem * sizeof(Type *);
-		type.p.pars = memcpy(xmalloc(size), types, size);
+	type.n.elem = ntypes;
+	if (ntypes <= 0) {
+		type.p.pars = NULL;
 	} else {
+		size = ntypes * sizeof(Type *);
+		type.p.pars = memcpy(xmalloc(size), types, size);
+	}
+	if (nsyms <= 0) {
 		pars = NULL;
-		type.p.pars = NULL;
+	} else {
+		size = (nsyms + 1) * sizeof(Symbol *);
+		pars = memcpy(xmalloc(size), syms, size);
+		pars[nsyms] = NULL;
 	}
-	push(dp, FTN, type.n.elem, type.p.pars, pars);
+	push(dp, (k_r) ? KRFTN : FTN, type.n.elem, type.p.pars, pars);
 }
 
 static void declarator(struct declarators *dp, unsigned ns);
@@ -757,51 +815,47 @@
 	return sym;
 }
 
-static void
-prototype(Symbol *sym)
-{
-	int n;
-	Symbol **p;
-
-	emit(ODECL, sym);
-	/*
-	 * avoid non used warnings in prototypes
-	 */
-	n = sym->type->n.elem;
-	for (p = sym->u.pars;  n-- > 0; ++p) {
-		if (*p == NULL)
-			continue;
-		(*p)->flags |= ISUSED;
-	}
-	free(sym->u.pars);
-	sym->u.pars = NULL;
-	popctx();
-}
-
 void
 decl(void)
 {
-	Symbol *sym;
+	Symbol **p, *par, *sym, *ocurfun;
 
 	if (accept(';'))
 		return;
 	sym = dodcl(1, identifier, NS_IDEN, NULL);
 
-	/*
-	 * Functions only can appear at global context,
-	 * but due to parameter context, we have to check
-	 * against GLOBALCTX+1
-	 */
 	if (sym->type->op != FTN) {
 		expect(';');
 		return;
 	}
 
+	ocurfun = curfun;
+	curfun = sym;
+	/*
+	 * Functions only can appear at global context,
+	 * but due to parameter context, we have to check
+	 * against GLOBALCTX+1
+	 */
 	if (curctx != GLOBALCTX+1 || yytoken == ';') {
-		prototype(sym);
+		emit(ODECL, sym);
+		/*
+		 * avoid non used warnings in prototypes
+		 */
+		for (p = sym->u.pars;  p && *p; ++p)
+			(*p)->flags |= ISUSED;
+		popctx();
 		expect(';');
+		free(sym->u.pars);
+		sym->u.pars = NULL;
+		curfun = ocurfun;
 		return;
 	}
+	if (sym->type->k_r) {
+		while (yytoken != '{') {
+			par = dodcl(1, parameter, NS_IDEN, sym->type);
+			expect(';');
+		}
+	}
 
 	if (sym->flags & ISTYPEDEF)
 		errorp("function definition declared 'typedef'");
@@ -811,14 +865,13 @@
 		sym->flags &= ~ISEXTERN;
 		sym->flags |= ISGLOBAL;
 	}
+
 	sym->flags |= ISDEFINED;
 	sym->flags &= ~ISEMITTED;
-	curfun = sym;
 	emit(OFUN, sym);
-	free(sym->u.pars);
 	compound(NULL, NULL, NULL);
 	emit(OEFUN, NULL);
-	curfun = NULL;
+	curfun = ocurfun;
 }
 
 static void
--- a/cc1/expr.c
+++ b/cc1/expr.c
@@ -339,9 +339,9 @@
 	if (ltp->arith && rtp->arith) {
 		arithconv(&lp, &rp);
 	} else if ((ltp->op == PTR || rtp->op == PTR) &&
-	           op == OADD || op == OSUB) {
+	           (op == OADD || op == OSUB)) {
 		return parithmetic(op, rp, lp);
-	} else {
+	} else if (op != OINC && op != ODEC) {
 		errorp("incorrect arithmetic operands");
 	}
 	return simplify(op, lp->type, lp, rp);
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
@@ -111,6 +111,10 @@
 			killsym(sym);
 		}
 		labels = NULL;
+		if (curfun) {
+			free(curfun->u.pars);
+			curfun->u.pars = NULL;
+		}
 	}
 
 	for (sym = head; sym && sym->ctx > curctx; sym = next) {
--- a/cc1/types.c
+++ b/cc1/types.c
@@ -436,11 +436,15 @@
 	Type **tbl, type;
 	unsigned t;
 	Type *bp;
-	int c;
+	int c, k_r = 0;
 
 	if (op == PTR && tp == voidtype)
 		return pvoidtype;
 
+	if (op == KRFTN) {
+		k_r = 1;
+		op = FTN;
+	}
 	switch (op) {
 	case PTR:     c = L_POINTER;  break;
 	case ARY:     c = L_ARRAY;    break;
@@ -458,6 +462,7 @@
 	type.integer = 0;
 	type.printed = 0;
 	type.aggreg = 0;
+	type.k_r = k_r;
 	type.letter = c;
 	type.p.pars = pars;
 	type.n.elem = nelem;