diff Python/compile.c @ 86:a6934380c6e7 legacy-trunk

"Compiling" version
author Guido van Rossum <guido@python.org>
date Thu, 20 Dec 1990 15:06:42 +0000
parents 3028acaa56b0
children c9a5fe1660f5
line wrap: on
line diff
--- a/Python/compile.c	Sun Nov 18 17:44:34 1990 +0000
+++ b/Python/compile.c	Thu Dec 20 15:06:42 1990 +0000
@@ -1,31 +1,49 @@
 /* Compile an expression node to intermediate code */
 
-#include <stdio.h>
-#include <ctype.h>
-#include "string.h"
+/* XXX TO DO:
+   XXX Compute maximum needed stack sizes while compiling
+   XXX Generate simple jump for break/return outside 'try...finally'
+   XXX Include function name in code (and module names?)
+*/
 
-#include "PROTO.h"
-#include "object.h"
-#include "objimpl.h"
-#include "intobject.h"
-#include "floatobject.h"
-#include "stringobject.h"
-#include "listobject.h"
+#include "allobjects.h"
+
 #include "node.h"
 #include "token.h"
 #include "graminit.h"
-#include "errors.h"
 #include "compile.h"
 #include "opcode.h"
+#include "structmember.h"
+
+#include <ctype.h>
+
+#define OFF(x) offsetof(codeobject, x)
+
+static struct memberlist code_memberlist[] = {
+	{"co_code",	T_OBJECT,	OFF(co_code)},
+	{"co_consts",	T_OBJECT,	OFF(co_consts)},
+	{"co_names",	T_OBJECT,	OFF(co_names)},
+	{"co_filename",	T_OBJECT,	OFF(co_filename)},
+	{NULL}	/* Sentinel */
+};
+
+static object *
+code_getattr(co, name)
+	codeobject *co;
+	char *name;
+{
+	return getmember((char *)co, code_memberlist, name);
+}
 
 static void
-code_dealloc(c)
-	codeobject *c;
+code_dealloc(co)
+	codeobject *co;
 {
-	XDECREF(c->co_code);
-	XDECREF(c->co_consts);
-	XDECREF(c->co_names);
-	DEL(c);
+	XDECREF(co->co_code);
+	XDECREF(co->co_consts);
+	XDECREF(co->co_names);
+	XDECREF(co->co_filename);
+	DEL(co);
 }
 
 typeobject Codetype = {
@@ -36,7 +54,7 @@
 	0,
 	code_dealloc,	/*tp_dealloc*/
 	0,		/*tp_print*/
-	0,		/*tp_getattr*/
+	code_getattr,	/*tp_getattr*/
 	0,		/*tp_setattr*/
 	0,		/*tp_compare*/
 	0,		/*tp_repr*/
@@ -45,13 +63,14 @@
 	0,		/*tp_as_mapping*/
 };
 
-static codeobject *newcodeobject PROTO((object *, object *, object *));
+static codeobject *newcodeobject PROTO((object *, object *, object *, char *));
 
 static codeobject *
-newcodeobject(code, consts, names)
+newcodeobject(code, consts, names, filename)
 	object *code;
 	object *consts;
 	object *names;
+	char *filename;
 {
 	codeobject *co;
 	int i;
@@ -78,6 +97,10 @@
 		co->co_consts = consts;
 		INCREF(names);
 		co->co_names = names;
+		if ((co->co_filename = newstringobject(filename)) == NULL) {
+			DECREF(co);
+			co = NULL;
+		}
 	}
 	return co;
 }
@@ -90,10 +113,13 @@
 	object *c_names;	/* list of strings (names) */
 	int c_nexti;		/* index into c_code */
 	int c_errors;		/* counts errors occurred */
+	int c_infunction;	/* set when compiling a function */
+	int c_loops;		/* counts nested loops */
+	char *c_filename;	/* filename of current node */
 };
 
 /* Prototypes */
-static int com_init PROTO((struct compiling *));
+static int com_init PROTO((struct compiling *, char *));
 static void com_free PROTO((struct compiling *));
 static void com_done PROTO((struct compiling *));
 static void com_node PROTO((struct compiling *, struct _node *));
@@ -108,8 +134,9 @@
 static void com_addopname PROTO((struct compiling *, int, node *));
 
 static int
-com_init(c)
+com_init(c, filename)
 	struct compiling *c;
+	char *filename;
 {
 	if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL)
 		goto fail_3;
@@ -119,6 +146,9 @@
 		goto fail_1;
 	c->c_nexti = 0;
 	c->c_errors = 0;
+	c->c_infunction = 0;
+	c->c_loops = 0;
+	c->c_filename = filename;
 	return 1;
 	
   fail_1:
