shithub: scc

Download patch

ref: 79059d14d5c6a36a81e74697aabdab5901c59b5c
parent: 828528f9e6b85837d6b804aac5cbc18f97116bfb
parent: 348cbf56cdf4a39bf18b451ecd32e2df57b86fb1
author: Roberto E. Vargas Caballero <[email protected]>
date: Sun Feb 15 14:40:01 EST 2015

Merge remote-tracking branch 'gitorius/master'

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -26,6 +26,7 @@
 	NS_IDEN = 0,
 	NS_TAG,
 	NS_LABEL,
+	NS_STRUCTS,
 	NR_NAMESPACES
 };
 
@@ -32,31 +33,19 @@
 typedef struct ctype Type;
 typedef struct symbol Symbol;
 
-typedef struct field {
-	char *name;
-	Type *type;
-	int id;
-	struct field *next;
-} Field;
-
-typedef struct funpar {
-	Type *type;
-	struct funpar *next;
-} Funpar;
-
 struct ctype {
 	uint8_t op;           /* type builder operator */
+	uint8_t ns;
 	char letter;          /* letter of the type */
-	bool defined : 1; /* type defined (is not a forward reference) */
-	bool sign : 1;    /* sign type */
+	bool defined : 1;     /* type defined (is not a forward reference) */
+	bool sign : 1;        /* sign type */
 	struct ctype *type;   /* base type */
 	struct ctype *next;   /* next element in the hash */
-	union typeval {
-		unsigned char rank;   /* convertion rank */
-		short nelem;          /* number of elements in arrays */
-		struct funpar *pars;  /* function parameters */
-		Field *fields; /* aggregate fields */
-	} u;
+	Type **pars;         /* type parameters */
+	union {
+		unsigned char rank;  /* convertion rank */
+		short elem;          /* number of type parameters */
+	} n;
 };
 
 
@@ -67,18 +56,18 @@
 	Type *type;
 	short id;
 	uint8_t ctx;
+	uint8_t ns;
 	uint8_t token;
-	struct {
-		bool isglobal : 1;
-		bool isstatic : 1;
-		bool isauto : 1;
-		bool isregister : 1;
-		bool isdefined : 1;
-	} s;
+	bool isglobal : 1;
+	bool isstatic : 1;
+	bool isauto : 1;
+	bool isregister : 1;
+	bool isdefined : 1;
+	bool isfield : 1;
+	bool isparameter : 1;
 	union {
 		int i;
 		char *s;
-		struct symbol *sym;
 		uint8_t token;
 	} u;
 	struct symbol *next;
@@ -87,17 +76,17 @@
 
 extern bool eqtype(Type *tp1, Type *tp2);
 extern Type *ctype(int8_t type, int8_t sign, int8_t size),
-	*mktype(Type *tp, uint8_t op, void *data);
+	*mktype(Type *tp, uint8_t op, short nelem, void *data);
 
 extern Symbol
 	*lookup(char *s, unsigned char ns),
 	*install(char *s, unsigned char ns);
 
+extern void pushctx(void), popctx(void);
+
 typedef struct caselist Caselist;
 
 extern void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
-extern Type *aggregate(Type *(*fun)(void));
-extern void context(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
 
 extern Type *typename(void);
 
@@ -157,6 +146,7 @@
 	void (*code)(struct node *);
 	Type *type;
 	uint8_t typeop;
+	uint8_t nchilds;
 	struct {
 		bool lvalue : 1;
 		bool symbol: 1;
@@ -166,7 +156,6 @@
 		Symbol *sym;
 		Type *type;
 		char op;
-		Field *field;
 	} u;
 	struct node *childs[];
 } Node;
@@ -178,11 +167,13 @@
 	OA_MOD, OA_ADD, OA_SUB, OA_SHL, OA_SHR,
 	OA_AND, OA_XOR, OA_OR, OADDR,ONEG, OCPL, OEXC,
 	OCOMMA,
+	/* TODO: This order is important, but must be changed */
+	OAND, OOR,
 	/*
 	  * Complementary relational operators only differ in less
 	 * significant bit
 	 */
-	OEQ = 0x40, ONE, OLT, OGE, OLE, OGT, OAND, OOR
+	OEQ = 0x40, ONE, OLT, OGE, OLE, OGT
 };
 
 extern void
@@ -194,7 +185,8 @@
 	emitswitch(short, Node *), emitcase(Symbol *, Node *),
 	emitret(Type *tp),
 	emitfun(Symbol *sym),
-	emitdefault(Symbol *);
+	emitdefault(Symbol *),
+	emitstruct(Symbol *sym), emitestruct(void);
 
 extern Node
 	*node(void (*code)(Node *),
@@ -205,12 +197,15 @@
 	*sizeofcode(Type *tp), 
 	*ternarycode(Node *cond, Node *ifyes, Node *ifno),
 	*symcode(Symbol *sym),
-	*fieldcode(Node *child, struct field *fp);
+	*fieldcode(Node *child, Symbol *field);
 
+extern void freetree(Node *np);
+
 #define NEGATE(n, v) ((n)->u.op ^= (v))
 /* TODO: remove some of these ugly macros */
 #define ISNODEBIN(n) ((n)->code == emitbin)
-#define ISNODECMP(n) (ISNODEBIN(n) && (n)->u.op & 0x40)
+#define ISNODECMP(n) (ISNODEBIN(n) && (n)->u.op >= OEQ)
+#define ISNODELOG(n) (ISNODEBIN(n) && (n)->u.op >= OAND)
 
 extern Node *expr(void);
 extern void extdecl(void), decl(void);
--- a/cc1/code.c
+++ b/cc1/code.c
@@ -1,6 +1,7 @@
 
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <cc.h>
 #include "cc1.h"
@@ -58,6 +59,7 @@
 	np->code = code;
 	np->type = tp;
 	np->typeop = tp->op;
+	np->nchilds = nchilds;
 	np->u = u;
 	np->b.symbol = np->b.lvalue = 0;
 
@@ -64,19 +66,36 @@
 	return np;
 }
 
+void
+freetree(Node *np)
+{
+	Node **p;
+
+	if (!np)
+		return;
+
+	for (p = np->childs; np->nchilds--; ++p)
+		freetree(*p);
+	free(np);
+}
+
 static void
-emitsym2(Symbol *sym)
+emitvar(Symbol *sym)
 {
 	char c;
 
-	if (sym->s.isstatic && !sym->s.isglobal)
+	if (sym->isstatic && !sym->isglobal)
 		c = 'T';
-	else if (sym->s.isstatic && sym->s.isglobal)
+	else if (sym->isstatic && sym->isglobal)
 		c = 'Y';
-	else if (sym->s.isglobal)
+	else if (sym->isglobal)
 		c = 'G';
-	else if (sym->s.isregister)
-		c = 'Q';
+	else if (sym->isregister)
+		c = 'R';
+	else if (sym->isfield)
+		c = 'M';
+	else if (sym->isparameter)
+		c = 'P';
 	else
 		c = 'A';
 	printf("%c%d", c, sym->id);
@@ -98,10 +117,22 @@
 }
 
 void
+emitstruct(Symbol *sym)
+{
+	printf("S%d\t(\n", sym->id);
+}
+
+void
+emitestruct(void)
+{
+	puts(")");
+}
+
+void
 emitsym(Node *np)
 {
 	putchar('\t');
-	(np->b.constant) ? emitconst(np) : emitsym2(np->u.sym);
+	(np->b.constant) ? emitconst(np) : emitvar(np->u.sym);
 }
 
 static void
