Add co_stacksize field to codeobject structure, and stacksize argument
to PyCode_New() argument list.  Move MAXBLOCKS constant to conpile.h.

Added accurate calculation of the actual stack size needed by the
generated code.

Also commented out all fprintf statements (except for a new one to
diagnose stack underflow, and one in #ifdef'ed out code), and added
some new TO DO suggestions (now that the stacksize is taken of the TO
DO list).
diff --git a/Python/compile.c b/Python/compile.c
index 5429e80..5562751 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -32,13 +32,14 @@
 /* Compile an expression node to intermediate code */
 
 /* XXX TO DO:
-   XXX Compute maximum needed stack sizes while compiling;
-   XXX   then frame object can be one malloc and no stack checks are needed
-   XXX add __doc__ attribute == co_doc to code object attributes
-   XXX don't execute doc string
+   XXX add __doc__ attribute == co_doc to code object attributes?
+   XXX   (it's currently the first item of the co_const tuple)
    XXX Generate simple jump for break/return outside 'try...finally'
+   XXX Allow 'continue' inside try-finally
    XXX get rid of SET_LINENO instructions, use JAR's table trick
    XXX   (need an option to put them back in, for debugger!)
+   XXX New 1-byte opcode for loading None
+   XXX New opcode for loading the initial index for a for loop
    XXX other JAR tricks?
 */
 
@@ -67,6 +68,7 @@
 static struct memberlist code_memberlist[] = {
 	{"co_argcount",	T_INT,		OFF(co_argcount),	READONLY},
 	{"co_nlocals",	T_INT,		OFF(co_nlocals),	READONLY},
+	{"co_stacksize",T_INT,		OFF(co_stacksize),	READONLY},
 	{"co_flags",	T_INT,		OFF(co_flags),		READONLY},
 	{"co_code",	T_OBJECT,	OFF(co_code),		READONLY},
 	{"co_consts",	T_OBJECT,	OFF(co_consts),		READONLY},
@@ -177,10 +179,11 @@
 };
 
 codeobject *
-newcodeobject(argcount, nlocals, flags,
+newcodeobject(argcount, nlocals, stacksize, flags,
 	      code, consts, names, varnames, filename, name)
 	int argcount;
 	int nlocals;
+	int stacksize;
 	int flags;
 	object *code;
 	object *consts;
@@ -221,6 +224,7 @@
 	if (co != NULL) {
 		co->co_argcount = argcount;
 		co->co_nlocals = nlocals;
+		co->co_stacksize = stacksize;
 		co->co_flags = flags;
 		INCREF(code);
 		co->co_code = (stringobject *)code;
@@ -241,8 +245,6 @@
 
 /* Data structure used internally */
 
-#define MAXBLOCKS 20 /* Max static block nesting within a function */
-
 struct compiling {
 	object *c_code;		/* string */
 	object *c_consts;	/* list of objects */
@@ -259,11 +261,13 @@
 	int c_interactive;	/* generating code for interactive command */
 	int c_loops;		/* counts nested loops */
 	int c_begin;		/* begin of current loop, for 'continue' */
-	int c_block[MAXBLOCKS];	/* stack of block types */
+	int c_block[CO_MAXBLOCKS]; /* stack of block types */
 	int c_nblocks;		/* current block stack level */
 	char *c_filename;	/* filename of current node */
 	char *c_name;		/* name of object (e.g. function) */
 	int c_lineno;		/* Current line number */
+	int c_stacklevel;	/* Current stack level */
+	int c_maxstacklevel;	/* Maximum stack level */
 #ifdef PRIVATE_NAME_MANGLING
 	char *c_private;	/* for private name mangling */
 #endif
@@ -307,7 +311,7 @@
 	struct compiling *c;
 	int type;
 {
-	if (c->c_nblocks >= MAXBLOCKS) {
+	if (c->c_nblocks >= CO_MAXBLOCKS) {
 		com_error(c, SystemError, "too many statically nested blocks");
 	}
 	else {
@@ -332,6 +336,8 @@
 
 static int com_init PROTO((struct compiling *, char *));
 static void com_free PROTO((struct compiling *));
+static void com_push PROTO((struct compiling *, int));
+static void com_pop PROTO((struct compiling *, int));
 static void com_done PROTO((struct compiling *));
 static void com_node PROTO((struct compiling *, struct _node *));
 static void com_factor PROTO((struct compiling *, struct _node *));
@@ -380,6 +386,8 @@
 	c->c_filename = filename;
 	c->c_name = "?";
 	c->c_lineno = 0;
+	c->c_stacklevel = 0;
+	c->c_maxstacklevel = 0;
 	return 1;
 	
   fail_000:
@@ -409,6 +417,32 @@
 }
 
 static void
+com_push(c, n)
+	struct compiling *c;
+	int n;
+{
+	c->c_stacklevel += n;
+	if (c->c_stacklevel > c->c_maxstacklevel)
+		c->c_maxstacklevel = c->c_stacklevel;
+}
+
+static void
+com_pop(c, n)
+	struct compiling *c;
+	int n;
+{
+	if (c->c_stacklevel < n) {
+		fprintf(stderr,
+			"%s:%d: underflow! nexti=%d, level=%d, n=%d\n",
+			c->c_filename, c->c_lineno,
+			c->c_nexti, c->c_stacklevel, n);
+		c->c_stacklevel = 0;
+	}
+	else
+		c->c_stacklevel -= n;
+}
+
+static void
 com_done(c)
 	struct compiling *c;
 {
@@ -804,6 +838,7 @@
 	for (i = 0; i < NCH(n); i += 2)
 		com_node(c, CHILD(n, i));
 	com_addoparg(c, BUILD_LIST, len);
+	com_pop(c, len-1);
 }
 
 static void
@@ -817,10 +852,12 @@
 		/* We must arrange things just right for STORE_SUBSCR.
 		   It wants the stack to look like (value) (dict) (key) */
 		com_addbyte(c, DUP_TOP);
+		com_push(c, 1);
 		com_node(c, CHILD(n, i+2)); /* value */
 		com_addbyte(c, ROT_TWO);
 		com_node(c, CHILD(n, i)); /* key */
 		com_addbyte(c, STORE_SUBSCR);
+		com_pop(c, 3);
 	}
 }
 
@@ -836,19 +873,24 @@
 	ch = CHILD(n, 0);
 	switch (TYPE(ch)) {
 	case LPAR:
-		if (TYPE(CHILD(n, 1)) == RPAR)
+		if (TYPE(CHILD(n, 1)) == RPAR) {
 			com_addoparg(c, BUILD_TUPLE, 0);
+			com_push(c, 1);
+		}
 		else
 			com_node(c, CHILD(n, 1));
 		break;
 	case LSQB:
-		if (TYPE(CHILD(n, 1)) == RSQB)
+		if (TYPE(CHILD(n, 1)) == RSQB) {
 			com_addoparg(c, BUILD_LIST, 0);
+			com_push(c, 1);
+		}
 		else
 			com_list_constructor(c, CHILD(n, 1));
 		break;
 	case LBRACE: /* '{' [dictmaker] '}' */
 		com_addoparg(c, BUILD_MAP, 0);
+		com_push(c, 1);
 		if (TYPE(CHILD(n, 1)) != RBRACE)
 			com_dictmaker(c, CHILD(n, 1));
 		break;
@@ -865,6 +907,7 @@
 			DECREF(v);
 		}
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		break;
 	case STRING:
 		v = parsestrplus(n);
@@ -877,12 +920,14 @@
 			DECREF(v);
 		}
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		break;
 	case NAME:
 		com_addopname(c, LOAD_NAME, ch);
+		com_push(c, 1);
 		break;
 	default:
-		fprintf(stderr, "node type %d\n", TYPE(ch));
+		/* XXX fprintf(stderr, "node type %d\n", TYPE(ch)); */
 		com_error(c, SystemError, "com_atom: unexpected node type");
 	}
 }
@@ -905,11 +950,13 @@
 			com_node(c, CHILD(n, 1));
 			com_addbyte(c, op+2);
 		}