@@ -153,6 +183,8 @@
 {
 	int len;
 	if (byte < 0 || byte > 255) {
+		fprintf(stderr, "XXX compiling bad byte: %d\n", byte);
+		abort();
 		err_setstr(SystemError, "com_addbyte: byte out of range");
 		c->c_errors++;
 	}
@@ -1076,6 +1108,10 @@
 	node *n;
 {
 	REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */
+	if (!c->c_infunction) {
+		err_setstr(TypeError, "'return' outside function");
+		c->c_errors++;
+	}
 	if (NCH(n) == 2)
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
 	else
@@ -1134,6 +1170,9 @@
 	/*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */
 	for (i = 0; i+3 < NCH(n); i+=4) {
 		int a = 0;
+		node *ch = CHILD(n, i+1);
+		if (i > 0)
+			com_addoparg(c, SET_LINENO, ch->n_lineno);
 		com_node(c, CHILD(n, i+1));
 		com_addfwref(c, JUMP_IF_FALSE, &a);
 		com_addbyte(c, POP_TOP);
@@ -1158,10 +1197,13 @@
 	REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */
 	com_addfwref(c, SETUP_LOOP, &break_anchor);
 	begin = c->c_nexti;
+	com_addoparg(c, SET_LINENO, n->n_lineno);
 	com_node(c, CHILD(n, 1));
 	com_addfwref(c, JUMP_IF_FALSE, &anchor);
 	com_addbyte(c, POP_TOP);
+	c->c_loops++;
 	com_node(c, CHILD(n, 3));
+	c->c_loops--;
 	com_addoparg(c, JUMP_ABSOLUTE, begin);
 	com_backpatch(c, anchor);
 	com_addbyte(c, POP_TOP);
@@ -1190,9 +1232,12 @@
 	com_addoparg(c, LOAD_CONST, com_addconst(c, v));
 	XDECREF(v);
 	begin = c->c_nexti;
+	com_addoparg(c, SET_LINENO, n->n_lineno);
 	com_addfwref(c, FOR_LOOP, &anchor);
 	com_assign(c, CHILD(n, 1), 1/*assigning*/);
+	c->c_loops++;
 	com_node(c, CHILD(n, 5));
+	c->c_loops--;
 	com_addoparg(c, JUMP_ABSOLUTE, begin);
 	com_backpatch(c, anchor);
 	com_addbyte(c, POP_BLOCK);
@@ -1225,7 +1270,6 @@
 		<code for S>
 		POP_BLOCK
 		LOAD_CONST	<nil>
-		LOAD_CONST	<nil>
 	L:	<code for Sf>
 		END_FINALLY
    
@@ -1242,13 +1286,9 @@
 	stack until its level is the same as indicated on the
 	block stack.  (The label is ignored.)
    END_FINALLY:
-	Pops two entries from the *value* stack and re-raises
-	the exception they specify.  If the top entry is nil,
-	no exception is raised.  If it is a number, a pseudo
-	exception is raised ('return' or 'break').  Otherwise,
-	a real exception (specified by a string) is raised.
-	The second entry popped from the is the value that goes
-	with the exception (or the return value).
+	Pops a variable number of entries from the *value* stack
+	and re-raises the exception they specify.  The number of
+	entries popped depends on the (pseudo) exception type.
    
    The block stack is unwound when an exception is raised:
    when a SETUP_FINALLY entry is found, the exception is pushed
@@ -1257,6 +1297,9 @@
    stack.
    
    Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...":
+   (The contents of the value stack is shown in [], with the top
+   at the right; 'tb' is trace-back info, 'val' the exception's
+   associated value, and 'exc' the exception.)
    
    Value stack		Label	Instruction	Argument
    []				SETUP_EXCEPT	L1
@@ -1264,22 +1307,23 @@
    []				POP_BLOCK
    []				JUMP_FORWARD	L0
    
-   [val, exc]		L1:	DUP
-   [val, exc, exc]		<evaluate E1>
-   [val, exc, exc, E1]		COMPARE_OP	EXC_MATCH
-   [val, exc, 1-or-0]		JUMP_IF_FALSE	L2
-   [val, exc, 1]		POP
-   [val, exc]			POP
-   [val]			<assign to V1>
+   [tb, val, exc]	L1:	DUP				)
+   [tb, val, exc, exc]		<evaluate E1>			)
+   [tb, val, exc, exc, E1]	COMPARE_OP	EXC_MATCH	) only if E1
+   [tb, val, exc, 1-or-0]	JUMP_IF_FALSE	L2		)
+   [tb, val, exc, 1]		POP				)
+   [tb, val, exc]		POP
+   [tb, val]			<assign to V1>	(or POP if no V1)
+   [tb]				POP
    []				<code for S1>
    				JUMP_FORWARD	L0
    
-   [val, exc, 0]	L2:	POP
-   [val, exc]			DUP
+   [tb, val, exc, 0]	L2:	POP
+   [tb, val, exc]		DUP
    .............................etc.......................
 
-   [val, exc, 0]	Ln+1:	POP
-   [val, exc]	   		END_FINALLY	# re-raise exception
+   [tb, val, exc, 0]	Ln+1:	POP
+   [tb, val, exc]	   	END_FINALLY	# re-raise exception
    
    []			L0:	<next statement>
    
@@ -1323,6 +1367,7 @@
 				break;
 			}
 			except_anchor = 0;