@@ -113,7 +144,7 @@
 void
 emitdcl(Symbol *sym)
 {
-	emitsym2(sym);
+	emitvar(sym);
 	putchar('\t');
 	emittype(sym->type);
 	putchar('\n');
@@ -185,6 +216,7 @@
 {
 	(*np->code)(np);
 	printf("\tk%c\n", np->type->letter);
+	fflush(stdout);
 }
 
 void
@@ -191,7 +223,7 @@
 emitfun(Symbol *sym)
 {
 	printf("%c%d\tF\t%s\t{\n",
-	       sym->s.isglobal ? 'G' : 'Y', sym->id, sym->name);
+	       sym->isglobal ? 'G' : 'Y', sym->id, sym->name);
 }
 
 void
@@ -264,14 +296,14 @@
 
 	child = np->childs[0];
 	(*child->code)(child);
-
-	printf("\tM%d", np->u.field->id);
+	putchar('\t');
+	emitvar(np->u.sym);
 }
 
 Node *
-fieldcode(Node *child, struct field *fp)
+fieldcode(Node *child, Symbol *field)
 {
-	Node *np = node(emitfield, fp->type, FIELD(fp), 1);
+	Node *np = node(emitfield, field->type, SYM(field), 1);
 	np->childs[0] = child;
 	return np;
 }
@@ -284,7 +316,7 @@
 	np->childs[0] = child;
 	return np;
 }
-	
+
 Node *
 unarycode(char op, Type *tp, Node *child)
 {
--- a/cc1/decl.c
+++ b/cc1/decl.c
@@ -15,20 +15,18 @@
 
 struct dcldata {
 	uint8_t op;
-	union dclunion {
-		unsigned short nelem;
-		Symbol *sym;
-		Funpar *pars;
-	} u;
+	unsigned short nelem;
+	void *data;
 };
 
 static struct dcldata *
-queue(struct dcldata *dp, uint8_t op, union dclunion u)
+queue(struct dcldata *dp, uint8_t op, short nelem, void *data)
 {
 	if (dp->op == 255)
 		error("too much declarators");
 	dp->op = op;
-	dp->u = u;
+	dp->nelem = nelem;
+	dp->data = data;
 	return dp + 1;
 }
 
@@ -37,78 +35,88 @@
 {
 	expect('[');
 	expect(']');
-	return queue(dp, ARY, (union dclunion) {.nelem = 0});
+	return queue(dp, ARY, 0, NULL);
 }
 
-static Type *parameter(void);
+static Symbol *parameter(void);
 
 static struct dcldata *
 fundcl(struct dcldata *dp)
 {
-	uint8_t n = 0;
-	Funpar *fp;
+	size_t siz;
+	uint8_t n, i, noname;
+	Type *pars[NR_FUNPARAM], **tp = pars;
+	Symbol *syms[NR_FUNPARAM], **sp = syms, *sym;
 
+	pushctx();
 	expect('(');
 
+	n = noname = 0;
 	do {
-		Type *tp;
-
-		if ((tp = parameter()) == voidtype) {
+		if ((sym = parameter()) == NULL) {
 			if (n == 0)
 				break;
-			else
-				error("incorrect void parameter");
+			error("incorrect void parameter");
 		}
-		/* TODO: Use an array and allocate memory at the end */
-		fp = xmalloc(sizeof(*fp));
-		fp->type = tp;
-		fp->next = NULL;
-		if (!dp->u.pars) {
-			dp->u.pars = fp;
-		} else {
-			register Funpar *p, *q;
-
-			for (p = dp->u.pars; q = p->next; p = q)
-				/* nothing */;
-			p->next = fp;
-		}
-		++n;
+		if (n++ == NR_FUNPARAM)
+			error("too much parameters in function definition");
+		*sp++ = sym;
+		*tp++ = sym->type;
+		noname |= sym->name[0] == '\0';
 	} while (accept(','));
 
-ret:
-	expect(')');;
-	return queue(dp, FTN, (union dclunion) {.pars = fp});
+	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)
+			emitdcl(*sp++);
+	}
+
+	return queue(dp, FTN, n, tp);
 }
 
 static Symbol *
-newiden(void)
+newiden(uint8_t ns)
 {
 	Symbol *sym;
 	extern uint8_t curctx;
 
-	if (yylval.sym && yylval.sym->ctx == curctx)
+	if (yylval.sym && yylval.sym->ctx == curctx && yylval.sym->ns == ns)
 		error("redeclaration of '%s'", yytext);
-	sym = install(yytext, NS_IDEN);
+	sym = install(yytext, ns);
 	next();
 	return sym;
 }
 
-static struct dcldata *declarator0(struct dcldata *dp);
+static struct dcldata *declarator0(struct dcldata *dp, uint8_t ns);
 
 static struct dcldata *
-directdcl(struct dcldata *dp)
+directdcl(struct dcldata *dp, uint8_t ns)
 {
 	register Symbol *sym;
 
 	if (accept('(')) {
-		dp = declarator0(dp);
+		dp = declarator0(dp, ns);
 		expect(')');
 	} else {
 		if (yytoken == IDEN || yytoken == TYPEIDEN)
-			sym = newiden();
+			sym = newiden(ns);
 		else
-			sym = install("", NS_IDEN);
-		dp = queue(dp, IDEN, (union dclunion) {.sym = sym});
+			sym = install("", ns);
+		dp = queue(dp, IDEN, 0, sym);
 	}
 
 	for (;;) {
@@ -121,7 +129,7 @@
 }
 
 static struct dcldata*
-declarator0(struct dcldata *dp)
+declarator0(struct dcldata *dp, uint8_t ns)
 {
 	register uint8_t  n;
 
@@ -130,16 +138,16 @@
 			/* nothing */;
 	}
 
-	dp = directdcl(dp);
+	dp = directdcl(dp, ns);
 
 	while (n--)
-		dp = queue(dp, PTR, (union dclunion) {});
+		dp = queue(dp, PTR, 0, NULL);
 
 	return dp;
 }
 
 static Symbol *