+		com_pop(c, 1);
 	}
 	else {
 		com_node(c, CHILD(n, 0));
 		com_node(c, CHILD(n, 2));
 		com_addbyte(c, op+3);
+		com_pop(c, 2);
 	}
 }
 
@@ -920,7 +967,7 @@
 	object **pkeywords;
 {
 	node *m;
-	REQ(n, argument); /* [test '='] test; really [ keyword '='] keyword */
+	REQ(n, argument); /* [test '='] test; really [keyword '='] test */
 	if (NCH(n) == 1) {
 		if (*pkeywords != NULL) {
 			com_error(c, SyntaxError,
@@ -952,6 +999,7 @@
 				if (dict2insert(*pkeywords, v, v) != 0)
 					c->c_errors++;
 			com_addoparg(c, LOAD_CONST, com_addconst(c, v));
+			com_push(c, 1);
 			DECREF(v);
 		}
 	}
@@ -984,6 +1032,7 @@
 			com_error(c, SyntaxError, "more than 255 arguments");
 		}
 		com_addoparg(c, CALL_FUNCTION, na | (nk << 8));
+		com_pop(c, na + 2*nk);
 	}
 }
 
@@ -1007,6 +1056,7 @@
 	/* first argument */
 	if (TYPE(CHILD(n,i)) == COLON) {
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_push(c, 1);
 		i++;
 	}
 	else {
@@ -1020,7 +1070,10 @@
 		com_node(c, CHILD(n,i));
 		i++;
 	}
