summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1990-11-18 17:27:39 (GMT)
committerGuido van Rossum <guido@python.org>1990-11-18 17:27:39 (GMT)
commit10dc2e8097e7a431367e72f46ddba91be93aa159 (patch)
tree21d30678e4b505163daa5083e0f4a4159e67f5c0 /Python
parentd5b70f5bacb27f96cbdf7f304d88fe8ede2a72c9 (diff)
downloadcpython-10dc2e8097e7a431367e72f46ddba91be93aa159.zip
cpython-10dc2e8097e7a431367e72f46ddba91be93aa159.tar.gz
cpython-10dc2e8097e7a431367e72f46ddba91be93aa159.tar.bz2
Initial revision
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c1560
-rw-r--r--Python/compile.c1537
2 files changed, 3097 insertions, 0 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
new file mode 100644
index 0000000..6a303ca
--- /dev/null
+++ b/Python/ceval.c
@@ -0,0 +1,1560 @@
+/* Evaluate compiled expression nodes */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "string.h"
+
+#include "PROTO.h"
+#include "object.h"
+#include "objimpl.h"
+#include "intobject.h"
+#include "stringobject.h"
+#include "tupleobject.h"
+#include "listobject.h"
+#include "dictobject.h"
+#include "builtinobject.h"
+#include "methodobject.h"
+#include "moduleobject.h"
+#include "context.h"
+#include "funcobject.h"
+#include "classobject.h"
+#include "token.h"
+#include "graminit.h"
+#include "run.h"
+#include "import.h"
+#include "support.h"
+#include "sysmodule.h"
+#include "compile.h"
+#include "opcode.h"
+
+/* List access macros */
+#ifdef NDEBUG
+#define GETITEM(v, i) GETLISTITEM((listobject *)(v), (i))
+#define GETITEMNAME(v, i) GETSTRINGVALUE((stringobject *)GETITEM((v), (i)))
+#else
+#define GETITEM(v, i) getlistitem((v), (i))
+#define GETITEMNAME(v, i) getstringvalue(getlistitem((v), (i)))
+#endif
+
+typedef struct {
+ int b_type; /* what kind of block this is */
+ int b_handler; /* where to jump to find handler */
+ int b_level; /* value stack level to pop to */
+} block;
+
+typedef struct _frame {
+ OB_HEAD
+ struct _frame *f_back; /* previous frame, or NULL */
+ codeobject *f_code; /* code segment */
+ object *f_locals; /* local symbol table (dictobject) */
+ object *f_globals; /* global symbol table (dictobject) */
+ object **f_valuestack; /* malloc'ed array */
+ block *f_blockstack; /* malloc'ed array */
+ int f_nvalues; /* size of f_valuestack */
+ int f_nblocks; /* size of f_blockstack */
+ int f_ivalue; /* index in f_valuestack */
+ int f_iblock; /* index in f_blockstack */
+ int f_nexti; /* index in f_code (next instruction) */
+} frameobject;
+
+#define is_frameobject(op) ((op)->ob_type == &Frametype)
+
+static void
+frame_dealloc(f)
+ frameobject *f;
+{
+ XDECREF(f->f_back);
+ XDECREF(f->f_code);
+ XDECREF(f->f_locals);
+ XDECREF(f->f_globals);
+ XDEL(f->f_valuestack);
+ XDEL(f->f_blockstack);
+ DEL(f);
+}
+typeobject Frametype = {
+ OB_HEAD_INIT(&Typetype)
+ 0,
+ "frame",
+ sizeof(frameobject),
+ 0,
+ frame_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 frameobject * newframeobject PROTO(
+ (frameobject *, codeobject *, object *, object *, int, int));
+
+static frameobject *
+newframeobject(back, code, locals, globals, nvalues, nblocks)
+ frameobject *back;
+ codeobject *code;
+ object *locals;
+ object *globals;
+ int nvalues;
+ int nblocks;
+{
+ frameobject *f;
+ if ((back != NULL && !is_frameobject(back)) ||
+ code == NULL || !is_codeobject(code) ||
+ locals == NULL || !is_dictobject(locals) ||
+ globals == NULL || !is_dictobject(globals) ||
+ nvalues < 0 || nblocks < 0) {
+ err_badcall();
+ return NULL;
+ }
+ f = NEWOBJ(frameobject, &Frametype);
+ if (f != NULL) {
+ if (back)
+ INCREF(back);
+ f->f_back = back;
+ INCREF(code);
+ f->f_code = code;
+ INCREF(locals);
+ f->f_locals = locals;
+ INCREF(globals);
+ f->f_globals = globals;
+ f->f_valuestack = NEW(object *, nvalues+1);
+ f->f_blockstack = NEW(block, nblocks+1);
+ f->f_nvalues = nvalues;
+ f->f_nblocks = nblocks;
+ f->f_ivalue = f->f_iblock = f->f_nexti = 0;
+ if (f->f_valuestack == NULL || f->f_blockstack == NULL) {
+ err_nomem();
+ DECREF(f);
+ f = NULL;
+ }
+ }
+ return f;
+}
+
+#define Push(f, v) ((f)->f_valuestack[(f)->f_ivalue++] = (v))
+#define Pop(f) ((f)->f_valuestack[--(f)->f_ivalue])
+#define Top(f) ((f)->f_valuestack[(f)->f_ivalue-1])
+#define Empty(f) ((f)->f_ivalue == 0)
+#define Full(f) ((f)->f_ivalue == (f)->f_nvalues)
+#define Nextbyte(f) (GETSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti++])
+#define Peekbyte(f) (GETSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti])
+#define Prevbyte(f) (GETSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti-1])
+#define Jumpto(f, x) ((f)->f_nexti = (x))
+#define Jumpby(f, x) ((f)->f_nexti += (x))
+#define Getconst(f, i) (GETITEM((f)->f_code->co_consts, (i)))
+#define Getname(f, i) (GETITEMNAME((f)->f_code->co_names, (i)))
+
+/* Corresponding functions, for debugging */
+
+static void
+push(f, v)
+ frameobject *f;
+ object *v;
+{
+ if (Full(f)) {
+ printf("stack overflow\n");
+ abort();
+ }
+ Push(f, v);
+}
+
+static object *
+pop(f)
+ frameobject *f;
+{
+ if (Empty(f)) {
+ printf("stack underflow\n");
+ abort();
+ }
+ return Pop(f);
+}
+
+static object *
+top(f)
+ frameobject *f;
+{
+ if (Empty(f)) {
+ printf("stack underflow\n");
+ abort();
+ }
+ return Top(f);
+}
+
+static int
+nextbyte(f)
+ frameobject *f;
+{
+ stringobject *code = (f)->f_code->co_code;
+ if (f->f_nexti >= getstringsize((object *)code)) {
+ printf("ran off end of instructions\n");
+ abort();
+ }
+ return GETSTRINGVALUE(code)[f->f_nexti++];
+}
+
+/* Tracing versions */
+
+static void
+trace_push(f, v)
+ frameobject *f;
+ object *v;
+{
+ printf("\tpush ");
+ printobject(v, stdout, 0);
+ printf("\n");
+ push(f, v);
+}
+
+static object *
+trace_pop(f)
+ frameobject *f;
+{
+ object *v;
+ v = pop(f);
+ printf("\tpop ");
+ printobject(v, stdout, 0);
+ printf("\n");
+ return v;
+}
+
+static object *
+trace_top(f)
+ frameobject *f;
+{
+ object *v;
+ v = top(f);
+ printf("\ttop ");
+ printobject(v, stdout, 0);
+ printf("\n");
+ return v;
+}
+
+static int
+trace_nextop(f)
+ frameobject *f;
+{
+ int op;
+ int arg;
+
+ printf("%d: ", f->f_nexti);
+ op = nextbyte(f);
+ if (op < HAVE_ARGUMENT)
+ printf("op %3d\n", op);
+ else {
+ arg = Peekbyte(f);
+ printf("op %3d arg %3d\n", op, arg);
+ }
+ return op;
+}
+
+/* Block management */
+
+static void
+setup_block(f, type, handler)
+ frameobject *f;
+ int type;
+ int handler;
+{
+ block *b;
+ if (f->f_iblock >= f->f_nblocks) {
+ printf("block stack overflow\n");
+ abort();
+ }
+ b = &f->f_blockstack[f->f_iblock++];
+ b->b_type = type;
+ b->b_level = f->f_ivalue;
+ b->b_handler = handler + f->f_nexti;
+}
+
+static block *
+pop_block(f)
+ frameobject *f;
+{
+ block *b;
+ if (f->f_iblock <= 0) {
+ printf("block stack underflow\n");
+ abort();
+ }
+ b = &f->f_blockstack[--f->f_iblock];
+ while (f->f_ivalue > b->b_level) {
+ object *v = Pop(f);
+ XDECREF(v);
+ }
+ return b;
+}
+
+
+/* XXX Mixing "print ...," and direct file I/O on stdin/stdout
+ XXX has some bad consequences. The needspace flag should
+ XXX really be part of the file object. */
+
+static int needspace;
+
+void
+flushline()
+{
+ FILE *fp = sysgetfile("stdout", stdout);
+ if (needspace) {
+ fprintf(fp, "\n");
+ needspace = 0;
+ }
+}
+
+static object *
+checkerror(ctx, v)
+ context *ctx;
+ object *v;
+{
+ if (v == NULL)
+ puterrno(ctx);
+ return v;
+}
+
+static object *
+add(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ v = (*v->ob_type->tp_as_number->nb_add)(v, w);
+ else if (v->ob_type->tp_as_sequence != NULL)
+ v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
+ else {
+ type_error(ctx, "+ not supported by operands");
+ return NULL;
+ }
+ return checkerror(ctx, v);
+}
+
+static object *
+sub(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return checkerror(ctx,
+ (*v->ob_type->tp_as_number->nb_subtract)(v, w));
+ type_error(ctx, "bad operand type(s) for -");
+ return NULL;
+}
+
+static object *
+mul(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ typeobject *tp;
+ if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
+ /* int*sequence -- swap v and w */
+ object *tmp = v;
+ v = w;
+ w = tmp;
+ }
+ tp = v->ob_type;
+ if (tp->tp_as_number != NULL)
+ return checkerror(ctx, (*tp->tp_as_number->nb_multiply)(v, w));
+ if (tp->tp_as_sequence != NULL) {
+ if (!is_intobject(w)) {
+ type_error(ctx, "can't multiply sequence with non-int");
+ return NULL;
+ }
+ if (tp->tp_as_sequence->sq_repeat == NULL) {
+ type_error(ctx, "sequence does not support *");
+ return NULL;
+ }
+ return checkerror(ctx, (*tp->tp_as_sequence->sq_repeat)
+ (v, (int)getintvalue(w)));
+ }
+ type_error(ctx, "bad operand type(s) for *");
+ return NULL;
+}
+
+static object *
+div(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return checkerror(ctx,
+ (*v->ob_type->tp_as_number->nb_divide)(v, w));
+ type_error(ctx, "bad operand type(s) for /");
+ return NULL;
+}
+
+static object *
+rem(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return checkerror(ctx,
+ (*v->ob_type->tp_as_number->nb_remainder)(v, w));
+ type_error(ctx, "bad operand type(s) for %");
+ return NULL;
+}
+
+static object *
+neg(ctx, v)
+ context *ctx;
+ object *v;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return checkerror(ctx,
+ (*v->ob_type->tp_as_number->nb_negative)(v));
+ type_error(ctx, "bad operand type(s) for unary -");
+ return NULL;
+}
+
+static object *
+pos(ctx, v)
+ context *ctx;
+ object *v;
+{
+ if (v->ob_type->tp_as_number != NULL)
+ return checkerror(ctx,
+ (*v->ob_type->tp_as_number->nb_positive)(v));
+ type_error(ctx, "bad operand type(s) for unary +");
+ return NULL;
+}
+
+static object *
+not(ctx, v)
+ context *ctx;
+ object *v;
+{
+ int outcome = testbool(ctx, v);
+ if (ctx->ctx_exception)
+ return NULL;
+ return checkerror(ctx, newintobject((long) !outcome));
+}
+
+static object *
+call_builtin(ctx, func, args)
+ context *ctx;
+ object *func;
+ object *args;
+{
+ if (is_builtinobject(func)) {
+ function funcptr = getbuiltinfunction(func);
+ return (*funcptr)(ctx, args);
+ }
+ if (is_methodobject(func)) {
+ method meth = getmethod(func);
+ object *self = getself(func);
+ return checkerror(ctx, (*meth)(self, args));
+ }
+ if (is_classobject(func)) {
+ if (args != NULL) {
+ type_error(ctx, "classobject() allows no arguments");
+ return NULL;
+ }
+ return checkerror(ctx, newclassmemberobject(func));
+ }
+ type_error(ctx, "call of non-function");
+ return NULL;
+}
+
+static object *eval_compiled PROTO((context *, codeobject *, object *, int));
+
+/* XXX Eventually, this should not call eval_compiled recursively
+ but create a new frame */
+
+static object *
+call_function(ctx, func, args)
+ context *ctx;
+ object *func;
+ object *args;
+{
+ object *newargs = NULL;
+ object *savelocals, *newlocals, *saveglobals;
+ object *c, *v;
+
+ if (is_classmethodobject(func)) {
+ object *self = classmethodgetself(func);
+ func = classmethodgetfunc(func);
+ if (args == NULL) {
+ args = self;
+ }
+ else {
+ newargs = checkerror(ctx, newtupleobject(2));
+ if (newargs == NULL)
+ return NULL;
+ INCREF(self);
+ INCREF(args);
+ settupleitem(newargs, 0, self);
+ settupleitem(newargs, 1, args);
+ args = newargs;
+ }
+ }
+ else {
+ if (!is_funcobject(func)) {
+ type_error(ctx, "call of non-function");
+ return NULL;
+ }
+ }
+
+ c = checkerror(ctx, getfunccode(func));
+ if (c == NULL) {
+ XDECREF(newargs);
+ return NULL;
+ }
+ if (!is_codeobject(c)) {
+ printf("Bad code\n");
+ abort();
+ }
+ newlocals = checkerror(ctx, newdictobject());
+ if (newlocals == NULL) {
+ XDECREF(newargs);
+ return NULL;
+ }
+
+ savelocals = ctx->ctx_locals;
+ ctx->ctx_locals = newlocals;
+ saveglobals = ctx->ctx_globals;
+ ctx->ctx_globals = getfuncglobals(func);
+
+ v = eval_compiled(ctx, (codeobject *)c, args, 1);
+
+ DECREF(ctx->ctx_locals);
+ ctx->ctx_locals = savelocals;
+ ctx->ctx_globals = saveglobals;
+
+ XDECREF(newargs);
+
+ return v;
+}
+
+static object *
+apply_subscript(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ typeobject *tp = v->ob_type;
+ if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) {
+ type_error(ctx, "unsubscriptable object");
+ return NULL;
+ }
+ if (tp->tp_as_sequence != NULL) {
+ int i;
+ if (!is_intobject(w)) {
+ type_error(ctx, "sequence subscript not int");
+ return NULL;
+ }
+ i = getintvalue(w);
+ return checkerror(ctx, (*tp->tp_as_sequence->sq_item)(v, i));
+ }
+ return checkerror(ctx, (*tp->tp_as_mapping->mp_subscript)(v, w));
+}
+
+static object *
+loop_subscript(ctx, v, w)
+ context *ctx;
+ object *v, *w;
+{
+ sequence_methods *sq = v->ob_type->tp_as_sequence;
+ int i, n;
+ if (sq == NULL) {
+ type_error(ctx, "loop over non-sequence");
+ return NULL;
+ }
+ i = getintvalue(w);
+ n = (*sq->sq_length)(v);
+ if (i >= n)
+ return NULL; /* End of loop */
+ return checkerror(ctx, (*sq->sq_item)(v, i));
+}
+
+static int
+slice_index(ctx, v, isize, pi)
+ context *ctx;
+ object *v;
+ int isize;
+ int *pi;
+{
+ if (v != NULL) {
+ if (!is_intobject(v)) {
+ type_error(ctx, "slice index must be int");
+ return 0;
+ }
+ *pi = getintvalue(v);
+ if (*pi < 0)
+ *pi += isize;
+ }
+ return 1;
+}
+
+static object *
+apply_slice(ctx, u, v, w) /* u[v:w] */
+ context *ctx;
+ object *u, *v, *w;
+{
+ typeobject *tp = u->ob_type;
+ int ilow, ihigh, isize;
+ if (tp->tp_as_sequence == NULL) {
+ type_error(ctx, "only sequences can be sliced");
+ return NULL;
+ }
+ ilow = 0;
+ isize = ihigh = (*tp->tp_as_sequence->sq_length)(u);
+ if (!slice_index(ctx, v, isize, &ilow))
+ return NULL;
+ if (!slice_index(ctx, w, isize, &ihigh))
+ return NULL;
+ return checkerror(ctx, (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh));
+}
+static void
+assign_subscript(ctx, w, key, v)
+ context *ctx;
+ object *w;
+ object *key;
+ object *v;
+{
+ typeobject *tp = w->ob_type;
+ sequence_methods *sq;
+ mapping_methods *mp;
+ int (*func)();
+ int err;
+ if ((sq = tp->tp_as_sequence) != NULL &&
+ (func = sq->sq_ass_item) != NULL) {
+ if (!is_intobject(key)) {
+ type_error(ctx, "sequence subscript must be integer");
+ return;
+ }
+ err = (*func)(w, (int)getintvalue(key), v);
+ }
+ else if ((mp = tp->tp_as_mapping) != NULL &&
+ (func = mp->mp_ass_subscript) != NULL) {
+ err = (*func)(w, key, v);
+ }
+ else {
+ type_error(ctx, "can't assign to this subscripted object");
+ return;
+ }
+ if (err != 0)
+ puterrno(ctx);
+}
+
+static void
+assign_slice(ctx, u, v, w, x) /* u[v:w] = x */
+ context *ctx;
+ object *u, *v, *w, *x;
+{
+ typeobject *tp = u->ob_type;
+ int ilow, ihigh, isize;
+ if (tp->tp_as_sequence == NULL ||
+ tp->tp_as_sequence->sq_ass_slice == NULL) {
+ type_error(ctx, "unassignable slice");
+ return;
+ }
+ ilow = 0;
+ isize = ihigh = (*tp->tp_as_sequence->sq_length)(u);
+ if (!slice_index(ctx, v, isize, &ilow))
+ return;
+ if (!slice_index(ctx, w, isize, &ihigh))
+ return;
+ if ((*tp->tp_as_sequence->sq_ass_slice)(u, ilow, ihigh, x) != 0)
+ puterrno(ctx);
+}
+
+static int
+cmp_exception(err, v)
+ object *err, *v;
+{
+ if (is_tupleobject(v)) {
+ int i, n;
+ n = gettuplesize(v);
+ for (i = 0; i < n; i++) {
+ if (err == gettupleitem(v, i))
+ return 1;
+ }
+ return 0;
+ }
+ return err == v;
+}
+
+static object *
+cmp_outcome(ctx, op, v, w)
+ register context *ctx;
+ enum cmp_op op;
+ register object *v;
+ register object *w;
+{
+ register int cmp;
+ register int res = 0;
+ switch (op) {
+ case IN:
+ case NOT_IN:
+ cmp = cmp_member(ctx, v, w);
+ break;
+ case IS:
+ case IS_NOT:
+ cmp = (v == w);
+ break;
+ case EXC_MATCH:
+ cmp = cmp_exception(v, w);
+ break;
+ default:
+ cmp = cmp_values(ctx, v, w);
+ }
+ if (ctx->ctx_exception)
+ return NULL;
+ switch (op) {
+ case EXC_MATCH:
+ case IS:
+ case IN: res = cmp; break;
+ case IS_NOT:
+ case NOT_IN: res = !cmp; break;
+ case LT: res = cmp < 0; break;
+ case LE: res = cmp <= 0; break;
+ case EQ: res = cmp == 0; break;
+ case NE: res = cmp != 0; break;
+ case GT: res = cmp > 0; break;
+ case GE: res = cmp >= 0; break;
+ /* XXX no default? */
+ }
+ v = res ? True : False;
+ INCREF(v);
+ return v;
+}
+
+static object *
+eval_compiled(ctx, co, arg, needvalue)
+ context *ctx;
+ codeobject *co;
+ object *arg;
+ int needvalue;
+{
+ frameobject *f;
+ register object *v;
+ register object *w;
+ register object *u;
+ register object *x;
+ char *name;
+ int n, i;
+ enum cmp_op op;
+ FILE *fp;
+#ifndef NDEBUG
+ int trace = dictlookup(ctx->ctx_globals, "__trace") != NULL;
+#endif
+
+ f = newframeobject(
+ (frameobject *)NULL, /*back*/
+ co, /*code*/
+ ctx->ctx_locals, /*locals*/
+ ctx->ctx_globals, /*globals*/
+ 50, /*nvalues*/
+ 20); /*nblocks*/
+ if (f == NULL) {
+ puterrno(ctx);
+ return NULL;
+ }
+
+#define EMPTY() Empty(f)
+#define FULL() Full(f)
+#define GETCONST(i) Getconst(f, i)
+#define GETNAME(i) Getname(f, i)
+#define JUMPTO(x) Jumpto(f, x)
+#define JUMPBY(x) Jumpby(f, x)
+
+#ifdef NDEBUG
+
+#define PUSH(v) Push(f, v)
+#define TOP() Top(f)
+#define POP() Pop(f)
+#define NEXTOP() Nextbyte(f)
+#define NEXTI() Nextbyte(f)
+
+#else
+
+#define PUSH(v) if(trace) trace_push(f, v); else push(f, v)
+#define TOP() (trace ? trace_top(f) : top(f))
+#define POP() (trace ? trace_pop(f) : pop(f))
+#define NEXTOP() (trace ? trace_nextop(f) : nextbyte(f))
+#define NEXTI() (nextbyte(f))
+
+#endif
+
+ if (arg != NULL) {
+ INCREF(arg);
+ PUSH(arg);
+ }
+
+ while (f->f_nexti < getstringsize((object *)f->f_code->co_code) &&
+ !ctx->ctx_exception) {
+
+ switch (NEXTOP()) {
+
+ case DUP_TOP:
+ v = TOP();
+ INCREF(v);
+ PUSH(v);
+ break;
+
+ case POP_TOP:
+ v = POP();
+ DECREF(v);
+ break;
+
+ case ROT_TWO:
+ v = POP();
+ w = POP();
+ PUSH(v);
+ PUSH(w);
+ break;
+
+ case ROT_THREE:
+ v = POP();
+ w = POP();
+ x = POP();
+ PUSH(v);
+ PUSH(x);
+ PUSH(w);
+ break;
+
+ case UNARY_POSITIVE:
+ v = POP();
+ u = pos(ctx, v);
+ DECREF(v);
+ PUSH(u);
+ break;
+
+ case UNARY_NEGATIVE:
+ v = POP();
+ u = neg(ctx, v);
+ DECREF(v);
+ PUSH(u);
+ break;
+
+ case UNARY_NOT:
+ v = POP();
+ u = not(ctx, v);
+ DECREF(v);
+ PUSH(u);
+ break;
+
+ case UNARY_CONVERT:
+ v = POP();
+ u = checkerror(ctx, reprobject(v));
+ DECREF(v);
+ PUSH(u);
+ break;
+
+ case UNARY_CALL:
+ v = POP();
+ if (is_classmemberobject(v) || is_funcobject(v))
+ u = call_function(ctx, v, (object *)NULL);
+ else
+ u = call_builtin(ctx, v, (object *)NULL);
+ DECREF(v);
+ PUSH(u);
+ break;
+
+ case BINARY_MULTIPLY:
+ w = POP();
+ v = POP();
+ u = mul(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case BINARY_DIVIDE:
+ w = POP();
+ v = POP();
+ u = div(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case BINARY_MODULO:
+ w = POP();
+ v = POP();
+ u = rem(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case BINARY_ADD:
+ w = POP();
+ v = POP();
+ u = add(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case BINARY_SUBTRACT:
+ w = POP();
+ v = POP();
+ u = sub(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case BINARY_SUBSCR:
+ w = POP();
+ v = POP();
+ u = apply_subscript(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case BINARY_CALL:
+ w = POP();
+ v = POP();
+ if (is_classmemberobject(v) || is_funcobject(v))
+ u = call_function(ctx, v, w);
+ else
+ u = call_builtin(ctx, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case SLICE:
+ w = NULL;
+ v = NULL;
+ u = POP();
+ x = apply_slice(ctx, u, v, w);
+ DECREF(u);
+ PUSH(x);
+ break;
+
+ case SLICE+1:
+ w = NULL;
+ v = POP();
+ u = POP();
+ x = apply_slice(ctx, u, v, w);
+ DECREF(u);
+ DECREF(v);
+ PUSH(x);
+ break;
+
+ case SLICE+2:
+ w = POP();
+ v = NULL;
+ u = POP();
+ x = apply_slice(ctx, u, v, w);
+ DECREF(u);
+ DECREF(w);
+ PUSH(x);
+ break;
+
+ case SLICE+3:
+ w = POP();
+ v = POP();
+ u = POP();
+ x = apply_slice(ctx, u, v, w);
+ DECREF(u);
+ DECREF(v);
+ DECREF(w);
+ PUSH(x);
+ break;
+
+ case STORE_SLICE:
+ w = NULL;
+ v = NULL;
+ u = POP();
+ x = POP();
+ assign_slice(ctx, u, v, w, x); /* u[:] = x */
+ DECREF(x);
+ DECREF(u);
+ break;
+
+ case STORE_SLICE+1:
+ w = NULL;
+ v = POP();
+ u = POP();
+ x = POP();
+ assign_slice(ctx, u, v, w, x); /* u[v:] = x */
+ DECREF(x);
+ DECREF(u);
+ DECREF(v);
+ break;
+
+ case STORE_SLICE+2:
+ w = POP();
+ v = NULL;
+ u = POP();
+ x = POP();
+ assign_slice(ctx, u, v, w, x); /* u[:w] = x */
+ DECREF(x);
+ DECREF(u);
+ DECREF(w);
+ break;
+
+ case STORE_SLICE+3:
+ w = POP();
+ v = POP();
+ u = POP();
+ x = POP();
+ assign_slice(ctx, u, v, w, x); /* u[v:w] = x */
+ DECREF(x);
+ DECREF(u);
+ DECREF(v);
+ DECREF(w);
+ break;
+
+ case DELETE_SLICE:
+ w = NULL;
+ v = NULL;
+ u = POP();
+ x = NULL;
+ assign_slice(ctx, u, v, w, x); /* del u[:] */
+ DECREF(u);
+ break;
+
+ case DELETE_SLICE+1:
+ w = NULL;
+ v = POP();
+ u = POP();
+ x = NULL;
+ assign_slice(ctx, u, v, w, x); /* del u[v:] */
+ DECREF(u);
+ DECREF(v);
+ break;
+
+ case DELETE_SLICE+2:
+ w = POP();
+ v = NULL;
+ u = POP();
+ x = NULL;
+ assign_slice(ctx, u, v, w, x); /* del u[:w] */
+ DECREF(u);
+ DECREF(w);
+ break;
+
+ case DELETE_SLICE+3:
+ w = POP();
+ v = POP();
+ u = POP();
+ x = NULL;
+ assign_slice(ctx, u, v, w, x); /* del u[v:w] */
+ DECREF(u);
+ DECREF(v);
+ DECREF(w);
+ break;
+
+ case STORE_SUBSCR:
+ w = POP();
+ v = POP();
+ u = POP();
+ /* v[w] = u */
+ assign_subscript(ctx, v, w, u);
+ DECREF(u);
+ DECREF(v);
+ DECREF(w);
+ break;
+
+ case DELETE_SUBSCR:
+ w = POP();
+ v = POP();
+ /* del v[w] */
+ assign_subscript(ctx, v, w, (object *)NULL);
+ DECREF(v);
+ DECREF(w);
+ break;
+
+ case PRINT_EXPR:
+ v = POP();
+ fp = sysgetfile("stdout", stdout);
+ /* Print value except if procedure result */
+ if (v != None) {
+ flushline();
+ printobject(v, fp, 0);
+ fprintf(fp, "\n");
+ }
+ DECREF(v);
+ break;
+
+ case PRINT_ITEM:
+ v = POP();
+ fp = sysgetfile("stdout", stdout);
+ if (needspace)
+ fprintf(fp, " ");
+ if (is_stringobject(v)) {
+ char *s = getstringvalue(v);
+ int len = getstringsize(v);
+ fwrite(s, 1, len, fp);
+ if (len > 0 && s[len-1] == '\n')
+ needspace = 0;
+ else
+ needspace = 1;
+ }
+ else {
+ printobject(v, fp, 0);
+ needspace = 1;
+ }
+ DECREF(v);
+ break;
+
+ case PRINT_NEWLINE:
+ fp = sysgetfile("stdout", stdout);
+ fprintf(fp, "\n");
+ needspace = 0;
+ break;
+
+ case BREAK_LOOP:
+ raise_pseudo(ctx, BREAK_PSEUDO);
+ break;
+
+ case RAISE_EXCEPTION:
+ v = POP();
+ w = POP();
+ if (!is_stringobject(w)) {
+ DECREF(v);
+ DECREF(v);
+ type_error(ctx, "exceptions must be strings");
+ }
+ else {
+ raise_exception(ctx, w, v);
+ }
+ break;
+
+ case RETURN_VALUE:
+ v = POP();
+ raise_pseudo(ctx, RETURN_PSEUDO);
+ ctx->ctx_errval = v;
+ break;
+
+ case REQUIRE_ARGS:
+ if (EMPTY())
+ type_error(ctx,
+ "function expects argument(s)");
+ break;
+
+ case REFUSE_ARGS:
+ if (!EMPTY())
+ type_error(ctx,
+ "function expects no argument(s)");
+ break;
+
+ case BUILD_FUNCTION:
+ v = POP();
+ x = checkerror(ctx, newfuncobject(v, ctx->ctx_globals));
+ DECREF(v);
+ PUSH(x);
+ break;
+
+ case POP_BLOCK:
+ (void) pop_block(f);
+ break;
+
+ case END_FINALLY:
+ v = POP();
+ w = POP();
+ if (is_intobject(v)) {
+ raise_pseudo(ctx, (int)getintvalue(v));
+ DECREF(v);
+ if (w == None)
+ DECREF(w);
+ else
+ ctx->ctx_errval = w;
+ }
+ else if (is_stringobject(v))
+ raise_exception(ctx, v, w);
+ else if (v == None) {
+ DECREF(v);
+ DECREF(w);
+ }
+ else {
+ sys_error(ctx, "'finally' pops bad exception");
+ }
+ break;
+
+ case STORE_NAME:
+ i = NEXTI();
+ name = GETNAME(i);
+ v = POP();
+ if (dictinsert(ctx->ctx_locals, name, v) != 0)
+ mem_error(ctx, "insert in symbol table");
+ DECREF(v);
+ break;
+
+ case DELETE_NAME:
+ i = NEXTI();
+ name = GETNAME(i);
+ if (dictremove(ctx->ctx_locals, name) != 0)
+ name_error(ctx, name);
+ break;
+
+ case UNPACK_TUPLE:
+ n = NEXTI();
+ v = POP();
+ if (!is_tupleobject(v)) {
+ type_error(ctx, "unpack non-tuple");
+ }
+ else if (gettuplesize(v) != n) {
+ error(ctx, "unpack tuple of wrong size");
+ }
+ else {
+ for (i = n; --i >= 0; ) {
+ w = gettupleitem(v, i);
+ INCREF(w);
+ PUSH(w);
+ }
+ }
+ DECREF(v);
+ break;
+
+ case UNPACK_LIST:
+ n = NEXTI();
+ v = POP();
+ if (!is_listobject(v)) {
+ type_error(ctx, "unpack non-list");
+ }
+ else if (getlistsize(v) != n) {
+ error(ctx, "unpack tuple of wrong size");
+ }
+ else {
+ for (i = n; --i >= 0; ) {
+ w = getlistitem(v, i);
+ INCREF(w);
+ PUSH(w);
+ }
+ }
+ DECREF(v);
+ break;
+
+ case STORE_ATTR:
+ i = NEXTI();
+ name = GETNAME(i);
+ v = POP();
+ u = POP();
+ /* v.name = u */
+ if (v->ob_type->tp_setattr == NULL) {
+ type_error(ctx, "object without writable attributes");
+ }
+ else {
+ if ((*v->ob_type->tp_setattr)(v, name, u) != 0)
+ puterrno(ctx);
+ }
+ DECREF(v);
+ DECREF(u);
+ break;
+
+ case DELETE_ATTR:
+ i = NEXTI();
+ name = GETNAME(i);
+ v = POP();
+ /* del v.name */
+ if (v->ob_type->tp_setattr == NULL) {
+ type_error(ctx,
+ "object without writable attributes");
+ }
+ else {
+ if ((*v->ob_type->tp_setattr)
+ (v, name, (object *)NULL) != 0)
+ puterrno(ctx);
+ }
+ DECREF(v);
+ break;
+
+ case LOAD_CONST:
+ i = NEXTI();
+ v = GETCONST(i);
+ INCREF(v);
+ PUSH(v);
+ break;
+
+ case LOAD_NAME:
+ i = NEXTI();
+ name = GETNAME(i);
+ v = dictlookup(ctx->ctx_locals, name);
+ if (v == NULL) {
+ v = dictlookup(ctx->ctx_globals, name);
+ if (v == NULL)
+ v = dictlookup(ctx->ctx_builtins, name);
+ }
+ if (v == NULL)
+ name_error(ctx, name);
+ /* XXX could optimize */
+ else
+ INCREF(v);
+ PUSH(v);
+ break;
+
+ case BUILD_TUPLE:
+ n = NEXTI();
+ v = checkerror(ctx, newtupleobject(n));
+ if (v != NULL) {
+ for (i = n; --i >= 0;) {
+ w = POP();
+ settupleitem(v, i, w);
+ }
+ }
+ PUSH(v);
+ break;
+
+ case BUILD_LIST:
+ n = NEXTI();
+ v = checkerror(ctx, newlistobject(n));
+ if (v != NULL) {
+ for (i = n; --i >= 0;) {
+ w = POP();
+ setlistitem(v, i, w);
+ }
+ }
+ PUSH(v);
+ break;
+
+ case BUILD_MAP:
+ (void) NEXTI();
+ v = checkerror(ctx, newdictobject());
+ PUSH(v);
+ break;
+
+ case LOAD_ATTR:
+ i = NEXTI();
+ name = GETNAME(i);
+ v = POP();
+ if (v->ob_type->tp_getattr == NULL) {
+ type_error(ctx, "attribute-less object");
+ u = NULL;
+ }
+ else {
+ u = checkerror(ctx,
+ (*v->ob_type->tp_getattr)(v, name));
+ }
+ DECREF(v);
+ PUSH(u);
+ break;
+
+ case COMPARE_OP:
+ op = NEXTI();
+ w = POP();
+ v = POP();
+ u = cmp_outcome(ctx, op, v, w);
+ DECREF(v);
+ DECREF(w);
+ PUSH(u);
+ break;
+
+ case IMPORT_NAME:
+ i = NEXTI();
+ name = GETNAME(i);
+ u = import_module(ctx, name);
+ if (u != NULL) {
+ INCREF(u);
+ PUSH(u);
+ }
+ break;
+
+ case IMPORT_FROM:
+ i = NEXTI();
+ name = GETNAME(i);
+ v = TOP();
+ w = getmoduledict(v);
+ x = dictlookup(w, name);
+ if (x == NULL)
+ name_error(ctx, name);
+ else if (dictinsert(ctx->ctx_locals, name, x) != 0)
+ puterrno(ctx);
+ break;
+
+ /* WARNING!
+ Don't assign an expression containing NEXTI() directly
+ to nexti. This expands to "nexti = ... + *nexti++"
+ which has undefined evaluation order. On some machines
+ (e.g., mips!) the nexti++ is done after the assignment
+ to nexti. */
+
+ case JUMP_FORWARD:
+ n = NEXTI();
+ JUMPBY(n);
+ break;
+
+ case JUMP_IF_FALSE:
+ n = NEXTI();
+ if (!testbool(ctx, TOP()))
+ JUMPBY(n);
+ break;
+
+ case JUMP_IF_TRUE:
+ n = NEXTI();
+ if (testbool(ctx, TOP()))
+ JUMPBY(n);
+ break;
+
+ case JUMP_ABSOLUTE:
+ n = NEXTI();
+ JUMPTO(n);
+ /* XXX Should check for interrupts more often? */
+ if (intrcheck())
+ intr_error(ctx);
+ break;
+
+ case FOR_LOOP:
+ /* for v in s: ...
+ On entry: stack contains s, i.
+ On exit: stack contains s, i+1, s[i];
+ but if loop exhausted:
+ s, i are popped, and we jump n bytes */
+ n = NEXTI();
+ w = POP(); /* Loop index */
+ v = POP(); /* Sequence object */
+ x = loop_subscript(ctx, v, w);
+ if (x != NULL) {
+ PUSH(v);
+ u = checkerror(ctx,
+ newintobject(getintvalue(w)+1));
+ PUSH(u);
+ DECREF(w);
+ PUSH(x);
+ }
+ else {
+ DECREF(v);
+ DECREF(w);
+ JUMPBY(n);
+ }
+ break;
+
+ case SETUP_LOOP:
+ n = NEXTI();
+ setup_block(f, SETUP_LOOP, n);
+ break;
+
+ case SETUP_EXCEPT:
+ n = NEXTI();
+ setup_block(f, SETUP_EXCEPT, n);
+ break;
+
+ case SETUP_FINALLY:
+ n = NEXTI();
+ setup_block(f, SETUP_FINALLY, n);
+ break;
+
+ default:
+ printf("opcode %d\n", Prevbyte(f));
+ sys_error(ctx, "eval_compiled: unknown opcode");
+ break;
+
+ }
+
+ /* Unwind block stack if an exception occurred */
+
+ while (ctx->ctx_exception && f->f_iblock > 0) {
+ block *b = pop_block(f);
+ if (b->b_type == SETUP_LOOP &&
+ ctx->ctx_exception == BREAK_PSEUDO) {
+ clear_exception(ctx);
+ JUMPTO(b->b_handler);
+ break;
+ }
+ else if (b->b_type == SETUP_FINALLY ||
+ b->b_type == SETUP_EXCEPT &&
+ ctx->ctx_exception == CATCHABLE_EXCEPTION) {
+ v = ctx->ctx_errval;
+ if (v == NULL)
+ v = None;
+ INCREF(v);
+ PUSH(v);
+ v = ctx->ctx_error;
+ if (v == NULL)
+ v = newintobject(ctx->ctx_exception);
+ else
+ INCREF(v);
+ PUSH(v);
+ clear_exception(ctx);
+ JUMPTO(b->b_handler);
+ break;
+ }
+ }
+ }
+
+ if (ctx->ctx_exception) {
+ while (!EMPTY()) {
+ v = POP();
+ XDECREF(v);
+ }
+ v = NULL;
+ if (ctx->ctx_exception == RETURN_PSEUDO) {
+ if (needvalue) {
+ v = ctx->ctx_errval;
+ INCREF(v);
+ clear_exception(ctx);
+ }
+ else {
+ /* XXX Can detect this statically! */
+ type_error(ctx, "unexpected return statement");
+ }
+ }
+ }
+ else {
+ if (needvalue)
+ v = POP();
+ else
+ v = NULL;
+ if (!EMPTY()) {
+ sys_error(ctx, "stack not cleaned up");
+ XDECREF(v);
+ while (!EMPTY()) {
+ v = POP();
+ XDECREF(v);
+ }
+ v = NULL;
+ }
+ }
+
+#undef EMPTY
+#undef FULL
+#undef GETCONST
+#undef GETNAME
+#undef JUMPTO
+#undef JUMPBY
+
+#undef NEXTOP
+#undef NEXTI
+#undef POP
+#undef TOP
+#undef PUSH
+
+ DECREF(f);
+ return v;
+
+}
+
+/* Provisional interface until everything is compilable */
+
+#include "node.h"
+
+static object *
+eval_or_exec(ctx, n, arg, needvalue)
+ context *ctx;
+ node *n;
+ object *arg;
+ int needvalue;
+{
+ object *v;
+ codeobject *co = compile(n);
+ if (co == NULL) {
+ puterrno(ctx);
+ return NULL;
+ }
+ v = eval_compiled(ctx, co, arg, needvalue);
+ DECREF(co);
+ return v;
+}
+
+object *
+eval_node(ctx, n)
+ context *ctx;
+ node *n;
+{
+ return eval_or_exec(ctx, n, (object *)NULL, 1/*needvalue*/);
+}
+
+void
+exec_node(ctx, n)
+ context *ctx;
+ node *n;
+{
+ (void) eval_or_exec(ctx, n, (object *)NULL, 0/*needvalue*/);
+}
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;
+}