-declarator(Type *tp, int8_t flags)
+declarator(Type *tp, int8_t flags, uint8_t ns)
 {
 	struct dcldata data[NR_DECLARATORS+2];
 	register struct dcldata *bp;
@@ -147,19 +155,11 @@
 
 	memset(data, 0, sizeof(data));
 	data[NR_DECLARATORS].op = 255;
-	for (bp = declarator0(data); bp >= data; --bp) {
-		switch (bp->op) {
-		case PTR:
-			tp = mktype(tp, PTR, NULL);
-			break;
-		case ARY:
-			tp = mktype(tp, ARY, &bp->u.nelem);
-			break;
-		case FTN:
-			tp = mktype(tp, FTN, bp->u.pars);
-			break;
-		case IDEN:
-			sym = bp->u.sym;
+	for (bp = declarator0(data, ns)-1; bp >= data; --bp) {
+		if (bp->op != IDEN) {
+			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')
@@ -231,7 +231,7 @@
 		if (dcl) {
 			if (size || sign)
 				goto invalid_type;
-			tp = aggregate(dcl);
+			tp = (*dcl)();
 		} else {
 			next();
 		}
@@ -253,9 +253,7 @@
 static struct node *
 initializer(Symbol *sym)
 {
-	register Type *tp = sym->type;
-
-	if (!sym->s.isdefined)
+	if (!sym->isdefined)
 		error("'%s' initialized and declared extern", sym->name);
 
 	if (accept('{')) {
@@ -266,72 +264,14 @@
 			expr();
 		} while (accept(','));
 	}
+	return NULL;
 }
 
-/* TODO: bitfields */
-
-static void
-newfield(Type *tp, Symbol *sym)
-{
-	register Field *p, *q;
-	register char *s, *t;
-
-	s = sym->name;
-	for (q = p = tp->u.fields; p; q = p, p = p->next) {
-		t = p->name;
-		if (*s == *t && !strcmp(s, t))
-			error("duplicated fields '%s' and '%s'", s, t);
-		if (sym->u.i == p->id)
-			error("duplicated enumeration fields '%s' and '%s'",
-			      s, t);
-	}
-
-	p = xmalloc(sizeof(*p));
-	p->name = xstrdup(s);
-	p->next = NULL;
-	p->id = sym->id;
-	p->type = sym->type;
-	if (!q)
-		tp->u.fields = p;
-	else
-		q->next = p;
-
-	return;
-}
-
-static void
-fielddcl(Type *base)
-{
-	Type *tp;
-	Symbol *sym;
-
-	switch (yytoken) {
-	case SCLASS:
-		error("storage class '%s' in struct/union field", yytext);
-	case IDEN: case TYPE: case TYPEIDEN: case TQUALIFIER:
-		tp = specifier(NULL);
-	case ';':
-		break;
-	default:
-		unexpected();
-	}
-
-	if (yytoken != ';') {
-		do {
-			sym = declarator(tp, ID_EXPECTED);
-			newfield(base, sym);
-		} while (accept(','));
-	}
-
-	expect(';');
-	return;
-}
-
-static Type *
+static Symbol *
 newtag(uint8_t tag)
 {
 	register Symbol *sym;
-	register Type *tp;
+	static uint8_t ns = NS_STRUCTS;
 
 	switch (yytoken) {
 	case IDEN: case TYPEIDEN:
@@ -343,32 +283,81 @@
 		sym = install("", NS_TAG);
 		break;
 	}
-	if (!sym->type)
-		sym->type = mktype(NULL, tag, NULL);
-	tp = sym->type;
-	if (tp->op != tag)
+	if (!sym->type) {
+		if (ns == NS_STRUCTS + NR_MAXSTRUCTS)
+			error("too much tags declared");
+		sym->type = mktype(NULL, tag, 0, NULL);
+		sym->type->ns = ns++;
+	}
+	
+	if (sym->type->op != tag)
 		error("'%s' defined as wrong kind of tag", yytext);
-	return tp;
+	return sym;
 }
 
+/* TODO: bitfields */
+
 static Type *
 structdcl(void)
 {
-	Type *tp;
-	uint8_t tag;
+	Type *tagtype, *buff[NR_MAXSTRUCTS], **bp = &buff[0];
+	Symbol *tagsym, *sym;
+	uint8_t tag, n;
+	size_t siz;
 
 	tag = yylval.token;
 	next();
-	tp = newtag(tag);
-	if (accept('{')) {
-		if (tp->defined)
-			error("redefinition of struct/union '%s'", yytext);
-		tp->defined = 1;
-		while (!accept('}'))
-			fielddcl(tp);
+	tagsym = newtag(tag);
+	tagtype = tagsym->type;
+	if (!accept('{'))
+		return tagtype;
+
+	if (tagtype->defined)
+		error("redefinition of struct/union '%s'", yytext);
+	tagtype->defined = 1;
+	emitstruct(tagsym);
+
+	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->isfield = 1;
+			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;
+			emitdcl(sym);
+		} while (accept(','));
+		expect(';');
 	}
 
-	return tp;
+	emitestruct();
+	if ((n = bp - buff) != 0) {
+		siz = sizeof(Type *) * n;
+		tagtype->n.elem = n;
+		tagtype->pars = memcpy(xmalloc(siz), buff, siz);
+	}
+	return tagtype;
 }
 
 static Type *
@@ -379,7 +368,8 @@
 	int val = 0;
 
 	next();
-	tp = newtag(ENUM);
+	tp = newtag(ENUM)->type;
+
 	if (yytoken == ';')
 		return tp;
 
@@ -390,12 +380,11 @@
 	while (yytoken != '}') {
 		if (yytoken != IDEN)
 			unexpected();
-		sym = newiden();
+		sym = newiden(NS_IDEN);
 		sym->type = inttype;
 		if (accept('='))
 			initializer(sym);
 		sym->u.i = val++;
-		newfield(tp, sym);
 		if (!accept(','))
 			break;
 	}
@@ -404,7 +393,7 @@
 	return tp;
 }
 
-static Type *
+static Symbol *
 parameter(void)
 {
 	Symbol *sym;
@@ -412,21 +401,25 @@
 	Type *tp;
 
 	if ((tp = specifier(&sclass)) == voidtype)
-		return tp;
-	sym = declarator(tp, ID_ACCEPTED);
-	sym->s.isdefined = 1;
-	/* TODO: check type of the parameter */
+		return NULL;
+	sym = declarator(tp, ID_ACCEPTED, NS_IDEN);
+	sym->isparameter = 1;
+	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->s.isregister = 1;
+		sym->isregister = 1;
 		break;
 	case 0:
-		sym->s.isauto = 1;
+		sym->isauto = 1;
 		break;
 	default:
 		error("bad storage class in function parameter");
 	}
-	return sym->type;
+	return sym;
 }
 
 void
@@ -441,9 +434,8 @@
 		return;
 
 	do {
-		sym = declarator(tp, ID_EXPECTED);
-		sym->s.isdefined = 1;
-		isfun = sym->type->op != FTN;
+		sym = declarator(tp, ID_EXPECTED, NS_IDEN);
+		isfun = sym->type->op == FTN;
 
 		switch (sclass) {
 		case TYPEDEF:
@@ -450,13 +442,13 @@
 			sym->token = TYPEIDEN;
 			continue;
 		case STATIC:
-			sym->s.isstatic = 1;
+			sym->isstatic = 1;
 			break;
 		case EXTERN:
-			sym->s.isdefined = 0;
+			sym->isdefined = 0;
 			break;
 		case REGISTER:
-			sym->s.isregister = 1;
+			sym->isregister = 1;
 			if (isfun)
 				goto bad_function;
 			break;
@@ -465,7 +457,7 @@
 				goto bad_function;
 			/* passtrough */
 		default:
-			sym->s.isauto = 1;
+			sym->isauto = 1;
 			break;
 		}
 		if (accept('='))
@@ -490,7 +482,7 @@
 	tp = specifier(&sclass);
 	if (sclass)
 		error("class storage in type name");
-	sym = declarator(tp, ID_FORBIDDEN);
+	sym = declarator(tp, ID_FORBIDDEN, NS_IDEN);
 	return  sym->type;
 }
 
@@ -508,20 +500,19 @@
 		if (accept(';'))
 			return;
 		do {
-			sym = declarator(base, ID_EXPECTED);
+			sym = declarator(base, ID_EXPECTED, NS_IDEN);
 			tp = sym->type;
-			sym->s.isstatic = 1;
-			sym->s.isglobal= 1;
-			sym->s.isdefined = 1;
+			sym->isstatic = 1;
+			sym->isglobal= 1;
 
 			switch (sclass) {
 			case REGISTER: case AUTO:
 				error("incorrect storage class for file-scope declaration");
 			case STATIC:
-				sym->s.isglobal = 0;
+				sym->isglobal = 0;
 				break;
 			case EXTERN:
-				sym->s.isdefined = 0;
+				sym->isdefined = 0;
 				break;
 			case TYPEDEF:
 				sym->token = TYPEIDEN;
@@ -535,8 +526,9 @@
 			} else if (yytoken == '{') {
 				curfun = sym;
 				emitfun(sym);
-				context(NULL, NULL, NULL);
+				compound(NULL, NULL, NULL);
 				emitefun();
+				popctx();
 				return;
 			}
 		} while (accept(','));
--- a/cc1/expr.c
+++ b/cc1/expr.c
@@ -32,7 +32,7 @@
 	if (options.npromote)
 		return np;
 	tp = np->type;
-	r = tp->u.rank;
+	r = tp->n.rank;
 	if  (r > RANK_UINT || tp == inttype || tp == uinttype)
 		return np;
 	return castcode(np, (r == RANK_UINT) ? uinttype : inttype);
@@ -51,7 +51,7 @@
 	tp1 = np1->type;
 	tp2 = np2->type;
 	if (tp1 != tp2) {
-		if ((n = tp1->u.rank - tp2->u.rank) > 0)
+		if ((n = tp1->n.rank - tp2->n.rank) > 0)
 			np2 = castcode(np2, tp1);
 		else if (n < 0)
 			np1 = castcode(np1, tp2);
@@ -74,7 +74,7 @@
 {
 	if (!np)
 		return NULL;
-	if (!ISNODECMP(np))
+	if (!ISNODELOG(np))
 		return np;
 	return ternarycode(np, symcode(one), symcode(zero));
 }
@@ -114,7 +114,7 @@
 static Node *
 decay(Node *np)
 {
-	return unarycode(OADDR, mktype(np->type, PTR, NULL), np);
+	return unarycode(OADDR, mktype(np->type, PTR, 0, NULL), np);
 }
 
 /*
@@ -292,19 +292,20 @@
 static Node *
 field(Node *np)
 {
-	Field *fp;
+	extern uint8_t lex_ns;
+	Symbol *sym;
 
-	if (yytoken != IDEN)
-		unexpected();
 	switch (np->typeop) {
 	case STRUCT: case UNION:
-		for (fp = np->type->u.fields; fp; fp = fp->next) {
-			if (!strcmp(fp->name, yytext)) {
-				next();
-				return fieldcode(np, fp);
-			}
-		}
-		error("field '%s' not found", yytext);
+		lex_ns = np->type->ns;
+		next();
+		if (yytoken != IDEN)
+			unexpected();
+		if ((sym = yylval.sym) == NULL)
+			error("incorrect field in struct/union");
+		lex_ns = NS_IDEN;
+		next();
+		return fieldcode(np, sym);
 	default:
 		error("struct or union expected");
 	}
@@ -376,9 +377,9 @@
 {
 	if (!np->b.lvalue)
 		error("lvalue required in unary expression");
-	if (np->b.symbol && np->u.sym->s.isregister)
+	if (np->b.symbol && np->u.sym->isregister)
 		error("address of register variable '%s' requested", yytext);
-	return unarycode(op, mktype(np->type, PTR, 0), np);
+	return unarycode(op, mktype(np->type, PTR, 0, NULL), np);
 }
 
 static Node *
@@ -435,8 +436,7 @@
 		expect(')');
 		break;
 	default:
-		np = NULL;
-		break;
+		unexpected();
 	}
 	return np;
 }
@@ -483,7 +483,6 @@
 		case INDIR:
 			np1 = content(OPTR, np1);
 		case '.':
-			next();
 			np1 = field(np1);
 			break;
 		case '(':
@@ -545,12 +544,12 @@
 		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;
+	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();
 	}
 
@@ -559,15 +558,17 @@
 }
 
 static Node *
-cast2(void)
+cast(void)
 {
 	register Node *np1, *np2;
 	register Type *tp;
 
-	switch(yytoken) {
+	if (!accept('('))
+		return unary();
+
+	switch (yytoken) {
 	case TQUALIFIER: case TYPE:
 		tp = typename();
-		expect(')');
 		switch (tp->op) {
 		case ARY:
 			error("cast specify an array type");
@@ -582,17 +583,12 @@
 		}
 		break;
 	default:
-		np2 = unary();
-		expect(')');
+		np2 = expr();
 		break;
 	}
-	return np2;
-}
+	expect(')');
 
-static Node *
-cast(void)
-{
-	return (accept('(')) ? cast2() : unary();
+	return np2;
 }
 
 static Node *
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -10,6 +10,7 @@
 #include "cc1.h"
 
 static FILE *yyin;
+uint8_t lex_ns = NS_IDEN;
 const char *filename;
 unsigned linenum;
 
@@ -181,7 +182,7 @@
 	*bp = '\0';
 	sym = install("", NS_IDEN);
 	sym->u.s = xstrdup(buf);
-	sym->type = mktype(chartype, PTR, 0);
+	sym->type = mktype(chartype, PTR, 0, NULL);
 	yylval.sym = sym;
 	return STRING;
 }
@@ -202,7 +203,7 @@
 	*bp = '\0';
 	ungetc(c, yyin);
 
-	sym = yylval.sym = lookup(yytext, NS_IDEN);
+	sym = yylval.sym = lookup(yytext, lex_ns);
 	if (!sym || sym->token == IDEN)
 		return IDEN;
 	yylval.token = sym->u.token;
--- a/cc1/stmt.c
+++ b/cc1/stmt.c
@@ -31,15 +31,15 @@
 
 	if ((sym = lookup(s, NS_LABEL)) != NULL) {
 		if (define) {
-			if (sym->s.isdefined)
+			if (sym->isdefined)
 				error("label '%s' already defined", s);
-			sym->s.isdefined = 1;
+			sym->isdefined = 1;
 		}
 		return sym;
 	}
 
 	sym = install(s, NS_LABEL);
-	sym->s.isdefined = define;
+	sym->isdefined = define;
 	return sym;
 }
 
@@ -46,9 +46,15 @@
 static void
 stmtexp(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 {
-	if (yytoken != ';')
-		emitexp(expr());
+	Node *np = NULL;;
+
+	if (yytoken != ';') {
+		np = expr();
+		emitexp(np);
+	}
+
 	expect(';');
+	freetree(np);
 }
 
 static Node *
@@ -82,6 +88,7 @@
 	emitjump(begin, np);
 	emiteloop();
 	emitlabel(end);
+	freetree(np);
 }
 
 static void
@@ -96,11 +103,11 @@
 
 	expect(FOR);
 	expect('(');
-	einit = expr();
+	einit = (yytoken != ';') ? expr() : NULL;
 	expect(';');
-	econd = expr();
+	econd = (yytoken != ';') ? expr() : NULL;
 	expect(';');
-	einc = expr();
+	einc = (yytoken != ')') ? expr() : NULL;
 	expect(')');
 
 	emitexp(einit);
@@ -113,6 +120,9 @@
 	emitjump(begin, econd);
 	emiteloop();
 	emitlabel(end);
+	freetree(einit);
+	freetree(econd);
+	freetree(einc);
 }
 
 static void
@@ -119,6 +129,7 @@
 Dowhile(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 {
 	Symbol *begin, *end;
+	Node *np;
 
 	begin = install("", NS_LABEL);
 	end = install("", NS_LABEL);
@@ -127,9 +138,11 @@
 	emitlabel(begin);
 	stmt(end, begin, lswitch);
 	expect(WHILE);
-	emitjump(begin, condition());
+	np = condition();
+	emitjump(begin, np);
 	emiteloop();
 	emitlabel(end);
+	freetree(np);
 }
 
 static void
@@ -139,7 +152,7 @@
 	Type *tp = curfun->type->type;
 
 	expect(RETURN);
-	np  = eval(expr());
+	np = (yytoken != ';') ? eval(expr()) : NULL;
 	expect(';');
 	if (!np) {
 		if (tp != voidtype)
@@ -153,6 +166,7 @@
 	}
 	emitret(tp);
 	emitexp(np);
+	freetree(np);
 }
 
 static void
@@ -215,8 +229,7 @@
 
 	expect(SWITCH);
 	expect ('(');
-	if ((cond = expr()) == NULL)
-		unexpected();
+	cond = expr();
 	if ((cond = convert(cond, inttype, 0)) == NULL)
 		error("incorrect type in switch statement");
 	expect (')');
@@ -230,11 +243,13 @@
 	for (p = lcase.head; p; p = next) {
 		emitcase(p->label, p->expr);
 		next = p->next;
+		freetree(p->expr);
 		free(p);
 	}
 	if (lcase.deflabel)
 		emitdefault(lcase.deflabel);
 	emitlabel(lbreak);
+	freetree(cond);
 }
 
 static void
@@ -246,8 +261,7 @@
 	expect(CASE);
 	if (!lswitch)
 		error("case label not within a switch statement");
-	if ((np = expr()) == NULL)
-		unexpected();
+	np = expr();
 	if ((np = convert(np, inttype, 0)) == NULL)
 		error("incorrect type in case statement");
 	expect(':');
@@ -291,17 +305,19 @@
 	} else {
 		emitlabel(lelse);
 	}
+	freetree(np);
 }
 
 void
 compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 {
+	pushctx();
 	expect('{');
+
 	for (;;) {
 		switch (yytoken) {
 		case '}':
-			next();
-			return;
+			goto end_compound;
 		case TYPEIDEN:
 			if (ahead() == ':')
 				goto statement;
@@ -314,6 +330,11 @@
 			stmt(lbreak, lcont, lswitch);
 		}
 	}
+
+end_compound:
+	popctx();
+	expect('}');
+	return;
 }
 
 static void
@@ -320,9 +341,10 @@
 stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 {
 	void (*fun)(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
+	Node *np;
 
 	switch (yytoken) {
-	case '{':      fun = context;  break;
+	case '{':      fun = compound; break;
 	case RETURN:   fun = Return;   break;
 	case WHILE:    fun = While;    break;
 	case FOR:      fun = For;      break;
@@ -340,9 +362,10 @@
 		break;
 	case '@':
 		next();
-		emitprint(expr());
-		break;
-		next();
+		np = expr();
+		emitprint(np);
+		freetree(np);
+		return;
 	}
 	(*fun)(lbreak, lcont, lswitch);
 }
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
@@ -10,8 +10,8 @@
 #define NR_SYM_HASH 32
 
 uint8_t curctx;
-short localcnt;
-short globalcnt;
+static short localcnt;
+static short globalcnt;
 
 static struct symtab {
 	Symbol *head;
@@ -38,8 +38,10 @@
 	for (sym = tbl->head; sym; sym = next) {
 		if (sym->ctx <= curctx)
 			break;
-		if (ns == NS_LABEL && !sym->s.isdefined)
+		if (ns == NS_LABEL && !sym->isdefined)
 			error("label '%s' is not defined", sym->name);
+		if (ns == NS_TAG)
+			sym->type->defined = 0;
 		tbl->htab[hash(sym->name)] = sym->hash;
 		next = tbl->head = sym->next;
 		free(sym->name);
@@ -47,26 +49,19 @@
 	}
 }
 
-Type *
-aggregate(Type * (*fun)(void))
+void
+pushctx(void)
 {
-	Type *tp;
-
 	++curctx;
-	tp = (*fun)();
-	--curctx;
-	freesyms(NS_IDEN);
-	return tp;
 }
 
 void
-context(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+popctx(void)
 {
-	++curctx;
-	compound(lbreak, lcont, lswitch);
 	--curctx;
 	freesyms(NS_IDEN);
 	freesyms(NS_TAG);
+	freesyms(NS_STRUCTS);
 	if (curctx == 0) {
 		localcnt = 0;
 		freesyms(NS_LABEL);
@@ -79,9 +74,9 @@
 	struct symtab *tbl;
 	register Symbol *sym;
 
-	tbl = &symtab[ns];
+	tbl = &symtab[(ns > NS_STRUCTS) ? NS_STRUCTS : ns];
 	for (sym = tbl->htab[hash(s)]; sym; sym = sym->hash) {
-		if (!strcmp(sym->name, s))
+		if (!strcmp(sym->name, s) && sym->ns == ns)
 			return sym;
 	}
 
@@ -99,8 +94,9 @@
 	sym->ctx = curctx;
 	sym->token = IDEN;
 	sym->id = (curctx) ? ++localcnt : ++globalcnt;
-	sym->s.isdefined = 1;
-	tbl = &symtab[ns];
+	sym->isdefined = 1;
+	sym->ns = ns;
+	tbl = &symtab[(ns > NS_STRUCTS) ? NS_STRUCTS : ns];
 	sym->next = tbl->head;
 	tbl->head = sym;
 
--- a/cc1/types.c
+++ b/cc1/types.c
@@ -23,13 +23,13 @@
 		.op = INT,
 		.letter = L_BOOL,
 		.defined = 1,
-		.u.rank = RANK_BOOL
+		.n.rank = RANK_BOOL
 	},
 	*schartype = &(Type) {
 		.op = INT,
 		.letter = L_SCHAR,
 		.defined = 1,
-		.u.rank = RANK_SCHAR
+		.n.rank = RANK_SCHAR
 	},
 	*uchartype = &(Type) {
 		.op = INT,
@@ -36,7 +36,7 @@
 		.letter = L_UCHAR,
 		.sign = 1,
 		.defined = 1,
-		.u.rank = RANK_UCHAR
+		.n.rank = RANK_UCHAR
 	},
 	*chartype = &(Type) {
 		.op = INT,
@@ -43,19 +43,19 @@
 		.letter = L_CHAR,
 		.sign = 1,
 		.defined = 1,
-		.u.rank = RANK_CHAR
+		.n.rank = RANK_CHAR
 	},
 	*ushortype = &(Type) {
 		.op = INT,
 		.letter = L_USHORT,
 		.defined = 1,
-		.u.rank = RANK_USHORT
+		.n.rank = RANK_USHORT
 	},
 	*shortype = &(Type) {
 		.op = INT,
 		.letter = L_SHORT,
 		.defined = 1,
-		.u.rank = RANK_SHORT
+		.n.rank = RANK_SHORT
 	},
 	*uinttype = &(Type) {
 		.op = INT,
@@ -62,19 +62,19 @@
 		.letter = L_UINT,
 		.sign = 1,
 		.defined = 1,
-		.u.rank = RANK_UINT
+		.n.rank = RANK_UINT
 	},
 	*inttype = &(Type) {
 		.op = INT,
 		.letter = L_INT,
 		.defined = 1,
-		.u.rank = RANK_INT
+		.n.rank = RANK_INT
 	},
 	*longtype = &(Type) {
 		.op = INT,
 		.letter = L_LONG,
 		.defined = 1,
-		.u.rank = RANK_LONG
+		.n.rank = RANK_LONG
 	},
 	*ulongtype = &(Type) {
 		.op = INT,
@@ -81,7 +81,7 @@
 		.letter = L_ULONG,
 		.sign = 1,
 		.defined = 1,
-		.u.rank = RANK_ULONG
+		.n.rank = RANK_ULONG
 	},
 	*ullongtype = &(Type) {
 		.op = INT,
@@ -88,31 +88,31 @@
 		.letter = L_ULLONG,
 		.sign = 1,
 		.defined = 1,
-		.u.rank = RANK_ULLONG
+		.n.rank = RANK_ULLONG
 	},
 	*llongtype = &(Type) {
 		.op = INT,
 		.letter = L_LLONG,
 		.defined = 1,
-		.u.rank = RANK_LLONG
+		.n.rank = RANK_LLONG
 	},
 	*floattype = &(Type) {
 		.op = FLOAT,
 		.letter = L_FLOAT,
 		.defined = 1,
-		.u.rank = RANK_FLOAT
+		.n.rank = RANK_FLOAT
 	},
 	*doubletype = &(Type) {
 		.op = FLOAT,
 		.letter = L_DOUBLE,
 		.defined = 1,
-		.u.rank = RANK_DOUBLE
+		.n.rank = RANK_DOUBLE
 	},
 	*ldoubletype = &(Type) {
 		.op = FLOAT,
 		.letter = L_LDOUBLE,
 		.defined = 1,
-		.u.rank = RANK_LDOUBLE
+		.n.rank = RANK_LDOUBLE
 	};
 
 Type *
@@ -186,69 +186,45 @@
 }
 
 Type *
-mktype(Type *tp, uint8_t op, void *data)
+mktype(Type *tp, uint8_t op, short nelem, void *data)
 {
-	static Type *typetab[NR_TYPE_HASH], **tbl;
-	static uint8_t t, def;
+	static Type *typetab[NR_TYPE_HASH], **tbl, type;
+	static uint8_t t;
 	register Type *bp;
-	char letter, look;
-	union typeval u;
+	static char letters[] = {
+		[PTR] = L_POINTER,   [ARY] = L_ARRAY,
+		[FTN] = L_FUNCTION,  [ENUM] = L_INT,
+		[STRUCT] = L_STRUCT, [UNION] = L_UNION
+	};
 
-	switch (op) {
-	case PTR:
-		if (tp == voidtype)
-			return pvoidtype;
-		letter = L_POINTER;
-		def = 1;
-		look = 1;
-		break;
-	case ARY:
-		u.nelem = *(unsigned short *) data;
-		letter = L_ARRAY;
-		def = u.nelem != 0;
-		look = 1;
-		break;
-	case FTN:
-		u.pars = data;
-		letter = L_FUNCTION;
-		def = 1;
-		look = 0;
-		break;
-	case ENUM:
-		letter = L_INT;
-		def = 1;
-		look = 0;
-		break;
-	case STRUCT: case UNION:
-		letter = (op == STRUCT) ? L_STRUCT : L_UNION;
-		def = 0;
-		look = 0;
-		u.fields = NULL;
-		break;
-	default:
-		fputs("internal type error, aborting\n", stderr);
-		abort();
-	}
+	if (op == PTR && tp == voidtype)
+		return pvoidtype;
 
-	t = (op  ^  (uint8_t) ((unsigned short) tp >> 3))
-	         & NR_TYPE_HASH-1;
+	type.type = tp;
+	type.op = op;
+	type.sign = 0;
+	type.letter = letters[op];
+	type.pars = data;
+	type.n.elem = nelem;
+	type.ns = 0;
+
+	if (op == ARY && nelem == 0 || op == STRUCT || op == UNION)
+		type.defined = 0;
+	else
+		type.defined = 1;
+
+	t = (op ^ (uint8_t) ((unsigned short) tp >> 3)) & NR_TYPE_HASH-1;
 	tbl = &typetab[t];
-	if (look) {
-		for (bp = *tbl; bp; bp = bp->next) {
-			if (bp->type == tp && bp->op == op &&
-			    (op != ARY || bp->u.nelem == u.nelem)) {
-				return bp;
-			}
+	for (bp = *tbl; bp; bp = bp->next) {
+		if (eqtype(bp, &type)) {
+			free(data);
+			return bp;
 		}
 	}
 
-	bp = xcalloc(1, sizeof(*bp));
+	bp = xmalloc(sizeof(*bp));
+	*bp = type;
 	bp->next = *tbl;
-	bp->type = tp;
-	bp->op = op;
-	bp->letter = letter;
-	bp->defined = def;
-	bp->u = u;
 	return *tbl = bp;
 }
 
@@ -255,42 +231,29 @@
 bool
 eqtype(Type *tp1, Type *tp2)
 {
+	uint8_t n;
+	Type **p1, **p2;
+
 	if (tp1 == tp2)
 		return 1;
-	if (tp1->op != tp2->op)
+	if (tp1->op != tp2->op || tp1->n.elem != tp2->n.elem)
 		return 0;
 	switch (tp1->op) {
+	case ARY:
 	case PTR:
 		return eqtype(tp1->type, tp2->type);
-	/* TODO: use the same struct for function parameters and fields */
-	case FTN: {
-		Funpar *fp1 = tp1->u.pars, *fp2 = tp2->u.pars;
-
-		while (fp1 && fp2) {
-			if (!eqtype(fp1->type, fp2->type))
-				break;
-			fp1 = fp1->next;
-			fp2 = fp2->next;
-		}
-		return fp1 == fp2;
-	}
 	case UNION:
-	case STRUCT: {
-		Field *fp1 = tp1->u.fields, *fp2 = tp2->u.fields;
-
-		while (fp1 && fp2) {
-			if (!eqtype(fp1->type, fp2->type))
-				break;
-			fp1 = fp1->next;
-			fp2 = fp2->next;
+	case STRUCT:
+	case FTN:
+		p1 = tp1->pars, p2 = tp2->pars;
+		for (n = tp1->n.elem; n != 0; --n) {
+			if (!eqtype(*p1++, *p2++))
+				return 0;
 		}
-		return fp1 == fp2;
-	}
-	case ARY:
-		if (!eqtype(tp1->type, tp2->type))
-			return 0;
-		return tp1->u.nelem == tp2->u.nelem;
-	case ENUM: case INT: case FLOAT:
+		return 1;
+	case ENUM:
+		/* TODO: Check when two enum are the same type */
+	case INT: case FLOAT:
 		return tp1->letter == tp2->letter;
 	default:
 		fputs("internal type error, aborting\n", stderr);
--- a/cc2/Makefile
+++ b/cc2/Makefile
@@ -1,5 +1,5 @@
 
-OBJS = main.o parser.o cgen.o
+OBJS = main.o parser.o cgen.o code.o optm.o
 
 CPPFLAGS = -I../inc
 LDFLAGS = -L../lib
--- a/cc2/cc2.h
+++ b/cc2/cc2.h
@@ -1,12 +1,16 @@
 
+typedef struct symbol Symbol;
+typedef struct node Node;
+
 typedef struct {
 	short size;
 	uint8_t align;
+	char letter;
 	bool sign : 1;
 	bool c_int : 1;
 } Type;
 
-typedef struct symbol {
+struct symbol {
 	char *name;
 	bool public : 1;
 	bool extrn : 1;
@@ -23,11 +27,12 @@
 		struct {
 			short locals;
 			short params;
+			Node **body;
 		} f;
 	} u;
-} Symbol;
+};
 
-typedef struct node {
+struct node {
 	char op;
 	char subop;
 	Type *type;
@@ -39,7 +44,7 @@
 		char reg;
 	} u;
 	struct node *left, *right;
-} Node;
+};
 
 enum nerrors {
 	EINTNUM,       /* too much internal identifiers */
@@ -94,7 +99,23 @@
 
 #define ADDABLE 10
 
+
+enum {
+	PUSH, POP, LD, ADD, RET, ADDI, LDI, ADDR, ADDX, ADCX, LDX,
+	LDFX
+};
+
+enum {
+	A = 1, B, C, D, E, H, L, IYL, IYH, NREGS,
+	IXL, IXH, F, I, SP, AF, HL, DE, BC, IX, IY
+};
+
 extern void error(unsigned nerror, ...);
-extern void genaddable(Node *list[]);
-extern void generate(Symbol *sym, Node *list[]);
+extern Node *genaddable(Node *np);
+extern void generate(Symbol *fun);
 extern void genstack(Symbol *fun);
+extern void apply(Node *list[], Node *(*fun)(Node *));
+extern Symbol *parse(void);
+extern void code(char op, ...);
+extern Node *optimize(Node *np);
+extern void prtree(Node *np);
--- a/cc2/cgen.c
+++ b/cc2/cgen.c
@@ -9,86 +9,11 @@
 
 #include <stdio.h>
 
-/* TODO: Change emit to code */
-enum {
-	PUSH, POP, LD, ADD, RET, ADDI, LDI, ADDR, ADDX, ADCX, LDX,
-	LDFX
-};
-
-enum {
-	A = 1, B, C, D, E, H, L, IYL, IYH, NREGS,
-	IXL, IXH, F, I, SP, AF, HL, DE, BC, IX, IY
-};
-
-static char *opnames[] = {
-	[PUSH] = "PUSH", [POP] = "POP", [LD]  = "LD", [ADD] = "ADD",
-	[RET]  = "RET" , [ADDI]= "ADD", [LDI] = "LD", [ADDX] = "ADD",
-	[ADCX] = "ADC" , [LDX] = "LD" , [LDFX] = "LD"
-};
-
-static char *regnames[] = {
-	[AF] = "AF", [HL] = "HL", [DE] = "DE", [BC] = "BC", [IX] = "IX",
-	[IY] = "IY", [SP] = "SP", [A]  = "A",  [F]  = "F",  [B]  = "B",
-	[C]  = "C",  [D]  = "D",  [E]  = "E",  [H]  = "H",  [L]  = "L",
-	[IXL]= "IXL",[IXH]= "IXH",[IYL]= "IYL",[IYH]= "IYH", [I] = "I"
-};
-
 static bool reguse[NREGS];
 static char upper[] = {[DE] = D, [HL] = H, [BC] = B, [IX] = IXH, [IY] = IYH};
 static char lower[] = {[DE] = E, [HL] = L, [BC] = C, [IX] = IXL, [IY] = IYL};
 
-void
-emit(char op, ...)
-{
-	va_list va;
-	uint8_t reg1, reg2;
-	TINT imm;
-	short off;
-	char *label;
 
-	va_start(va, op);
-	switch (op) {
-	case RET:
-		printf("\t%s\n", opnames[op]);
-		break;
-	case PUSH: case POP:
-		reg1 = va_arg(va, int);
-		printf("\t%s\t%s\n", opnames[op], regnames[reg1]);
-		break;
-	case ADD: case LD:
-		reg1 = va_arg(va, int);
-		reg2 = va_arg(va, int);
-		printf("\t%s\t%s,%s\n",
-		       opnames[op], regnames[reg1], regnames[reg2]);
-		break;
-	case ADDI: case LDI:
-		reg1 = va_arg(va, int);
-		imm = va_arg(va, int);
-		printf("\t%s\t%s,%d\n", opnames[op], regnames[reg1], imm);
-		break;
-	case ADDX: case ADCX: case LDFX:
-		reg1 = va_arg(va, int);
-		reg2 = va_arg(va, int);
-		off = va_arg(va, int);
-		printf("\t%s\t%s,(%s%+d)\n",
-		       opnames[op], regnames[reg1], regnames[reg2], off);
-		break;
-	case LDX:
-		reg1 = va_arg(va, int);
-		off = va_arg(va, int);
-		reg2 = va_arg(va, int);
-		printf("\t%s\t(%s%+d),%s\n",
-		       opnames[op], regnames[reg1], off, regnames[reg2]);
-		break;
-	case ADDR:
-		label = va_arg(va, char *);
-		printf("%s:\n", label);
-		break;
-	}
-
-	va_end(va);
-}
-
 static char
 allocreg(Node *np)
 {
@@ -136,11 +61,11 @@
 		sym = np->u.sym;
 		switch (tp->size) {
 		case 1:
-			emit(LDFX, reg, IX, sym->u.v.off);
+			code(LDFX, reg, IX, sym->u.v.off);
 			break;
 		case 2:
-			emit(LDFX, lower[reg], IX, sym->u.v.off);
-			emit(LDFX, upper[reg], IX, sym->u.v.off+1);
+			code(LDFX, lower[reg], IX, sym->u.v.off);
+			code(LDFX, upper[reg], IX, sym->u.v.off+1);
 			break;
 		case 4:
 		case 8:
@@ -168,7 +93,7 @@
 }
 
 static void
-cgen(Node *np)
+cgen(Node *np, Node *parent)
 {
 	Node *lp, *rp;
 	TINT imm;
@@ -179,14 +104,16 @@
 	lp = np->left;
 	rp = np->right;
 	if (np->addable >= ADDABLE) {
+		if (parent && parent->op == OASSIG)
+			return;
 		move(np);
 		return;
 	}
 
 	if (!lp) {
-		cgen(rp);
+		cgen(rp, np);
 	} else if (!rp) {
-		cgen(lp);
+		cgen(lp, np);
 	} else {
 		Node *p, *q;
 		if (lp->complex > rp->complex)
@@ -193,11 +120,10 @@
 			p = lp, q = rp;
 		else
 			p = rp, q = lp;
-		cgen(p);
-		cgen(q);
+		cgen(p, np);
+		cgen(q, np);
 	}
 
-	assert(lp && lp->op == REG || rp && rp->op == REG);
 	switch (np->op) {
 	case OADD:
 		switch (np->type->size) {
@@ -208,10 +134,12 @@
 				rp = np->right;
 			} else if (lp->u.reg != A) {
 				/* TODO: Move A to variable */
-				emit(PUSH, AF);
-				emit(LD, A, lp->u.reg);
+				code(PUSH, AF);
+				code(LD, A, lp->u.reg);
 			}
-			emit(ADD, A, rp->u.reg);
+			code(ADD, A, rp->u.reg);
+			np->op = REG;
+			np->u.reg = A;
 			break;
 		case 2:
 			if (rp->u.reg == HL || rp->u.reg == IY) {
@@ -220,11 +148,13 @@
 				rp = np->right;
 			} else if (lp->u.reg != HL && lp->u.reg != IY) {
 				/* TODO: Move HL to variable */
-				emit(PUSH, HL);
-				emit(LD, H, upper[lp->u.reg]);
-				emit(LD, L, lower[lp->u.reg]);
+				code(PUSH, HL);
+				code(LD, H, upper[lp->u.reg]);
+				code(LD, L, lower[lp->u.reg]);
 			}
-			emit(ADD, lp->u.reg, rp->u.reg);
+			code(ADD, lp->u.reg, rp->u.reg);
+			np->op = REG;
+			np->u.reg = lp->u.reg;
 			break;
 		case 4:
 		case 8:
@@ -231,38 +161,62 @@
 			abort();
 		}
 		break;
+	case OASSIG:
+		switch (np->type->size) {
+		case 1:
+			switch (lp->op) {
+			case AUTO:
+				code(LDX, IX, lp->u.sym->u.v.off, rp->u.reg);
+				break;
+			case REG:
+			case MEM:
+			default:
+				abort();
+			}
+			break;
+		default:
+			abort();
+		}
+		break;
 	default:
 		abort();
 	}
 }
 
+static Node *
+applycgen(Node *np)
+{
+	cgen(np, NULL);
+	return NULL;
+}
+
 void
-generate(Symbol *sym, Node *list[])
+generate(Symbol *fun)
 {
 	extern char odebug;
-	Node *np;
-	char frame = sym->u.f.locals != 0 || odebug;
+	char frame = fun->u.f.locals != 0 || odebug;
 
-	emit(ADDR, sym->name);
+	code(ADDR, fun->name);
 	if (frame) {
-		emit(PUSH, IX);
-		emit(LD, IX, SP);
-		emit(LDI, HL, -sym->u.f.locals);
-		emit(ADD, HL, SP);
-		emit(LD, SP, HL);
+		code(PUSH, IX);
+		code(LD, IX, SP);
+		code(LDI, HL, -fun->u.f.locals);
+		code(ADD, HL, SP);
+		code(LD, SP, HL);
 	}
 
-	while (np = *list++)
-		cgen(np);
+	apply(fun->u.f.body, applycgen);
 
 	if (frame) {
-		emit(LD, SP, IX);
-		emit(POP, IX);
-		emit(RET);
+		code(LD, SP, IX);
+		code(POP, IX);
+		code(RET);
 	}
 }
 
 /*
+ * This is strongly influenced by
+ * http://plan9.bell-labs.com/sys/doc/compiler.ps
  * calculate addresability as follows
  *     AUTO => 11          value+fp
  *     REGISTER => 13      register
@@ -269,13 +223,13 @@
  *     STATIC => 12        (value)
  *     CONST => 20         $value
  */
-static void
-xaddable(Node *np)
+Node *
+genaddable(Node *np)
 {
 	Node *lp, *rp;
 
 	if (!np)
-		return;
+		return np;
 
 	np->complex = 0;
 	np->addable = 0;
@@ -296,14 +250,14 @@
 		break;
 	default:
 		if (lp)
-			xaddable(lp);
+			genaddable(lp);
 		if (rp)
-			xaddable(rp);
+			genaddable(rp);
 		break;
 	}
 
 	if (np->addable > 10)
-		return;
+		return np;
 	if (lp)
 		np->complex = lp->complex;
 	if (rp) {
@@ -316,15 +270,5 @@
 	}
 	if (np->complex == 0)
 		++np->complex;
-	return;
+	return np;
 }
-
-void
-genaddable(Node *list[])
-{
-	Node *np;
-
-	while (np = *list++)
-		xaddable(np);
-}
-
--- /dev/null
+++ b/cc2/code.c
@@ -1,0 +1,69 @@
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cc.h>
+#include "cc2.h"
+
+
+static char *opnames[] = {
+	[PUSH] = "PUSH", [POP] = "POP", [LD]  = "LD", [ADD] = "ADD",
+	[RET]  = "RET" , [ADDI]= "ADD", [LDI] = "LD", [ADDX] = "ADD",
+	[ADCX] = "ADC" , [LDX] = "LD" , [LDFX] = "LD"
+};
+
+static char *regnames[] = {
+	[AF] = "AF", [HL] = "HL", [DE] = "DE", [BC] = "BC", [IX] = "IX",
+	[IY] = "IY", [SP] = "SP", [A]  = "A",  [F]  = "F",  [B]  = "B",
+	[C]  = "C",  [D]  = "D",  [E]  = "E",  [H]  = "H",  [L]  = "L",
+	[IXL]= "IXL",[IXH]= "IXH",[IYL]= "IYL",[IYH]= "IYH", [I] = "I"
+};
+
+static char *opfmt[] = {
+	[RET]  = "\to",
+	[PUSH] = "\to\tr",
+	[POP]  = "\to\tr",
+	[ADD]  = "\to\tr,r",
+	[LD]   = "\to\tr,r",
+	[ADDI] = "\to\tr,i",
+	[LDI]  = "\to\tr,i",
+	[ADDX] = "\to\tr,(r+i)",
+	[ADCX] = "\to\tr,(r+i)",
+	[LDFX] = "\to\tr,(r+i)",
+	[LDX]  = "\to\t(r+i),r",
+	[ADDR] = "a:"
+};
+
+void
+code(char op, ...)
+{
+	va_list va;
+	char *cp, c;
+
+	va_start(va, op);
+	for (cp = opfmt[op]; c = *cp; ++cp) {
+		switch (c) {
+		case 'o':
+			fputs(opnames[op], stdout);
+			break;
+		case 'r':
+			fputs(regnames[va_arg(va, int)], stdout);
+			break;
+		case 'i':
+			printf("%d", va_arg(va, int));
+			break;
+		case 'a':
+			fputs(va_arg(va, char *), stdout);
+			break;
+		default:
+			putchar(c);
+			break;
+		}
+	}
+	putchar('\n');
+
+	va_end(va);
+}
--- a/cc2/main.c
+++ b/cc2/main.c
@@ -9,8 +9,6 @@
 #include "cc2.h"
 #include "error.h"
 
-extern void parse(void);
-
 char odebug;
 
 void
@@ -30,5 +28,11 @@
 int
 main(void)
 {
-	parse();
+	Symbol *fun;
+
+	while (!feof(stdin) && (fun = parse())) {
+		apply(fun->u.f.body, optimize);
+		apply(fun->u.f.body, genaddable);
+		generate(fun);
+	}
 }
--- /dev/null
+++ b/cc2/optm.c
@@ -1,0 +1,43 @@
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <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->c_int && np->type->size >= tp->size) {
+			np = np->left;
+			goto repeat;
+		}
+		break;
+	case OASSIG:
+		tp = np->type;
+		break;
+	default:
+		np->type = tp;
+	}
+
+	np->left = optcasts(np->left, tp);
+	np->right = optcasts(np->right, tp);
+	return np;			
+}
+
+Node *
+optimize(Node *np)
+{
+	np = optcasts(np, np->type);
+	return np;
+}
--- a/cc2/parser.c
+++ b/cc2/parser.c
@@ -20,12 +20,13 @@
 };
 
 static Symbol *curfun;
