Initial revision
diff --git a/Python/compile.c b/Python/compile.c
new file mode 100644
index 0000000..03a1e32
--- /dev/null
+++ b/Python/compile.c
@@ -0,0 +1,1537 @@
+#define DEBUG
+/* Compile an expression node to intermediate code */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "string.h"
+
+#include "PROTO.h"
+#include "object.h"
+#include "objimpl.h"
+#include "intobject.h"
+#include "floatobject.h"
+#include "stringobject.h"
+#include "listobject.h"
+#include "node.h"
+#include "token.h"
+#include "graminit.h"
+#include "errors.h"
+#include "compile.h"
+#include "opcode.h"
+
+static void
+code_dealloc(c)
+	codeobject *c;
+{
+	XDECREF(c->co_code);
+	XDECREF(c->co_consts);
+	XDECREF(c->co_names);
+	DEL(c);
+}
+
+typeobject Codetype = {
+	OB_HEAD_INIT(&Typetype)
+	0,
+	"code",
+	sizeof(codeobject),
+	0,
+	code_dealloc,	/*tp_dealloc*/
+	0,		/*tp_print*/
+	0,		/*tp_getattr*/
+	0,		/*tp_setattr*/
+	0,		/*tp_compare*/
+	0,		/*tp_repr*/
+	0,		/*tp_as_number*/
+	0,		/*tp_as_sequence*/
+	0,		/*tp_as_mapping*/
+};
+
+static codeobject *newcodeobject PROTO((object *, object *, object *));
+
+static codeobject *
+newcodeobject(code, consts, names)
+	object *code;
+	object *consts;
+	object *names;
+{
+	codeobject *co;
+	int i;
+	/* Check argument types */
+	if (code == NULL || !is_stringobject(code) ||
+		consts == NULL || !is_listobject(consts) ||
+		names == NULL || !is_listobject(names)) {
+		err_badcall();
+		return NULL;
+	}
+	/* Make sure the list of names contains only strings */
+	for (i = getlistsize(names); --i >= 0; ) {
+		object *v = getlistitem(names, i);
+		if (v == NULL || !is_stringobject(v)) {
+			err_badcall();
+			return NULL;
+		}
+	}
+	co = NEWOBJ(codeobject, &Codetype);
+	if (co != NULL) {
+		INCREF(code);
+		co->co_code = (stringobject *)code;
+		INCREF(consts);
+		co->co_consts = consts;
+		INCREF(names);
+		co->co_names = names;
+	}
+	return co;
+}
+
+
+/* Data structure used internally */
+struct compiling {
+	object *c_code;		/* string */
+	object *c_consts;	/* list of objects */
+	object *c_names;	/* list of strings (names) */
+	int c_nexti;		/* index into c_code */
+	int c_errors;		/* counts errors occurred */
+};
+
+/* Prototypes */
+static int com_init PROTO((struct compiling *));
+static void com_free PROTO((struct compiling *));
+static void com_done PROTO((struct compiling *));
+static void com_node PROTO((struct compiling *, struct _node *));
+static void com_addbyte PROTO((struct compiling *, int));
+static void com_addint PROTO((struct compiling *, int));
+static void com_addoparg PROTO((struct compiling *, int, int));
+static void com_addfwref PROTO((struct compiling *, int, int *));
+static void com_backpatch PROTO((struct compiling *, int));
+static int com_add PROTO((struct compiling *, object *, object *));
+static int com_addconst PROTO((struct compiling *, object *));
+static int com_addname PROTO((struct compiling *, object *));
+static void com_addopname PROTO((struct compiling *, int, node *));
+
+static int
+com_init(c)
+	struct compiling *c;
+{
+	if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL)
+		goto fail_3;
+	if ((c->c_consts = newlistobject(0)) == NULL)
+		goto fail_2;
+	if ((c->c_names = newlistobject(0)) == NULL)
+		goto fail_1;
+	c->c_nexti = 0;
+	c->c_errors = 0;
+	return 1;
+	
+  fail_1:
+	DECREF(c->c_consts);
+  fail_2:
+	DECREF(c->c_code);
+  fail_3:
+ 	return 0;
+}
+
+static void
+com_free(c)
+	struct compiling *c;
+{
+	XDECREF(c->c_code);
+	XDECREF(c->c_consts);
+	XDECREF(c->c_names);
+}
+
+static void
+com_done(c)
+	struct compiling *c;
+{
+	if (c->c_code != NULL)
+		resizestring(&c->c_code, c->c_nexti);
+}
+
+static void
+com_addbyte(c, byte)
+	struct compiling *c;
+	int byte;
+{
+	int len;
+	if (byte < 0 || byte > 255) {
+		err_setstr(SystemError, "com_addbyte: byte out of range");
+		c->c_errors++;
+	}
+	if (c->c_code == NULL)
+		return;
+	len = getstringsize(c->c_code);
+	if (c->c_nexti >= len) {
+		if (resizestring(&c->c_code, len+1000) != 0) {
+			c->c_errors++;
+			return;
+		}
+	}
+	getstringvalue(c->c_code)[c->c_nexti++] = byte;
+}
+
+static void
+com_addint(c, x)
+	struct compiling *c;
+	int x;
+{
+	com_addbyte(c, x);
+}
+
+static void
+com_addoparg(c, op, arg)
+	struct compiling *c;
+	int op;
+	int arg;
+{
+	com_addbyte(c, op);
+	com_addint(c, arg);
+}
+
+static void
+com_addfwref(c, op, p_anchor)
+	struct compiling *c;
+	int op;
+	int *p_anchor;
+{
+	/* Compile a forward reference for backpatching */
+	int here;
+	int anchor;
+	com_addbyte(c, op);
+	here = c->c_nexti;
+	anchor = *p_anchor;
+	*p_anchor = here;
+	com_addint(c, anchor == 0 ? 0 : here - anchor);
+}
+
+static void
+com_backpatch(c, anchor)
+	struct compiling *c;
+	int anchor; /* Must be nonzero */
+{
+	unsigned char *code = (unsigned char *) getstringvalue(c->c_code);
+	int target = c->c_nexti;
+	int lastanchor = 0;
+	int dist;
+	int prev;
+	for (;;) {
+		/* Make the JUMP instruction at anchor point to target */
+		prev = code[anchor];
+		dist = target - (anchor+1);
+		if (dist > 255 && lastanchor &&
+				code[lastanchor-1] == code[anchor-1]) {
+			/* Attempt to jump to a similar jump closer by */
+/* XXX Show that it works */
+fprintf(stderr, "com_backpatch: huge jump rescued (?)\n");
+			target = lastanchor-1;
+			dist = target - (anchor+1);
+			lastanchor = 0;
+		}
+		if (dist > 255) {
+			err_setstr(SystemError, "relative jump > 255 bytes");
+			c->c_errors++;
+		}
+		code[anchor] = dist;
+		if (!prev)
+			break;
+		lastanchor = anchor;
+		anchor -= prev;
+	}
+}
+
+/* Handle constants and names uniformly */
+
+static int
+com_add(c, list, v)
+	struct compiling *c;
+	object *list;
+	object *v;
+{
+	/* XXX Should look through list for object with same value */
+	int i = getlistsize(list);
+	if (addlistitem(list, v) != 0)
+		c->c_errors++;
+	return i;
+}
+
+static int
+com_addconst(c, v)
+	struct compiling *c;
+	object *v;
+{
+	return com_add(c, c->c_consts, v);
+}
+
+static int
+com_addname(c, v)
+	struct compiling *c;
+	object *v;
+{
+	return com_add(c, c->c_names, v);
+}
+
+static void
+com_addopname(c, op, n)
+	struct compiling *c;
+	int op;
+	node *n;
+{
+	object *v;
+	int i;
+	char *name;
+	if (TYPE(n) == STAR)
+		name = "*";
+	else {
+		REQ(n, NAME);
+		name = STR(n);
+	}
+	if ((v = newstringobject(name)) == NULL) {
+		c->c_errors++;
+		i = 255;
+	}
+	else {
+		i = com_addname(c, v);
+		DECREF(v);
+	}
+	com_addoparg(c, op, i);
+}
+
+static object *
+parsenumber(s)
+	char *s;
+{
+	extern long strtol();
+	extern double atof();
+	char *end = s;
+	long x;
+	x = strtol(s, &end, 0);
+	if (*end == '\0')
+		return newintobject(x);
+	if (*end == '.' || *end == 'e' || *end == 'E')
+		return newfloatobject(atof(s));
+	err_setstr(RuntimeError, "bad number syntax");
+	return NULL;
+}
+
+static object *
+parsestr(s)
+	char *s;
+{
+	object *v;
+	int len;
+	char *buf;
+	char *p;
+	int c;
+	if (*s != '\'') {
+		err_badcall();
+		return NULL;
+	}
+	s++;
+	len = strlen(s);
+	if (s[--len] != '\'') {
+		err_badcall();
+		return NULL;
+	}
+	if (strchr(s, '\\') == NULL)
+		return newsizedstringobject(s, len);
+	v = newsizedstringobject((char *)NULL, len);
+	p = buf = getstringvalue(v);
+	while (*s != '\0' && *s != '\'') {
+		if (*s != '\\') {
+			*p++ = *s++;
+			continue;
+		}
+		s++;
+		switch (*s++) {
+		/* XXX This assumes ASCII! */
+		case '\\': *p++ = '\\'; break;
+		case '\'': *p++ = '\''; break;
+		case 'b': *p++ = '\b'; break;
+		case 'f': *p++ = '\014'; break; /* FF */
+		case 't': *p++ = '\t'; break;
+		case 'n': *p++ = '\n'; break;
+		case 'r': *p++ = '\r'; break;
+		case 'v': *p++ = '\013'; break; /* VT */
+		case 'E': *p++ = '\033'; break; /* ESC, not C */
+		case 'a': *p++ = '\007'; break; /* BEL, not classic C */
+		case '0': case '1': case '2': case '3':
+		case '4': case '5': case '6': case '7':
+			c = s[-1] - '0';
+			if ('0' <= *s && *s <= '7') {
+				c = (c<<3) + *s++ - '0';
+				if ('0' <= *s && *s <= '7')
+					c = (c<<3) + *s++ - '0';
+			}
+			*p++ = c;
+			break;
+		case 'x':
+			if (isxdigit(*s)) {
+				sscanf(s, "%x", &c);
+				*p++ = c;
+				do {
+					s++;
+				} while (isxdigit(*s));
+				break;
+			}
+		/* FALLTHROUGH */
+		default: *p++ = '\\'; *p++ = s[-1]; break;
+		}
+	}
+	resizestring(&v, (int)(p - buf));
+	return v;
+}
+
+static void
+com_list_constructor(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int len;
+	int i;
+	object *v, *w;
+	if (TYPE(n) != testlist)
+		REQ(n, exprlist);
+	/* exprlist: expr (',' expr)* [',']; likewise for testlist */
+	len = (NCH(n) + 1) / 2;
+	for (i = 0; i < NCH(n); i += 2)
+		com_node(c, CHILD(n, i));
+	com_addoparg(c, BUILD_LIST, len);
+}
+
+static void
+com_atom(c, n)
+	struct compiling *c;
+	node *n;
+{
+	node *ch;
+	object *v;
+	int i;
+	REQ(n, atom);
+	ch = CHILD(n, 0);
+	switch (TYPE(ch)) {
+	case LPAR:
+		if (TYPE(CHILD(n, 1)) == RPAR)
+			com_addoparg(c, BUILD_TUPLE, 0);
+		else
+			com_node(c, CHILD(n, 1));
+		break;
+	case LSQB:
+		if (TYPE(CHILD(n, 1)) == RSQB)
+			com_addoparg(c, BUILD_LIST, 0);
+		else
+			com_list_constructor(c, CHILD(n, 1));
+		break;
+	case LBRACE:
+		com_addoparg(c, BUILD_MAP, 0);
+		break;
+	case BACKQUOTE:
+		com_node(c, CHILD(n, 1));
+		com_addbyte(c, UNARY_CONVERT);
+		break;
+	case NUMBER:
+		if ((v = parsenumber(STR(ch))) == NULL) {
+			c->c_errors++;
+			i = 255;
+		}
+		else {
+			i = com_addconst(c, v);
+			DECREF(v);
+		}
+		com_addoparg(c, LOAD_CONST, i);
+		break;
+	case STRING:
+		if ((v = parsestr(STR(ch))) == NULL) {
+			c->c_errors++;
+			i = 255;
+		}
+		else {
+			i = com_addconst(c, v);
+			DECREF(v);
+		}
+		com_addoparg(c, LOAD_CONST, i);
+		break;
+	case NAME:
+		com_addopname(c, LOAD_NAME, ch);
+		break;
+	default:
+		fprintf(stderr, "node type %d\n", TYPE(ch));
+		err_setstr(SystemError, "com_atom: unexpected node type");
+		c->c_errors++;
+	}
+}
+
+static void
+com_slice(c, n, op)
+	struct compiling *c;
+	node *n;
+	int op;
+{
+	if (NCH(n) == 1) {
+		com_addbyte(c, op);
+	}
+	else if (NCH(n) == 2) {
+		if (TYPE(CHILD(n, 0)) != COLON) {
+			com_node(c, CHILD(n, 0));
+			com_addbyte(c, op+1);
+		}
+		else {
+			com_node(c, CHILD(n, 1));
+			com_addbyte(c, op+2);
+		}
+	}
+	else {
+		com_node(c, CHILD(n, 0));
+		com_node(c, CHILD(n, 2));
+		com_addbyte(c, op+3);
+	}
+}
+
+static void
+com_apply_subscript(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, subscript);
+	if (NCH(n) == 1 && TYPE(CHILD(n, 0)) != COLON) {
+		/* It's a single subscript */
+		com_node(c, CHILD(n, 0));
+		com_addbyte(c, BINARY_SUBSCR);
+	}
+	else {
+		/* It's a slice: [expr] ':' [expr] */
+		com_slice(c, n, SLICE);
+	}
+}
+
+static void
+com_call_function(c, n)
+	struct compiling *c;
+	node *n; /* EITHER testlist OR ')' */
+{
+	if (TYPE(n) == RPAR) {
+		com_addbyte(c, UNARY_CALL);
+	}
+	else {
+		com_node(c, n);
+		com_addbyte(c, BINARY_CALL);
+	}
+}
+
+static void
+com_select_member(c, n)
+	struct compiling *c;
+	node *n;
+{
+	com_addopname(c, LOAD_ATTR, n);
+}
+
+static void
+com_apply_trailer(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, trailer);
+	switch (TYPE(CHILD(n, 0))) {
+	case LPAR:
+		com_call_function(c, CHILD(n, 1));
+		break;
+	case DOT:
+		com_select_member(c, CHILD(n, 1));
+		break;
+	case LSQB:
+		com_apply_subscript(c, CHILD(n, 1));
+		break;
+	default:
+		err_setstr(SystemError,
+			"com_apply_trailer: unknown trailer type");
+		c->c_errors++;
+	}
+}
+
+static void
+com_factor(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	REQ(n, factor);
+	if (TYPE(CHILD(n, 0)) == PLUS) {
+		com_factor(c, CHILD(n, 1));
+		com_addbyte(c, UNARY_POSITIVE);
+	}
+	else if (TYPE(CHILD(n, 0)) == MINUS) {
+		com_factor(c, CHILD(n, 1));
+		com_addbyte(c, UNARY_NEGATIVE);
+	}
+	else {
+		com_atom(c, CHILD(n, 0));
+		for (i = 1; i < NCH(n); i++)
+			com_apply_trailer(c, CHILD(n, i));
+	}
+}
+
+static void
+com_term(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	int op;
+	REQ(n, term);
+	com_factor(c, CHILD(n, 0));
+	for (i = 2; i < NCH(n); i += 2) {
+		com_factor(c, CHILD(n, i));
+		switch (TYPE(CHILD(n, i-1))) {
+		case STAR:
+			op = BINARY_MULTIPLY;
+			break;
+		case SLASH:
+			op = BINARY_DIVIDE;
+			break;
+		case PERCENT:
+			op = BINARY_MODULO;
+			break;
+		default:
+			err_setstr(SystemError,
+				"com_term: term operator not *, / or %");
+			c->c_errors++;
+			op = 255;
+		}
+		com_addbyte(c, op);
+	}
+}
+
+static void
+com_expr(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	int op;
+	REQ(n, expr);
+	com_term(c, CHILD(n, 0));
+	for (i = 2; i < NCH(n); i += 2) {
+		com_term(c, CHILD(n, i));
+		switch (TYPE(CHILD(n, i-1))) {
+		case PLUS:
+			op = BINARY_ADD;
+			break;
+		case MINUS:
+			op = BINARY_SUBTRACT;
+			break;
+		default:
+			err_setstr(SystemError,
+				"com_expr: expr operator not + or -");
+			c->c_errors++;
+			op = 255;
+		}
+		com_addbyte(c, op);
+	}
+}
+
+static enum cmp_op
+cmp_type(n)
+	node *n;
+{
+	REQ(n, comp_op);
+	/* comp_op: '<' | '>' | '=' | '>' '=' | '<' '=' | '<' '>'
+	          | 'in' | 'not' 'in' | 'is' | 'is' not' */
+	if (NCH(n) == 1) {
+		n = CHILD(n, 0);
+		switch (TYPE(n)) {
+		case LESS:	return LT;
+		case GREATER:	return GT;
+		case EQUAL:	return EQ;
+		case NAME:	if (strcmp(STR(n), "in") == 0) return IN;
+				if (strcmp(STR(n), "is") == 0) return IS;
+		}
+	}
+	else if (NCH(n) == 2) {
+		int t2 = TYPE(CHILD(n, 1));
+		switch (TYPE(CHILD(n, 0))) {
+		case LESS:	if (t2 == EQUAL)	return LE;
+				if (t2 == GREATER)	return NE;
+				break;
+		case GREATER:	if (t2 == EQUAL)	return GE;
+				break;
+		case NAME:	if (strcmp(STR(CHILD(n, 1)), "in") == 0)
+					return NOT_IN;
+				if (strcmp(STR(CHILD(n, 0)), "is") == 0)
+					return IS_NOT;
+		}
+	}
+	return BAD;
+}
+
+static void
+com_comparison(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	enum cmp_op op;
+	int anchor;
+	REQ(n, comparison); /* comparison: expr (comp_op expr)* */
+	com_expr(c, CHILD(n, 0));
+	if (NCH(n) == 1)
+		return;
+	
+	/****************************************************************
+	   The following code is generated for all but the last
+	   comparison in a chain:
+	   
+	   label:	on stack:	opcode:		jump to:
+	   
+			a		<code to load b>
+			a, b		DUP_TOP
+			a, b, b		ROT_THREE
+			b, a, b		COMPARE_OP
+			b, 0-or-1	JUMP_IF_FALSE	L1
+			b, 1		POP_TOP
+			b		
+	
+	   We are now ready to repeat this sequence for the next
+	   comparison in the chain.
+	   
+	   For the last we generate:
+	   
+	   		b		<code to load c>
+	   		b, c		COMPARE_OP
+	   		0-or-1		
+	   
+	   If there were any jumps to L1 (i.e., there was more than one
+	   comparison), we generate:
+	   
+	   		0-or-1		JUMP_FORWARD	L2
+	   L1:		b, 0		ROT_TWO
+	   		0, b		POP_TOP
+	   		0
+	   L2:
+	****************************************************************/
+	
+	anchor = 0;
+	
+	for (i = 2; i < NCH(n); i += 2) {
+		com_expr(c, CHILD(n, i));
+		if (i+2 < NCH(n)) {
+			com_addbyte(c, DUP_TOP);
+			com_addbyte(c, ROT_THREE);
+		}
+		op = cmp_type(CHILD(n, i-1));
+		if (op == BAD) {
+			err_setstr(SystemError,
+				"com_comparison: unknown comparison op");
+			c->c_errors++;
+		}
+		com_addoparg(c, COMPARE_OP, op);
+		if (i+2 < NCH(n)) {
+			com_addfwref(c, JUMP_IF_FALSE, &anchor);
+			com_addbyte(c, POP_TOP);
+		}
+	}
+	
+	if (anchor) {
+		int anchor2 = 0;
+		com_addfwref(c, JUMP_FORWARD, &anchor2);
+		com_backpatch(c, anchor);
+		com_addbyte(c, ROT_TWO);
+		com_addbyte(c, POP_TOP);
+		com_backpatch(c, anchor2);
+	}
+}
+
+static void
+com_not_test(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, not_test); /* 'not' not_test | comparison */
+	if (NCH(n) == 1) {
+		com_comparison(c, CHILD(n, 0));
+	}
+	else {
+		com_not_test(c, CHILD(n, 1));
+		com_addbyte(c, UNARY_NOT);
+	}
+}
+
+static void
+com_and_test(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	int anchor;
+	REQ(n, and_test); /* not_test ('and' not_test)* */
+	anchor = 0;
+	i = 0;
+	for (;;) {
+		com_not_test(c, CHILD(n, i));
+		if ((i += 2) >= NCH(n))
+			break;
+		com_addfwref(c, JUMP_IF_FALSE, &anchor);
+		com_addbyte(c, POP_TOP);
+	}
+	if (anchor)
+		com_backpatch(c, anchor);
+}
+
+static void
+com_test(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	int anchor;
+	REQ(n, test); /* and_test ('and' and_test)* */
+	anchor = 0;
+	i = 0;
+	for (;;) {
+		com_and_test(c, CHILD(n, i));
+		if ((i += 2) >= NCH(n))
+			break;
+		com_addfwref(c, JUMP_IF_TRUE, &anchor);
+		com_addbyte(c, POP_TOP);
+	}
+	if (anchor)
+		com_backpatch(c, anchor);
+}
+
+static void
+com_list(c, n)
+	struct compiling *c;
+	node *n;
+{
+	/* exprlist: expr (',' expr)* [',']; likewise for testlist */
+	if (NCH(n) == 1) {
+		com_node(c, CHILD(n, 0));
+	}
+	else {
+		int i;
+		int len;
+		len = (NCH(n) + 1) / 2;
+		for (i = 0; i < NCH(n); i += 2)
+			com_node(c, CHILD(n, i));
+		com_addoparg(c, BUILD_TUPLE, len);
+	}
+}
+
+
+/* Begin of assignment compilation */
+
+static void com_assign_name PROTO((struct compiling *, node *, int));
+static void com_assign PROTO((struct compiling *, node *, int));
+
+static void
+com_assign_attr(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n);
+}
+
+static void
+com_assign_slice(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	com_slice(c, n, assigning ? STORE_SLICE : DELETE_SLICE);
+}
+
+static void
+com_assign_subscript(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	com_node(c, n);
+	com_addbyte(c, assigning ? STORE_SUBSCR : DELETE_SUBSCR);
+}
+
+static void
+com_assign_trailer(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	char *name;
+	REQ(n, trailer);
+	switch (TYPE(CHILD(n, 0))) {
+	case LPAR: /* '(' [exprlist] ')' */
+		err_setstr(TypeError, "can't assign to function call");
+		c->c_errors++;
+		break;
+	case DOT: /* '.' NAME */
+		com_assign_attr(c, CHILD(n, 1), assigning);
+		break;
+	case LSQB: /* '[' subscript ']' */
+		n = CHILD(n, 1);
+		REQ(n, subscript); /* subscript: expr | [expr] ':' [expr] */
+		if (NCH(n) > 1 || TYPE(CHILD(n, 0)) == COLON)
+			com_assign_slice(c, n, assigning);
+		else
+			com_assign_subscript(c, CHILD(n, 0), assigning);
+		break;
+	default:
+		err_setstr(TypeError, "unknown trailer type");
+		c->c_errors++;
+	}
+}
+
+static void
+com_assign_tuple(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	int i;
+	if (TYPE(n) != testlist)
+		REQ(n, exprlist);
+	if (assigning)
+		com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2);
+	for (i = 0; i < NCH(n); i += 2)
+		com_assign(c, CHILD(n, i), assigning);
+}
+
+static void
+com_assign_list(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	int i;
+	if (assigning)
+		com_addoparg(c, UNPACK_LIST, (NCH(n)+1)/2);
+	for (i = 0; i < NCH(n); i += 2)
+		com_assign(c, CHILD(n, i), assigning);
+}
+
+static void
+com_assign_name(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	REQ(n, NAME);
+	com_addopname(c, assigning ? STORE_NAME : DELETE_NAME, n);
+}
+
+static void
+com_assign(c, n, assigning)
+	struct compiling *c;
+	node *n;
+	int assigning;
+{
+	/* Loop to avoid trivial recursion */
+	for (;;) {
+		switch (TYPE(n)) {
+		case exprlist:
+		case testlist:
+			if (NCH(n) > 1) {
+				com_assign_tuple(c, n, assigning);
+				return;
+			}
+			n = CHILD(n, 0);
+			break;
+		case test:
+		case and_test:
+		case not_test:
+			if (NCH(n) > 1) {
+				err_setstr(TypeError,
+					"can't assign to operator");
+				c->c_errors++;
+				return;
+			}
+			n = CHILD(n, 0);
+			break;
+		case comparison:
+			if (NCH(n) > 1) {
+				err_setstr(TypeError,
+					"can't assign to operator");
+				c->c_errors++;
+				return;
+			}
+			n = CHILD(n, 0);
+			break;
+		case expr:
+			if (NCH(n) > 1) {
+				err_setstr(TypeError,
+					"can't assign to operator");
+				c->c_errors++;
+				return;
+			}
+			n = CHILD(n, 0);
+			break;
+		case term:
+			if (NCH(n) > 1) {
+				err_setstr(TypeError,
+					"can't assign to operator");
+				c->c_errors++;
+				return;
+			}
+			n = CHILD(n, 0);
+			break;
+		case factor: /* ('+'|'-') factor | atom trailer* */
+			if (TYPE(CHILD(n, 0)) != atom) { /* '+' | '-' */
+				err_setstr(TypeError,
+					"can't assign to operator");
+				c->c_errors++;
+				return;
+			}
+			if (NCH(n) > 1) { /* trailer present */
+				int i;
+				com_node(c, CHILD(n, 0));
+				for (i = 1; i+1 < NCH(n); i++) {
+					com_apply_trailer(c, CHILD(n, i));
+				} /* NB i is still alive */
+				com_assign_trailer(c,
+						CHILD(n, i), assigning);
+				return;
+			}
+			n = CHILD(n, 0);
+			break;
+		case atom:
+			switch (TYPE(CHILD(n, 0))) {
+			case LPAR:
+				n = CHILD(n, 1);
+				if (TYPE(n) == RPAR) {
+					/* XXX Should allow () = () ??? */
+					err_setstr(TypeError,
+						"can't assign to ()");
+					c->c_errors++;
+					return;
+				}
+				break;
+			case LSQB:
+				n = CHILD(n, 1);
+				if (TYPE(n) == RSQB) {
+					err_setstr(TypeError,
+						"can't assign to []");
+					c->c_errors++;
+					return;
+				}
+				com_assign_list(c, n, assigning);
+				return;
+			case NAME:
+				com_assign_name(c, CHILD(n, 0), assigning);
+				return;
+			default:
+				err_setstr(TypeError,
+						"can't assign to constant");
+				c->c_errors++;
+				return;
+			}
+			break;
+		default:
+			fprintf(stderr, "node type %d\n", TYPE(n));
+			err_setstr(SystemError, "com_assign: bad node");
+			c->c_errors++;
+			return;
+		}
+	}
+}
+
+static void
+com_expr_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, expr_stmt); /* exprlist ('=' exprlist)* NEWLINE */
+	com_node(c, CHILD(n, NCH(n)-2));
+	if (NCH(n) == 2) {
+		com_addbyte(c, PRINT_EXPR);
+	}
+	else {
+		int i;
+		for (i = 0; i < NCH(n)-3; i+=2) {
+			if (i+2 < NCH(n)-3)
+				com_addbyte(c, DUP_TOP);
+			com_assign(c, CHILD(n, i), 1/*assign*/);
+		}
+	}
+}
+
+static void
+com_print_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	REQ(n, print_stmt); /* 'print' (test ',')* [test] NEWLINE */
+	for (i = 1; i+1 < NCH(n); i += 2) {
+		com_node(c, CHILD(n, i));
+		com_addbyte(c, PRINT_ITEM);
+	}
+	if (TYPE(CHILD(n, NCH(n)-2)) != COMMA)
+		com_addbyte(c, PRINT_NEWLINE);
+}
+
+static void
+com_return_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */
+	if (NCH(n) == 2)
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+	else
+		com_node(c, CHILD(n, 1));
+	com_addbyte(c, RETURN_VALUE);
+}
+
+static void
+com_raise_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, raise_stmt); /* 'raise' expr [',' expr] NEWLINE */
+	com_node(c, CHILD(n, 1));
+	if (NCH(n) > 3)
+		com_node(c, CHILD(n, 3));
+	else
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+	com_addbyte(c, RAISE_EXCEPTION);
+}
+
+static void
+com_import_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	REQ(n, import_stmt);
+	/* 'import' NAME (',' NAME)* NEWLINE |
+	   'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE */
+	if (STR(CHILD(n, 0))[0] == 'f') {
+		/* 'from' NAME 'import' ... */
+		REQ(CHILD(n, 1), NAME);
+		com_addopname(c, IMPORT_NAME, CHILD(n, 1));
+		for (i = 3; i < NCH(n); i += 2)
+			com_addopname(c, IMPORT_FROM, CHILD(n, i));
+		com_addbyte(c, POP_TOP);
+	}
+	else {
+		for (i = 1; i < NCH(n); i += 2) {
+			com_addopname(c, IMPORT_NAME, CHILD(n, i));
+			com_addopname(c, STORE_NAME, CHILD(n, i));
+		}
+	}
+}
+
+static void
+com_if_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	int anchor = 0;
+	REQ(n, if_stmt);
+	/*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */
+	for (i = 0; i+3 < NCH(n); i+=4) {
+		int a = 0;
+		com_node(c, CHILD(n, i+1));
+		com_addfwref(c, JUMP_IF_FALSE, &a);
+		com_addbyte(c, POP_TOP);
+		com_node(c, CHILD(n, i+3));
+		com_addfwref(c, JUMP_FORWARD, &anchor);
+		com_backpatch(c, a);
+		com_addbyte(c, POP_TOP);
+	}
+	if (i+2 < NCH(n))
+		com_node(c, CHILD(n, i+2));
+	com_backpatch(c, anchor);
+}
+
+static void
+com_while_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int break_anchor = 0;
+	int anchor = 0;
+	int begin;
+	REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */
+	com_addfwref(c, SETUP_LOOP, &break_anchor);
+	begin = c->c_nexti;
+	com_node(c, CHILD(n, 1));
+	com_addfwref(c, JUMP_IF_FALSE, &anchor);
+	com_addbyte(c, POP_TOP);
+	com_node(c, CHILD(n, 3));
+	com_addoparg(c, JUMP_ABSOLUTE, begin);
+	com_backpatch(c, anchor);
+	com_addbyte(c, POP_TOP);
+	com_addbyte(c, POP_BLOCK);
+	if (NCH(n) > 4)
+		com_node(c, CHILD(n, 6));
+	com_backpatch(c, break_anchor);
+}
+
+static void
+com_for_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	object *v;
+	int break_anchor = 0;
+	int anchor = 0;
+	int begin;
+	REQ(n, for_stmt);
+	/* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */
+	com_addfwref(c, SETUP_LOOP, &break_anchor);
+	com_node(c, CHILD(n, 3));
+	v = newintobject(0L);
+	if (v == NULL)
+		c->c_errors++;
+	com_addoparg(c, LOAD_CONST, com_addconst(c, v));
+	XDECREF(v);
+	begin = c->c_nexti;
+	com_addfwref(c, FOR_LOOP, &anchor);
+	com_assign(c, CHILD(n, 1), 1/*assigning*/);
+	com_node(c, CHILD(n, 5));
+	com_addoparg(c, JUMP_ABSOLUTE, begin);
+	com_backpatch(c, anchor);
+	com_addbyte(c, POP_BLOCK);
+	if (NCH(n) > 8)
+		com_node(c, CHILD(n, 8));
+	com_backpatch(c, break_anchor);
+}
+
+static void
+com_try_stmt(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int finally_anchor = 0;
+	int except_anchor = 0;
+	REQ(n, try_stmt);
+	/* 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] */
+	if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) {
+		/* Have a 'finally' clause */
+		com_addfwref(c, SETUP_FINALLY, &finally_anchor);
+	}
+	if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == except_clause) {
+		/* Have an 'except' clause */
+		com_addfwref(c, SETUP_EXCEPT, &except_anchor);
+	}
+	com_node(c, CHILD(n, 2));
+	if (except_anchor) {
+		int end_anchor = 0;
+		int i;
+		node *ch;
+		com_addbyte(c, POP_BLOCK);
+		com_addfwref(c, JUMP_FORWARD, &end_anchor);
+		com_backpatch(c, except_anchor);
+		for (i = 3;
+			i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
+								i += 3) {
+			/* except_clause: 'except' [expr [',' expr]] */
+			int next_anchor = 0;
+			if (NCH(ch) > 1) {
+				com_addbyte(c, DUP_TOP);
+				com_node(c, CHILD(ch, 1));
+				com_addoparg(c, COMPARE_OP, EXC_MATCH);
+				com_addfwref(c, JUMP_IF_FALSE, &next_anchor);
+				com_addbyte(c, POP_TOP);
+			}
+			com_addbyte(c, POP_TOP);
+			if (NCH(ch) > 3)
+				com_assign(c, CHILD(ch, 3), 1/*assigning*/);
+			else
+				com_addbyte(c, POP_TOP);
+			com_node(c, CHILD(n, i+2));
+			com_addfwref(c, JUMP_FORWARD, &end_anchor);
+			if (next_anchor)
+				com_backpatch(c, next_anchor);
+		}
+		com_addbyte(c, END_FINALLY);
+		com_backpatch(c, end_anchor);
+	}
+	if (finally_anchor) {
+		com_addbyte(c, POP_BLOCK);
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_backpatch(c, finally_anchor);
+		com_node(c, CHILD(n, NCH(n)-1));
+		com_addbyte(c, END_FINALLY);
+	}
+}
+
+static void
+com_suite(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, suite);
+	/* simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT */
+	if (NCH(n) == 1) {
+		com_node(c, CHILD(n, 0));
+	}
+	else {
+		int i;
+		for (i = 0; i < NCH(n); i++) {
+			node *ch = CHILD(n, i);
+			if (TYPE(ch) == stmt)
+				com_node(c, ch);
+		}
+	}
+}
+
+static void
+com_funcdef(c, n)
+	struct compiling *c;
+	node *n;
+{
+	object *v;
+	REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
+	v = (object *)compile(n);
+	if (v == NULL)
+		c->c_errors++;
+	else {
+		int i = com_addconst(c, v);
+		com_addoparg(c, LOAD_CONST, i);
+		com_addbyte(c, BUILD_FUNCTION);
+		com_addopname(c, STORE_NAME, CHILD(n, 1));
+		DECREF(v);
+	}
+}
+
+static void
+com_classdef(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, classdef);
+	/*
+	classdef: 'class' NAME parameters ['=' baselist] ':' suite
+	baselist: atom arguments (',' atom arguments)*
+	arguments: '(' [testlist] ')'
+	*/
+	err_setstr(SystemError, "can't compile 'class' yet");
+	c->c_errors++;
+}
+
+static void
+com_node(c, n)
+	struct compiling *c;
+	node *n;
+{
+	switch (TYPE(n)) {
+	
+	/* Definition nodes */
+	
+	case funcdef:
+		com_funcdef(c, n);
+		break;
+	case classdef:
+		com_classdef(c, n);
+		break;
+	
+	/* Trivial parse tree nodes */
+	
+	case stmt:
+	case simple_stmt:
+	case flow_stmt:
+	case compound_stmt:
+		com_node(c, CHILD(n, 0));
+		break;
+
+	/* Statement nodes */
+	
+	case expr_stmt:
+		com_expr_stmt(c, n);
+		break;
+	case print_stmt:
+		com_print_stmt(c, n);
+		break;
+	case del_stmt: /* 'del' exprlist NEWLINE */
+		com_assign(c, CHILD(n, 1), 0/*delete*/);
+		break;
+	case pass_stmt:
+		break;
+	case break_stmt:
+		com_addbyte(c, BREAK_LOOP);
+		break;
+	case return_stmt:
+		com_return_stmt(c, n);
+		break;
+	case raise_stmt:
+		com_raise_stmt(c, n);
+		break;
+	case import_stmt:
+		com_import_stmt(c, n);
+		break;
+	case if_stmt:
+		com_if_stmt(c, n);
+		break;
+	case while_stmt:
+		com_while_stmt(c, n);
+		break;
+	case for_stmt:
+		com_for_stmt(c, n);
+		break;
+	case try_stmt:
+		com_try_stmt(c, n);
+		break;
+	case suite:
+		com_suite(c, n);
+		break;
+	
+	/* Expression nodes */
+	
+	case testlist:
+		com_list(c, n);
+		break;
+	case test:
+		com_test(c, n);
+		break;
+	case and_test:
+		com_and_test(c, n);
+		break;
+	case not_test:
+		com_not_test(c, n);
+		break;
+	case comparison:
+		com_comparison(c, n);
+		break;
+	case exprlist:
+		com_list(c, n);
+		break;
+	case expr:
+		com_expr(c, n);
+		break;
+	case term:
+		com_term(c, n);
+		break;
+	case factor:
+		com_factor(c, n);
+		break;
+	case atom:
+		com_atom(c, n);
+		break;
+	
+	default:
+		fprintf(stderr, "node type %d\n", TYPE(n));
+		err_setstr(SystemError, "com_node: unexpected node type");
+		c->c_errors++;
+	}
+}
+
+static void com_fplist PROTO((struct compiling *, node *));
+
+static void
+com_fpdef(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */
+	if (TYPE(CHILD(n, 0)) == LPAR)
+		com_fplist(c, CHILD(n, 1));
+	else
+		com_addopname(c, STORE_NAME, CHILD(n, 0));
+}
+
+static void
+com_fplist(c, n)
+	struct compiling *c;
+	node *n;
+{
+	REQ(n, fplist); /* fplist: fpdef (',' fpdef)* */
+	if (NCH(n) == 1) {
+		com_fpdef(c, CHILD(n, 0));
+	}
+	else {
+		int i;
+		com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2);
+		for (i = 0; i < NCH(n); i += 2)
+			com_fpdef(c, CHILD(n, i));
+	}
+}
+
+static void
+com_file_input(c, n)
+	struct compiling *c;
+	node *n;
+{
+	int i;
+	REQ(n, file_input); /* (NEWLINE | stmt)* ENDMARKER */
+	for (i = 0; i < NCH(n); i++) {
+		node *ch = CHILD(n, i);
+		if (TYPE(ch) != ENDMARKER && TYPE(ch) != NEWLINE)
+			com_node(c, ch);
+	}
+}
+
+/* Top-level compile-node interface */
+
+static void
+compile_funcdef(c, n)
+	struct compiling *c;
+	node *n;
+{
+	node *ch;
+	REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
+	ch = CHILD(n, 2); /* parameters: '(' [fplist] ')' */
+	ch = CHILD(ch, 1); /* ')' | fplist */
+	if (TYPE(ch) == RPAR)
+		com_addbyte(c, REFUSE_ARGS);
+	else {
+		com_addbyte(c, REQUIRE_ARGS);
+		com_fplist(c, ch);
+	}
+	com_node(c, CHILD(n, 4));
+	com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+	com_addbyte(c, RETURN_VALUE);
+}
+
+static void
+compile_node(c, n)
+	struct compiling *c;
+	node *n;
+{
+	switch (TYPE(n)) {
+	
+	case single_input:
+		/* NEWLINE | simple_stmt | compound_stmt NEWLINE */
+		n = CHILD(n, 0);
+		if (TYPE(n) != NEWLINE)
+			com_node(c, n);
+		break;
+	
+	case file_input:
+		com_file_input(c, n);
+		break;
+	
+	case expr_input:
+	case eval_input:
+		com_node(c, CHILD(n, 0));
+		break;
+	
+	case funcdef:
+		compile_funcdef(c, n);
+		break;
+	
+	default:
+		fprintf(stderr, "node type %d\n", TYPE(n));
+		err_setstr(SystemError, "compile_node: unexpected node type");
+		c->c_errors++;
+	}
+}
+
+codeobject *
+compile(n)
+	node *n;
+{
+	struct compiling sc;
+	codeobject *co;
+	if (!com_init(&sc))
+		return NULL;
+	compile_node(&sc, n);
+	com_done(&sc);
+	if (sc.c_errors == 0)
+		co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names);
+	else
+		co = NULL;
+	com_free(&sc);
+	return co;
+}