shithub: scc

Download patch

ref: 4f18f449b7ddb35be623af059e5e8a570c60ed15
parent: c73066ae16b32b24682b0e4fe6fe651f8779142d
parent: 62155438ef96682214a7ef7160c2b493b22ea5f6
author: Roberto E. Vargas Caballero <[email protected]>
date: Fri Aug 12 05:06:43 EDT 2016

Merge branch 'master' into qbe

--- a/README
+++ b/README
@@ -63,3 +63,11 @@
 problems without this complexity (and they are the more usual
 way of writing such code).
 
+- Definition of variables with incomplete type
+  ---------------------------------------------
+
+C89 allows the definition of variables with incomplete type that
+have external linkage and file scope. The type of the variable
+is the composition of all the definitions find in the file. The exact
+rules are a bit complex (3.7.2), and SCC ignores  them at this moment
+and it does not allow any definition of variables with incomplete type.
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -200,6 +200,7 @@
 	OBAND,
 	OBXOR,
 	OBOR,
+	OSNEG,
 	ONEG,
 	OCPL,
 	OAND,
@@ -349,7 +350,7 @@
 extern void cpperror(char *fmt, ...);
 
 /* types.c */
-extern int eqtype(Type *tp1, Type *tp2);
+extern int eqtype(Type *tp1, Type *tp2, int eqflag);
 extern Type *ctype(unsigned type, unsigned sign, unsigned size);
 extern Type *mktype(Type *tp, int op, TINT nelem, Type *data[]);
 extern Type *duptype(Type *base);
@@ -420,7 +421,7 @@
 extern int expand(char *begin, Symbol *sym);
 extern void incdir(char *dir);
 extern void outcpp(void);
-extern void defdefine(char *macro, char *val);
+extern void defdefine(char *macro, char *val, char *source);
 extern void undefmacro(char *s);
 
 /*
--- a/cc1/code.c
+++ b/cc1/code.c
@@ -50,7 +50,8 @@
 	[OA_XOR] = ":^",
 	[OA_OR] = ":|",
 	[OADDR] = "'",
-	[ONEG] = "_",
+	[OSNEG] = "_",
+	[ONEG] = "n",
 	[OCPL] = "~",
 	[OAND] = "a",
 	[OOR] = "o",
@@ -104,6 +105,7 @@
 	[OA_XOR] = emitbin,
 	[OA_OR] = emitbin,
 	[OADDR] = emitbin,
+	[OSNEG] = emitbin,
 	[ONEG] = emitbin,
 	[OCPL] = emitbin,
 	[OAND] = emitbin,
--- a/cc1/cpp.c
+++ b/cc1/cpp.c
@@ -23,7 +23,7 @@
 int disexpand;
 
 void
-defdefine(char *macro, char *val)
+defdefine(char *macro, char *val, char *source)
 {
 	char *def, *fmt = "#define %s %s";
 
@@ -32,7 +32,7 @@
 	def = xmalloc(strlen(fmt) + strlen(macro) + strlen(val));
 
 	sprintf(def, fmt, macro, val);
-	allocinput("command-line", NULL, def);
+	allocinput(source, NULL, def);
 	input->nline = ++ncmdlines;
 	cpp();
 	delinput();
@@ -78,17 +78,17 @@
 	tm = localtime(&t);
 	strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm);
 	strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm);
-	defdefine("__DATE__", sdate);
-	defdefine("__TIME__", stime);
-	defdefine("__STDC_VERSION__", "199409L");
-	defdefine("__LINE__", NULL);
-	defdefine("__FILE__", NULL);
+	defdefine("__DATE__", sdate, "built-in");
+	defdefine("__TIME__", stime, "built-in");
+	defdefine("__STDC_VERSION__", "199409L", "built-in");
+	defdefine("__LINE__", NULL, "built-in");
+	defdefine("__FILE__", NULL, "built-in");
 
 	symline = lookup(NS_CPP, "__LINE__");
 	symfile = lookup(NS_CPP, "__FILE__");
 
 	for (bp = list; *bp; ++bp)
-		defdefine(*bp, NULL);
+		defdefine(*bp, "1", "built-in");
 
 	ncmdlines = 0;
 }
@@ -652,8 +652,10 @@
 {
 	int status;
 
-	if (cppctx == 0)
-		error("#else without #ifdef/ifndef");
+	if (cppctx == 0) {
+		cpperror("#else without #ifdef/ifndef");
+		return;
+	}
 
 	status = (ifstatus[cppctx-1] ^= 1);
 	cppoff += (status) ? -1 : 1;
--- a/cc1/decl.c
+++ b/cc1/decl.c
@@ -118,13 +118,15 @@
 }
 
 static int
-empty(Symbol *sym, Type *tp)
+empty(Symbol *sym, Type *tp, int param)
 {
 	if (!sym->name) {
 		sym->type = tp;
 		switch (tp->op) {
 		default:
-			warn("empty declaration");
+			 /* warn if it is not a parameter */
+			if (!param)
+				warn("empty declaration");
 		case STRUCT:
 		case UNION:
 		case ENUM:
@@ -175,7 +177,7 @@
 		errorp("incorrect function type for a function parameter");
 		return NULL;
 	}