-static Node *stack[NR_STACKSIZ], **stackp = stack;
-static Node *listexp[NR_EXPRESSIONS], **listp = listexp;
-static Node nodepool[NR_NODEPOOL], *newp = nodepool;
+static Node *stack[NR_STACKSIZ], **stackp;
+static Node *listexp[NR_EXPRESSIONS], **listp;
+static Node nodepool[NR_NODEPOOL], *newp;
 
 
 Type l_int8 = {
+	.letter = L_INT8,
 	.size = 1,
 	.align = 2,
 	.sign = 1,
@@ -33,6 +34,7 @@
 };
 
 Type l_int16 = {
+	.letter = L_INT16,
 	.size = 2,
 	.align = 2,
 	.sign = 1,
@@ -40,6 +42,7 @@
 };
 
 Type l_int32 = {
+	.letter = L_INT32,
 	.size = 4,
 	.align = 4,
 	.sign = 1,
@@ -47,6 +50,7 @@
 };
 
 Type l_int64 = {
+	.letter = L_INT64,
 	.size = 8,
 	.align = 8,
 	.sign = 1,
@@ -54,6 +58,7 @@
 };
 
 Type l_uint8 = {
+	.letter = L_UINT8,
 	.size = 1,
 	.align = 2,
 	.c_int = 1,
@@ -60,6 +65,7 @@
 };
 
 Type l_uint16 = {
+	.letter = L_UINT16,
 	.size = 2,
 	.align = 2,
 	.c_int = 1,
@@ -66,6 +72,7 @@
 };
 
 Type l_uint32 = {
+	.letter = L_UINT32,
 	.size = 4,
 	.align = 4,
 	.c_int = 1,
@@ -72,11 +79,39 @@
 };
 
 Type l_uint64 = {
+	.letter = L_UINT64,
 	.size = 8,
 	.align = 8,
 	.c_int = 1,
 };
 