-	else com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+	else {
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_push(c, 1);
+	}
 	/* remaining arguments */
 	for (; i < NCH(n); i++) {
 		ns++;
@@ -1029,11 +1082,13 @@
 		if (NCH(ch) == 1) {
 			/* right argument of ':' missing */
 			com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+			com_push(c, 1);
 		}
 		else
 			com_node(c, CHILD(ch,1));
 	}
 	com_addoparg(c, BUILD_SLICE, ns);
+	com_pop(c, 1 + (ns == 3));
 }
 
 static void
@@ -1045,8 +1100,10 @@
 	REQ(n, subscript);
 	ch = CHILD(n,0);
 	/* check for rubber index */
-	if (TYPE(ch) == DOT && TYPE(CHILD(n,1)) == DOT)
+	if (TYPE(ch) == DOT && TYPE(CHILD(n,1)) == DOT) {
 		com_addoparg(c, LOAD_CONST, com_addconst(c, Py_Ellipsis));
+		com_push(c, 1);
+	}
 	else {
 		/* check for slice */
 		if ((TYPE(ch) == COLON || NCH(n) > 1))
@@ -1070,15 +1127,20 @@
 	if (NCH(n) == 1) {
 		node *sub = CHILD(n, 0); /* subscript */
 		/* Make it is a simple slice.
-           should have exactly one colon. */
+		   Should have exactly one colon. */
         if ((TYPE(CHILD(sub, 0)) == COLON
              || (NCH(sub) > 1 && TYPE(CHILD(sub, 1)) == COLON))
-            && (TYPE(CHILD(sub,NCH(sub)-1)) != sliceop)) {
+            && (TYPE(CHILD(sub,NCH(sub)-1)) != sliceop))
+	{
 			if (assigning == OP_APPLY)
 				op = SLICE;
 			else
 				op = ((assigning == OP_ASSIGN) ? STORE_SLICE : DELETE_SLICE);
 			com_slice(c, sub, op);
+			if (op == STORE_SLICE)
+				com_pop(c, 2);
+			else if (op == DELETE_SLICE)
+				com_pop(c, 1);
 			return;
 		}
 	}
@@ -1086,13 +1148,25 @@
 	for (i = 0; i < NCH(n); i += 2)
 		com_subscript(c, CHILD(n, i));
 	/* Put multiple subscripts into a tuple */
-	if (NCH(n) > 1)
-		com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 2);
-	if (assigning == OP_APPLY)
+	if (NCH(n) > 1) {
+		i = (NCH(n)+1) / 2;
+		com_addoparg(c, BUILD_TUPLE, i);
+		com_pop(c, i-1);
+	}
+	if (assigning == OP_APPLY) {
 		op = BINARY_SUBSCR;
-	else
-		op = ((assigning == OP_ASSIGN) ? STORE_SUBSCR : DELETE_SUBSCR);
+		i = 1;
+	}
+	else if (assigning == OP_ASSIGN) {
+		op = STORE_SUBSCR;
+		i = 3;
+	}
+	else {
+		op = DELETE_SUBSCR;
+		i = 2;
+	}
 	com_addbyte(c, op);
+	com_pop(c, i);
 }
 
 static void
@@ -1129,6 +1203,7 @@
 		if (TYPE(CHILD(n, i)) == DOUBLESTAR) {
 			com_factor(c, CHILD(n, i+1));
 			com_addbyte(c, BINARY_POWER);
+			com_pop(c, 1);
 			break;
 		}
 		else
@@ -1186,6 +1261,7 @@
 			op = 255;
 		}
 		com_addbyte(c, op);
+		com_pop(c, 1);
 	}
 }
 
@@ -1213,6 +1289,7 @@
 			op = 255;
 		}
 		com_addbyte(c, op);