+			com_addoparg(c, SET_LINENO, ch->n_lineno);
 			if (NCH(ch) > 1) {
 				com_addbyte(c, DUP_TOP);
 				com_node(c, CHILD(ch, 1));
@@ -1335,6 +1380,7 @@
 				com_assign(c, CHILD(ch, 3), 1/*assigning*/);
 			else
 				com_addbyte(c, POP_TOP);
+			com_addbyte(c, POP_TOP);
 			com_node(c, CHILD(n, i+2));
 			com_addfwref(c, JUMP_FORWARD, &end_anchor);
 			if (except_anchor) {
@@ -1346,11 +1392,13 @@
 		com_backpatch(c, end_anchor);
 	}
 	if (finally_anchor) {
+		node *ch;
 		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));
+		ch = CHILD(n, NCH(n)-1);
+		com_addoparg(c, SET_LINENO, ch->n_lineno);
+		com_node(c, ch);
 		com_addbyte(c, END_FINALLY);
 	}
 }
@@ -1382,7 +1430,7 @@
 {
 	object *v;
 	REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
-	v = (object *)compile(n);
+	v = (object *)compile(n, c->c_filename);
 	if (v == NULL)
 		c->c_errors++;
 	else {
@@ -1426,7 +1474,7 @@
 		com_bases(c, CHILD(n, 4));
 	else
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
-	v = (object *)compile(n);
+	v = (object *)compile(n, c->c_filename);
 	if (v == NULL)
 		c->c_errors++;
 	else {
@@ -1459,9 +1507,13 @@
 	/* Trivial parse tree nodes */
 	
 	case stmt:
+	case flow_stmt:
+		com_node(c, CHILD(n, 0));
+		break;
+
 	case simple_stmt:
-	case flow_stmt:
 	case compound_stmt:
+		com_addoparg(c, SET_LINENO, n->n_lineno);
 		com_node(c, CHILD(n, 0));
 		break;
 
@@ -1479,6 +1531,10 @@
 	case pass_stmt:
 		break;
 	case break_stmt:
+		if (c->c_loops == 0) {
+			err_setstr(TypeError, "'break' outside loop");
+			c->c_errors++;
+		}
 		com_addbyte(c, BREAK_LOOP);
 		break;
 	case return_stmt:
@@ -1608,48 +1664,50 @@
 		com_addbyte(c, REQUIRE_ARGS);
 		com_fplist(c, ch);
 	}
+	c->c_infunction = 1;
 	com_node(c, CHILD(n, 4));
+	c->c_infunction = 0;
 	com_addoparg(c, LOAD_CONST, com_addconst(c, None));
 	com_addbyte(c, RETURN_VALUE);
 }
 
 static void
-compile_classdef(c, n)
-	struct compiling *c;
-	node *n;
-{
-	node *ch;
-	REQ(n, classdef);
-	/*
-	classdef: 'class' NAME parameters ['=' baselist] ':' suite
-	*/
-	com_addbyte(c, REFUSE_ARGS);
-	com_node(c, CHILD(n, NCH(n)-1));
-	com_addbyte(c, LOAD_LOCALS);
-	com_addbyte(c, RETURN_VALUE);
-}
-
-static void
 compile_node(c, n)
 	struct compiling *c;
 	node *n;
 {
+	com_addoparg(c, SET_LINENO, n->n_lineno);
+	
 	switch (TYPE(n)) {
 	
 	case single_input:
 		/* NEWLINE | simple_stmt | compound_stmt NEWLINE */
+		com_addbyte(c, REFUSE_ARGS);
 		n = CHILD(n, 0);
 		if (TYPE(n) != NEWLINE)
 			com_node(c, n);
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_addbyte(c, RETURN_VALUE);
 		break;
 	
 	case file_input:
+		com_addbyte(c, REFUSE_ARGS);
 		com_file_input(c, n);
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_addbyte(c, RETURN_VALUE);
 		break;
 	
 	case expr_input:
+		com_addbyte(c, REFUSE_ARGS);
+		com_node(c, CHILD(n, 0));
+		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
+		com_addbyte(c, RETURN_VALUE);
+		break;
+	
 	case eval_input:
+		com_addbyte(c, REFUSE_ARGS);
 		com_node(c, CHILD(n, 0));
+		com_addbyte(c, RETURN_VALUE);
 		break;
 	
 	case funcdef:
@@ -1657,7 +1715,11 @@
 		break;
 	
 	case classdef:
-		compile_classdef(c, n);
+		/* 'class' NAME parameters ['=' baselist] ':' suite */
+		com_addbyte(c, REFUSE_ARGS);
+		com_node(c, CHILD(n, NCH(n)-1));
+		com_addbyte(c, LOAD_LOCALS);
+		com_addbyte(c, RETURN_VALUE);
 		break;
 	
 	default:
@@ -1668,17 +1730,18 @@
 }
 
 codeobject *
-compile(n)
+compile(n, filename)
 	node *n;
+	char *filename;
 {
 	struct compiling sc;
 	codeobject *co;
-	if (!com_init(&sc))
+	if (!com_init(&sc, filename))
 		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);
+		co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names, filename);
 	else
 		co = NULL;
 	com_free(&sc);