+
+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 *list[], Node *(*fun)(Node *))
+{
+	Node *np;
+
+	while (np = *list)
+		*list++ = (*fun)(np);
+}
+
 static Symbol *
 parameter(char *num)
 {
@@ -390,17 +425,6 @@
 	sym->u.l.addr = listp - listexp;
 }
 
-static void
-endfunction(char *token)
-{
-	if (!curfun)
-		error(ESYNTAX);
-	listp = NULL;
-	genaddable(listexp);
-	generate(curfun, listexp);
-	curfun = NULL;
-}
-
 static Symbol *
 declaration(uint8_t t, char class, char *token)
 {
@@ -444,7 +468,7 @@
 
 	sym->type = FUN;
 	curfun = sym;
-	listp = listexp;
+	sym->u.f.body = listp = listexp;
 	newp = nodepool;
 }
 
@@ -464,7 +488,7 @@
 	sym->u.v.off = 1-curfun->u.f.locals;
 }
 
-void
+Symbol *
 parse(void)
 {
 	void (*fun)(char *tok);
@@ -472,6 +496,11 @@
 	int c;
 	char line[MAXLINE];
 
+	curfun = NULL;
+	stackp = stack;
+	listp = listexp;
+	newp = nodepool;
+
 	for (;;) {
 		switch (c = getchar()) {
 		case 'L':
@@ -493,10 +522,15 @@
 			fun = globdcl;
 			break;
 		case '}':
-			fun = endfunction;
-			break;
+			if (!curfun)
+				error(ESYNTAX);
+			return curfun;
 		case EOF:
-			goto found_eof;
+			if (ferror(stdin))
+				error(EFERROR, strerror(errno));
+			if (curfun)
+				goto syntax_error;
+			return NULL;
 		case '\n':
 			continue;
 		default:
@@ -514,11 +548,10 @@
 	}
 
 found_eof:
-	if (ferror(stdin))
-		error(EFERROR, strerror(errno));
-	if (!curfun)
-		return;
 
+
+	if (!curfun)
+		return curfun;
 syntax_error:
 	error(ESYNTAX);
 }