+		com_pop(c, 1);
 	}
 }
 
@@ -1240,6 +1317,7 @@
 			op = 255;
 		}
 		com_addbyte(c, op);
+		com_pop(c, 1);
 	}
 }
 
@@ -1263,6 +1341,7 @@
 			op = 255;
 		}
 		com_addbyte(c, op);
+		com_pop(c, 1);
 	}
 }
 
@@ -1286,6 +1365,7 @@
 			op = 255;
 		}
 		com_addbyte(c, op);
+		com_pop(c, 1);
 	}
 }
 
@@ -1309,6 +1389,7 @@
 			op = 255;
 		}
 		com_addbyte(c, op);
+		com_pop(c, 1);
 	}
 }
 
@@ -1387,7 +1468,7 @@
 	   L1:		b, 0		ROT_TWO
 	   		0, b		POP_TOP
 	   		0
-	   L2:
+	   L2:		0-or-1
 	****************************************************************/
 	
 	anchor = 0;
@@ -1396,6 +1477,7 @@
 		com_expr(c, CHILD(n, i));
 		if (i+2 < NCH(n)) {
 			com_addbyte(c, DUP_TOP);
+			com_push(c, 1);
 			com_addbyte(c, ROT_THREE);
 		}
 		op = cmp_type(CHILD(n, i-1));
@@ -1404,9 +1486,11 @@
 				  "com_comparison: unknown comparison op");
 		}
 		com_addoparg(c, COMPARE_OP, op);
+		com_pop(c, 1);
 		if (i+2 < NCH(n)) {
 			com_addfwref(c, JUMP_IF_FALSE, &anchor);
 			com_addbyte(c, POP_TOP);
+			com_pop(c, 1);
 		}
 	}
 	
@@ -1451,6 +1535,7 @@
 			break;
 		com_addfwref(c, JUMP_IF_FALSE, &anchor);
 		com_addbyte(c, POP_TOP);
+		com_pop(c, 1);
 	}
 	if (anchor)
 		com_backpatch(c, anchor);
@@ -1461,7 +1546,7 @@
 	struct compiling *c;
 	node *n;
 {
-	REQ(n, test); /* and_test ('and' and_test)* | lambdef */
+	REQ(n, test); /* and_test ('or' and_test)* | lambdef */
 	if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
 		object *v;
 		int i;
@@ -1476,7 +1561,9 @@
 			DECREF(v);
 		}
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		com_addoparg(c, MAKE_FUNCTION, ndefs);
+		com_pop(c, ndefs);
 	}
 	else {
 		int anchor = 0;
@@ -1487,6 +1574,7 @@
 				break;
 			com_addfwref(c, JUMP_IF_TRUE, &anchor);
 			com_addbyte(c, POP_TOP);
+			com_pop(c, 1);
 		}
 		if (anchor)
 			com_backpatch(c, anchor);
@@ -1510,6 +1598,7 @@
 		for (i = 0; i < NCH(n); i += 2)
 			com_node(c, CHILD(n, i));
 		com_addoparg(c, BUILD_TUPLE, len);
+		com_pop(c, len-1);
 	}
 }
 
@@ -1526,6 +1615,7 @@
 	int assigning;
 {
 	com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n);
+	com_pop(c, assigning ? 2 : 1);
 }
 
 static void
@@ -1559,8 +1649,11 @@
 	int i;
 	if (TYPE(n) != testlist)
 		REQ(n, exprlist);
-	if (assigning)
-		com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2);
+	if (assigning) {
+		i = (NCH(n)+1)/2;
+		com_addoparg(c, UNPACK_TUPLE, i);
+		com_push(c, i-1);
+	}
 	for (i = 0; i < NCH(n); i += 2)
 		com_assign(c, CHILD(n, i), assigning);
 }
@@ -1572,8 +1665,11 @@
 	int assigning;
 {
 	int i;
-	if (assigning)
-		com_addoparg(c, UNPACK_LIST, (NCH(n)+1)/2);
+	if (assigning) {
+		i = (NCH(n)+1)/2;
+		com_addoparg(c, UNPACK_LIST, i);
+		com_push(c, i-1);
+	}
 	for (i = 0; i < NCH(n); i += 2)
 		com_assign(c, CHILD(n, i), assigning);
 }
@@ -1586,6 +1682,8 @@
 {
 	REQ(n, NAME);
 	com_addopname(c, assigning ? STORE_NAME : DELETE_NAME, n);
+	if (assigning)
+		com_pop(c, 1);
 }
 
 static void