-	if (!empty(sym, tp)) {
+	if (!empty(sym, tp, 1)) {
 		Symbol *p = install(NS_IDEN, sym);
 		if (!p && !(funtp->prop & TK_R)) {
 			errorp("redefinition of parameter '%s'", name);
@@ -615,7 +617,7 @@
 	TINT n = structp->n.elem;
 	int err = 0;
 
-	if (empty(sym, tp))
+	if (empty(sym, tp, 0))
 		return sym;
 	if (tp->op == FTN) {
 		errorp("invalid type in struct/union");
@@ -662,7 +664,7 @@
 	int flags;
 	char *name = sym->name;
 
-	if (!eqtype(sym->type, tp)) {
+	if (!eqtype(sym->type, tp, 1)) {
 		errorp("conflicting types for '%s'", name);
 		return sym;
 	}
@@ -724,7 +726,7 @@
 	int sclass = dcl->sclass;
 	char *name = sym->name;
 
-	if (empty(sym, tp))
+	if (empty(sym, tp, 0))
 		return sym;
 
 	/* TODO: Add warning about ANSI limits */
--- a/cc1/expr.c
+++ b/cc1/expr.c
@@ -37,22 +37,6 @@
 	return 0;
 }
 
-int
-isnodecmp(int op)
-{
-	switch (op) {
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGE:
-	case OLE:
-	case OGT:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
 static Node *
 promote(Node *np)
 {
@@ -144,9 +128,6 @@
 static Node *
 chkternary(Node *yes, Node *no)
 {
-	yes = decay(yes);
-	no = decay(no);
-
 	/*
 	 * FIXME:
 	 * We are ignoring type qualifiers here,
@@ -154,7 +135,7 @@
 	 * take a look to 6.5.15
 	 */
 
-	if (!eqtype(yes->type, no->type)) {
+	if (!eqtype(yes->type, no->type, 1)) {
 		if ((yes->type->prop & TARITH) && (no->type->prop & TARITH)) {
 			arithconv(&yes, &no);
 		} else if (yes->type->op != PTR && no->type->op != PTR) {
@@ -181,7 +162,7 @@
 			if (null(no))
 				no = convert(no, yes->type, 0);
 
-			if (!eqtype(yes->type, no->type))
+			if (!eqtype(yes->type, no->type, 1))
 				goto wrong_type;
 		}
 	}
@@ -254,7 +235,7 @@
 	if (!(np->type->prop & TARITH))
 		error("unary operator requires numerical operand");
 	np = promote(np);
-	if (op == ONEG && np->op == ONEG)
+	if (op == OSNEG && np->op == OSNEG)
 		return np->left;
 	if (op == OADD)
 		return np;
@@ -266,7 +247,7 @@
 {
 	Type *oldtp = np->type;
 
-	if (eqtype(newtp, oldtp))
+	if (eqtype(newtp, oldtp, 0))
 		return np;
 
 	switch (oldtp->op) {
@@ -295,7 +276,8 @@
 				return NULL;
 			break;
 		case PTR:
-			if (iscast ||
+			if (eqtype(newtp, oldtp, 1) ||
+			    iscast ||
 			    newtp == pvoidtype || oldtp == pvoidtype) {
 				np->type = newtp;
 				return np;
@@ -318,7 +300,12 @@
 	if (lp->type->op != PTR)
 		XCHG(lp, rp, np);
 
+	tp = rp->type;
+	if (tp->op == PTR && !(tp->type->prop & TDEFINED))
+		goto incomplete;
 	tp = lp->type;
+	if (!(tp->type->prop & TDEFINED))
+		goto incomplete;
 	size = sizeofnode(tp->type);
 
 	if (op == OSUB && BTYPE(rp) == PTR) {
@@ -336,9 +323,13 @@
 
 	return simplify(OADD, tp, lp, rp);
 
+incomplete:
+	errorp("invalid use of undefined type");
+	return lp;
 incorrect:
 	errorp("incorrect arithmetic operands");
-	return node(OADD, tp, lp, rp);
+	return lp;
+
 }
 
 static Node *
@@ -371,7 +362,7 @@
 			err = 1;
 		rp = convert(rp, pvoidtype, 1);
 	} else if (rp->type->op == PTR) {
-		if (!eqtype(lp->type, rp->type))
+		if (!eqtype(lp->type, rp->type, 1))
 			err = 1;
 	} else {
 		err = 1;
@@ -386,9 +377,6 @@
 {
 	Type *ltp, *rtp;
 
-	lp = decay(lp);
-	rp = decay(rp);
-
 	ltp = lp->type;
 	rtp = rp->type;
 
@@ -409,8 +397,6 @@
 negop(int op)
 {
 	switch (op) {
-	case OAND: return OOR;
-	case OOR:  return OAND;
 	case OEQ:  return ONE;
 	case ONE:  return OEQ;
 	case OLT:  return OGE;
@@ -425,11 +411,32 @@
 Node *
 negate(Node *np)
 {
-	if (np->op == OSYM) {
+	int op = np->op;
+
+	switch (np->op) {
+	case OSYM:
 		assert(np->flags&NCONST && np->type->prop&TINTEGER);
 		np->sym = (np->sym->u.i) ? zero : one;
-	} else {
-		np->op = negop(np->op);
+		break;
+	case OOR:
+	case OAND:
+		if (np->op == ONEG) {
+			Node *new = np->left;
+			free(np);
+			return new;
+		}
+		np = node(ONEG, inttype, np, NULL);
+		break;
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGE:
+	case OLE:
+	case OGT:
+		np->op = negop(op);
+		break;
+	default:
+		abort();
 	}
 
 	return np;
@@ -438,14 +445,23 @@
 static Node *
 exp2cond(Node *np, char neg)
 {
-	np = decay(np);
 	if (np->type->prop & TAGGREG) {
 		errorp("used struct/union type value where scalar is required");
-		np = constnode(zero);
+		return constnode(zero);
 	}
-	if (isnodecmp(np->op))
+	switch (np->op) {
+	case OOR:
+	case OAND:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGE:
+	case OLE:
+	case OGT:
 		return (neg) ? negate(np) : np;
-	return compare((neg) ?  OEQ : ONE, np, constnode(zero));
+	default:
+		return compare((neg) ?  OEQ : ONE, np, constnode(zero));
+	}
 }
 
 static Node *
@@ -491,11 +507,9 @@
 static Node *
 content(char op, Node *np)
 {
-	np = decay(np);
-	switch (BTYPE(np)) {
-	case ARY:
-	case FTN:
-	case PTR:
+	if (BTYPE(np) != PTR) {
+		errorp("invalid argument of memory indirection");
+	} else {
 		if (np->op == OADDR) {
 			Node *new = np->left;
 			new->type = np->type->type;
@@ -505,10 +519,8 @@
 			np = node(op, np->type->type, np, NULL);
 		}
 		np->flags |= NLVAL;
-		return np;
-	default:
-		error("invalid argument of memory indirection");
 	}
+	return np;
 }
 
 static Node *
@@ -519,7 +531,7 @@
 
 	if (!(lp->type->prop & TINTEGER) && !(rp->type->prop & TINTEGER))
 		error("array subscript is not an integer");
-	np = arithmetic(OADD, decay(lp), decay(rp));
+	np = arithmetic(OADD, lp, rp);
 	tp = np->type;
 	if (tp->op != PTR)
 		errorp("subscripted value is neither array nor pointer");
@@ -529,7 +541,7 @@
 static Node *
 assignop(char op, Node *lp, Node *rp)
 {
-	if ((rp = convert(decay(rp), lp->type, 0)) == NULL) {
+	if ((rp = convert(rp, lp->type, 0)) == NULL) {
 		errorp("incompatible types when assigning");
 		return lp;
 	}
@@ -549,6 +561,10 @@
 	if (!(tp->prop & TDEFINED)) {
 		errorp("invalid use of undefined type");
 		return np;
+	} else if (tp->op == PTR && !(tp->type->prop & TDEFINED)) {
+		errorp("%s of pointer to an incomplete type",
+		       (op == OINC) ? "increment" : "decrement");
+		return np;
 	} else if (tp->prop & TARITH) {
 		inc = constnode(one);
 	} else if (tp->op == PTR) {
@@ -565,16 +581,26 @@
 {
 	Node *new;
 
-	if (BTYPE(np) != FTN) {
-		chklvalue(np);
-		if (np->sym && (np->sym->flags & SREGISTER))
-			errorp("address of register variable '%s' requested", yytext);
-		if (np->op == OPTR) {
-			Node *new = np->left;
-			free(np);
-			return new;
-		}
+	/*
+	 * ansi c accepts & applied to a function name, and it generates
+	 * a function pointer
+	 */
+	if (np->op == OSYM) {
+		if (np->type->op == FTN)
+			return decay(np);
+		if (np->type->op == ARY)
+			goto dont_check_lvalue;
 	}
+	chklvalue(np);
+
+dont_check_lvalue:
+	if (np->sym && (np->sym->flags & SREGISTER))
+		errorp("address of register variable '%s' requested", yytext);
+	if (np->op == OPTR) {
+		Node *new = np->left;
+		free(np);
+		return new;
+	}
 	new = node(op, mktype(np->type, PTR, 0, NULL), np, NULL);
 
 	if (np->sym && np->sym->flags & (SGLOBAL|SLOCAL|SPRIVATE))
@@ -585,7 +611,6 @@
 static Node *
 negation(char op, Node *np)
 {
-	np = decay(np);
 	if (!(np->type->prop & TARITH) && np->type->op != PTR) {
 		errorp("invalid argument of unary '!'");
 		freetree(np);
@@ -636,7 +661,7 @@
 		sym->flags |= SHASINIT;
 		emit(ODECL, sym);
 		emit(OINIT, np);
-		np = decay(varnode(sym));
+		np = varnode(sym);
 		next();
 		break;
 	case CONSTANT:
@@ -688,7 +713,7 @@
 	toomany = 0;
 
 	do {
-		arg = decay(assign());
+		arg = assign();
 		argtype = *targs;
 		if (argtype == ellipsistype) {
 			n = 0;
@@ -727,43 +752,8 @@
 	return node(OCALL, rettype, np, par);
 }
 
-static Node *
-postfix(Node *lp)
-{
-	Node *rp;
+static Node *unary(int);
 
-	if (!lp)
-		lp = primary();
-	for (;;) {
-		switch (yytoken) {
-		case '[':
-			next();
-			rp = expr();
-			lp = array(lp, rp);
-			expect(']');
-			break;
-		case DEC:
-		case INC:
-			lp = incdec(lp, (yytoken == INC) ? OINC : ODEC);
-			next();
-			break;
-		case INDIR:
-			lp = content(OPTR, lp);
-		case '.':
-			lp = field(lp);
-			break;
-		case '(':
-			lp = arguments(lp);
-			lp->flags |= NEFFECT;
-			break;
-		default:
-			return lp;
-		}
-	}
-}
-
-static Node *unary(void);
-
 static Type *
 typeof(Node *np)
 {
@@ -788,7 +778,7 @@
 		tp = typename();
 		break;
 	default:
-		tp = typeof(unary());
+		tp = typeof(unary(0));
 		break;
 	}
 	expect(')');
@@ -795,19 +785,68 @@
 	return tp;
 }
 
-static Node *cast(void);
+static Node *
+postfix(Node *lp)
+{
+	Node *rp;
 
+	for (;;) {
+		switch (yytoken) {
+		case '[':
+		case DEC:
+		case INC:
+		case INDIR:
+		case '.':
+		case '(':
+			lp = decay(lp);
+			switch (yytoken) {
+			case '[':
+				next();
+				rp = expr();
+				expect(']');
+				lp = array(lp, rp);
+				break;
+			case DEC:
+			case INC:
+				lp = incdec(lp, (yytoken == INC) ? OINC : ODEC);
+				next();
+				break;
+			case INDIR:
+				lp = content(OPTR, lp);
+			case '.':
+				lp = field(lp);
+				break;
+			case '(':
+				lp = arguments(lp);
+				lp->flags |= NEFFECT;
+				break;
+			}
+			break;
+		default:
+			return lp;
+		}
+	}
+}
+
+static Node *cast(int);
+
 static Node *
-unary(void)
+unary(int needdecay)
 {
-	Node *(*fun)(char, Node *);
+	Node *(*fun)(char, Node *), *np;
 	char op;
 	Type *tp;
 
 	switch (yytoken) {
+	case '!': op = 0;     fun = negation;     break;
+	case '+': op = OADD;  fun = numericaluop; break;
+	case '-': op = OSNEG; fun = numericaluop; break;
+	case '~': op = OCPL;  fun = integeruop;   break;
+	case '&': op = OADDR; fun = address;      break;
+	case '*': op = OPTR;  fun = content;      break;
 	case SIZEOF:
 		next();
-		tp = (yytoken == '(') ? sizeexp() : typeof(unary());
+		tp = (yytoken == '(') ? sizeexp() : typeof(unary(0));
 		if (!(tp->prop & TDEFINED))
 			errorp("sizeof applied to an incomplete type");
 		return sizeofnode(tp);
@@ -815,22 +854,24 @@
 	case DEC:
 		op = (yytoken == INC) ? OA_ADD : OA_SUB;
 		next();
-		return incdec(unary(), op);
-	case '!': op = 0;     fun = negation;     break;
-	case '+': op = OADD;  fun = numericaluop; break;
-	case '-': op = ONEG;  fun = numericaluop; break;
-	case '~': op = OCPL;  fun = integeruop;   break;
-	case '&': op = OADDR; fun = address;      break;
-	case '*': op = OPTR;  fun = content;      break;
-	default:  return postfix(NULL);
+		np = incdec(unary(1), op);
+		goto chk_decay;
+	default:
+		np = postfix(primary());
+		goto chk_decay;
 	}
 
 	next();
-	return (*fun)(op, cast());
+	np = (*fun)(op, cast(op != OADDR));
+
+chk_decay:
+	if (needdecay)
+		np = decay(np);
+	return np;
 }
 
 static Node *
-cast(void)
+cast(int needdecay)
 {
 	Node *lp, *rp;
 	Type *tp;
@@ -837,7 +878,7 @@
 	static int nested;
 
 	if (!accept('('))
-		return unary();
+		return unary(needdecay);
 
 	switch (yytoken) {
 	case TQUALIFIER:
@@ -852,7 +893,7 @@
 		case ARY:
 			error("cast specifies an array type");
 		default:
-			lp = cast();
+			lp = cast(needdecay);
 			if ((rp = convert(lp,  tp, 1)) == NULL)
 				error("bad type conversion requested");
 			rp->flags &= ~NLVAL;
@@ -879,7 +920,7 @@
 	Node *np, *(*fun)(char, Node *, Node *);
 	char op;
 
-	np = cast();
+	np = cast(1);
 	for (;;) {
 		switch (yytoken) {
 		case '*': op = OMUL; fun = arithmetic; break;
@@ -888,7 +929,7 @@
 		default: return np;
 		}
 		next();
-		np = (*fun)(op, np, cast());
+		np = (*fun)(op, np, cast(1));
 	}
 }
 
--- a/cc1/fold.c
+++ b/cc1/fold.c
@@ -188,7 +188,8 @@
 	case OLE:   i = l <= r; break;
 	case OEQ:   i = l == r; break;
 	case ONE:   i = l != r; break;
-	case ONEG:  i = -l;     break;
+	case ONEG:  i = !l;     break;
+	case OSNEG: i = -l;     break;
 	case OCPL:  i = ~l;     break;
 	default:    return 0;
 	}
@@ -213,7 +214,8 @@
 	case OBAND: u = l & r;  break;
 	case OBXOR: u = l ^ r;  break;
 	case OBOR:  u = l | r;  break;
-	case ONEG:  u = -l;     break;
+	case ONEG:  u = !l;     break;
+	case OSNEG: u = -l;     break;
 	case OCPL:  u = ~l;     break;
 	case OAND:  i = l && r; goto sign;
 	case OOR:   i = l || r; goto sign;
--- a/cc1/init.c
+++ b/cc1/init.c
@@ -134,7 +134,7 @@
 
 		return np;
 	}
-	if (eqtype(tp, np->type))
+	if (eqtype(tp, np->type, 1))
 		return np;
 	if ((aux = convert(decay(np), tp, 0)) != NULL)
 		return aux;
--- a/cc1/main.c
+++ b/cc1/main.c
@@ -38,7 +38,7 @@
 	else
 		p = "1";
 
-	defdefine(macro, p);
+	defdefine(macro, p, "command-line");
 }
 
 static void
--- a/cc1/tests/test001.c
+++ b/cc1/tests/test001.c
@@ -9,13 +9,13 @@
 G6	I	F	"main
 {
 \
-V8	K	#N13
-Y7	V8	"	(
+V9	K	#N13
+Y8	V9	"	(
 	#"hello world
 	#K0A
 	#K00
 )
-	X4	Y7	'P	pP	cI
+	X4	Y8	'P	pP	cI
 	h	#I0
 }
 */
--- /dev/null
+++ b/cc1/tests/test065.c
@@ -1,0 +1,66 @@
+/* See LICENSE file for copyright and license details. */
+
+/*
+name: TEST065
+description: Test decay mixed with * operators
+error:
+test065.c:65: error: decrement of pointer to an incomplete type
+test065.c:65: error: invalid use of undefined type
+test065.c:66: warning: 'argv' defined but not used
+output:
+G7	I	F	"main
+{
+A1	I	"argc
+A5	P	"argv
+\
+V8	I	#N1
+A9	V8	"v
+A12	P	"p
+A14	P	"f1
+A15	P	"f2
+	A9	#I0	:I
+	A12	A9	'P	:P
+	A14	G7	'P	:P
+	A15	G7	'P	:P
+	y	L18	A1	#I0	!I
+	h	#I1
+L18
+	y	L19	G7	#I0	pI	#P0	pP	cI	#I0	=I
+	h	#I2
+L19
+	y	L20	A14	@F	#I0	pI	#P0	pP	cI	#I0	=I
+	h	#I3
+L20
+	y	L21	A15	@F	#I0	pI	#P0	pP	cI	#I0	=I
+	h	#I4
+L21
+	y	L22	A12	@I	#I0	!I
+	h	#I0
+L22
+*/
+
+int
+main(int argc, char *argv[])
+{
+	int v[1];
+	int (*p)[];
+	int (*f1)(int ,char *[]);
+	int (*f2)(int ,char *[]);
+
+	v[0] = 0;
+	p = &v;
+	f1 = &main;
+	f2 = main;
+	if (argc == 0)
+		return 1;
+	if ((****main)(0, 0))
+		return 2;
+	if ((****f1)(0, 0))
+		return 3;
+	if ((****f2)(0, 0))
+		return 4;
+	if (!(*p)[0])
+		return 0;
+
+	return (*++p)[0] || p[1][0];
+}
--- a/cc1/types.c
+++ b/cc1/types.c
@@ -296,7 +296,7 @@
 	t = (op ^ (uintptr_t) tp >> 3) & NR_TYPE_HASH-1;
 	tbl = &typetab[t];
 	for (bp = *tbl; bp; bp = bp->next) {
-		if (eqtype(bp, &type) && op != STRUCT && op != UNION) {
+		if (eqtype(bp, &type, 0) && op != STRUCT && op != UNION) {
 			/*
 			 * pars was allocated by the caller
 			 * but the type already exists, so
@@ -314,7 +314,7 @@
 }
 
 int
-eqtype(Type *tp1, Type *tp2)
+eqtype(Type *tp1, Type *tp2, int equiv)
 {
 	TINT n;
 	Type **p1, **p2;
@@ -333,16 +333,18 @@
 			return 0;
 		p1 = tp1->p.pars, p2 = tp2->p.pars;
 		for (n = tp1->n.elem; n > 0; --n) {
-			if (!eqtype(*p1++, *p2++))
+			if (!eqtype(*p1++, *p2++, equiv))
 				return 0;
 		}
 		goto check_base;
 	case ARY:
+		if (equiv && (tp1->n.elem == 0 || tp2->n.elem == 0))
+			goto check_base;
 		if (tp1->n.elem != tp2->n.elem)
 			return 0;
 	case PTR:
 	check_base:
-		return eqtype(tp1->type, tp2->type);
+		return eqtype(tp1->type, tp2->type, equiv);
 	case VOID:
 	case ENUM:
 		return 0;
--- a/cc2.old/Makefile
+++ /dev/null
@@ -1,23 +1,0 @@
-.POSIX:
-
-include ../config.mk
-
-OBJS = main.o parser.o cgen.o code.o optm.o peep.o
-
-all: cc2
-
-
-$(OBJS): ../inc/cc.h ../inc/sizes.h cc2.h
-main.o: error.h
-
-error.h: cc2.h
-	rm -f $@; trap 'rm -f $$$$.h' EXIT INT QUIT
-	awk -f generror cc2.h > $$$$.h && mv $$$$.h $@
-
-cc2: $(OBJS) ../lib/libcc.a
-	$(CC) $(LDFLAGS) $(OBJS) ../lib/libcc.a -o $@
-
-clean:
-	rm -f $(OBJS)
-	rm -f cc2 error.h
-
--- a/cc2.old/cast.patch
+++ /dev/null
@@ -1,61 +1,0 @@
-diff --git a/cc2/cgen.c b/cc2/cgen.c
-index be4ff41..8839505 100644
---- a/cc2/cgen.c
-+++ b/cc2/cgen.c
-@@ -449,16 +449,50 @@ cast(Node *np)
- {
- 	Node *lp = np->left;
- 	uint8_t reg;
-+	int8_t delta;
- 
--	if (lp->type.size != np->type.size)
-+	swtich (lp->type.size) {
-+	case 1:
-+		switch (np->type.size) {
-+		case 1:
-+			break;
-+		case 2:
-+			if (lp->op != REG)
-+				move(lp, np);
-+			np->reg = reg = lp->reg;
-+			if (lp->sign && np->sign) {
-+				code(BIT, lp, imm(7));
-+				code(JRZ, .., ..);
-+				code(LDI, regs[upper[reg]], imm(-1));
-+				code(JR, ..., ...);
-+			}
-+			reguse[pair[reg]] = reguse[reg] = np;
-+			code(LDI, regs[lower[reg]], imm(0));
-+			break;
-+		default:
-+			abort();
-+		}
-+		break;
-+	case 2:
-+		switch (np->type.size) {
-+		case 1:
-+			if (lp->op == REG) {
-+				reguse[upper[reg]] = NULL;
-+				reg = lower[reg];
-+				np->reg = reg;
-+				reguse[pair[reg]] = reguse[reg] = np;
-+			}
-+			break;
-+		case 2:
-+			break;
-+		default:
-+			abort();
-+		}
-+	default:
- 		abort();
-+	}
- 	lp->used = 1;
- 	np->sym = lp->sym;
--	if ((np->op = lp->op) == REG) {
--		reg = lp->reg;
--		np->reg = reg;
--		reguse[pair[reg]] = reguse[reg] = np;
--	}
- }
- 
- static void (*opnodes[])(Node *) = {
--- a/cc2.old/cc2.h
+++ /dev/null
@@ -1,179 +1,0 @@
-
-#define SIGNF 1
-#define INTF  2
-
-#define NONE       0
-#define AUTO      'A'
-#define REG       'R'
-#define MEM       'T'
-#define PAR       'P'
-#define CONST     '#'
-#define INDEX     'I'
-#define LABEL     'L'
-#define OADD      '+'
-#define OSUB      '-'
-#define OASSIG    ':'
-#define OINC      ';'
-#define OMOD      '%'
-#define ODIV      '/'
-#define OSHL      'l'
-#define OSHR      'r'
-#define OBAND     '&'
-#define OBOR      '|'
-#define OBXOR     '^'
-#define OPTR      '@'
-#define OADDR     'a'
-#define OLT       '<'
-#define OGT       '>'
-#define OGE       ']'
-#define OLE       '['
-#define OEQ       '='
-#define ONE       '!'
-#define OOR       'o'
-#define OAND      'y'
-#define OCAST     'c'
-#define ONEG      '_'
-#define OCPL      '~'
-#define OCOMMA    ','
-#define ORET      'y'
-
-#define ADDABLE 10
-
-
-typedef struct symbol Symbol;
-typedef struct node Node;
-typedef struct inst Inst;
-typedef struct addr Addr;
-typedef struct type Type;
-
-struct type {
-	unsigned short size;
-	uint8_t align;
-	char letter;
-	uint8_t flags;
-};
-
-struct symbol {
-	unsigned short id;
-	char *name;
-	char kind;
-	bool public : 1;
-	bool extrn : 1;
-	bool index : 1;
-	union {
-		/* TODO: Admit inmediate of other type */
-		TINT imm;
-		struct {
-			Type type;
-			char sclass;
-			short off;
-		} v;
-		Inst *pc;
-		struct {
-			short locals;
-			short params;
-			Node **body;
-		} f;
-	} u;
-};
-
-struct node {
-	uint8_t op;
-	uint8_t subop;
-	Type type;
-	uint8_t complex;
-	uint8_t addable;
-	uint8_t reg;
-	Symbol *sym;
-	bool used : 1;
-	struct node *left, *right;
-};
-
-
-struct addr {
-	char kind;
-	union {
-		uint8_t reg;
-		TINT i;
-		Symbol *sym;
-	} u;
-};
-
-struct inst {
-	uint8_t op;
-	Addr from, to;
-	Symbol *label;
-	Inst *next, *prev;
-};
-
-enum nerrors {
-	EINTNUM,       /* too much internal identifiers */
-	EEXTNUM,       /* too much external identifiers */
-	EPARNUM,       /* too much parameters */
-	ENODEOV,       /* node overflow */
-	ESTACKO,       /* stack overflow */
-	ESTACKU,       /* stack underflow */
-	EEXPROV,       /* expression overflow */
-	ETYPERR,       /* incorrect type in expression */
-	EEXPBAL,       /* expression not balanced */
-	ESYNTAX,       /* syntax error */
-	ELNLINE,       /* line too long */
-	EFERROR,       /* error reading from file:%s*/
-	ENUMERR
-};
-
-enum {
-	LDW,
-	LDL,
-	LDH,
-	MOV,
-	LDI,
-	ADD,
-	PUSH,
-	POP,
-	RET,
-	NOP,
-	INC,
-	SUB,
-	DEC,
-	JP,
-	AND,
-	OR,
-	XOR,
-	CPL,
-	NEG
-};
-
-enum {
-	A = 1, B, C, D, E, H, L, IYL, IYH, NREGS,
-	AF = NREGS, HL, DE, BC, IY, NPAIRS,
-	SP = NPAIRS, IX
-};
-
-extern Symbol *curfun;
-extern Inst *prog, *pc;
-
-/* main.c */
-extern void error(unsigned nerror, ...);
-
-/* cgen.c */
-extern void addable(void);
-extern void generate(void);
-extern void apply(Node *(*fun)(Node *));
-
-/* parser.c */
-extern void parse(void);
-extern void prtree(Node *np);
-
-/* code.c */
-extern void code(uint8_t op, Node *to, Node *from);
-extern void inscode(uint8_t op, Addr *to, Addr *from);
-extern void writeout(void);
-extern void delcode(void);
-
-/* optm.c */
-extern void optimize(void);
-extern Node *imm(TINT i);
-
-/* peep.c */
-extern void peephole(void);
--- a/cc2.old/cgen.c
+++ /dev/null
@@ -1,602 +1,0 @@
-
-#include <assert.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include "../inc/cc.h"
-#include "cc2.h"
-
-static Symbol retlabel = {
-	.kind = LABEL
-};
-
-static Node *reguse[NPAIRS];
-static uint8_t upper[] = {[DE] = D, [HL] = H, [BC] = B,  [IY] = IYH};
-static uint8_t lower[] = {[DE] = E, [HL] = L, [BC] = C, [IY] = IYL};
-static uint8_t pair[] = {
-	[A] = A,
-	[H] = HL, [L] = HL, [HL] = HL,
-	[B] = BC, [C] = BC, [BC] = BC,
-	[D] = DE, [E] = DE, [DE] = DE,
-	[IYL] = IY, [IYH] = IY, [IY] = IY
-};
-
-static Node regs[] = {
-	[E] =  {
-		.op = REG,
-		.reg = E
-	},
-	[D] = {
-		.op = REG,
-		.reg = D
-	},
-	[H] = {
-		.op = REG,
-		.reg = H
-	},
-	[L] = {
-		.op = REG,
-		.reg = L
-	},
-	[C] = {
-		.op= REG,
-		.reg = C
-	},
-	[B] = {
-		.op= REG,
-		.reg = B
-	},
-	[A] = {
-		.op= REG,
-		.reg = A
-	},
-	[IYL] = {
-		.op = REG,
-		.reg = IYL
-	},
-	[IYH] = {
-		.op = REG,
-		.reg = IYH
-	},
-	[DE] = {
-		.op = REG,
-		.reg = DE
-	},
-	[HL] = {
-		.op = REG,
-		.reg = HL
-	},
-	[BC] = {
-		.op = REG,
-		.reg = BC
-	},
-	[IX] = {
-		.op = REG,
-		.reg = IX
-	},
-	[IY] = {
-		.op = REG,
-		.reg = IY
-	},
-	[SP] = {
-		.op = REG,
-		.reg = SP
-	}
-};
-
-static void moveto(Node *np, uint8_t reg);
-
-static void
-allocreg(Node *np)
-{
-	static uint8_t reg8[] = {A, B, C, D, E, H, L, IYL, IY, 0};
-	static uint8_t reg16[] = {BC, DE, IY, 0};
-	Node *r;
-	uint8_t *ary, *bp, c;
-
-	switch (np->type.size) {
-	case 1:
-		ary = reg8;
-		break;
-	case 2:
-		ary = reg16;
-		break;
-	default:
-		abort();
-	}
-	for (bp = ary; c = *bp; ++bp) {
-		r = reguse[c];
-		if (!r || r->used) {
-			moveto(np, c);
-			return;
-		}
-	}
-	/* TODO: What to do here? */
-	abort();
-}
-
-static void
-spill(uint8_t reg)
-{
-	Node *np, *r;
-	Symbol *sym;
-	uint8_t p, h, l;
-
-	if ((np = reguse[reg]) == NULL)
-		return;
-	sym = np->sym;
-	r = &regs[reg];
-
-	switch (np->type.size) {
-	case 1:
-		if (sym) {
-			code(LDL, np, r);
-			np->op = sym->kind;
-		} else {
-			allocreg(np);
-		}
-		break;
-	default:
-		abort();
-	}
-
-	reguse[reg] = NULL;
-	p = pair[reg];
-	l = lower[p];
-	h = upper[p];
-	if (reg >= NREGS)
-		reguse[l] = reguse[h] = NULL;
-	else if (!reguse[l] && !reguse[h])
-		reguse[p] = NULL;
-}
-
-static void
-moveto(Node *np, uint8_t reg)
-{
-	Node *r = &regs[reg], *u = reguse[reg];
-	char op = np->op;
-
-	if (u) {
-		Symbol *sym = np->sym;
-		if (sym && sym == u->sym)
-			return;
-		else if (!np->used)
-			spill(reg);
-	}
-
-	switch (np->type.size) {
-	case 1:
-		switch (op) {
-		case MEM:
-		case AUTO:
-			code(LDL, r, np);
-			break;
-		case CONST:
-		case INDEX:
-			code(LDI, r, np);
-			break;
-		case REG:
-			code(MOV, r, np);
-			break;
-		default:
-			abort();
-		}
-		break;
-	case 2:
-		switch (op) {
-		case CONST:
-			code(LDL, r, np);
-			break;
-		case AUTO:
-			code(LDL, &regs[lower[reg]], np);
-			code(LDH, &regs[upper[reg]], np);
-			break;
-		default:
-			abort();
-		}
-		reguse[upper[reg]] = reguse[lower[reg]] =  np;
-		break;
-	default:
-		abort();
-	}
-	reguse[pair[reg]] = reguse[reg] = np;
-	np->op = REG;
-	np->reg = reg;
-}
-
-static void
-accum(Node *np)
-{
-	switch (np->type.size) {
-	case 1:
-		moveto(np, A);
-		break;
-	case 2:
-		moveto(np, HL);
-		break;
-	default:
-		abort();
-	}
-}
-
-static void
-index(Node *np)
-{
-	Node *u = reguse[HL];
-	Symbol *sym;
-
-	if (u && u->sym) {
-		if (u->op == INDEX && np->sym == u->sym) {
-			np->op = INDEX;
-			return;
-		} else {
-			spill(HL);
-		}
-	}
-	code(LDI, &regs[HL], np);
-	if (sym = np->sym)
-		sym->index = 1;
-	np->op = INDEX;
-	reguse[HL] = reguse[H] = reguse[L] = np;
-}
-
-static void
-move(Node *np, Node *parent)
-{
-	assert(np->type.size == 1);
-	switch (parent->op) {
-	case OASSIG:
-		allocreg(np);
-		break;
-	case ONEG:
-	case OCPL:
-		switch (np->op) {
-		case REG:
-			if (np->reg == A)
-				break;
-			/* PASSTHROUGH */
-		case PAR:
-		case AUTO:
-		case CONST:
-		case MEM:
-		case INDEX:
-			accum(np);
-			break;
-		default:
-			abort();
-		}
-		break;
-	case OADD:
-	case OSUB:
-	case OBAND:
-	case OBOR:
-	case OBXOR:
-		switch (np->op) {
-		case PAR:
-		case AUTO:
-		case CONST:
-		case INDEX:
-		case REG:
-			return;
-		case MEM:
-			index(np);
-			break;
-		default:
-			abort();
-		}
-		break;
-	default:
-		abort();
-	}
-}
-
-static void
-conmute(Node *np)
-{
-	Node *p, *q;
-
-	p = np->left;
-	q = np->right;
-	np->left = q;
-	np->right = p;
-}
-
-static void
-add(Node *np)
-{
-	Node *lp = np->left, *rp = np->right, *a;
-	uint8_t op;
-
-	switch (np->type.size) {
-	case 1:
-		a = reguse[A];
-		if (a == lp)
-			goto update_a;
-		if (a == rp)
-			goto conmute1;
-		if (lp->op == CONST) {
-			accum(rp);
-			goto conmute1;
-		}
-		accum(lp);
-		goto update_a;
-	conmute1:
-		conmute(np);
-		lp = np->left, rp = np->right;
-	update_a:
-		move(rp, np);
-		switch (np->op) {
-		case OADD:
-			op = ADD;
-			break;
-		case OSUB:
-			op = SUB;
-			break;
-		case OBAND:
-			op = AND;
-			break;
-		case OBOR:
-			op = OR;
-			break;
-		case OBXOR:
-			op = XOR;
-			break;
-		default:
-			abort();
-		}
-		code(op, lp, rp);
-		lp->used = rp->used = 1;
-		np->op = REG;
-		np->reg = A;
-		reguse[A] = np;
-		break;
-	default:
-		abort();
-	}
-}
-
-static void
-assign(Node *np)
-{
-	Node *lp = np->left, *rp = np->right;
-	Symbol *sym = lp->sym;
-
-	switch (np->type.size) {
-	case 1:
-		switch (lp->op) {
-		case MEM:
-			if (sym && sym->index)
-				lp->op = INDEX;
-			/* PASSTROUGH */
-		case INDEX:
-		case AUTO:
-			if (rp->op != REG)
-				move(rp, np);
-			lp->reg = rp->reg;
-			code(LDL, lp, rp);
-			break;
-		case REG:
-			code(MOV, lp, rp);
-			break;
-		default:
-			abort();
-		}
-		break;
-	default:
-		abort();
-	}
-
-	np->op = REG;
-	np->reg = lp->reg;
-	np->sym = rp->sym = lp->sym;
-	np->used = rp->used = lp->used = 1;
-}
-
-static void
-ret(Node *np)
-{
-	static Node retnode = {
-		.op = LABEL,
-		.sym = &retlabel
-	};
-
-	if (np->left)
-		accum(np->left);
-	code(JP, &retnode, NULL);
-}
-
-static void
-nop(Node *np)
-{
-}
-
-static void
-cpl(Node *np)
-{
-
-	Node *lp = np->left;
-	uint8_t op;
-
-	switch (np->type.size) {
-	case 1:
-		move(lp, np);
-		switch (np->op) {
-		case OCPL:
-			op = CPL;
-			break;
-		case ONEG:
-			op = NEG;
-			break;
-		default:
-			abort();
-		}
-		code(op, lp, NULL);
-		lp->used = 1;
-		np->sym = lp->sym;
-		np->reg = lp->reg;
-		np->op = REG;
-		reguse[A] = np;
-		break;
-	default:
-		abort();
-	}
-}
-
-static void
-cast(Node *np)
-{
-	Node *lp = np->left;
-	uint8_t reg;
-
-	if (lp->type.size != np->type.size)
-		abort();
-	lp->used = 1;
-	np->sym = lp->sym;
-	if ((np->op = lp->op) == REG) {
-		reg = lp->reg;
-		np->reg = reg;
-		reguse[pair[reg]] = reguse[reg] = np;
-	}
-}
-
-static void (*opnodes[])(Node *) = {
-	[OADD] = add,
-	[OSUB] = add,
-	[OASSIG] = assign,
-	[ORET] = ret,
-	[MEM] = nop,
-	[REG] = nop,
-	[AUTO] = nop,
-	[CONST] = nop,
-	[PAR] = nop,
-	[OBOR] = add,
-	[OBAND] = add,
-	[OBXOR] = add,
-	[OCPL] = cpl,
-	[ONEG] = cpl,
-	[OCAST] = cast
-};
-
-static void
-cgen(Node *np)
-{
-	Node *lp, *rp;
-
-	if (!np)
-		return;
-
-	if (np->addable >= ADDABLE)
-		return;
-
-	lp = np->left;
-	rp = np->right;
-	if (!lp) {
-		cgen(rp);
-	} else if (!rp) {
-		cgen(lp);
-	} else {
-		Node *p, *q;
-		if (lp->complex > rp->complex)
-			p = lp, q = rp;
-		else
-			p = rp, q = lp;
-		cgen(p);
-		cgen(q);
-	}
-	(*opnodes[np->op])(np);
-}
-
-void
-generate(void)
-{
-	uint8_t size = curfun->u.f.locals;
-	static short id = 1000;
-	Node **stmt, *np;
-
-	retlabel.id = id++;
-
-	code(PUSH, NULL, &regs[IX]);
-	code(MOV, &regs[IX], &regs[SP]);
-	if (size > 6) {
-		code(MOV, &regs[HL], imm(-size));
-		code(ADD, &regs[HL], &regs[SP]);
-		code(MOV, &regs[SP], &regs[HL]);
-	} else {
-		for (; size != 0; size-= 2)
-			code(PUSH, NULL, &regs[HL]);
-	}
-
-	for (stmt = curfun->u.f.body; np = *stmt; ++stmt)
-		cgen(np);
-
-	code(MOV, &regs[SP], &regs[IX]);
-	retlabel.u.pc = pc;
-	pc->label = &retlabel;
-	code(POP, &regs[IX], NULL);
-	code(RET, NULL, NULL);
-}
-
-/*
- * This is strongly influenced by
- * http://plan9.bell-labs.com/sys/doc/compiler.ps (/sys/doc/compiler.ps)
- * calculate addresability as follows
- *     AUTO => 11          value+fp
- *     REGISTER => 13      register
- *     STATIC => 12        (value)
- *     CONST => 20         $value
- */
-Node *
-genaddable(Node *np)
-{
-	Node *lp, *rp;
-
-	if (!np)
-		return np;
-
-	np->complex = 0;
-	np->addable = 0;
-	lp = np->left;
-	rp = np->right;
-	switch (np->op) {
-	case AUTO:
-		np->addable = 11;
-		break;
-	case REG:
-		np->addable = 13;
-		break;
-	case MEM:
-		np->addable = 12;
-		break;
-	case CONST:
-		np->addable = 20;
-		break;
-	default:
-		if (lp)
-			genaddable(lp);
-		if (rp)
-			genaddable(rp);
-		break;
-	}
-
-	if (np->addable > 10)
-		return np;
-	if (lp)
-		np->complex = lp->complex;
-	if (rp) {
-		int8_t d = np->complex - rp->complex;
-
-		if (d == 0)
-			++np->complex;
-		else if (d < 0)
-			np->complex = rp->complex;
-	}
-	if (np->complex == 0)
-		++np->complex;
-	return np;
-}
-
-void
-addable(void)
-{
-	apply(genaddable);
-}
--- a/cc2.old/code.c
+++ /dev/null
@@ -1,229 +1,0 @@
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <stdio.h>
-
-#include "../inc/cc.h"
-#include "cc2.h"
-
-static char *regnames[] = {
-	[AF] = "AF",
-	[HL] = "HL", [DE] = "DE", [BC] = "BC",
-	[IX] = "IX", [IY] = "IY", [SP] = "SP",
-	[A]  = "A",
-	[B]  = "B", [C]  = "C",
-	[D]  = "D",  [E]  = "E",
-	[H]  = "H",  [L]  = "L",
-	[IYL]= "IYL",[IYH]= "IYH"
-};
-
-static void inst0(void), inst1(void), inst2(void);
-
-static void (*instcode[])(void) = {
-	[LDW] = inst2,
-	[LDL] = inst2,
-	[LDH] = inst2,
-	[LDI] = inst2,
-	[MOV] = inst2,
-	[ADD] = inst2,
-	[PUSH] = inst1,
-	[POP] = inst1,
-	[RET] = inst0,
-	[NOP] = inst0,
-	[INC] = inst1,
-	[SUB] = inst2,
-	[DEC] = inst1,
-	[JP] = inst1,
-	[AND] = inst2,
-	[OR] = inst2,
-	[XOR] = inst2,
-	[CPL] = inst1,
-	[NEG] = inst1
-
-};
-
-static char *insttext[] = {
-	[LDW] = "LD",
-	[LDL] = "LD",
-	[LDH] = "LD",
-	[LDI] = "LD",
-	[MOV] = "LD",
-	[ADD] = "ADD",
-	[PUSH] = "PUSH",
-	[POP] = "POP",
-	[RET] = "RET",
-	[NOP] = "NOP",
-	[INC] = "INC",
-	[SUB] = "SUB",
-	[DEC] = "DEC",
-	[JP] = "JP",
-	[AND] = "AND",
-	[OR] = "OR",
-	[XOR] = "XOR",
-	[CPL] = "CPL",
-	[NEG] = "NEG"
-};
-
-Inst *pc, *prog;
-
-static void
-nextpc(void)
-{
-	Inst *new;
-
-	new = xmalloc(sizeof(*new));
-
-	if (!pc) {
-		new->next = NULL;
-		prog = new;
-	} else {
-		new->next = pc->next;
-		pc->next = new;
-	}
-
-	new->prev = pc;
-	new->to.kind = NONE;
-	new->from.kind = NONE;
-	pc = new;
-}
-
-void
-addr(char op, Node *np, Addr *addr)
-{
-	switch (addr->kind = np->op) {
-	case REG:
-		addr->u.reg = np->reg;
-		break;
-	case CONST:
-		addr->u.i = np->sym->u.imm;
-		break;
-	case AUTO:
-		addr->u.i = np->sym->u.v.off;
-		break;
-	case LABEL:
-	case MEM:
-		addr->u.sym = np->sym;
-		break;
-	case INDEX:
-		break;
-	default:
-		abort();
-	}
-}
-
-void
-code(uint8_t op, Node *to, Node *from)
-{
-
-	nextpc();
-	if (from)
-		addr(op, from, &pc->from);
-	if (to)
-		addr(op, to, &pc->to);
-	pc->op = op;
-}
-
-void
-inscode(uint8_t op, Addr *to, Addr *from)
-{
-	nextpc();
-	if (from)
-		pc->from = *from;
-	if (to)
-		pc->to = *to;
-	pc->op = op;
-}
-
-void
-delcode(void)
-{
-	Inst *prev = pc->prev, *next = pc->next;
-
-	free(pc);
-	if (!prev) {
-		pc = next;
-		prog = NULL;
-	} else {
-		pc = prev;
-		prev->next = next;
-		if (next)
-			next->prev = prev;
-	}
-}
-
-void
-writeout(void)
-{
-	if (!prog)
-		return;
-
-	for (pc = prog; pc; pc = pc->next) {
-		if (pc->label)
-			printf("L%d:", pc->label->id);
-		(*instcode[pc->op])();
-	}
-}
-
-static void
-addr2txt(uint8_t op, Addr *a)
-{
-	Symbol *sym;
-
-	switch (a->kind) {
-	case REG:
-		fputs(regnames[a->u.reg], stdout);
-		break;
-	case CONST:
-		printf("%d", a->u.i);
-		break;
-	case PAR:
-	case AUTO:
-		printf("(IX%+d)", a->u.i);
-		break;
-	case LABEL:
-		sym = a->u.sym;
-		printf("L%d", sym->id);
-		break;
-	case INDEX:
-		fputs("(HL)", stdout);
-		break;
-	case MEM:
-		sym = a->u.sym;
-		if (sym->name)
-			printf((op == LDI) ? "%s" : "(%s)", sym->name);
-		else
-			printf((op == LDI) ? "T%u" : "(T%u)", sym->id);
-		break;
-	default:
-		abort();
-	}
-}
-
-static void
-inst0(void)
-{
-	printf("\t%s\n", insttext[pc->op]);
-}
-
-static void
-inst1(void)
-{
-	uint8_t op = pc->op;
-
-	printf("\t%s\t", insttext[op]);
-	addr2txt(op, (pc->to.kind != NONE) ? &pc->to : &pc->from);
-	putchar('\n');
-}
-
-static void
-inst2(void)
-{
-	uint8_t op = pc->op;
-
-	printf("\t%s\t", insttext[op]);
-	addr2txt(op, &pc->to);
-	putchar(',');
-	addr2txt(op, &pc->from);
-	putchar('\n');
-}
--- a/cc2.old/generror
+++ /dev/null
@@ -1,19 +1,0 @@
-
-BEGIN {
-	print "char *errlist[] = {"
-}
-/^enum nerrors \{/ {
-	inhome = 1
-}
-inhome && /E[A-Z]*, / {
-	sub(/,/, "", $1)
-	printf("\t[%s] = \"", $1)
-	for (i = 3; i < NF-1; ++i)
-		printf("%s ", $i)
-	printf("%s\",\n", $(NF-1));
-}
-inhome && /^}/ {
-	print "};"
-	inhome = 0
-}
-
--- a/cc2.old/main.c
+++ /dev/null
@@ -1,56 +1,0 @@
-
-#include <stdarg.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "../inc/cc.h"
-
-#include "cc2.h"
-#include "error.h"
-
-char odebug;
-
-void
-error(unsigned nerror, ...)
-{
-	va_list va;
-	va_start(va, nerror);
-	if (nerror >= ENUMERR)
-		fprintf(stderr, "incorrect error number '%d'", nerror);
-	else
-		vfprintf(stderr, errlist[nerror], va);
-	va_end(va);
-	putc('\n', stderr);
-	exit(1);
-}
-
-bool
-moreinput(void)
-{
-	int c;
-
-repeat:
-	if (feof(stdin))
-		return 0;
-	if ((c = getchar()) == '\n' || c == EOF)
-		goto repeat;
-	ungetc(c, stdin);
-	return 1;
-}
-
-int
-main(void)
-{
-	fputs("cc2 is not updated with the output of cc1", stderr);
-	exit(1);
-	while (moreinput()) {
-		parse();
-		optimize();
-		addable();
-		generate();
-		peephole();
-		writeout();
-	}
-	return 0;
-}
--- a/cc2.old/optm.c
+++ /dev/null
@@ -1,51 +1,0 @@
-
-#include <stddef.h>
-#include <inttypes.h>
-
-#include "../inc/cc.h"
-#include "cc2.h"
-
-
-#include <stdio.h>
-
-static Node *
-optcasts(Node *np, Type *tp)
-{
-	if (!np)
-		return NULL;
-
-repeat:
-	switch (np->op) {
-	case OCAST:
-		/* TODO: be careful with the sign */
-		if (np->type.flags&INTF && np->type.size >= tp->size) {
-			np = np->left;
-			goto repeat;
-		}
-		break;
-	case OASSIG:
-		tp = &np->type;
-		break;
-	default:
-		if (np->type.size > tp->size)
-			np->type = *tp;
-		break;
-	}
-
-	np->left = optcasts(np->left, tp);
-	np->right = optcasts(np->right, tp);
-	return np;
-}
-
-static Node *
-opt(Node *np)
-{
-	np = optcasts(np, &np->type);
-	return np;
-}
-
-void
-optimize(void)
-{
-	apply(opt);
-}
--- a/cc2.old/parser.c
+++ /dev/null
@@ -1,603 +1,0 @@
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "../inc/cc.h"
-#include "../inc/sizes.h"
-
-#include "cc2.h"
-
-#define MAXLINE 200
-#define NR_STACKSIZ 32
-#define NR_NODEPOOL 128
-#define NR_EXPRESSIONS 64
-
-enum {
-	LOCAL, GLOBAL, PARAMETER
-};
-
-Symbol *curfun;
-static Node *stack[NR_STACKSIZ], **stackp;
-static Node *listexp[NR_EXPRESSIONS], **listp;
-static Node nodepool[NR_NODEPOOL], *newp;
-
-
-static Type Funct = {
-	.letter = L_FUNCTION,
-};
-
-static Type l_int8 = {
-	.letter = L_INT8,
-	.size = 1,
-	.align = 2,
-	.flags = SIGNF | INTF
-};
-
-static Type l_int16 = {
-	.letter = L_INT16,
-	.size = 2,
-	.align = 2,
-	.flags = SIGNF | INTF
-
-};
-
-static Type l_int32 = {
-	.letter = L_INT32,
-	.size = 4,
-	.align = 4,
-	.flags = SIGNF | INTF
-
-};
-
-static Type l_int64 = {
-	.letter = L_INT64,
-	.size = 8,
-	.align = 8,
-	.flags = SIGNF | INTF
-
-};
-
-static Type l_uint8 = {
-	.letter = L_UINT8,
-	.size = 1,
-	.align = 2,
-	.flags =  INTF
-};
-
-static Type l_uint16 = {
-	.letter = L_UINT16,
-	.size = 2,
-	.align = 2,
-	.flags =  INTF
-};
-
-static Type l_uint32 = {
-	.letter = L_UINT32,
-	.size = 4,
-	.align = 4,
-	.flags =  INTF
-};
-
-static Type l_uint64 = {
-	.letter = L_UINT64,
-	.size = 8,
-	.align = 8,
-	.flags =  INTF
-};
-
-static void cast(char *), operator(char *), assignment(char *), increment(char *),
-            globvar(char *), localvar(char *), paramvar(char *), label(char *),
-            immediate(char *), unary(char *), oreturn(char *);
-
-/*TODO: Remove hardcoded symbols */
-
-static void (*optbl[])(char *) = {
-	[L_INT8] = cast,
-	[L_INT16] = cast,
-	[L_INT32] = cast,
-	[L_INT64] = cast,
-	[L_UINT8] = cast,
-	[L_UINT16] = cast,
-	[L_UINT32] = cast,
-	[L_UINT64] = cast,
-	[L_BOOL] = cast,
-	[L_FLOAT] = cast,
-	[L_DOUBLE] = cast,
-	[L_LDOUBLE] = cast,
-	[L_POINTER] = cast,
-	[L_VOID] = cast,
-	['+'] = operator,
-	['%'] = operator,
-	['-'] = operator,
-	['*'] = operator,
-	['/'] = operator,
-	['l'] = operator,
-	['r'] = operator,
-	['&'] = operator,
-	['|'] = operator,
-	['^'] = operator,
-	[':'] = assignment,
-	[';'] = increment,
-	['Y'] = globvar,
-	['A'] = localvar,
-	['K'] = localvar,
-	['T'] = localvar,
-	['G'] = globvar,
-	['P'] = paramvar,
-	['L'] = label,
-	['#'] = immediate,
-	['@'] = unary,
-	['a'] = unary,
-	['<'] = operator,
-	['>'] = operator,
-	[']'] = operator,
-	['['] = operator,
-	['='] = operator,
-	['!'] = unary,
-	['y'] = oreturn,
-	['j'] = NULL,
-	['o'] = operator,
-	['_'] = unary,
-	['~'] = unary,
-	[','] = operator,
-	['\177'] = NULL
-};
-
-static void
-prnode(Node *np)
-{
-	if (np->left)
-		prnode(np->left);
-	if (np->right)
-		prnode(np->right);
-	fprintf(stderr, "\t%c%c", np->op, np->type.letter);
-}
-
-void
-prtree(Node *np)
-{
-	prnode(np);
-	putc('\n', stderr);
-}
-
-void
-apply(Node *(*fun)(Node *))
-{
-	Node **list, *np;
-
-	for (list = curfun->u.f.body; np = *list; ++list)
-		*list++ = (*fun)(np);
-}
-
-static Symbol *
-parameter(char *num)
-{
-	static Symbol tbl[NR_FUNPARAM];
-	Symbol *sym;
-	unsigned i = atoi(num);
-
-	if (!curfun)
-		error(ESYNTAX);
-	if (i >= NR_FUNPARAM)
-		error(EPARNUM);
-	sym = &tbl[i];
-	sym->id = i;
-	return sym;
-}
-
-static Symbol *
-local(char *num)
-{
-	static Symbol tbl[NR_INT_IDENT];
-	Symbol *sym;
-	unsigned i = atoi(num);
-
-	if (!curfun)
-		error(ESYNTAX);
-	if (i >= NR_INT_IDENT)
-		error(EINTNUM);
-	sym = &tbl[i];
-	sym->id = i;
-	return sym;
-}
-
-static Symbol *
-global(char *num)
-{
-	static Symbol tbl[NR_EXT_IDENT];
-	Symbol *sym;
-	unsigned i = atoi(num);
-
-	if (i >= NR_EXT_IDENT)
-		error(EEXTNUM);
-
-	sym = &tbl[i];
-	sym->id = i;
-	return sym;
-}
-
-static Node *
-newnode(void)
-{
-	if (newp == &nodepool[NR_NODEPOOL])
-		error(ENODEOV);
-	return newp++;
-}
-
-Node *
-imm(TINT i)
-{
-	Node *np = newnode();
-
-	np->op = CONST;
-	np->type = l_int16;
-	/* FIX: memory leak */
-	np->sym = xmalloc(sizeof(Symbol));
-	np->sym->u.imm = i;
-	np->left = np->right = NULL;
-	return np;
-}
-
-static void
-push(Node *np)
-{
-	if (stackp == &stack[NR_STACKSIZ])
-		error(ESTACKO);
-	*stackp++ = np;
-}
-
-static Node *
-pop(void)
-{
-	if (stackp == stack)
-		error(ESTACKU);
-	return *--stackp;
-}
-
-static Type *
-gettype(char *type)
-{
-	switch (type[0]) {
-	case L_INT8:
-		return &l_int8;
-	case L_INT16:
-		return &l_int16;
-	case L_INT32:
-		return &l_int32;
-	case L_INT64:
-		return &l_int64;
-	case L_UINT8:
-		return &l_uint8;
-	case L_UINT16:
-		return &l_uint16;
-	case L_UINT32:
-		return &l_uint32;
-	case L_UINT64:
-		return &l_uint64;
-	case L_FUNCTION:
-		return &Funct;
-	default:
-		error(ETYPERR);
-	}
-}
-
-static Symbol *
-symbol(uint8_t t, char *token)
-{
-	Symbol *sym;
-	static Symbol *(*tbl[3])(char *)= {
-		[LOCAL] = local,
-		[GLOBAL] = global,
-		[PARAMETER] = parameter
-	};
-	sym = (*tbl[t])(token+1);
-	sym->kind = *token;
-	return sym;
-}
-
-static void
-variable(uint8_t t, char *token)
-{
-	Node *np = newnode();
-	Symbol *sym = symbol(t, token);
-
-	np->sym = sym;
-	np->op = sym->u.v.sclass;
-	np->type = sym->u.v.type;
-	np->left = np->right = NULL;
-	push(np);
-}
-
-static void
-localvar(char *token)
-{
-	variable(LOCAL, token);
-}
-
-static void
-globvar(char *token)
-{
-	variable(GLOBAL, token);
-}
-
-static void
-paramvar(char *token)
-{
-	variable(PARAMETER, token);
-}
-
-static void
-immediate(char *token)
-{
-	/* TODO: check type of immediate */
-	push(imm(atoi(token+2)));
-}
-
-static void
-unary(char *token)
-{
-	Node *np = newnode();
-
-	np->right = NULL;
-	np->left = pop();
-	np->type = *gettype(token+1);
-	np->op = token[0];
-	push(np);
-}
-
-static void
-operator(char *token)
-{
-	Node *np = newnode();
-
-	np->right = pop();
-	np->left = pop();
-	np->type = *gettype(token+1);
-	np->op = token[0];
-	push(np);
-}
-
-static void
-label(char *token)
-{
-	Node *np = newnode();
-
-	np->left = np->right = NULL;
-	np->op = LABEL;
-	np->sym = local(token);
-	push(np);
-}
-
-static void
-increment(char *token)
-{
-	Node *np = newnode();
-
-	np->right = pop();
-	np->left = pop();
-	np->type = *gettype(token+2);
-	np->op = token[0];
-	switch (np->subop = token[1]) {
-	case '-': case '+':
-		push(np);
-		break;
-	default:
-		error(ESYNTAX);
-	}
-}
-
-static void
-assignment(char *token)
-{
-	Node *np = newnode();
-
-	np->right = pop();
-	np->left = pop();
-	np->op = *token;
-	switch (*++token) {
-	case OADD: case OSUB: case OINC:  case OMOD: case ODIV:
-	case OSHL: case OSHR: case OBAND: case OBOR: case OBXOR:
-		np->subop = *++token;
-	default:
-		np->type = *gettype(token);
-		break;
-	}
-	push(np);
-}
-
-static void
-cast(char *token)
-{
-	Node *np = newnode();
-
-	np->right = NULL;
-	np->left = pop();
-	np->op = OCAST;
-	np->type = *gettype(token+1);
-	push(np);
-}
-
-static void
-expr(char *token)
-{
-	void (*fun)(char *);
-	unsigned c;
-
-	do {
-		if ((c = token[0]) > 0x7f || (fun = optbl[c]) == NULL)
-			error(ESYNTAX);
-		(*fun)(token);
-	} while (token = strtok(NULL, "\t"));
-}
-
-static void
-expression(char *token)
-{
-	Node *np;
-
-	if (!curfun)
-		error(ESYNTAX);
-
-	expr(token);
-
-	np = pop();
-	if (stackp != stack)
-		error(EEXPBAL);
-	if (listp == &listexp[NR_EXPRESSIONS])
-		error(EEXPROV);
-	*listp++ = np;
-}
-
-static void
-oreturn(char *token)
-{
-	Node *np = newnode(), *lp;
-
-	np->op = token[0];
-
-	if (token = strtok(NULL, "\t")) {
-		expr(token);
-		lp = pop();
-		np->left = lp;
-		np->type = lp->type;
-	} else {
-		np->left = NULL;
-	}
-	np->right = NULL;
-	push(np);
-}
-
-static void
-deflabel(char *token)
-{
-	Symbol *sym;
-
-	if (!curfun)
-		error(ESYNTAX);
-	sym = local(token);
-}
-
-static Symbol *
-declaration(uint8_t t, char class, char *token)
-{
-	Symbol *sym = symbol(t, token);
-	char *s;
-
-	free(sym->name);
-	memset(sym, 0, sizeof(*sym));
-	sym->u.v.sclass = class;
-
-	if ((s = strtok(NULL, "\t")) == NULL)
-		error(ESYNTAX);
-	sym->u.v.type = *gettype(s);
-	if ((s = strtok(NULL, "\t")) != NULL)
-		sym->name = xstrdup(s);
-
-	return sym;
-}
-
-static void
-globdcl(char *token)
-{
-	Symbol *sym = declaration(GLOBAL, MEM, token);
-
-	switch (token[0]) {
-	case 'X':
-		sym->extrn = 1;
-		break;
-	case 'G':
-		sym->public = 1;
-		break;
-	}
-
-	if (sym->u.v.type.letter != L_FUNCTION)
-		return;
-
-	if (curfun)
-		error(ESYNTAX);
-
-	curfun = sym;
-	sym->u.f.body = listp = listexp;
-	newp = nodepool;
-}
-
-static void
-paramdcl(char *token)
-{
-	Symbol *sym = declaration(PARAMETER, AUTO, token);
-	sym->u.v.off = -curfun->u.f.params;
-	curfun->u.f.params += sym->u.v.type.size;
-}
-
-static void
-localdcl(char *token)
-{
-	Symbol *sym = declaration(LOCAL, token[0], token);
-	char sclass = *token;
-
-	if (sclass == 'A' || sclass == 'R') {
-		uint8_t size = sym->u.v.type.size;
-		/* stack elements are 2 byte multiple */
-		if (size == 1)
-			++size;
-		curfun->u.f.locals += size;
-		sym->u.v.off = curfun->u.f.locals;
-	}
-}
-
-void
-parse(void)
-{
-	void (*fun)(char *tok);
-	uint8_t len;
-	int c;
-	char line[MAXLINE];
-
-	curfun = NULL;
-	stackp = stack;
-	listp = listexp;
-	newp = nodepool;
-
-	for (;;) {
-		switch (c = getchar()) {
-		case 'L':
-			fun = deflabel;
-			break;
-		case '\t':
-			fun = expression;
-			break;
-		case 'S':
-			/* TODO: struct */
-			break;
-		case 'P':
-			fun = paramdcl;
-			break;
-		case 'A': case 'R': case 'T':
-			fun = localdcl;
-			break;
-		case 'Y': case 'G':
-			fun = globdcl;
-			break;
-		case '}':
-			if (curfun)
-				return;
-		default:
-			goto syntax_error;
-		}
-
-		ungetc(c, stdin);
-		if (!fgets(line, sizeof(line), stdin))
-			break;
-		len = strlen(line);
-		if (line[len-1] != '\n')
-			error(ELNLINE);
-		line[len-1] = '\0';
-		(*fun)(strtok(line, "\t"));
-	}
-
-syntax_error:
-	error(ESYNTAX);
-}
--- a/cc2.old/peep.c
+++ /dev/null
@@ -1,39 +1,0 @@
-
-#include <inttypes.h>
-#include <stddef.h>
-
-#include "../inc/cc.h"
-#include "cc2.h"
-
-void
-peephole(void)
-{
-	Addr to, from;
-	TINT i;
-	uint8_t op;
-
-	for (pc = prog; pc; pc = pc->next) {
-		to = pc->to;
-		from = pc->from;
-
-		switch (pc->op) {
-		case SUB:
-		case ADD:
-			if (from.kind == CONST) {
-				if ((i = from.u.i) == 0 || i < 4) {
-					delcode();
-					op = (pc->op == ADD) ? INC : DEC;
-
-					while (i--)
-						inscode(op, &to, NULL);
-				}
-			/* TODO: More optimizations (ex: -1) */
-			}
-			break;
-		case JP:
-			if (to.u.sym->u.pc == pc->next)
-				delcode();
-			break;
-		}
-	}
-}
--- a/cc2/cc2.h
+++ b/cc2/cc2.h
@@ -81,7 +81,7 @@
 	OBXOR    = '^',
 	OCPL     = '~',
 	OASSIG   = ':',
-	ONEG     = '_',
+	OSNEG    = '_',
 	OCALL    = 'c',
 	OPAR     = 'p',
 	OFIELD   = '.',
@@ -91,12 +91,13 @@
 	OADDR    = '\'',
 	OAND     = 'a',
 	OOR      = 'o',
+	ONEG     = 'n',
 	OPTR     = '@',
 	OCAST    = 'g',
 	OINC     = 'i',
 	ODEC     = 'd',
 	/*statements */
-	ONOP     = 'n',
+	ONOP     = 'q',
 	OJMP     = 'j',
 	OBRANCH  = 'y',
 	ORET     = 'h',
--- a/cc2/parser.c
+++ b/cc2/parser.c
@@ -92,11 +92,12 @@
 	['\t']  = {     stmt,    NULL,                     0},
 
 	['~']   = {     NULL,   unary, .u.op =          OCPL},
-	['_']   = {     NULL,   unary, .u.op =          ONEG},
+	['_']   = {     NULL,   unary, .u.op =         OSNEG},
 	['\'']  = {     NULL,   unary, .u.op =         OADDR},
 	['@']   = {     NULL,   unary, .u.op =          OPTR},
 	['g']   = {     NULL,   unary, .u.op =         OCAST},
 	['p']   = {     NULL,   unary, .u.op =          OPAR},
+	['n']   = {     NULL,   unary, .u.op =          ONEG},
 
 	['a']   = {     NULL,  binary, .u.op =          OAND},
 	['o']   = {     NULL,  binary, .u.op =           OOR},
--- a/libc/include/amd64-sysv/assert.h
+++ b/libc/include/amd64-sysv/assert.h
@@ -3,7 +3,7 @@
 #define _ASSERT_H
 
 #ifndef NDEBUG
-#define assert(exp) __assert(#exp, __FILE__, __LINE__)
+#define assert(exp) __assert(exp, #exp, __FILE__, __LINE__)
 #endif
 
 #endif
--- a/libc/include/amd64-sysv/stdio.h
+++ b/libc/include/amd64-sysv/stdio.h
@@ -75,5 +75,5 @@
 extern FILE *tmpfile(void);
 extern FILE *tmpnam(char *s);
 
-extern FILE *stdin, *stdio, *stderr;
+extern FILE *stdin, *stdout, *stderr;
 #endif
--- a/libc/include/i386-sysv/assert.h
+++ b/libc/include/i386-sysv/assert.h
@@ -3,7 +3,7 @@
 #define _ASSERT_H
 
 #ifndef NDEBUG
-#define assert(exp) __assert(#exp, __FILE__, __LINE__)
+#define assert(exp) __assert(exp, #exp, __FILE__, __LINE__)
 #endif
 
 #endif
--- a/libc/include/i386-sysv/stdio.h
+++ b/libc/include/i386-sysv/stdio.h
@@ -75,5 +75,5 @@
 extern FILE *tmpfile(void);
 extern FILE *tmpnam(char *s);
 
-extern FILE *stdin, *stdio, *stderr;
+extern FILE *stdin, *stdout, *stderr;
 #endif
--- a/libc/include/qbe/assert.h
+++ b/libc/include/qbe/assert.h
@@ -3,7 +3,7 @@
 #define _ASSERT_H
 
 #ifndef NDEBUG
-#define assert(exp) __assert(#exp, __FILE__, __LINE__)
+#define assert(exp) __assert(exp, #exp, __FILE__, __LINE__)
 #endif
 
 #endif
--- a/libc/include/qbe/stdio.h
+++ b/libc/include/qbe/stdio.h
@@ -75,5 +75,5 @@
 extern FILE *tmpfile(void);
 extern FILE *tmpnam(char *s);
 
-extern FILE *stdin, *stdio, *stderr;
+extern FILE *stdin, *stdout, *stderr;
 #endif
--- a/libc/include/z80/assert.h
+++ b/libc/include/z80/assert.h
@@ -3,7 +3,7 @@
 #define _ASSERT_H
 
 #ifndef NDEBUG
-#define assert(exp) __assert(#exp, __FILE__, __LINE__)
+#define assert(exp) __assert(exp, #exp, __FILE__, __LINE__)
 #endif
 
 #endif
--- a/libc/include/z80/stdio.h
+++ b/libc/include/z80/stdio.h
@@ -75,5 +75,5 @@
 extern FILE *tmpfile(void);
 extern FILE *tmpnam(char *s);
 
-extern FILE *stdin, *stdio, *stderr;
+extern FILE *stdin, *stdout, *stderr;
 #endif