summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1990-12-20 15:06:42 (GMT)
committerGuido van Rossum <guido@python.org>1990-12-20 15:06:42 (GMT)
commit3f5da24ea304e674a9abbdcffc4d671e32aa70f1 (patch)
treee932e31cb9381f40b7c87c377638216c043b5cfc /Python/compile.c
parent226d79eb4a776dd54c9e4544b17deaf928bcef3a (diff)
downloadcpython-3f5da24ea304e674a9abbdcffc4d671e32aa70f1.zip
cpython-3f5da24ea304e674a9abbdcffc4d671e32aa70f1.tar.gz
cpython-3f5da24ea304e674a9abbdcffc4d671e32aa70f1.tar.bz2
"Compiling" version
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c197
1 files changed, 130 insertions, 67 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 2f5fd69..87acf39 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1,31 +1,49 @@
/* 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"
+/* 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 "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 @@ typeobject Codetype = {
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 @@ typeobject Codetype = {
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 @@ newcodeobject(code, consts, names)
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 @@ struct compiling {
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 int com_addname PROTO((struct compiling *, object *));
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 @@ com_init(c)
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 @@ com_addbyte(c, byte)
{
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 @@ com_return_stmt(c, n)
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 @@ com_if_stmt(c, n)
/*'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 @@ com_while_stmt(c, n)
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_for_stmt(c, n)
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 @@ com_for_stmt(c, n)
<code for S>
POP_BLOCK
LOAD_CONST <nil>
- LOAD_CONST <nil>
L: <code for Sf>
END_FINALLY
@@ -1242,13 +1286,9 @@ com_for_stmt(c, n)
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 @@ com_for_stmt(c, n)
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 @@ com_for_stmt(c, n)
[] 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 @@ com_try_stmt(c, n)
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_try_stmt(c, n)
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_try_stmt(c, n)
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 @@ com_funcdef(c, n)
{
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_classdef(c, n)
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 @@ com_node(c, n)
/* Trivial parse tree nodes */
case stmt:
- case simple_stmt:
case flow_stmt:
+ com_node(c, CHILD(n, 0));
+ break;
+
+ case simple_stmt:
case compound_stmt:
+ com_addoparg(c, SET_LINENO, n->n_lineno);
com_node(c, CHILD(n, 0));
break;
@@ -1479,6 +1531,10 @@ com_node(c, n)
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 @@ compile_funcdef(c, n)
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 @@ compile_node(c, n)
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 @@ compile_node(c, n)
}
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);