@@ -1686,13 +1784,14 @@
 			return;
 		
 		default:
-			fprintf(stderr, "node type %d\n", TYPE(n));
+			/* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
 			com_error(c, SystemError, "com_assign: bad node");
 			return;
 		
 		}
 	}
 }
+/* Forward */ static node *get_rawdocstring PROTO((node *));
 
 static void
 com_expr_stmt(c, n)
@@ -1700,18 +1799,24 @@
 	node *n;
 {
 	REQ(n, expr_stmt); /* testlist ('=' testlist)* */
+	/* Forget it if we have just a doc string here */
+	if (NCH(n) == 1 && get_rawdocstring(n) != NULL)
+		return;
 	com_node(c, CHILD(n, NCH(n)-1));
 	if (NCH(n) == 1) {
 		if (c->c_interactive)
 			com_addbyte(c, PRINT_EXPR);
 		else
 			com_addbyte(c, POP_TOP);
+		com_pop(c, 1);
 	}
 	else {
 		int i;
 		for (i = 0; i < NCH(n)-2; i+=2) {
-			if (i+2 < NCH(n)-2)
+			if (i+2 < NCH(n)-2) {
 				com_addbyte(c, DUP_TOP);
+				com_push(c, 1);
+			}
 			com_assign(c, CHILD(n, i), OP_ASSIGN);
 		}
 	}
@@ -1727,6 +1832,7 @@
 	for (i = 1; i < NCH(n); i += 2) {
 		com_node(c, CHILD(n, i));
 		com_addbyte(c, PRINT_ITEM);
+		com_pop(c, 1);
 	}
 	if (TYPE(CHILD(n, NCH(n)-1)) != COMMA)
 		com_addbyte(c, PRINT_NEWLINE);
@@ -1742,11 +1848,14 @@
 	if (!c->c_infunction) {
 		com_error(c, SyntaxError, "'return' outside function");
 	}
-	if (NCH(n) < 2)
+	if (NCH(n) < 2) {
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_push(c, 1);
+	}
 	else
 		com_node(c, CHILD(n, 1));
 	com_addbyte(c, RETURN_VALUE);
+	com_pop(c, 1);
 }
 
 static void
@@ -1754,6 +1863,7 @@
 	struct compiling *c;
 	node *n;
 {
+	int i;
 	REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
 	com_node(c, CHILD(n, 1));
 	if (NCH(n) > 3) {
@@ -1761,7 +1871,9 @@
 		if (NCH(n) > 5)
 			com_node(c, CHILD(n, 5));
 	}
-	com_addoparg(c, RAISE_VARARGS, NCH(n)/2);
+	i = NCH(n)/2;
+	com_addoparg(c, RAISE_VARARGS, i);
+	com_pop(c, i);
 }
 
 static void
@@ -1777,16 +1889,20 @@
 		/* 'from' dotted_name 'import' ... */
 		REQ(CHILD(n, 1), dotted_name);
 		com_addopname(c, IMPORT_NAME, CHILD(n, 1));
+		com_push(c, 1);
 		for (i = 3; i < NCH(n); i += 2)
 			com_addopname(c, IMPORT_FROM, CHILD(n, i));
 		com_addbyte(c, POP_TOP);
+		com_pop(c, 1);
 	}
 	else {
 		/* 'import' ... */
 		for (i = 1; i < NCH(n); i += 2) {
 			REQ(CHILD(n, i), dotted_name);
 			com_addopname(c, IMPORT_NAME, CHILD(n, i));
+			com_push(c, 1);
 			com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0));
+			com_pop(c, 1);
 		}
 	}
 }
@@ -1868,9 +1984,10 @@
 	return i;
 }
 
+#ifdef SUPPORT_OBSOLETE_ACCESS
+
 #define strequ(a, b) (strcmp((a), (b)) == 0)
 
-#ifdef SUPPORT_OBSOLETE_ACCESS
 static void
 com_access_stmt(c, n)
 	struct compiling *c;
@@ -1939,13 +2056,18 @@
 	com_node(c, CHILD(n, 1));
 	if (NCH(n) >= 4)
 		com_node(c, CHILD(n, 3));
-	else
+	else {
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_push(c, 1);
+	}
 	if (NCH(n) >= 6)
 		com_node(c, CHILD(n, 5));
-	else
+	else {
 		com_addbyte(c, DUP_TOP);
+		com_push(c, 1);
+	}
 	com_addbyte(c, EXEC_STMT);
+	com_pop(c, 3);
 }
 
 static void
@@ -1965,9 +2087,11 @@
 		com_node(c, CHILD(n, i+1));
 		com_addfwref(c, JUMP_IF_FALSE, &a);
 		com_addbyte(c, POP_TOP);
+		com_pop(c, 1);
 		com_node(c, CHILD(n, i+3));
 		com_addfwref(c, JUMP_FORWARD, &anchor);
 		com_backpatch(c, a);
+		/* We jump here with an extra entry which we now pop */
 		com_addbyte(c, POP_TOP);
 	}
 	if (i+2 < NCH(n))
@@ -1991,12 +2115,14 @@
 	com_node(c, CHILD(n, 1));
 	com_addfwref(c, JUMP_IF_FALSE, &anchor);
 	com_addbyte(c, POP_TOP);
+	com_pop(c, 1);
 	c->c_loops++;
 	com_node(c, CHILD(n, 3));
 	c->c_loops--;
 	com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
 	c->c_begin = save_begin;
 	com_backpatch(c, anchor);
+	/* We jump here with one entry more on the stack */
 	com_addbyte(c, POP_TOP);
 	com_addbyte(c, POP_BLOCK);
 	block_pop(c, SETUP_LOOP);
@@ -2023,10 +2149,12 @@
 	if (v == NULL)
 		c->c_errors++;
 	com_addoparg(c, LOAD_CONST, com_addconst(c, v));
+	com_push(c, 1);
 	XDECREF(v);
 	c->c_begin = c->c_nexti;
 	com_addoparg(c, SET_LINENO, n->n_lineno);
 	com_addfwref(c, FOR_LOOP, &anchor);
+	com_push(c, 1);
 	com_assign(c, CHILD(n, 1), OP_ASSIGN);
 	c->c_loops++;
 	com_node(c, CHILD(n, 5));
@@ -2034,6 +2162,7 @@
 	com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
 	c->c_begin = save_begin;
 	com_backpatch(c, anchor);
+	com_pop(c, 2); /* FOR_LOOP has popped these */
 	com_addbyte(c, POP_BLOCK);
 	block_pop(c, SETUP_LOOP);
 	if (NCH(n) > 8)
@@ -2128,34 +2257,49 @@
 	for (i = 3;
 	     i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
 	     i += 3) {
-		/* except_clause: 'except' [expr [',' expr]] */
+		/* except_clause: 'except' [expr [',' var]] */
 		if (except_anchor == 0) {
 			com_error(c, SyntaxError,
 				  "default 'except:' must be last");
 			break;
 		}
 		except_anchor = 0;
+		com_push(c, 3); /* tb, val, exc pushed by exception */
 		com_addoparg(c, SET_LINENO, ch->n_lineno);
 		if (NCH(ch) > 1) {
 			com_addbyte(c, DUP_TOP);
+			com_push(c, 1);
 			com_node(c, CHILD(ch, 1));
 			com_addoparg(c, COMPARE_OP, EXC_MATCH);
+			com_pop(c, 1);
 			com_addfwref(c, JUMP_IF_FALSE, &except_anchor);
 			com_addbyte(c, POP_TOP);
+			com_pop(c, 1);
 		}
 		com_addbyte(c, POP_TOP);
+		com_pop(c, 1);
 		if (NCH(ch) > 3)
 			com_assign(c, CHILD(ch, 3), OP_ASSIGN);
-		else
+		else {
 			com_addbyte(c, POP_TOP);
+			com_pop(c, 1);
+		}
 		com_addbyte(c, POP_TOP);
+		com_pop(c, 1);
 		com_node(c, CHILD(n, i+2));
 		com_addfwref(c, JUMP_FORWARD, &end_anchor);
 		if (except_anchor) {
 			com_backpatch(c, except_anchor);
+			/* We come in with [tb, val, exc, 0] on the
+			   stack; one pop and it's the same as
+			   expected at the start of the loop */
 			com_addbyte(c, POP_TOP);
 		}
 	}
+	/* We actually come in here with [tb, val, exc] but the
+	   END_FINALLY will zap those and jump around.
+	   The c_stacklevel does not reflect them so we need not pop
+	   anything. */
 	com_addbyte(c, END_FINALLY);
 	com_backpatch(c, else_anchor);
 	if (i < NCH(n))
@@ -2178,12 +2322,18 @@
 	block_pop(c, SETUP_FINALLY);
 	block_push(c, END_FINALLY);
 	com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+	/* While the generated code pushes only one item,
+	   the try-finally handling can enter here with
+	   up to three items.  OK, here are the details:
+	   3 for an exception, 2 for RETURN, 1 for BREAK. */
+	com_push(c, 3);
 	com_backpatch(c, finally_anchor);
 	ch = CHILD(n, NCH(n)-1);
 	com_addoparg(c, SET_LINENO, ch->n_lineno);
 	com_node(c, ch);
 	com_addbyte(c, END_FINALLY);
 	block_pop(c, END_FINALLY);
+	com_pop(c, 3); /* Matches the com_push above */
 }
 
 static void
@@ -2200,38 +2350,37 @@
 		com_try_except(c, n);
 }
 
-static object *
-get_docstring(n)
+static node *
+get_rawdocstring(n)
 	node *n;
 {
 	int i;
 
+  /* Label to avoid tail recursion */
+  next:
 	switch (TYPE(n)) {
 
 	case suite:
-		if (NCH(n) == 1)
-			return get_docstring(CHILD(n, 0));
-		else {
-			for (i = 0; i < NCH(n); i++) {
-				node *ch = CHILD(n, i);
-				if (TYPE(ch) == stmt)
-					return get_docstring(ch);
-			}
+		if (NCH(n) == 1) {
+			n = CHILD(n, 0);
+			goto next;
 		}
-		break;
-
+		/* Fall through */
 	case file_input:
 		for (i = 0; i < NCH(n); i++) {
 			node *ch = CHILD(n, i);
-			if (TYPE(ch) == stmt)
-				return get_docstring(ch);
+			if (TYPE(ch) == stmt) {
+				n = ch;
+				goto next;
+			}
 		}
 		break;
 
 	case stmt:
 	case simple_stmt:
 	case small_stmt:
-		return get_docstring(CHILD(n, 0));
+		n = CHILD(n, 0);
+		goto next;
 
 	case expr_stmt:
 	case testlist:
@@ -2247,19 +2396,31 @@
 	case term:
 	case factor:
 	case power:
-		if (NCH(n) == 1)
-			return get_docstring(CHILD(n, 0));
+		if (NCH(n) == 1) {
+			n = CHILD(n, 0);
+			goto next;
+		}
 		break;
 
 	case atom:
 		if (TYPE(CHILD(n, 0)) == STRING)
-			return parsestrplus(n);
+			return n;
 		break;
 
 	}
 	return NULL;
 }
 
+static object *
+get_docstring(n)
+	node *n;
+{
+	n = get_rawdocstring(n);
+	if (n == NULL)
+		return NULL;
+	return parsestrplus(n);
+}
+
 static void
 com_suite(c, n)
 	struct compiling *c;
@@ -2345,6 +2506,7 @@
 			if (ndefs) {
 				com_addoparg(c, LOAD_CONST,
 					     com_addconst(c, None));
+				com_push(c, 1);
 				ndefs++;
 			}
 		}
@@ -2368,8 +2530,11 @@
 		int i = com_addconst(c, v);
 		int ndefs = com_argdefs(c, n);
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		com_addoparg(c, MAKE_FUNCTION, ndefs);
+		com_pop(c, ndefs);
 		com_addopname(c, STORE_NAME, CHILD(n, 1));
+		com_pop(c, 1);
 		DECREF(v);
 	}
 }
@@ -2384,7 +2549,9 @@
 	/* testlist: test (',' test)* [','] */
 	for (i = 0; i < NCH(n); i += 2)
 		com_node(c, CHILD(n, i));
-	com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 2);
+	i = (NCH(n)+1) / 2;
+	com_addoparg(c, BUILD_TUPLE, i);
+	com_pop(c, i-1);
 }
 
 static void
@@ -2403,10 +2570,13 @@
 	/* Push the class name on the stack */
 	i = com_addconst(c, v);
 	com_addoparg(c, LOAD_CONST, i);
+	com_push(c, 1);
 	DECREF(v);
 	/* Push the tuple of base classes on the stack */
-	if (TYPE(CHILD(n, 2)) != LPAR)
+	if (TYPE(CHILD(n, 2)) != LPAR) {
 		com_addoparg(c, BUILD_TUPLE, 0);
+		com_push(c, 1);
+	}
 	else
 		com_bases(c, CHILD(n, 3));
 	v = (object *)icompile(n, c);
@@ -2415,9 +2585,11 @@
 	else {
 		i = com_addconst(c, v);
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		com_addoparg(c, MAKE_FUNCTION, 0);
 		com_addoparg(c, CALL_FUNCTION, 0);
 		com_addbyte(c, BUILD_CLASS);
+		com_pop(c, 2);
 		com_addopname(c, STORE_NAME, CHILD(n, 1));
 		DECREF(v);
 	}
@@ -2569,7 +2741,7 @@
 		break;
 	
 	default:
-		fprintf(stderr, "node type %d\n", TYPE(n));
+		/* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
 		com_error(c, SystemError, "com_node: unexpected node type");
 	}
 }
@@ -2584,8 +2756,10 @@
 	REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */
 	if (TYPE(CHILD(n, 0)) == LPAR)
 		com_fplist(c, CHILD(n, 1));
-	else
+	else {
 		com_addoparg(c, STORE_FAST, com_newlocal(c, STR(CHILD(n, 0))));
+		com_pop(c, 1);
+	}
 }
 
 static void
@@ -2598,8 +2772,9 @@
 		com_fpdef(c, CHILD(n, 0));
 	}
 	else {
-		int i;
-		com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2);
+		int i = (NCH(n)+1)/2;
+		com_addoparg(c, UNPACK_TUPLE, i);
+		com_push(c, i-1);
 		for (i = 0; i < NCH(n); i += 2)
 			com_fpdef(c, CHILD(n, i));
 	}
@@ -2684,6 +2859,7 @@
 			fp = CHILD(ch, 0);
 			if (TYPE(fp) != NAME) {
 				com_addoparg(c, LOAD_FAST, ilocal);
+				com_push(c, 1);
 				com_fpdef(c, ch);
 			}
 			ilocal++;
@@ -2711,7 +2887,9 @@
 		int i = com_addconst(c, doc);
 		DECREF(doc);
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		com_addopnamestr(c, STORE_NAME, "__doc__");
+		com_pop(c, 1);
 	}
 	for (i = 0; i < NCH(n); i++) {
 		node *ch = CHILD(n, i);
@@ -2746,7 +2924,9 @@
 	com_node(c, CHILD(n, 4));
 	c->c_infunction = 0;
 	com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+	com_push(c, 1);
 	com_addbyte(c, RETURN_VALUE);
+	com_pop(c, 1);
 }
 
 static void
@@ -2768,6 +2948,7 @@
 		ch = CHILD(n, 2);
 	com_node(c, ch);
 	com_addbyte(c, RETURN_VALUE);
+	com_pop(c, 1);
 }
 
 static void
@@ -2789,13 +2970,17 @@
 		int i = com_addconst(c, doc);
 		DECREF(doc);
 		com_addoparg(c, LOAD_CONST, i);
+		com_push(c, 1);
 		com_addopnamestr(c, STORE_NAME, "__doc__");
+		com_pop(c, 1);
 	}
 	else
 		(void) com_addconst(c, None);
 	com_node(c, ch);
 	com_addbyte(c, LOAD_LOCALS);
+	com_push(c, 1);
 	com_addbyte(c, RETURN_VALUE);
+	com_pop(c, 1);
 }
 
 static void
@@ -2814,19 +2999,24 @@
 		if (TYPE(n) != NEWLINE)
 			com_node(c, n);
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_push(c, 1);
 		com_addbyte(c, RETURN_VALUE);
+		com_pop(c, 1);
 		c->c_interactive--;
 		break;
 	
 	case file_input: /* A whole file, or built-in function exec() */
 		com_file_input(c, n);
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_push(c, 1);
 		com_addbyte(c, RETURN_VALUE);
+		com_pop(c, 1);
 		break;
 	
 	case eval_input: /* Built-in function input() */
 		com_node(c, CHILD(n, 0));
 		com_addbyte(c, RETURN_VALUE);
+		com_pop(c, 1);
 		break;
 	
 	case lambdef: /* anonymous function definition */
@@ -2842,7 +3032,7 @@
 		break;
 	
 	default:
-		fprintf(stderr, "node type %d\n", TYPE(n));
+		/* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
 		com_error(c, SystemError,
 			  "compile_node: unexpected node type");
 	}
@@ -3001,6 +3191,7 @@
 		if (!err_occurred())
 			co = newcodeobject(sc.c_argcount,
 					   sc.c_nlocals,
+					   sc.c_maxstacklevel,
 					   sc.c_flags,
 					   sc.c_code,
 					   consts,