]> granicus.if.org Git - python/commitdiff
Merge ast-branch to head
authorJeremy Hylton <jeremy@alum.mit.edu>
Thu, 20 Oct 2005 19:59:25 +0000 (19:59 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Thu, 20 Oct 2005 19:59:25 +0000 (19:59 +0000)
This change implements a new bytecode compiler, based on a
transformation of the parse tree to an abstract syntax defined in
Parser/Python.asdl.

The compiler implementation is not complete, but it is in stable
enough shape to run the entire test suite excepting two disabled
tests.

54 files changed:
Include/Python-ast.h [new file with mode: 0644]
Include/Python.h
Include/asdl.h [new file with mode: 0644]
Include/ast.h [new file with mode: 0644]
Include/code.h [new file with mode: 0644]
Include/compile.h
Include/pyport.h
Include/pythonrun.h
Include/symtable.h
Lib/cgitb.py
Lib/compiler/pyassem.py
Lib/pydoc.py
Lib/test/output/test_grammar
Lib/test/output/test_profile
Lib/test/test_code.py [new file with mode: 0644]
Lib/test/test_doctest.py
Lib/test/test_eof.py
Lib/test/test_generators.py
Lib/test/test_genexps.py
Lib/test/test_grammar.py
Lib/test/test_import.py
Lib/test/test_parser.py
Lib/test/test_repr.py
Lib/test/test_scope.py
Makefile.pre.in
Misc/ACKS
Modules/_hotshot.c
Modules/symtablemodule.c
Objects/codeobject.c [new file with mode: 0644]
Objects/frameobject.c
Objects/funcobject.c
Objects/typeobject.c
PCbuild/pythoncore.vcproj
Parser/.cvsignore
Parser/Python.asdl [new file with mode: 0644]
Parser/asdl.py [new file with mode: 0644]
Parser/asdl_c.py [new file with mode: 0755]
Parser/grammar.mak
Parser/parsetok.c
Parser/spark.py [new file with mode: 0644]
Python/Python-ast.c [new file with mode: 0644]
Python/asdl.c [new file with mode: 0644]
Python/ast.c [new file with mode: 0644]
Python/bltinmodule.c
Python/ceval.c
Python/compile.c
Python/future.c
Python/import.c
Python/marshal.c
Python/pythonrun.c
Python/symtable.c
Python/sysmodule.c
Python/traceback.c
Tools/compiler/dumppyc.py

diff --git a/Include/Python-ast.h b/Include/Python-ast.h
new file mode 100644 (file)
index 0000000..0859acf
--- /dev/null
@@ -0,0 +1,418 @@
+/* File automatically generated by ../Parser/asdl_c.py */
+
+#include "asdl.h"
+
+typedef struct _mod *mod_ty;
+
+typedef struct _stmt *stmt_ty;
+
+typedef struct _expr *expr_ty;
+
+typedef enum _expr_context { Load=1, Store=2, Del=3, AugLoad=4, AugStore=5,
+                             Param=6 } expr_context_ty;
+
+typedef struct _slice *slice_ty;
+
+typedef enum _boolop { And=1, Or=2 } boolop_ty;
+
+typedef enum _operator { Add=1, Sub=2, Mult=3, Div=4, Mod=5, Pow=6, LShift=7,
+                         RShift=8, BitOr=9, BitXor=10, BitAnd=11, FloorDiv=12 }
+                         operator_ty;
+
+typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty;
+
+typedef enum _cmpop { Eq=1, NotEq=2, Lt=3, LtE=4, Gt=5, GtE=6, Is=7, IsNot=8,
+                      In=9, NotIn=10 } cmpop_ty;
+
+typedef struct _comprehension *comprehension_ty;
+
+typedef struct _excepthandler *excepthandler_ty;
+
+typedef struct _arguments *arguments_ty;
+
+typedef struct _keyword *keyword_ty;
+
+typedef struct _alias *alias_ty;
+
+struct _mod {
+        enum { Module_kind=1, Interactive_kind=2, Expression_kind=3,
+               Suite_kind=4 } kind;
+        union {
+                struct {
+                        asdl_seq *body;
+                } Module;
+                
+                struct {
+                        asdl_seq *body;
+                } Interactive;
+                
+                struct {
+                        expr_ty body;
+                } Expression;
+                
+                struct {
+                        asdl_seq *body;
+                } Suite;
+                
+        } v;
+};
+
+struct _stmt {
+        enum { FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3,
+               Delete_kind=4, Assign_kind=5, AugAssign_kind=6, Print_kind=7,
+               For_kind=8, While_kind=9, If_kind=10, Raise_kind=11,
+               TryExcept_kind=12, TryFinally_kind=13, Assert_kind=14,
+               Import_kind=15, ImportFrom_kind=16, Exec_kind=17,
+               Global_kind=18, Expr_kind=19, Pass_kind=20, Break_kind=21,
+               Continue_kind=22 } kind;
+        union {
+                struct {
+                        identifier name;
+                        arguments_ty args;
+                        asdl_seq *body;
+                        asdl_seq *decorators;
+                } FunctionDef;
+                
+                struct {
+                        identifier name;
+                        asdl_seq *bases;
+                        asdl_seq *body;
+                } ClassDef;
+                
+                struct {
+                        expr_ty value;
+                } Return;
+                
+                struct {
+                        asdl_seq *targets;
+                } Delete;
+                
+                struct {
+                        asdl_seq *targets;
+                        expr_ty value;
+                } Assign;
+                
+                struct {
+                        expr_ty target;
+                        operator_ty op;
+                        expr_ty value;
+                } AugAssign;
+                
+                struct {
+                        expr_ty dest;
+                        asdl_seq *values;
+                        bool nl;
+                } Print;
+                
+                struct {
+                        expr_ty target;
+                        expr_ty iter;
+                        asdl_seq *body;
+                        asdl_seq *orelse;
+                } For;
+                
+                struct {
+                        expr_ty test;
+                        asdl_seq *body;
+                        asdl_seq *orelse;
+                } While;
+                
+                struct {
+                        expr_ty test;
+                        asdl_seq *body;
+                        asdl_seq *orelse;
+                } If;
+                
+                struct {
+                        expr_ty type;
+                        expr_ty inst;
+                        expr_ty tback;
+                } Raise;
+                
+                struct {
+                        asdl_seq *body;
+                        asdl_seq *handlers;
+                        asdl_seq *orelse;
+                } TryExcept;
+                
+                struct {
+                        asdl_seq *body;
+                        asdl_seq *finalbody;
+                } TryFinally;
+                
+                struct {
+                        expr_ty test;
+                        expr_ty msg;
+                } Assert;
+                
+                struct {
+                        asdl_seq *names;
+                } Import;
+                
+                struct {
+                        identifier module;
+                        asdl_seq *names;
+                } ImportFrom;
+                
+                struct {
+                        expr_ty body;
+                        expr_ty globals;
+                        expr_ty locals;
+                } Exec;
+                
+                struct {
+                        asdl_seq *names;
+                } Global;
+                
+                struct {
+                        expr_ty value;
+                } Expr;
+                
+        } v;
+        int lineno;
+};
+
+struct _expr {
+        enum { BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4,
+               Dict_kind=5, ListComp_kind=6, GeneratorExp_kind=7, Yield_kind=8,
+               Compare_kind=9, Call_kind=10, Repr_kind=11, Num_kind=12,
+               Str_kind=13, Attribute_kind=14, Subscript_kind=15, Name_kind=16,
+               List_kind=17, Tuple_kind=18 } kind;
+        union {
+                struct {
+                        boolop_ty op;
+                        asdl_seq *values;
+                } BoolOp;
+                
+                struct {
+                        expr_ty left;
+                        operator_ty op;
+                        expr_ty right;
+                } BinOp;
+                
+                struct {
+                        unaryop_ty op;
+                        expr_ty operand;
+                } UnaryOp;
+                
+                struct {
+                        arguments_ty args;
+                        expr_ty body;
+                } Lambda;
+                
+                struct {
+                        asdl_seq *keys;
+                        asdl_seq *values;
+                } Dict;
+                
+                struct {
+                        expr_ty elt;
+                        asdl_seq *generators;
+                } ListComp;
+                
+                struct {
+                        expr_ty elt;
+                        asdl_seq *generators;
+                } GeneratorExp;
+                
+                struct {
+                        expr_ty value;
+                } Yield;
+                
+                struct {
+                        expr_ty left;
+                        asdl_seq *ops;
+                        asdl_seq *comparators;
+                } Compare;
+                
+                struct {
+                        expr_ty func;
+                        asdl_seq *args;
+                        asdl_seq *keywords;
+                        expr_ty starargs;
+                        expr_ty kwargs;
+                } Call;
+                
+                struct {
+                        expr_ty value;
+                } Repr;
+                
+                struct {
+                        object n;
+                } Num;
+                
+                struct {
+                        string s;
+                } Str;
+                
+                struct {
+                        expr_ty value;
+                        identifier attr;
+                        expr_context_ty ctx;
+                } Attribute;
+                
+                struct {
+                        expr_ty value;
+                        slice_ty slice;
+                        expr_context_ty ctx;
+                } Subscript;
+                
+                struct {
+                        identifier id;
+                        expr_context_ty ctx;
+                } Name;
+                
+                struct {
+                        asdl_seq *elts;
+                        expr_context_ty ctx;
+                } List;
+                
+                struct {
+                        asdl_seq *elts;
+                        expr_context_ty ctx;
+                } Tuple;
+                
+        } v;
+        int lineno;
+};
+
+struct _slice {
+        enum { Ellipsis_kind=1, Slice_kind=2, ExtSlice_kind=3, Index_kind=4 }
+               kind;
+        union {
+                struct {
+                        expr_ty lower;
+                        expr_ty upper;
+                        expr_ty step;
+                } Slice;
+                
+                struct {
+                        asdl_seq *dims;
+                } ExtSlice;
+                
+                struct {
+                        expr_ty value;
+                } Index;
+                
+        } v;
+};
+
+struct _comprehension {
+        expr_ty target;
+        expr_ty iter;
+        asdl_seq *ifs;
+};
+
+struct _excepthandler {
+        expr_ty type;
+        expr_ty name;
+        asdl_seq *body;
+};
+
+struct _arguments {
+        asdl_seq *args;
+        identifier vararg;
+        identifier kwarg;
+        asdl_seq *defaults;
+};
+
+struct _keyword {
+        identifier arg;
+        expr_ty value;
+};
+
+struct _alias {
+        identifier name;
+        identifier asname;
+};
+
+mod_ty Module(asdl_seq * body);
+mod_ty Interactive(asdl_seq * body);
+mod_ty Expression(expr_ty body);
+mod_ty Suite(asdl_seq * body);
+stmt_ty FunctionDef(identifier name, arguments_ty args, asdl_seq * body,
+                    asdl_seq * decorators, int lineno);
+stmt_ty ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int
+                 lineno);
+stmt_ty Return(expr_ty value, int lineno);
+stmt_ty Delete(asdl_seq * targets, int lineno);
+stmt_ty Assign(asdl_seq * targets, expr_ty value, int lineno);
+stmt_ty AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno);
+stmt_ty Print(expr_ty dest, asdl_seq * values, bool nl, int lineno);
+stmt_ty For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse,
+            int lineno);
+stmt_ty While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno);
+stmt_ty If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno);
+stmt_ty Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno);
+stmt_ty TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int
+                  lineno);
+stmt_ty TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno);
+stmt_ty Assert(expr_ty test, expr_ty msg, int lineno);
+stmt_ty Import(asdl_seq * names, int lineno);
+stmt_ty ImportFrom(identifier module, asdl_seq * names, int lineno);
+stmt_ty Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno);
+stmt_ty Global(asdl_seq * names, int lineno);
+stmt_ty Expr(expr_ty value, int lineno);
+stmt_ty Pass(int lineno);
+stmt_ty Break(int lineno);
+stmt_ty Continue(int lineno);
+expr_ty BoolOp(boolop_ty op, asdl_seq * values, int lineno);
+expr_ty BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno);
+expr_ty UnaryOp(unaryop_ty op, expr_ty operand, int lineno);
+expr_ty Lambda(arguments_ty args, expr_ty body, int lineno);
+expr_ty Dict(asdl_seq * keys, asdl_seq * values, int lineno);
+expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno);
+expr_ty GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno);
+expr_ty Yield(expr_ty value, int lineno);
+expr_ty Compare(expr_ty left, asdl_seq * ops, asdl_seq * comparators, int
+                lineno);
+expr_ty Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty
+             starargs, expr_ty kwargs, int lineno);
+expr_ty Repr(expr_ty value, int lineno);
+expr_ty Num(object n, int lineno);
+expr_ty Str(string s, int lineno);
+expr_ty Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int
+                  lineno);
+expr_ty Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int
+                  lineno);
+expr_ty Name(identifier id, expr_context_ty ctx, int lineno);
+expr_ty List(asdl_seq * elts, expr_context_ty ctx, int lineno);
+expr_ty Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno);
+slice_ty Ellipsis(void);
+slice_ty Slice(expr_ty lower, expr_ty upper, expr_ty step);
+slice_ty ExtSlice(asdl_seq * dims);
+slice_ty Index(expr_ty value);
+comprehension_ty comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs);
+excepthandler_ty excepthandler(expr_ty type, expr_ty name, asdl_seq * body);
+arguments_ty arguments(asdl_seq * args, identifier vararg, identifier kwarg,
+                       asdl_seq * defaults);
+keyword_ty keyword(identifier arg, expr_ty value);
+alias_ty alias(identifier name, identifier asname);
+void free_mod(mod_ty);
+void free_stmt(stmt_ty);
+void free_expr(expr_ty);
+void free_expr_context(expr_context_ty);
+void free_slice(slice_ty);
+void free_boolop(boolop_ty);
+void free_operator(operator_ty);
+void free_unaryop(unaryop_ty);
+void free_cmpop(cmpop_ty);
+void free_comprehension(comprehension_ty);
+void free_excepthandler(excepthandler_ty);
+void free_arguments(arguments_ty);
+void free_keyword(keyword_ty);
+void free_alias(alias_ty);
+int marshal_write_mod(PyObject **, int *, mod_ty);
+int marshal_write_stmt(PyObject **, int *, stmt_ty);
+int marshal_write_expr(PyObject **, int *, expr_ty);
+int marshal_write_expr_context(PyObject **, int *, expr_context_ty);
+int marshal_write_slice(PyObject **, int *, slice_ty);
+int marshal_write_boolop(PyObject **, int *, boolop_ty);
+int marshal_write_operator(PyObject **, int *, operator_ty);
+int marshal_write_unaryop(PyObject **, int *, unaryop_ty);
+int marshal_write_cmpop(PyObject **, int *, cmpop_ty);
+int marshal_write_comprehension(PyObject **, int *, comprehension_ty);
+int marshal_write_excepthandler(PyObject **, int *, excepthandler_ty);
+int marshal_write_arguments(PyObject **, int *, arguments_ty);
+int marshal_write_keyword(PyObject **, int *, keyword_ty);
+int marshal_write_alias(PyObject **, int *, alias_ty);
index 2d48d2eaa107f685cf41bcf44e0559ff365844b6..f941cbad229643b085cafa56406d550bdd6a56ba 100644 (file)
 #include "pystrtod.h"
 
 /* _Py_Mangle is defined in compile.c */
-PyAPI_FUNC(int) _Py_Mangle(char *p, char *name, \
-                                char *buffer, size_t maxlen);
+PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name);
 
 /* PyArg_GetInt is deprecated and should not be used, use PyArg_Parse(). */
 #define PyArg_GetInt(v, a)     PyArg_Parse((v), "i", (a))
diff --git a/Include/asdl.h b/Include/asdl.h
new file mode 100644 (file)
index 0000000..8ad46fa
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef Py_ASDL_H
+#define Py_ASDL_H
+
+typedef PyObject * identifier;
+typedef PyObject * string;
+typedef PyObject * object;
+
+typedef enum {false, true} bool;
+
+/* It would be nice if the code generated by asdl_c.py was completely
+   independent of Python, but it is a goal the requires too much work
+   at this stage.  So, for example, I'll represent identifiers as
+   interned Python strings.
+*/
+
+/* XXX A sequence should be typed so that its use can be typechecked. */
+
+/* XXX We shouldn't pay for offset when we don't need APPEND. */
+
+typedef struct {
+    int size;
+    int offset;
+    void *elements[1];
+} asdl_seq;
+
+asdl_seq *asdl_seq_new(int size);
+void asdl_seq_free(asdl_seq *);
+
+#ifdef Py_DEBUG
+#define asdl_seq_GET(S, I) (S)->elements[(I)]
+#define asdl_seq_SET(S, I, V) { \
+        int _asdl_i = (I); \
+        assert((S) && _asdl_i < (S)->size); \
+        (S)->elements[_asdl_i] = (V); \
+}
+#define asdl_seq_APPEND(S, V) { \
+        assert((S) && (S)->offset < (S)->size); \
+        (S)->elements[(S)->offset++] = (V); \
+}
+#else
+#define asdl_seq_GET(S, I) (S)->elements[(I)]
+#define asdl_seq_SET(S, I, V) (S)->elements[I] = (V)
+#define asdl_seq_APPEND(S, V) (S)->elements[(S)->offset++] = (V)
+#endif
+#define asdl_seq_LEN(S) ((S) == NULL ? 0 : (S)->size)
+
+/* Routines to marshal the basic types. */
+int marshal_write_int(PyObject **, int *, int);
+int marshal_write_bool(PyObject **, int *, bool);
+int marshal_write_identifier(PyObject **, int *, identifier);
+int marshal_write_string(PyObject **, int *, string);
+int marshal_write_object(PyObject **, int *, object);
+
+#endif /* !Py_ASDL_H */
diff --git a/Include/ast.h b/Include/ast.h
new file mode 100644 (file)
index 0000000..8912f38
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef Py_AST_H
+#define Py_AST_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern DL_IMPORT(mod_ty) PyAST_FromNode(const node *, PyCompilerFlags *flags,
+                                       const char *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_AST_H */
diff --git a/Include/code.h b/Include/code.h
new file mode 100644 (file)
index 0000000..e6478b0
--- /dev/null
@@ -0,0 +1,73 @@
+/* Definitions for bytecode */
+
+#ifndef Py_CODE_H
+#define Py_CODE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Bytecode object */
+typedef struct {
+    PyObject_HEAD
+    int co_argcount;           /* #arguments, except *args */
+    int co_nlocals;            /* #local variables */
+    int co_stacksize;          /* #entries needed for evaluation stack */
+    int co_flags;              /* CO_..., see below */
+    PyObject *co_code;         /* instruction opcodes */
+    PyObject *co_consts;       /* list (constants used) */
+    PyObject *co_names;                /* list of strings (names used) */
+    PyObject *co_varnames;     /* tuple of strings (local variable names) */
+    PyObject *co_freevars;     /* tuple of strings (free variable names) */
+    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
+    /* The rest doesn't count for hash/cmp */
+    PyObject *co_filename;     /* string (where it was loaded from) */
+    PyObject *co_name;         /* string (name, for reference) */
+    int co_firstlineno;                /* first source line number */
+    PyObject *co_lnotab;       /* string (encoding addr<->lineno mapping) */
+} PyCodeObject;
+
+/* Masks for co_flags above */
+#define CO_OPTIMIZED   0x0001
+#define CO_NEWLOCALS   0x0002
+#define CO_VARARGS     0x0004
+#define CO_VARKEYWORDS 0x0008
+#define CO_NESTED       0x0010
+#define CO_GENERATOR    0x0020
+/* The CO_NOFREE flag is set if there are no free or cell variables.
+   This information is redundant, but it allows a single flag test
+   to determine whether there is any extra work to be done when the
+   call frame it setup.
+*/
+#define CO_NOFREE       0x0040
+/* XXX Temporary hack.  Until generators are a permanent part of the
+   language, we need a way for a code object to record that generators
+   were *possible* when it was compiled.  This is so code dynamically
+   compiled *by* a code object knows whether to allow yield stmts.  In
+   effect, this passes on the "from __future__ import generators" state
+   in effect when the code block was compiled. */
+#define CO_GENERATOR_ALLOWED    0x1000 /* no longer used in an essential way */
+#define CO_FUTURE_DIVISION     0x2000
+
+#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
+
+extern DL_IMPORT(PyTypeObject) PyCode_Type;
+
+#define PyCode_Check(op) ((op)->ob_type == &PyCode_Type)
+#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars))
+
+/* Public interface */
+DL_IMPORT(PyCodeObject *) PyCode_New(
+       int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *,
+       PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *); 
+        /* same as struct above */
+DL_IMPORT(int) PyCode_Addr2Line(PyCodeObject *, int);
+
+/* for internal use only */
+#define _PyCode_GETCODEPTR(co, pp) \
+       ((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \
+        ((co)->co_code, 0, (void **)(pp)))
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_CODE_H */
index 82bf70862e66738253a67da3fc6572cc237798e4..27a3f76a0f93daee3a493f4df546b255c057c082 100644 (file)
@@ -1,5 +1,6 @@
-
-/* Definitions for bytecode */
+#ifndef Py_CODE_H
+#include "code.h"
+#endif
 
 #ifndef Py_COMPILE_H
 #define Py_COMPILE_H
@@ -7,55 +8,6 @@
 extern "C" {
 #endif
 
-/* Bytecode object */
-typedef struct {
-    PyObject_HEAD
-    int co_argcount;           /* #arguments, except *args */
-    int co_nlocals;            /* #local variables */
-    int co_stacksize;          /* #entries needed for evaluation stack */
-    int co_flags;              /* CO_..., see below */
-    PyObject *co_code;         /* instruction opcodes */
-    PyObject *co_consts;       /* list (constants used) */
-    PyObject *co_names;                /* list of strings (names used) */
-    PyObject *co_varnames;     /* tuple of strings (local variable names) */
-    PyObject *co_freevars;     /* tuple of strings (free variable names) */
-    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
-    /* The rest doesn't count for hash/cmp */
-    PyObject *co_filename;     /* string (where it was loaded from) */
-    PyObject *co_name;         /* string (name, for reference) */
-    int co_firstlineno;                /* first source line number */
-    PyObject *co_lnotab;       /* string (encoding addr<->lineno mapping) */
-} PyCodeObject;
-
-/* Masks for co_flags above */
-#define CO_OPTIMIZED   0x0001
-#define CO_NEWLOCALS   0x0002
-#define CO_VARARGS     0x0004
-#define CO_VARKEYWORDS 0x0008
-#define CO_NESTED       0x0010
-#define CO_GENERATOR    0x0020
-/* The CO_NOFREE flag is set if there are no free or cell variables.
-   This information is redundant, but it allows a single flag test
-   to determine whether there is any extra work to be done when the
-   call frame it setup.
-*/
-#define CO_NOFREE       0x0040
-/* XXX Temporary hack.  Until generators are a permanent part of the
-   language, we need a way for a code object to record that generators
-   were *possible* when it was compiled.  This is so code dynamically
-   compiled *by* a code object knows whether to allow yield stmts.  In
-   effect, this passes on the "from __future__ import generators" state
-   in effect when the code block was compiled. */
-#define CO_GENERATOR_ALLOWED    0x1000 /* no longer used in an essential way */
-#define CO_FUTURE_DIVISION     0x2000
-
-PyAPI_DATA(PyTypeObject) PyCode_Type;
-
-#define PyCode_Check(op) ((op)->ob_type == &PyCode_Type)
-#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars))
-
-#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
-
 /* Public interface */
 struct _node; /* Declare the existence of this type */
 PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *);
@@ -68,19 +20,22 @@ PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
 /* Future feature support */
 
 typedef struct {
-    int ff_found_docstring;
-    int ff_last_lineno;
-    int ff_features;
+    int ff_features;      /* flags set by future statements */
+    int ff_lineno;        /* line number of last future statement */
 } PyFutureFeatures;
 
-PyAPI_FUNC(PyFutureFeatures *) PyNode_Future(struct _node *, const char *);
-PyAPI_FUNC(PyCodeObject *) PyNode_CompileFlags(struct _node *, const char *,
-                                             PyCompilerFlags *);
-
 #define FUTURE_NESTED_SCOPES "nested_scopes"
 #define FUTURE_GENERATORS "generators"
 #define FUTURE_DIVISION "division"
 
+struct _mod; /* Declare the existence of this type */
+DL_IMPORT(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
+                                       PyCompilerFlags *);
+DL_IMPORT(PyFutureFeatures *) PyFuture_FromAST(struct _mod *, const char *);
+
+#define ERR_LATE_FUTURE \
+"from __future__ imports must occur at the beginning of the file"
+
 #ifdef __cplusplus
 }
 #endif
index 2440c55f7a250cef09fc6395a80796b0a686f43a..ea2091b9cb81a7d8ad3bababfb627fd1dcce4f30 100644 (file)
@@ -583,6 +583,7 @@ typedef     struct fd_set {
 
 #ifndef INT_MAX
 #define INT_MAX 2147483647
+#define INT_MIN (-INT_MAX - 1)
 #endif
 
 #ifndef LONG_MAX
index f461d1329c1930204b08de97955af59f89d526a4..490613eb770d005a33d6e48061155dbd88eb2816 100644 (file)
@@ -29,46 +29,37 @@ PyAPI_FUNC(int) Py_IsInitialized(void);
 PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void);
 PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
 
-PyAPI_FUNC(int) PyRun_AnyFile(FILE *, const char *);
-PyAPI_FUNC(int) PyRun_AnyFileEx(FILE *, const char *, int);
-
-PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_AnyFileExFlags(FILE *, const char *, int, PyCompilerFlags *);
-
-PyAPI_FUNC(int) PyRun_SimpleString(const char *);
+PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, char *, PyCompilerFlags *);
+PyAPI_FUNC(int) PyRun_AnyFileExFlags(FILE *, char *, int, PyCompilerFlags *);
 PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_SimpleFile(FILE *, const char *);
-PyAPI_FUNC(int) PyRun_SimpleFileEx(FILE *, const char *, int);
 PyAPI_FUNC(int) PyRun_SimpleFileExFlags(FILE *, const char *, int, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_InteractiveOne(FILE *, const char *);
 PyAPI_FUNC(int) PyRun_InteractiveOneFlags(FILE *, const char *, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_InteractiveLoop(FILE *, const char *);
 PyAPI_FUNC(int) PyRun_InteractiveLoopFlags(FILE *, const char *, PyCompilerFlags *);
 
-PyAPI_FUNC(struct _node *) PyParser_SimpleParseString(const char *, int);
-PyAPI_FUNC(struct _node *) PyParser_SimpleParseFile(FILE *, const char *, int);
-PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int, int);
-PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlagsFilename(const char *,
-                                                                 const char *,
-                                                                 int,
-                                                                 int);
+PyAPI_FUNC(struct _mod *) PyParser_ASTFromString(const char *, const char *, 
+                                                int, PyCompilerFlags *flags);
+PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile(FILE *, const char *, int, 
+                                              char *, char *,
+                                               PyCompilerFlags *, int *);
+#define PyParser_SimpleParseString(S, B) \
+        PyParser_SimpleParseStringFlags(S, B, 0)
+#define PyParser_SimpleParseFile(FP, S, B) \
+        PyParser_SimpleParseFileFlags(FP, S, B, 0)
+PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int, 
+                                                         int);
 PyAPI_FUNC(struct _node *) PyParser_SimpleParseFileFlags(FILE *, const char *,
                                                        int, int);
 
-PyAPI_FUNC(PyObject *) PyRun_String(const char *, int, PyObject *, PyObject *);
-PyAPI_FUNC(PyObject *) PyRun_File(FILE *, const char *, int, PyObject *, PyObject *);
-PyAPI_FUNC(PyObject *) PyRun_FileEx(FILE *, const char *, int,
-                                  PyObject *, PyObject *, int);
-PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, PyObject *,
-                                       PyCompilerFlags *);
-PyAPI_FUNC(PyObject *) PyRun_FileFlags(FILE *, const char *, int, PyObject *, 
-                                     PyObject *, PyCompilerFlags *);
-PyAPI_FUNC(PyObject *) PyRun_FileExFlags(FILE *, const char *, int, PyObject *, 
-                                       PyObject *, int, PyCompilerFlags *);
-
-PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int);
+PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, 
+                                        PyObject *, PyCompilerFlags *);
+
+PyAPI_FUNC(PyObject *) PyRun_FileExFlags(FILE *, const char *, int, 
+                                        PyObject *, PyObject *, int, 
+                                        PyCompilerFlags *);
+
+#define Py_CompileString(str, p, s) Py_CompileStringFlags(str, p, s, NULL)
 PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *, const char *, int,
-                                           PyCompilerFlags *);
+                                            PyCompilerFlags *);
 PyAPI_FUNC(struct symtable *) Py_SymtableString(const char *, const char *, int);
 
 PyAPI_FUNC(void) PyErr_Print(void);
@@ -84,6 +75,25 @@ PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *);
 /* Bootstrap */
 PyAPI_FUNC(int) Py_Main(int argc, char **argv);
 
+/* Use macros for a bunch of old variants */
+#define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL)
+#define PyRun_AnyFile(fp, name) PyRun_AnyFileExFlags(fp, name, 0, NULL)
+#define PyRun_AnyFileEx(fp, name, closeit) \
+       PyRun_AnyFileExFlags(fp, name, closeit, NULL)
+#define PyRun_AnyFileFlags(fp, name, flags) \
+       PyRun_AnyFileExFlags(fp, name, 0, flags)
+#define PyRun_SimpleString(s, f) PyRunSimpleStringFlags(s, f, NULL)
+#define PyRun_SimpleFile(f, p) PyRun_SimpleFileExFlags(f, p, 0, NULL)
+#define PyRun_SimpleFileEx(f, p, c) PyRun_SimpleFileExFlags(f, p, c, NULL)
+#define PyRun_InteractiveOne(f, p) PyRun_InteractiveOneFlags(f, p, NULL)
+#define PyRun_InteractiveLoop(f, p) PyRun_InteractiveLoopFlags(f, p, NULL)
+#define PyRun_File(fp, p, s, g, l) \
+        PyRun_FileExFlags(fp, p, s, g, l, 0, NULL)
+#define PyRun_FileEx(fp, p, s, g, l, c) \
+        PyRun_FileExFlags(fp, p, s, g, l, c, NULL)
+#define PyRun_FileFlags(fp, p, s, g, l, flags) \
+        PyRun_FileExFlags(fp, p, s, g, l, 0, flags)
+
 /* In getpath.c */
 PyAPI_FUNC(char *) Py_GetProgramFullPath(void);
 PyAPI_FUNC(char *) Py_GetPrefix(void);
index 628c3e6db22eae1a007a7818299cde30e6221f2d..646602c6dee29fb2215e21dae45d67c68e35cc5c 100644 (file)
@@ -4,64 +4,59 @@
 extern "C" {
 #endif
 
-/* A symbol table is constructed each time PyNode_Compile() is
-   called.  The table walks the entire parse tree and identifies each
-   use or definition of a variable. 
-
-   The symbol table contains a dictionary for each code block in a
-   module: The symbol dictionary for the block.  They keys of these
-   dictionaries are the name of all variables used or defined in the
-   block; the integer values are used to store several flags,
-   e.g. DEF_PARAM indicates that a variable is a parameter to a
-   function. 
-*/
+typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock }
+    block_ty;
 
 struct _symtable_entry;
 
 struct symtable {
-       int st_pass;             /* pass == 1 or 2 */
        const char *st_filename; /* name of file being compiled */
        struct _symtable_entry *st_cur; /* current symbol table entry */
+       struct _symtable_entry *st_top; /* module entry */
        PyObject *st_symbols;    /* dictionary of symbol table entries */
         PyObject *st_stack;      /* stack of namespace info */
        PyObject *st_global;     /* borrowed ref to MODULE in st_symbols */
-       int st_nscopes;          /* number of scopes */
-       int st_errors;           /* number of errors */
+       int st_nblocks;          /* number of blocks */
        char *st_private;        /* name of current class or NULL */
+        int st_tmpname;          /* temporary name counter */
        PyFutureFeatures *st_future; /* module's future features */
 };
 
 typedef struct _symtable_entry {
        PyObject_HEAD
-       PyObject *ste_id;        /* int: key in st_symbols) */
-       PyObject *ste_symbols;   /* dict: name to flags) */
-       PyObject *ste_name;      /* string: name of scope */
+       PyObject *ste_id;        /* int: key in st_symbols */
+       PyObject *ste_symbols;   /* dict: name to flags */
+       PyObject *ste_name;      /* string: name of block */
        PyObject *ste_varnames;  /* list of variable names */
        PyObject *ste_children;  /* list of child ids */
-       int ste_type;            /* module, class, or function */
-       int ste_lineno;          /* first line of scope */
-       int ste_optimized;       /* true if namespace can't be optimized */
-       int ste_nested;          /* true if scope is nested */
-       int ste_child_free;      /* true if a child scope has free variables,
+       block_ty ste_type;       /* module, class, or function */
+       int ste_unoptimized;     /* false if namespace is optimized */
+       int ste_nested : 1;      /* true if block is nested */
+       int ste_free : 1;        /* true if block has free variables */
+       int ste_child_free : 1;  /* true if a child block has free variables,
                                    including free refs to globals */
-       int ste_generator;       /* true if namespace is a generator */
+       int ste_generator : 1;   /* true if namespace is a generator */
+       int ste_varargs : 1;     /* true if block has varargs */
+       int ste_varkeywords : 1; /* true if block has varkeywords */
+       int ste_lineno;          /* first line of block */
        int ste_opt_lineno;      /* lineno of last exec or import * */
-       int ste_tmpname;         /* temporary name counter */
+       int ste_tmpname;         /* counter for listcomp temp vars */
        struct symtable *ste_table;
-} PySymtableEntryObject;
-
-PyAPI_DATA(PyTypeObject) PySymtableEntry_Type;
+} PySTEntryObject;
 
-#define PySymtableEntry_Check(op) ((op)->ob_type == &PySymtableEntry_Type)
+PyAPI_DATA(PyTypeObject) PySTEntry_Type;
 
-PyAPI_FUNC(PyObject *) PySymtableEntry_New(struct symtable *,
-                                                char *, int, int);
+#define PySTEntry_Check(op) ((op)->ob_type == &PySTEntry_Type)
 
-PyAPI_FUNC(struct symtable *) PyNode_CompileSymtable(struct _node *, const char *);
-PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
+PyAPI_FUNC(PySTEntryObject *) \
+       PySTEntry_New(struct symtable *, identifier, block_ty, void *, int);
+PyAPI_FUNC(int) PyST_GetScope(PySTEntryObject *, PyObject *);
 
+PyAPI_FUNC(struct symtable *) PySymtable_Build(mod_ty, const char *, 
+                                             PyFutureFeatures *);
+PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *);
 
-#define TOP "global"
+PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
 
 /* Flags for def-use information */
 
@@ -72,16 +67,19 @@ PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
 #define DEF_STAR 2<<3          /* parameter is star arg */
 #define DEF_DOUBLESTAR 2<<4    /* parameter is star-star arg */
 #define DEF_INTUPLE 2<<5       /* name defined in tuple in parameters */
-#define DEF_FREE 2<<6          /* name used but not defined in nested scope */
+#define DEF_FREE 2<<6          /* name used but not defined in nested block */
 #define DEF_FREE_GLOBAL 2<<7   /* free variable is actually implicit global */
 #define DEF_FREE_CLASS 2<<8    /* free variable from class's method */
 #define DEF_IMPORT 2<<9        /* assignment occurred via import */
 
 #define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT)
 
-#define TYPE_FUNCTION 1
-#define TYPE_CLASS 2
-#define TYPE_MODULE 3
+/* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol
+   table.  GLOBAL is returned from PyST_GetScope() for either of them. 
+   It is stored in ste_symbols at bits 12-14.
+*/
+#define SCOPE_OFF 11
+#define SCOPE_MASK 7
 
 #define LOCAL 1
 #define GLOBAL_EXPLICIT 2
@@ -89,9 +87,14 @@ PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
 #define FREE 4
 #define CELL 5
 
+/* The following three names are used for the ste_unoptimized bit field */
 #define OPT_IMPORT_STAR 1
 #define OPT_EXEC 2
 #define OPT_BARE_EXEC 4
+#define OPT_TOPLEVEL 8  /* top-level names, including eval and exec */
+
+#define GENERATOR 1
+#define GENERATOR_EXPRESSION 2
 
 #define GENERATOR 1
 #define GENERATOR_EXPRESSION 2
index 8d979b84453c6ef60cad6593b4745d47859a5be1..ae25cf13ad7ba9670464d2821ae80e9f47eb3d2f 100644 (file)
@@ -22,6 +22,7 @@ The default handler displays output as HTML.
 """
 
 __author__ = 'Ka-Ping Yee'
+
 __version__ = '$Revision$'
 
 import sys
index 0547eeb068a11af4a978bce9db3bbdba2bcb38c0..e1fb063193e091fb9d4543ee61f63f5ae9ad7d95 100644 (file)
@@ -364,16 +364,15 @@ class PyFlowGraph(FlowGraph):
 
     def getCode(self):
         """Get a Python code object"""
-        if self.stage == RAW:
-            self.computeStackDepth()
-            self.flattenGraph()
-        if self.stage == FLAT:
-            self.convertArgs()
-        if self.stage == CONV:
-            self.makeByteCode()
-        if self.stage == DONE:
-            return self.newCodeObject()
-        raise RuntimeError, "inconsistent PyFlowGraph state"
+        assert self.stage == RAW
+        self.computeStackDepth()
+        self.flattenGraph()
+        assert self.stage == FLAT
+        self.convertArgs()
+        assert self.stage == CONV
+        self.makeByteCode()
+        assert self.stage == DONE
+        return self.newCodeObject()
 
     def dump(self, io=None):
         if io:
index 4084b7e39d6ae8b5e105707b365e8e5f9a266acd..5d16fa5c7c7fbe87ffcb4d8fca7038ee813aef60 100755 (executable)
@@ -36,6 +36,7 @@ Reference Manual pages.
 
 __author__ = "Ka-Ping Yee <ping@lfw.org>"
 __date__ = "26 February 2001"
+
 __version__ = "$Revision$"
 __credits__ = """Guido van Rossum, for an excellent programming language.
 Tommy Burnette, the original creator of manpy.
index 6174e7aca7963fe5883c4fb0e58dffe546934772..fed41973d826526dcd8028ccbcec3e16653fd302 100644 (file)
@@ -34,6 +34,7 @@ continue + try/except ok
 continue + try/finally ok
 testing continue and break in try/except in loop
 return_stmt
+yield_stmt
 raise_stmt
 import_name
 import_from
index b46bb6ab739cdf09d46893c02b23a84144b63041..e74507596cce924d49f56d54c142671b65a5f26a 100644 (file)
@@ -7,7 +7,7 @@ test_profile
        12    0.000    0.000    0.012    0.001 :0(hasattr)
         8    0.000    0.000    0.000    0.000 :0(range)
         1    0.000    0.000    0.000    0.000 :0(setprofile)
-        1    0.000    0.000    1.000    1.000 <string>:1(?)
+        1    0.000    0.000    1.000    1.000 <string>:1(<module>)
         0    0.000             0.000          profile:0(profiler)
         1    0.000    0.000    1.000    1.000 profile:0(testfunc())
         1    0.400    0.400    1.000    1.000 test_profile.py:23(testfunc)
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
new file mode 100644 (file)
index 0000000..ff95c6a
--- /dev/null
@@ -0,0 +1,85 @@
+"""This module includes tests of the code object representation.
+
+>>> def f(x):
+...     def g(y):
+...         return x + y
+...     return g
+...
+
+>>> dump(f.func_code)
+name: f
+argcount: 1
+names: ()
+varnames: ('x', 'g')
+cellvars: ('x',)
+freevars: ()
+nlocals: 2
+flags: 3
+consts: ('None', '<code object g>')
+
+>>> dump(f(4).func_code)
+name: g
+argcount: 1
+names: ()
+varnames: ('y',)
+cellvars: ()
+freevars: ('x',)
+nlocals: 1
+flags: 19
+consts: ('None',)
+
+>>> def h(x, y):
+...     a = x + y
+...     b = x - y
+...     c = a * b
+...     return c
+... 
+>>> dump(h.func_code)
+name: h
+argcount: 2
+names: ()
+varnames: ('x', 'y', 'a', 'b', 'c')
+cellvars: ()
+freevars: ()
+nlocals: 5
+flags: 67
+consts: ('None',)
+
+>>> def attrs(obj):
+...     print obj.attr1
+...     print obj.attr2
+...     print obj.attr3
+
+>>> dump(attrs.func_code)
+name: attrs
+argcount: 1
+names: ('attr1', 'attr2', 'attr3')
+varnames: ('obj',)
+cellvars: ()
+freevars: ()
+nlocals: 1
+flags: 67
+consts: ('None',)
+
+"""
+
+def consts(t):
+    """Yield a doctest-safe sequence of object reprs."""
+    for elt in t:
+        r = repr(elt)
+        if r.startswith("<code object"):
+            yield "<code object %s>" % elt.co_name
+        else:
+            yield r
+
+def dump(co):
+    """Print out a text representation of a code object."""
+    for attr in ["name", "argcount", "names", "varnames", "cellvars",
+                 "freevars", "nlocals", "flags"]:
+        print "%s: %s" % (attr, getattr(co, "co_" + attr))
+    print "consts:", tuple(consts(co.co_consts))
+
+def test_main(verbose=None):
+    from test.test_support import run_doctest
+    from test import test_code
+    run_doctest(test_code, verbose)
index fc4841ae12e554dde39da5d58f7baeffe94d489b..9c39ee8a964a48ab7677b2f1ceb353880ba3283f 100644 (file)
@@ -1559,11 +1559,11 @@ Run the debugger on the docstring, and then restore sys.stdin.
 
     >>> try: doctest.debug_src(s)
     ... finally: sys.stdin = real_stdin
-    > <string>(1)?()
+    > <string>(1)<module>()
     (Pdb) next
     12
     --Return--
-    > <string>(1)?()->None
+    > <string>(1)<module>()->None
     (Pdb) print x
     12
     (Pdb) continue
@@ -1601,7 +1601,7 @@ def test_pdb_set_trace():
       >>> try: runner.run(test)
       ... finally: sys.stdin = real_stdin
       --Return--
-      > <doctest foo[1]>(1)?()->None
+      > <doctest foo[1]>(1)<module>()->None
       -> import pdb; pdb.set_trace()
       (Pdb) print x
       42
@@ -1637,7 +1637,7 @@ def test_pdb_set_trace():
       (Pdb) print y
       2
       (Pdb) up
-      > <doctest foo[1]>(1)?()
+      > <doctest foo[1]>(1)<module>()
       -> calls_set_trace()
       (Pdb) print x
       1
@@ -1686,7 +1686,7 @@ def test_pdb_set_trace():
       [EOF]
       (Pdb) next
       --Return--
-      > <doctest foo[2]>(1)?()->None
+      > <doctest foo[2]>(1)<module>()->None
       -> f(3)
       (Pdb) list
         1  -> f(3)
@@ -1779,7 +1779,7 @@ def test_pdb_set_trace_nested():
     (Pdb) print y
     1
     (Pdb) up
-    > <doctest foo[1]>(1)?()
+    > <doctest foo[1]>(1)<module>()
     -> calls_set_trace()
     (Pdb) print foo
     *** NameError: name 'foo' is not defined
index 683649d767cac6f49dccf13d4d37fac2ecfa0130..aae35182bd1811a5fa24143bd8ee8e84bf6e776c 100644 (file)
@@ -7,21 +7,21 @@ from test import test_support
 
 class EOFTestCase(unittest.TestCase):
     def test_EOFC(self):
+        expect = "EOL while scanning single-quoted string (<string>, line 1)"
         try:
             eval("""'this is a test\
             """)
         except SyntaxError, msg:
-            self.assertEqual(str(msg),
-                             "EOL while scanning single-quoted string (line 1)")
+            self.assertEqual(str(msg), expect)
         else:
             raise test_support.TestFailed
 
     def test_EOFS(self):
+        expect = "EOF while scanning triple-quoted string (<string>, line 1)"
         try:
             eval("""'''this is a test""")
         except SyntaxError, msg:
-            self.assertEqual(str(msg),
-                             "EOF while scanning triple-quoted string (line 1)")
+            self.assertEqual(str(msg), expect)
         else:
             raise test_support.TestFailed
 
index d226043ce35b49d59d5547264083c17fc8b0a47b..cb7e99209049dd831408ac2db4230c75fb9a89cc 100644 (file)
@@ -774,7 +774,7 @@ These are fine:
 ...         try:
 ...             1//0
 ...         except ZeroDivisionError:
-...             yield 666  # bad because *outer* try has finally
+...             yield 666 
 ...         except:
 ...             pass
 ...     finally:
index 7c6fe4a2e4f53178a839a844fa9b162168c9b480..894ce6a15a706ef3cfed95ce72c2ad3990b67646 100644 (file)
@@ -125,13 +125,12 @@ Verify that syntax error's are raised for genexps used as lvalues
     >>> (y for y in (1,2)) = 10
     Traceback (most recent call last):
        ...
-    SyntaxError: assign to generator expression not possible
+    SyntaxError: assignment to generator expression not possible (<doctest test.test_genexps.__test__.doctests[38]>, line 1)
 
     >>> (y for y in (1,2)) += 10
     Traceback (most recent call last):
        ...
-    SyntaxError: augmented assign to tuple literal, yield, or generator expression not possible
-
+    SyntaxError: augmented assignment to generator expression not possible (<doctest test.test_genexps.__test__.doctests[39]>, line 1)
 
 
 ########### Tests borrowed from or inspired by test_generators.py ############
index 1b4a506844d14ea0e0071e792b01263680b802b0..820fab58cbceab6894392cca3e5b3b952f9df112 100644 (file)
@@ -8,7 +8,7 @@
 # regression test, the filterwarnings() call has been added to
 # regrtest.py.
 
-from test.test_support import TestFailed, verify, check_syntax
+from test.test_support import TestFailed, verify, vereq, check_syntax
 import sys
 
 print '1. Parser'
@@ -157,28 +157,31 @@ def f2(one_argument): pass
 def f3(two, arguments): pass
 def f4(two, (compound, (argument, list))): pass
 def f5((compound, first), two): pass
-verify(f2.func_code.co_varnames == ('one_argument',))
-verify(f3.func_code.co_varnames == ('two', 'arguments'))
+vereq(f2.func_code.co_varnames, ('one_argument',))
+vereq(f3.func_code.co_varnames, ('two', 'arguments'))
 if sys.platform.startswith('java'):
-    verify(f4.func_code.co_varnames ==
+    vereq(f4.func_code.co_varnames,
            ('two', '(compound, (argument, list))', 'compound', 'argument',
                         'list',))
-    verify(f5.func_code.co_varnames ==
+    vereq(f5.func_code.co_varnames,
            ('(compound, first)', 'two', 'compound', 'first'))
 else:
-    verify(f4.func_code.co_varnames == ('two', '.2', 'compound',
-                                        'argument',  'list'))
-    verify(f5.func_code.co_varnames == ('.0', 'two', 'compound', 'first'))
+    vereq(f4.func_code.co_varnames,
+          ('two', '.1', 'compound', 'argument',  'list'))
+    vereq(f5.func_code.co_varnames,
+          ('.0', 'two', 'compound', 'first'))
 def a1(one_arg,): pass
 def a2(two, args,): pass
 def v0(*rest): pass
 def v1(a, *rest): pass
 def v2(a, b, *rest): pass
 def v3(a, (b, c), *rest): return a, b, c, rest
+# ceval unpacks the formal arguments into the first argcount names;
+# thus, the names nested inside tuples must appear after these names.
 if sys.platform.startswith('java'):
     verify(v3.func_code.co_varnames == ('a', '(b, c)', 'rest', 'b', 'c'))
 else:
-    verify(v3.func_code.co_varnames == ('a', '.2', 'rest', 'b', 'c'))
+    vereq(v3.func_code.co_varnames, ('a', '.1', 'rest', 'b', 'c'))
 verify(v3(1, (2, 3), 4) == (1, 2, 3, (4,)))
 def d01(a=1): pass
 d01()
@@ -410,6 +413,10 @@ def g1(): return
 def g2(): return 1
 g1()
 x = g2()
+check_syntax("class foo:return 1")
+
+print 'yield_stmt'
+check_syntax("class foo:yield 1")
 
 print 'raise_stmt' # 'raise' test [',' test]
 try: raise RuntimeError, 'just testing'
index b89f09b393cf3cc23b9dd9420959c64a89ff5128..72f27fad90a3a89c739b97437d0ac29b9df09e61 100644 (file)
@@ -192,3 +192,16 @@ def test_failing_reload():
             del sys.modules[TESTFN]
 
 test_failing_reload()
+
+def test_import_name_binding():
+    # import x.y.z binds x in the current namespace
+    import test as x
+    import test.test_support
+    assert x is test, x.__name__
+    assert hasattr(test.test_support, "__file__")
+
+    # import x.y.z as w binds z as w
+    import test.test_support as y
+    assert y is test.test_support, y.__name__
+
+test_import_name_binding()
index d1ace674dcb49170c09deb7bea5a79d091f6bdbc..771fe9db96898dada6df679cc9a9148225630127 100644 (file)
@@ -411,10 +411,32 @@ class IllegalSyntaxTestCase(unittest.TestCase):
                 (0, ''))
         self.check_bad_tree(tree, "malformed global ast")
 
+
+class CompileTestCase(unittest.TestCase):
+
+    # These tests are very minimal. :-(
+
+    def test_compile_expr(self):
+        st = parser.expr('2 + 3')
+        code = parser.compilest(st)
+        self.assertEquals(eval(code), 5)
+
+    def test_compile_suite(self):
+        st = parser.suite('x = 2; y = x + 3')
+        code = parser.compilest(st)
+        globs = {}
+        exec code in globs
+        self.assertEquals(globs['y'], 5)
+
+    def test_compile_error(self):
+        st = parser.suite('1 = 3 + 4')
+        self.assertRaises(SyntaxError, parser.compilest, st)
+
 def test_main():
     test_support.run_unittest(
         RoundtripLegalSyntaxTestCase,
-        IllegalSyntaxTestCase
+        IllegalSyntaxTestCase,
+        CompileTestCase,
     )
 
 
index 4ded4846f6355403bc0414d86c937970abd7bfce..a139473fe6682d68b639b2438afe8f277d99031b 100644 (file)
@@ -123,7 +123,7 @@ class ReprTests(unittest.TestCase):
 
     def test_lambda(self):
         self.failUnless(repr(lambda x: x).startswith(
-            "<function <lambda"))
+            "<function lambda"))
         # XXX anonymous functions?  see func_repr
 
     def test_builtin_function(self):
index bf9a658478b20d6c3e5f8891200b37321bee428f..34801bd1638c20b55b127fe6898af19400b87ccc 100644 (file)
@@ -1,4 +1,4 @@
-from test.test_support import verify, TestFailed, check_syntax
+from test.test_support import verify, TestFailed, check_syntax, vereq
 
 import warnings
 warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<string>")
@@ -13,8 +13,8 @@ def make_adder(x):
 inc = make_adder(1)
 plus10 = make_adder(10)
 
-verify(inc(1) == 2)
-verify(plus10(-2) == 8)
+vereq(inc(1), 2)
+vereq(plus10(-2), 8)
 
 print "2. extra nesting"
 
@@ -28,8 +28,8 @@ def make_adder2(x):
 inc = make_adder2(1)
 plus10 = make_adder2(10)
 
-verify(inc(1) == 2)
-verify(plus10(-2) == 8)
+vereq(inc(1), 2)
+vereq(plus10(-2), 8)
 
 print "3. simple nesting + rebinding"
 
@@ -42,8 +42,8 @@ def make_adder3(x):
 inc = make_adder3(0)
 plus10 = make_adder3(9)
 
-verify(inc(1) == 2)
-verify(plus10(-2) == 8)
+vereq(inc(1), 2)
+vereq(plus10(-2), 8)
 
 print "4. nesting with global but no free"
 
@@ -58,10 +58,10 @@ def make_adder4(): # XXX add exta level of indirection
 
 global_x = 1
 adder = make_adder4()
-verify(adder(1) == 2)
+vereq(adder(1), 2)
 
 global_x = 10
-verify(adder(-2) == 8)
+vereq(adder(-2), 8)
 
 print "5. nesting through class"
 
@@ -74,8 +74,8 @@ def make_adder5(x):
 inc = make_adder5(1)
 plus10 = make_adder5(10)
 
-verify(inc(1) == 2)
-verify(plus10(-2) == 8)
+vereq(inc(1), 2)
+vereq(plus10(-2), 8)
 
 print "6. nesting plus free ref to global"
 
@@ -89,8 +89,8 @@ def make_adder6(x):
 inc = make_adder6(1)
 plus10 = make_adder6(10)
 
-verify(inc(1) == 11) # there's only one global
-verify(plus10(-2) == 8)
+vereq(inc(1), 11) # there's only one global
+vereq(plus10(-2), 8)
 
 print "7. nearest enclosing scope"
 
@@ -103,7 +103,7 @@ def f(x):
     return g(2)
 
 test_func = f(10)
-verify(test_func(5) == 47)
+vereq(test_func(5), 47)
 
 print "8. mixed freevars and cellvars"
 
@@ -123,7 +123,7 @@ def f(x, y, z):
 
 g = f(1, 2, 3)
 h = g(2, 4, 6)
-verify(h() == 39)
+vereq(h(), 39)
 
 print "9. free variable in method"
 
@@ -141,9 +141,9 @@ def test():
     return Test()
 
 t = test()
-verify(t.test() == "var")
-verify(t.method_and_var() == "method")
-verify(t.actual_global() == "global")
+vereq(t.test(), "var")
+vereq(t.method_and_var(), "method")
+vereq(t.actual_global(), "global")
 
 method_and_var = "var"
 class Test:
@@ -158,9 +158,9 @@ class Test:
         return str(self)
 
 t = Test()
-verify(t.test() == "var")
-verify(t.method_and_var() == "method")
-verify(t.actual_global() == "global")
+vereq(t.test(), "var")
+vereq(t.method_and_var(), "method")
+vereq(t.actual_global(), "global")
 
 print "10. recursion"
 
@@ -175,7 +175,7 @@ def f(x):
     else:
         raise ValueError, "x must be >= 0"
 
-verify(f(6) == 720)
+vereq(f(6), 720)
 
 
 print "11. unoptimized namespaces"
@@ -252,24 +252,24 @@ print "12. lambdas"
 f1 = lambda x: lambda y: x + y
 inc = f1(1)
 plus10 = f1(10)
-verify(inc(1) == 2)
-verify(plus10(5) == 15)
+vereq(inc(1), 2)
+vereq(plus10(5), 15)
 
 f2 = lambda x: (lambda : lambda y: x + y)()
 inc = f2(1)
 plus10 = f2(10)
-verify(inc(1) == 2)
-verify(plus10(5) == 15)
+vereq(inc(1), 2)
+vereq(plus10(5), 15)
 
 f3 = lambda x: lambda y: global_x + y
 global_x = 1
 inc = f3(None)
-verify(inc(2) == 3)
+vereq(inc(2), 3)
 
 f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y)
 g = f8(1, 2, 3)
 h = g(2, 4, 6)
-verify(h() == 18)
+vereq(h(), 18)
 
 print "13. UnboundLocal"
 
@@ -306,21 +306,21 @@ def makeReturner(*lst):
         return lst
     return returner
 
-verify(makeReturner(1,2,3)() == (1,2,3))
+vereq(makeReturner(1,2,3)(), (1,2,3))
 
 def makeReturner2(**kwargs):
     def returner():
         return kwargs
     return returner
 
-verify(makeReturner2(a=11)()['a'] == 11)
+vereq(makeReturner2(a=11)()['a'], 11)
 
 def makeAddPair((a, b)):
     def addPair((c, d)):
         return (a + c, b + d)
     return addPair
 
-verify(makeAddPair((1, 2))((100, 200)) == (101,202))
+vereq(makeAddPair((1, 2))((100, 200)), (101,202))
 
 print "15. scope of global statements"
 # Examples posted by Samuele Pedroni to python-dev on 3/1/2001
@@ -337,8 +337,8 @@ def f():
             return h()
         return i()
     return g()
-verify(f() == 7)
-verify(x == 7)
+vereq(f(), 7)
+vereq(x, 7)
 
 # II
 x = 7
@@ -352,8 +352,8 @@ def f():
             return h()
         return i()
     return g()
-verify(f() == 2)
-verify(x == 7)
+vereq(f(), 2)
+vereq(x, 7)
 
 # III
 x = 7
@@ -368,8 +368,8 @@ def f():
             return h()
         return i()
     return g()
-verify(f() == 2)
-verify(x == 2)
+vereq(f(), 2)
+vereq(x, 2)
 
 # IV
 x = 7
@@ -384,8 +384,25 @@ def f():
             return h()
         return i()
     return g()
-verify(f() == 2)
-verify(x == 2)
+vereq(f(), 2)
+vereq(x, 2)
+
+# XXX what about global statements in class blocks?
+# do they affect methods?
+
+x = 12
+class Global:
+    global x
+    x = 13
+    def set(self, val):
+        x = val
+    def get(self):
+        return x
+
+g = Global()
+vereq(g.get(), 13)
+g.set(15)
+vereq(g.get(), 13)
 
 print "16. check leaks"
 
@@ -407,7 +424,7 @@ def f1():
 for i in range(100):
     f1()
 
-verify(Foo.count == 0)
+vereq(Foo.count, 0)
 
 print "17. class and global"
 
@@ -419,9 +436,9 @@ def test(x):
     return Foo()
 
 x = 0
-verify(test(6)(2) == 8)
+vereq(test(6)(2), 8)
 x = -1
-verify(test(3)(2) == 5)
+vereq(test(3)(2), 5)
 
 print "18. verify that locals() works"
 
@@ -437,7 +454,7 @@ def f(x):
 d = f(2)(4)
 verify(d.has_key('h'))
 del d['h']
-verify(d == {'x': 2, 'y': 7, 'w': 6})
+vereq(d, {'x': 2, 'y': 7, 'w': 6})
 
 print "19. var is bound and free in class"
 
@@ -449,7 +466,7 @@ def f(x):
     return C
 
 inst = f(3)()
-verify(inst.a == inst.m())
+vereq(inst.a, inst.m())
 
 print "20. interaction with trace function"
 
index 66bc88a193a4365c1159d7be8af239db646c67a9..7a69a6bf054c9f5d7f5c74280867f07d59d8e1ba 100644 (file)
@@ -216,10 +216,22 @@ PGOBJS=           \
 
 PGENOBJS=      $(PGENMAIN) $(POBJS) $(PGOBJS)
 
+##########################################################################
+# AST
+AST_H=         $(srcdir)/Include/Python-ast.h
+AST_C=         $(srcdir)/Python/Python-ast.c
+AST_ASDL=      $(srcdir)/Parser/Python.asdl
+
+ASDLGEN_FILES= $(srcdir)/Parser/asdl.py $(srcdir)/Parser/asdl_c.py
+# XXX Note that a build now requires Python exist before the build starts
+ASDLGEN=       $(srcdir)/Parser/asdl_c.py -h $(srcdir)/Include -c $(srcdir)/Python
 
 ##########################################################################
 # Python
 PYTHON_OBJS=   \
+               Python/Python-ast.o \
+               Python/asdl.o \
+               Python/ast.o \
                Python/bltinmodule.o \
                Python/exceptions.o \
                Python/ceval.o \
@@ -265,6 +277,7 @@ OBJECT_OBJS=        \
                Objects/cellobject.o \
                Objects/classobject.o \
                Objects/cobject.o \
+               Objects/codeobject.o \
                Objects/complexobject.o \
                Objects/descrobject.o \
                Objects/enumobject.o \
@@ -457,8 +470,10 @@ Parser/metagrammar.o:      $(srcdir)/Parser/metagrammar.c
 
 Parser/tokenizer_pgen.o:       $(srcdir)/Parser/tokenizer.c
 
+$(AST_H) $(AST_C): $(AST_ASDL) $(ASDLGEN_FILES)
+       $(ASDLGEN) $(AST_ASDL)
 
-Python/compile.o Python/symtable.o: $(GRAMMAR_H)
+Python/compile.o Python/symtable.o: $(GRAMMAR_H) $(AST_H)
 
 Python/getplatform.o: $(srcdir)/Python/getplatform.c
                $(CC) -c $(PY_CFLAGS) -DPLATFORM='"$(MACHDEP)"' -o $@ $(srcdir)/Python/getplatform.c
@@ -474,12 +489,15 @@ Objects/unicodectype.o:   $(srcdir)/Objects/unicodectype.c \
 
 PYTHON_HEADERS= \
                Include/Python.h \
+               Include/Python-ast.h \
+               Include/asdl.h \
                Include/abstract.h \
                Include/boolobject.h \
                Include/bufferobject.h \
                Include/ceval.h \
                Include/classobject.h \
                Include/cobject.h \
+               Include/code.h \
                Include/codecs.h \
                Include/compile.h \
                Include/complexobject.h \
index 58a2c86db1b0ab018418d72980d08ccb9739ec3b..b95902abb7a5df0cc5294fb48fa924de7783b394 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -165,6 +165,7 @@ Eugene Dvurechenski
 Maxim Dzumanenko
 Hans Eckardt
 Grant Edwards
+John Ehresman
 Andrew Eland
 Lance Ellinghaus
 David Ely
index b75b1a32fbd88e69b56c8c5d83ff170d4d781b44..08427284cc93066700ce147c3e383511e8b8c227 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include "Python.h"
+#include "code.h"
 #include "compile.h"
 #include "eval.h"
 #include "frameobject.h"
index 909a404fdc5fa55d2d9fb553f2adadf85722f225..7a52aae0e6e9ab30d6bd7d9f9d07d7bf5a142756 100644 (file)
@@ -1,6 +1,8 @@
 #include "Python.h"
 
+#include "code.h"
 #include "compile.h"
+#include "Python-ast.h"
 #include "symtable.h"
 
 static PyObject *
@@ -64,9 +66,9 @@ init_symtable(void)
        PyModule_AddIntConstant(m, "DEF_IMPORT", DEF_IMPORT);
        PyModule_AddIntConstant(m, "DEF_BOUND", DEF_BOUND);
 
-       PyModule_AddIntConstant(m, "TYPE_FUNCTION", TYPE_FUNCTION);
-       PyModule_AddIntConstant(m, "TYPE_CLASS", TYPE_CLASS);
-       PyModule_AddIntConstant(m, "TYPE_MODULE", TYPE_MODULE);
+       PyModule_AddIntConstant(m, "TYPE_FUNCTION", FunctionBlock);
+       PyModule_AddIntConstant(m, "TYPE_CLASS", ClassBlock);
+       PyModule_AddIntConstant(m, "TYPE_MODULE", ModuleBlock);
 
        PyModule_AddIntConstant(m, "OPT_IMPORT_STAR", OPT_IMPORT_STAR);
        PyModule_AddIntConstant(m, "OPT_EXEC", OPT_EXEC);
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
new file mode 100644 (file)
index 0000000..c5ddfd5
--- /dev/null
@@ -0,0 +1,453 @@
+#include "Python.h"
+#include "code.h"
+#include "structmember.h"
+
+#define NAME_CHARS \
+       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
+
+/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */
+
+static int
+all_name_chars(unsigned char *s)
+{
+       static char ok_name_char[256];
+       static unsigned char *name_chars = (unsigned char *)NAME_CHARS;
+
+       if (ok_name_char[*name_chars] == 0) {
+               unsigned char *p;
+               for (p = name_chars; *p; p++)
+                       ok_name_char[*p] = 1;
+       }
+       while (*s) {
+               if (ok_name_char[*s++] == 0)
+                       return 0;
+       }
+       return 1;
+}
+
+static void
+intern_strings(PyObject *tuple)
+{
+       int i;
+
+       for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
+               PyObject *v = PyTuple_GET_ITEM(tuple, i);
+               if (v == NULL || !PyString_CheckExact(v)) {
+                       Py_FatalError("non-string found in code slot");
+               }
+               PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
+       }
+}
+
+
+PyCodeObject *
+PyCode_New(int argcount, int nlocals, int stacksize, int flags,
+          PyObject *code, PyObject *consts, PyObject *names,
+          PyObject *varnames, PyObject *freevars, PyObject *cellvars,
+          PyObject *filename, PyObject *name, int firstlineno,
+          PyObject *lnotab)
+{
+       PyCodeObject *co;
+       int i;
+       /* Check argument types */
+       if (argcount < 0 || nlocals < 0 ||
+           code == NULL ||
+           consts == NULL || !PyTuple_Check(consts) ||
+           names == NULL || !PyTuple_Check(names) ||
+           varnames == NULL || !PyTuple_Check(varnames) ||
+           freevars == NULL || !PyTuple_Check(freevars) ||
+           cellvars == NULL || !PyTuple_Check(cellvars) ||
+           name == NULL || !PyString_Check(name) ||
+           filename == NULL || !PyString_Check(filename) ||
+           lnotab == NULL || !PyString_Check(lnotab) ||
+           !PyObject_CheckReadBuffer(code)) {
+               PyErr_BadInternalCall();
+               return NULL;
+       }
+       intern_strings(names);
+       intern_strings(varnames);
+       intern_strings(freevars);
+       intern_strings(cellvars);
+       /* Intern selected string constants */
+       for (i = PyTuple_Size(consts); --i >= 0; ) {
+               PyObject *v = PyTuple_GetItem(consts, i);
+               if (!PyString_Check(v))
+                       continue;
+               if (!all_name_chars((unsigned char *)PyString_AS_STRING(v)))
+                       continue;
+               PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i));
+       }
+       co = PyObject_NEW(PyCodeObject, &PyCode_Type);
+       if (co != NULL) {
+               co->co_argcount = argcount;
+               co->co_nlocals = nlocals;
+               co->co_stacksize = stacksize;
+               co->co_flags = flags;
+               Py_INCREF(code);
+               co->co_code = code;
+               Py_INCREF(consts);
+               co->co_consts = consts;
+               Py_INCREF(names);
+               co->co_names = names;
+               Py_INCREF(varnames);
+               co->co_varnames = varnames;
+               Py_INCREF(freevars);
+               co->co_freevars = freevars;
+               Py_INCREF(cellvars);
+               co->co_cellvars = cellvars;
+               Py_INCREF(filename);
+               co->co_filename = filename;
+               Py_INCREF(name);
+               co->co_name = name;
+               co->co_firstlineno = firstlineno;
+               Py_INCREF(lnotab);
+               co->co_lnotab = lnotab;
+       }
+       return co;
+}
+
+
+#define OFF(x) offsetof(PyCodeObject, x)
+
+static PyMemberDef 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},
+       {"co_names",    T_OBJECT,       OFF(co_names),          READONLY},
+       {"co_varnames", T_OBJECT,       OFF(co_varnames),       READONLY},
+       {"co_freevars", T_OBJECT,       OFF(co_freevars),       READONLY},
+       {"co_cellvars", T_OBJECT,       OFF(co_cellvars),       READONLY},
+       {"co_filename", T_OBJECT,       OFF(co_filename),       READONLY},
+       {"co_name",     T_OBJECT,       OFF(co_name),           READONLY},
+       {"co_firstlineno", T_INT,       OFF(co_firstlineno),    READONLY},
+       {"co_lnotab",   T_OBJECT,       OFF(co_lnotab),         READONLY},
+       {NULL}  /* Sentinel */
+};
+
+/* Helper for code_new: return a shallow copy of a tuple that is
+   guaranteed to contain exact strings, by converting string subclasses
+   to exact strings and complaining if a non-string is found. */
+static PyObject*
+validate_and_copy_tuple(PyObject *tup)
+{
+       PyObject *newtuple;
+       PyObject *item;
+       int i, len;
+
+       len = PyTuple_GET_SIZE(tup);
+       newtuple = PyTuple_New(len);
+       if (newtuple == NULL)
+               return NULL;
+
+       for (i = 0; i < len; i++) {
+               item = PyTuple_GET_ITEM(tup, i);
+               if (PyString_CheckExact(item)) {
+                       Py_INCREF(item);
+               }
+               else if (!PyString_Check(item)) {
+                       PyErr_Format(
+                               PyExc_TypeError,
+                               "name tuples must contain only "
+                               "strings, not '%.500s'",
+                               item->ob_type->tp_name);
+                       Py_DECREF(newtuple);
+                       return NULL;
+               }
+               else {
+                       item = PyString_FromStringAndSize(
+                               PyString_AS_STRING(item),
+                               PyString_GET_SIZE(item));
+                       if (item == NULL) {
+                               Py_DECREF(newtuple);
+                               return NULL;
+                       }
+               }
+               PyTuple_SET_ITEM(newtuple, i, item);
+       }
+
+       return newtuple;
+}
+
+PyDoc_STRVAR(code_doc,
+"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\
+      varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\
+\n\
+Create a code object.  Not for the faint of heart.");
+
+static PyObject *
+code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+       int argcount;
+       int nlocals;
+       int stacksize;
+       int flags;
+       PyObject *co = NULL;
+       PyObject *code;
+       PyObject *consts;
+       PyObject *names, *ournames = NULL;
+       PyObject *varnames, *ourvarnames = NULL;
+       PyObject *freevars = NULL, *ourfreevars = NULL;
+       PyObject *cellvars = NULL, *ourcellvars = NULL;
+       PyObject *filename;
+       PyObject *name;
+       int firstlineno;
+       PyObject *lnotab;
+
+       if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code",
+                             &argcount, &nlocals, &stacksize, &flags,
+                             &code,
+                             &PyTuple_Type, &consts,
+                             &PyTuple_Type, &names,
+                             &PyTuple_Type, &varnames,
+                             &filename, &name,
+                             &firstlineno, &lnotab,
+                             &PyTuple_Type, &freevars,
+                             &PyTuple_Type, &cellvars))
+               return NULL;
+
+       if (argcount < 0) {
+               PyErr_SetString(
+                       PyExc_ValueError,
+                       "code: argcount must not be negative");
+               goto cleanup;
+       }
+
+       if (nlocals < 0) {
+               PyErr_SetString(
+                       PyExc_ValueError,
+                       "code: nlocals must not be negative");
+               goto cleanup;
+       }
+
+       ournames = validate_and_copy_tuple(names);
+       if (ournames == NULL)
+               goto cleanup;
+       ourvarnames = validate_and_copy_tuple(varnames);
+       if (ourvarnames == NULL)
+               goto cleanup;
+       if (freevars)
+               ourfreevars = validate_and_copy_tuple(freevars);
+       else
+               ourfreevars = PyTuple_New(0);
+       if (ourfreevars == NULL)
+               goto cleanup;
+       if (cellvars)
+               ourcellvars = validate_and_copy_tuple(cellvars);
+       else
+               ourcellvars = PyTuple_New(0);
+       if (ourcellvars == NULL)
+               goto cleanup;
+
+       co = (PyObject *)PyCode_New(argcount, nlocals, stacksize, flags,
+                                   code, consts, ournames, ourvarnames,
+                                   ourfreevars, ourcellvars, filename,
+                                   name, firstlineno, lnotab);
+  cleanup:
+       Py_XDECREF(ournames);
+       Py_XDECREF(ourvarnames);
+       Py_XDECREF(ourfreevars);
+       Py_XDECREF(ourcellvars);
+       return co;
+}
+
+static void
+code_dealloc(PyCodeObject *co)
+{
+       Py_XDECREF(co->co_code);
+       Py_XDECREF(co->co_consts);
+       Py_XDECREF(co->co_names);
+       Py_XDECREF(co->co_varnames);
+       Py_XDECREF(co->co_freevars);
+       Py_XDECREF(co->co_cellvars);
+       Py_XDECREF(co->co_filename);
+       Py_XDECREF(co->co_name);
+       Py_XDECREF(co->co_lnotab);
+       PyObject_DEL(co);
+}
+
+static PyObject *
+code_repr(PyCodeObject *co)
+{
+       char buf[500];
+       int lineno = -1;
+       char *filename = "???";
+       char *name = "???";
+
+       if (co->co_firstlineno != 0)
+               lineno = co->co_firstlineno;
+       if (co->co_filename && PyString_Check(co->co_filename))
+               filename = PyString_AS_STRING(co->co_filename);
+       if (co->co_name && PyString_Check(co->co_name))
+               name = PyString_AS_STRING(co->co_name);
+       PyOS_snprintf(buf, sizeof(buf),
+                     "<code object %.100s at %p, file \"%.300s\", line %d>",
+                     name, co, filename, lineno);
+       return PyString_FromString(buf);
+}
+
+static int
+code_compare(PyCodeObject *co, PyCodeObject *cp)
+{
+       int cmp;
+       cmp = PyObject_Compare(co->co_name, cp->co_name);
+       if (cmp) return cmp;
+       cmp = co->co_argcount - cp->co_argcount;
+       if (cmp) goto normalize;
+       cmp = co->co_nlocals - cp->co_nlocals;
+       if (cmp) goto normalize;
+       cmp = co->co_flags - cp->co_flags;
+       if (cmp) goto normalize;
+       cmp = co->co_firstlineno - cp->co_firstlineno;
+       if (cmp) goto normalize;
+       cmp = PyObject_Compare(co->co_code, cp->co_code);
+       if (cmp) return cmp;
+       cmp = PyObject_Compare(co->co_consts, cp->co_consts);
+       if (cmp) return cmp;
+       cmp = PyObject_Compare(co->co_names, cp->co_names);
+       if (cmp) return cmp;
+       cmp = PyObject_Compare(co->co_varnames, cp->co_varnames);
+       if (cmp) return cmp;
+       cmp = PyObject_Compare(co->co_freevars, cp->co_freevars);
+       if (cmp) return cmp;
+       cmp = PyObject_Compare(co->co_cellvars, cp->co_cellvars);
+       return cmp;
+
+ normalize:
+       if (cmp > 0)
+               return 1;
+       else if (cmp < 0)
+               return -1;
+       else
+               return 0;
+}
+
+static long
+code_hash(PyCodeObject *co)
+{
+       long h, h0, h1, h2, h3, h4, h5, h6;
+       h0 = PyObject_Hash(co->co_name);
+       if (h0 == -1) return -1;
+       h1 = PyObject_Hash(co->co_code);
+       if (h1 == -1) return -1;
+       h2 = PyObject_Hash(co->co_consts);
+       if (h2 == -1) return -1;
+       h3 = PyObject_Hash(co->co_names);
+       if (h3 == -1) return -1;
+       h4 = PyObject_Hash(co->co_varnames);
+       if (h4 == -1) return -1;
+       h5 = PyObject_Hash(co->co_freevars);
+       if (h5 == -1) return -1;
+       h6 = PyObject_Hash(co->co_cellvars);
+       if (h6 == -1) return -1;
+       h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
+               co->co_argcount ^ co->co_nlocals ^ co->co_flags;
+       if (h == -1) h = -2;
+       return h;
+}
+
+/* XXX code objects need to participate in GC? */
+
+PyTypeObject PyCode_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "code",
+       sizeof(PyCodeObject),
+       0,
+       (destructor)code_dealloc,       /* tp_dealloc */
+       0,                              /* tp_print */
+       0,                              /* tp_getattr */
+       0,                              /* tp_setattr */
+       (cmpfunc)code_compare,          /* tp_compare */
+       (reprfunc)code_repr,            /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+       (hashfunc)code_hash,            /* tp_hash */
+       0,                              /* tp_call */
+       0,                              /* tp_str */
+       PyObject_GenericGetAttr,        /* tp_getattro */
+       0,                              /* tp_setattro */
+       0,                              /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,             /* tp_flags */
+       code_doc,                       /* tp_doc */
+       0,                              /* tp_traverse */
+       0,                              /* tp_clear */
+       0,                              /* tp_richcompare */
+       0,                              /* tp_weaklistoffset */
+       0,                              /* tp_iter */
+       0,                              /* tp_iternext */
+       0,                              /* tp_methods */
+       code_memberlist,                /* tp_members */
+       0,                              /* tp_getset */
+       0,                              /* tp_base */
+       0,                              /* tp_dict */
+       0,                              /* tp_descr_get */
+       0,                              /* tp_descr_set */
+       0,                              /* tp_dictoffset */
+       0,                              /* tp_init */
+       0,                              /* tp_alloc */
+       code_new,                       /* tp_new */
+};
+
+/* All about c_lnotab.
+
+c_lnotab is an array of unsigned bytes disguised as a Python string.  In -O
+mode, SET_LINENO opcodes aren't generated, and bytecode offsets are mapped
+to source code line #s (when needed for tracebacks) via c_lnotab instead.
+The array is conceptually a list of
+    (bytecode offset increment, line number increment)
+pairs.  The details are important and delicate, best illustrated by example:
+
+    byte code offset    source code line number
+        0                  1
+        6                  2
+       50                  7
+      350                 307
+      361                 308
+
+The first trick is that these numbers aren't stored, only the increments
+from one row to the next (this doesn't really work, but it's a start):
+
+    0, 1,  6, 1,  44, 5,  300, 300,  11, 1
+
+The second trick is that an unsigned byte can't hold negative values, or
+values larger than 255, so (a) there's a deep assumption that byte code
+offsets and their corresponding line #s both increase monotonically, and (b)
+if at least one column jumps by more than 255 from one row to the next, more
+than one pair is written to the table. In case #b, there's no way to know
+from looking at the table later how many were written.  That's the delicate
+part.  A user of c_lnotab desiring to find the source line number
+corresponding to a bytecode address A should do something like this
+
+    lineno = addr = 0
+    for addr_incr, line_incr in c_lnotab:
+        addr += addr_incr
+        if addr > A:
+            return lineno
+        lineno += line_incr
+
+In order for this to work, when the addr field increments by more than 255,
+the line # increment in each pair generated must be 0 until the remaining addr
+increment is < 256.  So, in the example above, com_set_lineno should not (as
+was actually done until 2.2) expand 300, 300 to 255, 255,  45, 45, but to
+255, 0,  45, 255,  0, 45.
+*/
+
+int
+PyCode_Addr2Line(PyCodeObject *co, int addrq)
+{
+       int size = PyString_Size(co->co_lnotab) / 2;
+       unsigned char *p = (unsigned char*)PyString_AsString(co->co_lnotab);
+       int line = co->co_firstlineno;
+       int addr = 0;
+       while (--size >= 0) {
+               addr += *p++;
+               if (addr > addrq)
+                       break;
+               line += *p++;
+       }
+       return line;
+}
index bc8cae9fe618ed62a4fb8243aa12d81e8237dd29..8ebf5004ab902160d3fcdfdd1f706527fab7c07b 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "Python.h"
 
+#include "code.h"
 #include "compile.h"
 #include "frameobject.h"
 #include "opcode.h"
index c0c91c95d17d8c625886f23cd2fc66eea168aad6..85cef6f917065c0d8f7973a85837214b89a9c45a 100644 (file)
@@ -2,7 +2,7 @@
 /* Function object implementation */
 
 #include "Python.h"
-#include "compile.h"
+#include "code.h"
 #include "eval.h"
 #include "structmember.h"
 
@@ -144,7 +144,9 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure)
                Py_XINCREF(closure);
        }
        else {
-               PyErr_SetString(PyExc_SystemError, "non-tuple closure");
+               PyErr_Format(PyExc_SystemError, 
+                            "expected tuple for closure, got '%.100s'",
+                            closure->ob_type->tp_name);
                return -1;
        }
        Py_XDECREF(((PyFunctionObject *) op) -> func_closure);
index 88c4a15d6753c19af595767f7c21257e901069ec..591c62b4f43184e3cba91061f4902cbd4c7184ff 100644 (file)
@@ -1737,20 +1737,14 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
                        goto bad_slots;
                for (i = j = 0; i < nslots; i++) {
                        char *s;
-                       char buffer[256];
                        tmp = PyTuple_GET_ITEM(slots, i);
                        s = PyString_AS_STRING(tmp);
                        if ((add_dict && strcmp(s, "__dict__") == 0) ||
                            (add_weak && strcmp(s, "__weakref__") == 0))
                                continue;
-                       if (_Py_Mangle(PyString_AS_STRING(name),
-                                      PyString_AS_STRING(tmp),
-                                      buffer, sizeof(buffer)))
-                       {
-                               tmp = PyString_FromString(buffer);
-                       } else {
-                               Py_INCREF(tmp);
-                       }
+                       tmp =_Py_Mangle(name, tmp);
+                        if (!tmp)
+                            goto bad_slots;
                        PyTuple_SET_ITEM(newslots, j, tmp);
                        j++;
                }
index 945fd5cb24f78ec7a731293ce5e0173e9089fff7..ff9e48bec4bcc9e3ce456041f16904a266c26148 100644 (file)
@@ -3,6 +3,7 @@
        ProjectType="Visual C++"
        Version="7.10"
        Name="pythoncore"
+       ProjectGUID="{7AFA1F0B-A8A1-455A-A832-BF263404BBEF}"
        SccProjectName="pythoncore"
        SccLocalPath="..">
        <Platforms>
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
+               <File
+                       RelativePath="..\Python\asdl.c">
+               </File>
+               <File
+                       RelativePath="..\Python\ast.c">
+               </File>
                <File
                        RelativePath="..\Modules\audioop.c">
                        <FileConfiguration
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
+               <File
+                       RelativePath="..\Objects\codeobject.c">
+               </File>
                <File
                        RelativePath="..\Modules\collectionsmodule.c">
                </File>
                <File
-                       RelativePath="..\Python\compile.c">
+                       RelativePath="..\Objects\complexobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\complexobject.c">
+                       RelativePath="..\PC\config.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\PC\config.c">
+                       RelativePath="..\Modules\cPickle.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\cPickle.c">
+                       RelativePath="..\Modules\cStringIO.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\cStringIO.c">
+                       RelativePath="..\Modules\datetimemodule.c">
+               </File>
+               <File
+                       RelativePath="..\Objects\descrobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\datetimemodule.c">
-               </File>
-               <File
-                       RelativePath="..\Objects\descrobject.c">
+                       RelativePath="..\Objects\dictobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\dictobject.c">
+                       RelativePath="..\PC\dl_nt.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\PC\dl_nt.c">
+                       RelativePath="..\Python\dynload_win.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\dynload_win.c">
+                       RelativePath="..\Objects\enumobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\enumobject.c">
+                       RelativePath="..\Modules\errnomodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\errnomodule.c">
+                       RelativePath="..\Python\errors.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\errors.c">
+                       RelativePath="..\Python\exceptions.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\exceptions.c">
+                       RelativePath="..\Objects\fileobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\fileobject.c">
+                       RelativePath="..\Parser\firstsets.c">
+               </File>
+               <File
+                       RelativePath="..\Objects\floatobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\floatobject.c">
+                       RelativePath="..\Objects\frameobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\frameobject.c">
+                       RelativePath="..\Python\frozen.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\frozen.c">
+                       RelativePath="..\Objects\funcobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\funcobject.c">
+                       RelativePath="..\Modules\functionalmodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
+               <File
+                       RelativePath="..\Parser\grammar.c">
+               </File>
                <File
                        RelativePath="..\Parser\grammar1.c">
                        <FileConfiguration
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
+               <File
+                       RelativePath="..\Python\compile.c">
+               </File>
                <File
                        RelativePath="..\Parser\node.c">
                        <FileConfiguration
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
-               <File
-                       RelativePath="..\Modules\parsermodule.c">
-               </File>
                <File
                        RelativePath="..\Parser\parsetok.c">
                        <FileConfiguration
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
+               <File
+                       RelativePath="..\Parser\pgen.c">
+               </File>
                <File
                        RelativePath="..\Modules\posixmodule.c">
                        <FileConfiguration
                <File
                        RelativePath="..\Python\pystrtod.c">
                </File>
+               <File
+                       RelativePath="..\Python\Python-ast.c">
+               </File>
                <File
                        RelativePath="..\PC\python_nt.rc">
                        <FileConfiguration
                        </FileConfiguration>
                </File>
                <File
+<<<<<<< pythoncore.vcproj
                         RelativePath="..\Modules\sha256module.c">
                        <FileConfiguration
                                Name="Release|Win32">
                </File>
                <File
                        RelativePath="..\Modules\signalmodule.c">
+=======
+                        RelativePath="..\Modules\sha256module.c">
+>>>>>>> 1.26.2.3
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\sliceobject.c">
+                        RelativePath="..\Modules\sha512module.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\stringobject.c">
+                       RelativePath="..\Modules\signalmodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\stropmodule.c">
+                       RelativePath="..\Objects\sliceobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\structmember.c">
+                       RelativePath="..\Objects\stringobject.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\structmodule.c">
+                       RelativePath="..\Modules\stropmodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Objects\structseq.c">
+                       RelativePath="..\Python\structmember.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\symtable.c">
+                       RelativePath="..\Modules\structmodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\symtablemodule.c">
+                       RelativePath="..\Objects\structseq.c">
+                       <FileConfiguration
+                               Name="Release|Win32">
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                                       Optimization="2"
+                                       AdditionalIncludeDirectories=""
+                                       PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
+                       </FileConfiguration>
+                       <FileConfiguration
+                               Name="Debug|Win32">
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                                       Optimization="0"
+                                       AdditionalIncludeDirectories=""
+                                       PreprocessorDefinitions="_DEBUG;USE_DL_EXPORT;WIN32;_WINDOWS;$(NoInherit)"/>
+                       </FileConfiguration>
+                       <FileConfiguration
+                               Name="ReleaseItanium|Win32">
+                               <Tool
+                                       Name="VCCLCompilerTool"
+                                       Optimization="2"
+                                       AdditionalIncludeDirectories=""
+                                       PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
+                       </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\sysmodule.c">
+                       RelativePath="..\Python\symtable.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Python\thread.c">
+                       RelativePath="..\Modules\symtablemodule.c">
+               </File>
+               <File
+                       RelativePath="..\Python\sysmodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\threadmodule.c">
+                       RelativePath="..\Python\thread.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Modules\timemodule.c">
+                       RelativePath="..\Modules\threadmodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                        </FileConfiguration>
                </File>
                <File
-                       RelativePath="..\Parser\tokenizer.c">
+                       RelativePath="..\Modules\timemodule.c">
                        <FileConfiguration
                                Name="Release|Win32">
                                <Tool
                                        PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;USE_DL_EXPORT;$(NoInherit)"/>
                        </FileConfiguration>
                </File>
+               <File
+                       RelativePath="..\Parser\tokenizer_pgen.c">
+               </File>
                <File
                        RelativePath="..\Python\traceback.c">
                        <FileConfiguration
index a7dd8e610eed90ded7d01d00fa4df0c46ba9b799..f300915f667eaa8e1d7fb2aa6ba0aff106e8474d 100644 (file)
@@ -1,3 +1,6 @@
 Makefile
 pgen
 add2lib
+asdl.pyc
+asdl_c.pyc
+spark.pyc
diff --git a/Parser/Python.asdl b/Parser/Python.asdl
new file mode 100644 (file)
index 0000000..0883d91
--- /dev/null
@@ -0,0 +1,107 @@
+-- ASDL's three builtin types are identifier, int, string
+
+module Python
+{
+       mod = Module(stmt* body)
+           | Interactive(stmt* body)
+           | Expression(expr body)
+
+           -- not really an actual node but useful in Jython's typesystem.
+           | Suite(stmt* body)
+
+       stmt = FunctionDef(identifier name, arguments args, 
+                           stmt* body, expr* decorators)
+             | ClassDef(identifier name, expr* bases, stmt* body)
+             | Return(expr? value)
+
+             | Delete(expr* targets)
+             | Assign(expr* targets, expr value)
+             | AugAssign(expr target, operator op, expr value)
+
+             -- not sure if bool is allowed, can always use int
+             | Print(expr? dest, expr* values, bool nl)
+
+             -- use 'orelse' because else is a keyword in target languages
+             | For(expr target, expr iter, stmt* body, stmt* orelse)
+             | While(expr test, stmt* body, stmt* orelse)
+             | If(expr test, stmt* body, stmt* orelse)
+
+             -- 'type' is a bad name
+             | Raise(expr? type, expr? inst, expr? tback)
+             | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
+             | TryFinally(stmt* body, stmt* finalbody)
+             | Assert(expr test, expr? msg)
+
+             | Import(alias* names)
+             | ImportFrom(identifier module, alias* names)
+
+             -- Doesn't capture requirement that locals must be
+             -- defined if globals is
+             -- still supports use as a function!
+             | Exec(expr body, expr? globals, expr? locals)
+
+             | Global(identifier* names)
+             | Expr(expr value)
+             | Pass | Break | Continue
+
+             -- XXX Jython will be different
+             attributes (int lineno)
+
+             -- BoolOp() can use left & right?
+       expr = BoolOp(boolop op, expr* values)
+            | BinOp(expr left, operator op, expr right)
+            | UnaryOp(unaryop op, expr operand)
+            | Lambda(arguments args, expr body)
+            | Dict(expr* keys, expr* values)
+            | ListComp(expr elt, comprehension* generators)
+            | GeneratorExp(expr elt, comprehension* generators)
+            | Yield(expr? value)
+            -- need sequences for compare to distinguish between
+            -- x < 4 < 3 and (x < 4) < 3
+            | Compare(expr left, cmpop* ops, expr* comparators)
+            | Call(expr func, expr* args, keyword* keywords,
+                        expr? starargs, expr? kwargs)
+            | Repr(expr value)
+            | Num(object n) -- a number as a PyObject.
+            | Str(string s) -- need to specify raw, unicode, etc?
+            -- other literals? bools?
+
+            -- the following expression can appear in assignment context
+            | Attribute(expr value, identifier attr, expr_context ctx)
+            | Subscript(expr value, slice slice, expr_context ctx)
+            | Name(identifier id, expr_context ctx)
+            | List(expr* elts, expr_context ctx) 
+            | Tuple(expr *elts, expr_context ctx)
+
+             attributes (int lineno)
+
+       expr_context = Load | Store | Del | AugLoad | AugStore | Param
+
+       slice = Ellipsis | Slice(expr? lower, expr? upper, expr? step) 
+             | ExtSlice(slice* dims) 
+             | Index(expr value) 
+
+       boolop = And | Or 
+
+       operator = Add | Sub | Mult | Div | Mod | Pow | LShift 
+                 | RShift | BitOr | BitXor | BitAnd | FloorDiv
+
+       unaryop = Invert | Not | UAdd | USub
+
+       cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn
+
+       comprehension = (expr target, expr iter, expr* ifs)
+
+       -- not sure what to call the first argument for raise and except
+
+       excepthandler = (expr? type, expr? name, stmt* body)
+
+       arguments = (expr* args, identifier? vararg, 
+                    identifier? kwarg, expr* defaults)
+
+        -- keyword arguments supplied to call
+        keyword = (identifier arg, expr value)
+
+        -- import name with optional 'as' alias.
+        alias = (identifier name, identifier? asname)
+}
diff --git a/Parser/asdl.py b/Parser/asdl.py
new file mode 100644 (file)
index 0000000..0db4e3b
--- /dev/null
@@ -0,0 +1,393 @@
+"""An implementation of the Zephyr Abstract Syntax Definition Language.
+
+See http://asdl.sourceforge.net/ and
+http://www.cs.princeton.edu/~danwang/Papers/dsl97/dsl97-abstract.html.
+
+Only supports top level module decl, not view.  I'm guessing that view
+is intended to support the browser and I'm not interested in the
+browser.
+"""
+
+#__metaclass__ = type
+
+import os
+import traceback
+
+import spark
+
+class Token:
+    # spark seems to dispatch in the parser based on a token's
+    # type attribute
+    def __init__(self, type, lineno):
+        self.type = type
+        self.lineno = lineno
+
+    def __str__(self):
+        return self.type
+
+    def __repr__(self):
+        return str(self)
+
+class Id(Token):
+    def __init__(self, value, lineno):
+        self.type = 'Id'
+        self.value = value
+        self.lineno = lineno
+
+    def __str__(self):
+        return self.value
+
+class ASDLSyntaxError:
+
+    def __init__(self, lineno, token=None, msg=None):
+        self.lineno = lineno
+        self.token = token
+        self.msg = msg
+
+    def __str__(self):
+        if self.msg is None:
+            return "Error at '%s', line %d" % (self.token, self.lineno)
+        else:
+            return "%s, line %d" % (self.msg, self.lineno)
+
+class ASDLScanner(spark.GenericScanner, object):
+
+    def tokenize(self, input):
+        self.rv = []
+        self.lineno = 1
+        super(ASDLScanner, self).tokenize(input)
+        return self.rv
+
+    def t_id(self, s):
+        r"[\w\.]+"
+        # XXX doesn't distinguish upper vs. lower, which is
+        # significant for ASDL.
+        self.rv.append(Id(s, self.lineno))
+
+    def t_xxx(self, s): # not sure what this production means
+        r"<="
+        self.rv.append(Token(s, self.lineno))
+
+    def t_punctuation(self, s):
+        r"[\{\}\*\=\|\(\)\,\?\:]"
+        self.rv.append(Token(s, self.lineno))
+
+    def t_comment(self, s):
+        r"\-\-[^\n]*"
+        pass
+
+    def t_newline(self, s):
+        r"\n"
+        self.lineno += 1
+
+    def t_whitespace(self, s):
+        r"[ \t]+"
+        pass
+
+    def t_default(self, s):
+        r" . +"
+        raise ValueError, "unmatched input: %s" % `s`
+
+class ASDLParser(spark.GenericParser, object):
+    def __init__(self):
+        super(ASDLParser, self).__init__("module")
+
+    def typestring(self, tok):
+        return tok.type
+
+    def error(self, tok):
+        raise ASDLSyntaxError(tok.lineno, tok)
+
+    def p_module_0(self, (module, name, _0, _1)):
+        " module ::= Id Id { } "
+        if module.value != "module":
+            raise ASDLSyntaxError(module.lineno,
+                                  msg="expected 'module', found %s" % module)
+        return Module(name, None)
+
+    def p_module(self, (module, name, _0, definitions, _1)):
+        " module ::= Id Id { definitions } "
+        if module.value != "module":
+            raise ASDLSyntaxError(module.lineno,
+                                  msg="expected 'module', found %s" % module)
+        return Module(name, definitions)
+
+    def p_definition_0(self, (definition,)):
+        " definitions ::= definition "
+        return definition
+
+    def p_definition_1(self, (definitions, definition)):
+        " definitions ::= definition definitions "
+        return definitions + definition
+
+    def p_definition(self, (id, _, type)):
+        " definition ::= Id = type "
+        return [Type(id, type)]
+
+    def p_type_0(self, (product,)):
+        " type ::= product "
+        return product
+
+    def p_type_1(self, (sum,)):
+        " type ::= sum "
+        return Sum(sum)
+
+    def p_type_2(self, (sum, id, _0, attributes, _1)):
+        " type ::= sum Id ( fields ) "
+        if id.value != "attributes":
+            raise ASDLSyntaxError(id.lineno,
+                                  msg="expected attributes, found %s" % id)
+        return Sum(sum, attributes)
+
+    def p_product(self, (_0, fields, _1)):
+        " product ::= ( fields ) "
+        # XXX can't I just construct things in the right order?
+        fields.reverse() 
+        return Product(fields)
+
+    def p_sum_0(self, (constructor,)):
+        " sum ::= constructor """
+        return [constructor]
+
+    def p_sum_1(self, (constructor, _, sum)):
+        " sum ::= constructor | sum "
+        return [constructor] + sum
+
+    def p_sum_2(self, (constructor, _, sum)):
+        " sum ::= constructor | sum "
+        return [constructor] + sum
+
+    def p_constructor_0(self, (id,)):
+        " constructor ::= Id "
+        return Constructor(id)
+
+    def p_constructor_1(self, (id, _0, fields, _1)):
+        " constructor ::= Id ( fields ) "
+        # XXX can't I just construct things in the right order?
+        fields.reverse() 
+        return Constructor(id, fields)
+
+    def p_fields_0(self, (field,)):
+        " fields ::= field "
+        return [field]
+
+    def p_fields_1(self, (field, _, fields)):
+        " fields ::= field , fields "
+        return fields + [field]
+
+    def p_field_0(self, (type,)):
+        " field ::= Id "
+        return Field(type)
+
+    def p_field_1(self, (type, name)):
+        " field ::= Id Id "
+        return Field(type, name)
+
+    def p_field_2(self, (type, _, name)):
+        " field ::= Id * Id "
+        return Field(type, name, seq=1)
+
+    def p_field_3(self, (type, _, name)):
+        " field ::= Id ? Id "
+        return Field(type, name, opt=1)
+
+    def p_field_4(self, (type, _)):
+        " field ::= Id * "
+        return Field(type, seq=1)
+
+    def p_field_5(self, (type, _)):
+        " field ::= Id ? "
+        return Field(type, opt=1)
+
+builtin_types = ("identifier", "string", "int", "bool", "object")
+
+# below is a collection of classes to capture the AST of an AST :-)
+# not sure if any of the methods are useful yet, but I'm adding them
+# piecemeal as they seem helpful
+
+class AST:
+    pass # a marker class
+
+class Module(AST):
+    def __init__(self, name, dfns):
+        self.name = name
+        self.dfns = dfns
+        self.types = {} # maps type name to value (from dfns)
+        for type in dfns:
+            self.types[type.name.value] = type.value
+
+    def __repr__(self):
+        return "Module(%s, %s)" % (self.name, self.dfns)
+
+class Type(AST):
+    def __init__(self, name, value):
+        self.name = name
+        self.value = value
+
+    def __repr__(self):
+        return "Type(%s, %s)" % (self.name, self.value)
+
+class Constructor(AST):
+    def __init__(self, name, fields=None):
+        self.name = name
+        self.fields = fields or []
+
+    def __repr__(self):
+        return "Constructor(%s, %s)" % (self.name, self.fields)
+
+class Field(AST):
+    def __init__(self, type, name=None, seq=0, opt=0):
+        self.type = type
+        self.name = name
+        self.seq = seq
+        self.opt = opt
+
+    def __repr__(self):
+        if self.seq:
+            extra = ", seq=1"
+        elif self.opt:
+            extra = ", opt=1"
+        else:
+            extra = ""
+        if self.name is None:
+            return "Field(%s%s)" % (self.type, extra)
+        else:
+            return "Field(%s, %s%s)" % (self.type, self.name, extra)
+
+class Sum(AST):
+    def __init__(self, types, attributes=None):
+        self.types = types
+        self.attributes = attributes or []
+
+    def __repr__(self):
+        if self.attributes is None:
+            return "Sum(%s)" % self.types
+        else:
+            return "Sum(%s, %s)" % (self.types, self.attributes)
+
+class Product(AST):
+    def __init__(self, fields):
+        self.fields = fields
+
+    def __repr__(self):
+        return "Product(%s)" % self.fields
+
+class VisitorBase(object):
+
+    def __init__(self, skip=0):
+        self.cache = {}
+        self.skip = skip
+
+    def visit(self, object, *args):
+        meth = self._dispatch(object)
+        if meth is None:
+            return
+        try:
+            meth(object, *args)
+        except Exception, err:
+            print "Error visiting", repr(object)
+            print err
+            traceback.print_exc()
+            # XXX hack
+            if hasattr(self, 'file'):
+                self.file.flush()
+            os._exit(1)
+
+    def _dispatch(self, object):
+        assert isinstance(object, AST), repr(object)
+        klass = object.__class__
+        meth = self.cache.get(klass)
+        if meth is None:
+            methname = "visit" + klass.__name__
+            if self.skip:
+                meth = getattr(self, methname, None)
+            else:
+                meth = getattr(self, methname)
+            self.cache[klass] = meth
+        return meth
+
+class Check(VisitorBase):
+
+    def __init__(self):
+        super(Check, self).__init__(skip=1)
+        self.cons = {}
+        self.errors = 0
+        self.types = {}
+
+    def visitModule(self, mod):
+        for dfn in mod.dfns:
+            self.visit(dfn)
+
+    def visitType(self, type):
+        self.visit(type.value, str(type.name))
+
+    def visitSum(self, sum, name):
+        for t in sum.types:
+            self.visit(t, name)
+
+    def visitConstructor(self, cons, name):
+        key = str(cons.name)
+        conflict = self.cons.get(key)
+        if conflict is None:
+            self.cons[key] = name
+        else:
+            print "Redefinition of constructor %s" % key
+            print "Defined in %s and %s" % (conflict, name)
+            self.errors += 1
+        for f in cons.fields:
+            self.visit(f, key)
+
+    def visitField(self, field, name):
+        key = str(field.type)
+        l = self.types.setdefault(key, [])
+        l.append(name)
+
+    def visitProduct(self, prod, name):
+        for f in prod.fields:
+            self.visit(f, name)
+
+def check(mod):
+    v = Check()
+    v.visit(mod)
+
+    for t in v.types:
+        if not mod.types.has_key(t) and not t in builtin_types:
+            v.errors += 1
+            uses = ", ".join(v.types[t])
+            print "Undefined type %s, used in %s" % (t, uses)
+    
+    return not v.errors
+
+def parse(file):
+    scanner = ASDLScanner()
+    parser = ASDLParser()
+
+    buf = open(file).read()
+    tokens = scanner.tokenize(buf)
+    try:
+        return parser.parse(tokens)
+    except ASDLSyntaxError, err:
+        print err
+        lines = buf.split("\n")
+        print lines[err.lineno - 1] # lines starts at 0, files at 1
+
+if __name__ == "__main__":
+    import glob
+    import sys
+
+    if len(sys.argv) > 1:
+        files = sys.argv[1:]
+    else:
+        testdir = "tests"
+        files = glob.glob(testdir + "/*.asdl")
+    
+    for file in files:
+        print file
+        mod = parse(file)
+        print "module", mod.name
+        print len(mod.dfns), "definitions"
+        if not check(mod):
+            print "Check failed"
+        else:
+            for dfn in mod.dfns:
+                print dfn.type
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
new file mode 100755 (executable)
index 0000000..7c6df4e
--- /dev/null
@@ -0,0 +1,621 @@
+#! /usr/bin/env python
+"""Generate C code from an ASDL description."""
+
+# TO DO
+# handle fields that have a type but no name
+
+import os, sys, traceback
+
+import asdl
+
+TABSIZE = 8
+MAX_COL = 80
+
+def get_c_type(name):
+    """Return a string for the C name of the type.
+
+    This function special cases the default types provided by asdl:
+    identifier, string, int, bool.
+    """
+    # XXX ack!  need to figure out where Id is useful and where string
+    if isinstance(name, asdl.Id):
+        name = name.value
+    if name in asdl.builtin_types:
+        return name
+    else:
+        return "%s_ty" % name
+
+def reflow_lines(s, depth):
+    """Reflow the line s indented depth tabs.
+
+    Return a sequence of lines where no line extends beyond MAX_COL
+    when properly indented.  The first line is properly indented based
+    exclusively on depth * TABSIZE.  All following lines -- these are
+    the reflowed lines generated by this function -- start at the same
+    column as the first character beyond the opening { in the first
+    line.
+    """
+    size = MAX_COL - depth * TABSIZE
+    if len(s) < size:
+        return [s]
+
+    lines = []
+    cur = s
+    padding = ""
+    while len(cur) > size:
+        i = cur.rfind(' ', 0, size)
+        # XXX this should be fixed for real
+        if i == -1 and 'GeneratorExp' in cur:
+            i = size + 3
+        assert i != -1, "Impossible line %d to reflow: %s" % (size, `s`)
+        lines.append(padding + cur[:i])
+        if len(lines) == 1:
+            # find new size based on brace
+            j = cur.find('{', 0, i)
+            if j >= 0:
+                j += 2 # account for the brace and the space after it
+                size -= j
+                padding = " " * j
+            else:
+                j = cur.find('(', 0, i)
+                if j >= 0:
+                    j += 1 # account for the paren (no space after it)
+                    size -= j
+                    padding = " " * j
+        cur = cur[i+1:]
+    else:
+        lines.append(padding + cur)
+    return lines
+
+def is_simple(sum):
+    """Return True if a sum is a simple.
+
+    A sum is simple if its types have no fields, e.g.
+    unaryop = Invert | Not | UAdd | USub
+    """
+
+    for t in sum.types:
+        if t.fields:
+            return False
+    return True
+
+class EmitVisitor(asdl.VisitorBase):
+    """Visit that emits lines"""
+
+    def __init__(self, file):
+        self.file = file
+        super(EmitVisitor, self).__init__()
+
+    def emit(self, s, depth, reflow=1):
+        # XXX reflow long lines?
+        if reflow:
+            lines = reflow_lines(s, depth)
+        else:
+            lines = [s]
+        for line in lines:
+            line = (" " * TABSIZE * depth) + line + "\n"
+            self.file.write(line)
+
+class TypeDefVisitor(EmitVisitor):
+    def visitModule(self, mod):
+        for dfn in mod.dfns:
+            self.visit(dfn)
+
+    def visitType(self, type, depth=0):
+        self.visit(type.value, type.name, depth)
+
+    def visitSum(self, sum, name, depth):
+        if is_simple(sum):
+            self.simple_sum(sum, name, depth)
+        else:
+            self.sum_with_constructors(sum, name, depth)
+
+    def simple_sum(self, sum, name, depth):
+        enum = []
+        for i in range(len(sum.types)):
+            type = sum.types[i]
+            enum.append("%s=%d" % (type.name, i + 1))
+        enums = ", ".join(enum)
+        ctype = get_c_type(name)
+        s = "typedef enum _%s { %s } %s;" % (name, enums, ctype)
+        self.emit(s, depth)
+        self.emit("", depth)
+
+    def sum_with_constructors(self, sum, name, depth):
+        ctype = get_c_type(name)
+        s = "typedef struct _%(name)s *%(ctype)s;" % locals()
+        self.emit(s, depth)
+        self.emit("", depth)
+
+    def visitProduct(self, product, name, depth):
+        ctype = get_c_type(name)
+        s = "typedef struct _%(name)s *%(ctype)s;" % locals()
+        self.emit(s, depth)
+        self.emit("", depth)
+
+class StructVisitor(EmitVisitor):
+    """Visitor to generate typdefs for AST."""
+
+    def visitModule(self, mod):
+        for dfn in mod.dfns:
+            self.visit(dfn)
+
+    def visitType(self, type, depth=0):
+        self.visit(type.value, type.name, depth)
+
+    def visitSum(self, sum, name, depth):
+        if not is_simple(sum):
+            self.sum_with_constructors(sum, name, depth)
+
+    def sum_with_constructors(self, sum, name, depth):
+        def emit(s, depth=depth):
+            self.emit(s % sys._getframe(1).f_locals, depth)
+        enum = []
+        for i in range(len(sum.types)):
+            type = sum.types[i]
+            enum.append("%s_kind=%d" % (type.name, i + 1))
+
+        emit("struct _%(name)s {")
+        emit("enum { " + ", ".join(enum) + " } kind;", depth + 1)
+        emit("union {", depth + 1)
+        for t in sum.types:
+            self.visit(t, depth + 2)
+        emit("} v;", depth + 1)
+        for field in sum.attributes:
+            # rudimentary attribute handling
+            type = str(field.type)
+            assert type in asdl.builtin_types, type
+            emit("%s %s;" % (type, field.name), depth + 1);
+        emit("};")
+        emit("")
+
+    def visitConstructor(self, cons, depth):
+        if cons.fields:
+            self.emit("struct {", depth)
+            for f in cons.fields:
+                self.visit(f, depth + 1)
+            self.emit("} %s;" % cons.name, depth)
+            self.emit("", depth)
+        else:
+            # XXX not sure what I want here, nothing is probably fine
+            pass
+
+    def visitField(self, field, depth):
+        # XXX need to lookup field.type, because it might be something
+        # like a builtin...
+        ctype = get_c_type(field.type)
+        name = field.name
+        if field.seq:
+            self.emit("asdl_seq *%(name)s;" % locals(), depth)
+        else:
+            self.emit("%(ctype)s %(name)s;" % locals(), depth)
+
+    def visitProduct(self, product, name, depth):
+        self.emit("struct _%(name)s {" % locals(), depth)
+        for f in product.fields:
+            self.visit(f, depth + 1)
+        self.emit("};", depth)
+        self.emit("", depth)
+
+class PrototypeVisitor(EmitVisitor):
+    """Generate function prototypes for the .h file"""
+
+    def visitModule(self, mod):
+        for dfn in mod.dfns:
+            self.visit(dfn)
+
+    def visitType(self, type):
+        self.visit(type.value, type.name)
+
+    def visitSum(self, sum, name):
+        if is_simple(sum):
+            pass # XXX
+        else:
+            for t in sum.types:
+                self.visit(t, name, sum.attributes)
+
+    def get_args(self, fields):
+        """Return list of C argument into, one for each field.
+
+        Argument info is 3-tuple of a C type, variable name, and flag
+        that is true if type can be NULL.
+        """
+        args = []
+        unnamed = {}
+        for f in fields:
+            if f.name is None:
+                name = f.type
+                c = unnamed[name] = unnamed.get(name, 0) + 1
+                if c > 1:
+                    name = "name%d" % (c - 1)
+            else:
+                name = f.name
+            # XXX should extend get_c_type() to handle this
+            if f.seq:
+                ctype = "asdl_seq *"
+            else:
+                ctype = get_c_type(f.type)
+            args.append((ctype, name, f.opt or f.seq))
+        return args
+
+    def visitConstructor(self, cons, type, attrs):
+        args = self.get_args(cons.fields)
+        attrs = self.get_args(attrs)
+        ctype = get_c_type(type)
+        self.emit_function(cons.name, ctype, args, attrs)
+
+    def emit_function(self, name, ctype, args, attrs, union=1):
+        args = args + attrs
+        if args:
+            argstr = ", ".join(["%s %s" % (atype, aname)
+                                for atype, aname, opt in args])
+        else:
+            argstr = "void"
+        self.emit("%s %s(%s);" % (ctype, name, argstr), 0)
+
+    def visitProduct(self, prod, name):
+        self.emit_function(name, get_c_type(name),
+                           self.get_args(prod.fields), [], union=0)
+
+class FunctionVisitor(PrototypeVisitor):
+    """Visitor to generate constructor functions for AST."""
+
+    def emit_function(self, name, ctype, args, attrs, union=1):
+        def emit(s, depth=0, reflow=1):
+            self.emit(s, depth, reflow)
+        argstr = ", ".join(["%s %s" % (atype, aname)
+                            for atype, aname, opt in args + attrs])
+        self.emit("%s" % ctype, 0)
+        emit("%s(%s)" % (name, argstr))
+        emit("{")
+        emit("%s p;" % ctype, 1)
+        for argtype, argname, opt in args:
+            # XXX hack alert: false is allowed for a bool
+            if not opt and not argtype == "bool":
+                emit("if (!%s) {" % argname, 1)
+                emit("PyErr_SetString(PyExc_ValueError,", 2)
+                msg = "field %s is required for %s" % (argname, name)
+                emit('                "%s");' % msg,
+                     2, reflow=0)
+                emit('return NULL;', 2)
+                emit('}', 1)
+
+        emit("p = (%s)malloc(sizeof(*p));" % ctype, 1)
+        emit("if (!p) {", 1)
+        emit("PyErr_SetString(PyExc_MemoryError, \"no memory\");", 2)
+        emit("return NULL;", 2)
+        emit("}", 1)
+        if union:
+            self.emit_body_union(name, args, attrs)
+        else:
+            self.emit_body_struct(name, args, attrs)
+        emit("return p;", 1)
+        emit("}")
+        emit("")
+
+    def emit_body_union(self, name, args, attrs):
+        def emit(s, depth=0, reflow=1):
+            self.emit(s, depth, reflow)
+        emit("p->kind = %s_kind;" % name, 1)
+        for argtype, argname, opt in args:
+            emit("p->v.%s.%s = %s;" % (name, argname, argname), 1)
+        for argtype, argname, opt in attrs:
+            emit("p->%s = %s;" % (argname, argname), 1)
+
+    def emit_body_struct(self, name, args, attrs):
+        def emit(s, depth=0, reflow=1):
+            self.emit(s, depth, reflow)
+        for argtype, argname, opt in args:
+            emit("p->%s = %s;" % (argname, argname), 1)
+        assert not attrs
+
+class PickleVisitor(EmitVisitor):
+
+    def visitModule(self, mod):
+        for dfn in mod.dfns:
+            self.visit(dfn)
+
+    def visitType(self, type):
+        self.visit(type.value, type.name)
+
+    def visitSum(self, sum, name):
+        pass
+
+    def visitProduct(self, sum, name):
+        pass
+
+    def visitConstructor(self, cons, name):
+        pass
+
+    def visitField(self, sum):
+        pass
+
+class MarshalPrototypeVisitor(PickleVisitor):
+
+    def prototype(self, sum, name):
+        ctype = get_c_type(name)
+        self.emit("int marshal_write_%s(PyObject **, int *, %s);"
+                  % (name, ctype), 0)
+
+    visitProduct = visitSum = prototype
+
+class FreePrototypeVisitor(PickleVisitor):
+
+    def prototype(self, sum, name):
+        ctype = get_c_type(name)
+        self.emit("void free_%s(%s);" % (name, ctype), 0)
+
+    visitProduct = visitSum = prototype
+
+_SPECIALIZED_SEQUENCES = ('stmt', 'expr')
+
+def find_sequence(fields, doing_specialization):
+    """Return True if any field uses a sequence."""
+    for f in fields:
+        if f.seq:
+            if not doing_specialization:
+                return True
+            if str(f.type) not in _SPECIALIZED_SEQUENCES:
+                return True
+    return False
+
+def has_sequence(types, doing_specialization):
+    for t in types:
+        if find_sequence(t.fields, doing_specialization):
+            return True
+    return False
+
+
+class StaticVisitor(PickleVisitor):
+    '''Very simple, always emit this static code'''
+
+    CODE = '''static void
+free_seq_exprs(asdl_seq *seq)
+{
+        int i, n;
+        n = asdl_seq_LEN(seq);
+        for (i = 0; i < n; i++)
+                free_expr((expr_ty)asdl_seq_GET(seq, i));
+        asdl_seq_free(seq);
+}
+
+static void
+free_seq_stmts(asdl_seq *seq)
+{
+        int i, n;
+        n = asdl_seq_LEN(seq);
+        for (i = 0; i < n; i++)
+                free_stmt((stmt_ty)asdl_seq_GET(seq, i));
+        asdl_seq_free(seq);
+}
+'''
+
+    def visit(self, object):
+        self.emit(self.CODE, 0, reflow=False)
+
+
+class FreeVisitor(PickleVisitor):
+
+    def func_begin(self, name, has_seq):
+        ctype = get_c_type(name)
+        self.emit("void", 0)
+        self.emit("free_%s(%s o)" % (name, ctype), 0)
+        self.emit("{", 0)
+        if has_seq:
+            self.emit("int i, n;", 1)
+            self.emit("asdl_seq *seq;", 1)
+            self.emit('', 0)
+        self.emit('if (!o)', 1)
+        self.emit('return;', 2)
+        self.emit('', 0)
+
+    def func_end(self):
+        self.emit("}", 0)
+        self.emit("", 0)
+
+    def visitSum(self, sum, name):
+        has_seq = has_sequence(sum.types, True)
+        self.func_begin(name, has_seq)
+        if not is_simple(sum):
+            self.emit("switch (o->kind) {", 1)
+            for i in range(len(sum.types)):
+                t = sum.types[i]
+                self.visitConstructor(t, i + 1, name)
+            self.emit("}", 1)
+            self.emit("", 0)
+            self.emit("free(o);", 1)
+        self.func_end()
+
+    def visitProduct(self, prod, name):
+        self.func_begin(name, find_sequence(prod.fields, True))
+        for field in prod.fields:
+            self.visitField(field, name, 1, True)
+        self.emit("", 0)
+        self.emit("free(o);", 1)
+        self.func_end()
+        
+    def visitConstructor(self, cons, enum, name):
+        self.emit("case %s_kind:" % cons.name, 1)
+        for f in cons.fields:
+            self.visitField(f, cons.name, 2, False)
+        self.emit("break;", 2)
+
+    def visitField(self, field, name, depth, product):
+        def emit(s, d):
+            self.emit(s, depth + d)
+        if product:
+            value = "o->%s" % field.name
+        else:
+            value = "o->v.%s.%s" % (name, field.name)
+        if field.seq:
+            self.emitSeq(field, value, depth, emit)
+
+        # XXX need to know the simple types in advance, so that we
+        # don't call free_TYPE() for them.
+
+        elif field.opt:
+            emit("if (%s) {" % value, 0)
+            self.free(field, value, depth + 1)
+            emit("}", 0)
+        else:
+            self.free(field, value, depth)
+
+    def emitSeq(self, field, value, depth, emit):
+        # specialize for freeing sequences of statements and expressions
+        if str(field.type) in _SPECIALIZED_SEQUENCES:
+            c_code = "free_seq_%ss(%s);" % (field.type, value)
+            emit(c_code, 0)
+        else:
+            emit("seq = %s;" % value, 0)
+            emit("n = asdl_seq_LEN(seq);", 0)
+            emit("for (i = 0; i < n; i++)", 0)
+            self.free(field, "asdl_seq_GET(seq, i)", depth + 1)
+            emit("asdl_seq_free(seq);", 0)
+
+    def free(self, field, value, depth):
+        if str(field.type) in ("identifier", "string", "object"):
+            ctype = get_c_type(field.type)
+            self.emit("Py_DECREF((%s)%s);" % (ctype, value), depth)
+        elif str(field.type) == "bool":
+            return
+        else:
+            ctype = get_c_type(field.type)
+            self.emit("free_%s((%s)%s);" % (field.type, ctype, value), depth)
+        
+
+class MarshalFunctionVisitor(PickleVisitor):
+
+    def func_begin(self, name, has_seq):
+        ctype = get_c_type(name)
+        self.emit("int", 0)
+        self.emit("marshal_write_%s(PyObject **buf, int *off, %s o)" %
+                  (name, ctype), 0)
+        self.emit("{", 0)
+        # XXX: add declaration of "int i;" properly
+        if has_seq or True:
+            self.emit("int i;", 1) # XXX only need it for sequences
+
+    def func_end(self):
+        self.emit("return 1;", 1)
+        self.emit("}", 0)
+        self.emit("", 0)
+    
+    def visitSum(self, sum, name):
+        has_seq = has_sequence(sum.types, False)
+        self.func_begin(name, has_seq)
+        simple = is_simple(sum)
+        if simple:
+            self.emit("switch (o) {", 1)
+        else:
+            self.emit("switch (o->kind) {", 1)
+        for i in range(len(sum.types)):
+            t = sum.types[i]
+            self.visitConstructor(t, i + 1, name, simple)
+        self.emit("}", 1)
+        self.func_end()
+
+    def visitProduct(self, prod, name):
+        self.func_begin(name, find_sequence(prod.fields, True))
+        for field in prod.fields:
+            self.visitField(field, name, 1, 1)
+        self.func_end()
+            
+    def visitConstructor(self, cons, enum, name, simple):
+        if simple:
+            self.emit("case %s:" % cons.name, 1)
+            self.emit("marshal_write_int(buf, off, %d);" % enum, 2);
+            self.emit("break;", 2)
+        else:
+            self.emit("case %s_kind:" % cons.name, 1)
+            self.emit("marshal_write_int(buf, off, %d);" % enum, 2)
+            for f in cons.fields:
+                self.visitField(f, cons.name, 2, 0)
+            self.emit("break;", 2)
+
+    def visitField(self, field, name, depth, product):
+        def emit(s, d):
+            self.emit(s, depth + d)
+        if product:
+            value = "o->%s" % field.name
+        else:
+            value = "o->v.%s.%s" % (name, field.name)
+        if field.seq:
+            emit("marshal_write_int(buf, off, asdl_seq_LEN(%s));" % value, 0)
+            emit("for (i = 0; i < asdl_seq_LEN(%s); i++) {" % value, 0)
+            emit("void *elt = asdl_seq_GET(%s, i);" % value, 1);
+            ctype = get_c_type(field.type);
+            emit("marshal_write_%s(buf, off, (%s)elt);" % (field.type,
+                    ctype), 1)
+            emit("}", 0)
+        elif field.opt:
+            emit("if (%s) {" % value, 0)
+            emit("marshal_write_int(buf, off, 1);", 1)
+            emit("marshal_write_%s(buf, off, %s);" % (field.type, value), 1)
+            emit("}", 0)
+            emit("else {", 0)
+            emit("marshal_write_int(buf, off, 0);", 1)
+            emit("}", 0)
+        else:
+            emit("marshal_write_%s(buf, off, %s);" % (field.type, value), 0)
+
+class ChainOfVisitors:
+    def __init__(self, *visitors):
+        self.visitors = visitors
+
+    def visit(self, object):
+        for v in self.visitors:
+            v.visit(object)
+
+def main(srcfile):
+    auto_gen_msg = '/* File automatically generated by %s */\n' % sys.argv[0]
+    mod = asdl.parse(srcfile)
+    if not asdl.check(mod):
+        sys.exit(1)
+    if INC_DIR:
+        p = "%s/%s-ast.h" % (INC_DIR, mod.name)
+    else:
+        p = "%s-ast.h" % mod.name
+    f = open(p, "wb")
+    print >> f, auto_gen_msg
+    print >> f, '#include "asdl.h"\n'
+    c = ChainOfVisitors(TypeDefVisitor(f),
+                        StructVisitor(f),
+                        PrototypeVisitor(f),
+                        FreePrototypeVisitor(f),
+                        MarshalPrototypeVisitor(f),
+                        )
+    c.visit(mod)
+    f.close()
+
+    if SRC_DIR:
+        p = "%s/%s-ast.c" % (SRC_DIR, mod.name)
+    else:
+        p = "%s-ast.c" % mod.name
+    f = open(p, "wb")
+    print >> f, auto_gen_msg
+    print >> f, '#include "Python.h"'
+    print >> f, '#include "%s-ast.h"' % mod.name
+    print >> f
+    v = ChainOfVisitors(FunctionVisitor(f),
+                        StaticVisitor(f),
+                        FreeVisitor(f),
+                        MarshalFunctionVisitor(f),
+                        )
+    v.visit(mod)
+    f.close()
+
+if __name__ == "__main__":
+    import sys
+    import getopt
+
+    INC_DIR = ''
+    SRC_DIR = ''
+    opts, args = getopt.getopt(sys.argv[1:], "h:c:")
+    for o, v in opts:
+        if o == '-h':
+            INC_DIR = v
+        if o == '-c':
+            SRC_DIR = v
+    if len(args) != 1:
+        print "Must specify single input file"
+    main(args[0])
index a6f1abed171668e26d51cf897d05682fd80676ff..55f028ffb83fc9a6d4b43089ceb6fd1960d648ae 100644 (file)
@@ -15,7 +15,7 @@
 # particular case --pragma in PC\pyconfig.h, which demands that
 # python23.lib get linked in).
 
-LIBS= ..\PCbuild\python23.lib
+LIBS= ..\PCbuild\python25.lib
 
 CFLAGS= /I ..\Include /I ..\PC /D MS_NO_COREDLL /D PGEN /MD
 
index 1d25437f4cb2f005632c8363902113185eb32865..11d2232d61f607da4c2bd0f451e25151e31db0ea 100644 (file)
@@ -21,7 +21,7 @@ static void initerr(perrdetail *err_ret, const char* filename);
 node *
 PyParser_ParseString(const char *s, grammar *g, int start, perrdetail *err_ret)
 {
-       return PyParser_ParseStringFlags(s, g, start, err_ret, 0);
+       return PyParser_ParseStringFlagsFilename(s, NULL, g, start, err_ret, 0);
 }
 
 node *
@@ -56,7 +56,6 @@ PyParser_ParseStringFlagsFilename(const char *s, const char *filename,
        return parsetok(tok, g, start, err_ret, flags);
 }
 
-
 /* Parse input coming from a file.  Return error code, print some errors. */
 
 node *
@@ -210,7 +209,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
 }
 
 static void
-initerr(perrdetail *err_ret, const charfilename)
+initerr(perrdetail *err_ret, const char *filename)
 {
        err_ret->error = E_OK;
        err_ret->filename = filename;
diff --git a/Parser/spark.py b/Parser/spark.py
new file mode 100644 (file)
index 0000000..00d9733
--- /dev/null
@@ -0,0 +1,840 @@
+#  Copyright (c) 1998-2002 John Aycock
+#  
+#  Permission is hereby granted, free of charge, to any person obtaining
+#  a copy of this software and associated documentation files (the
+#  "Software"), to deal in the Software without restriction, including
+#  without limitation the rights to use, copy, modify, merge, publish,
+#  distribute, sublicense, and/or sell copies of the Software, and to
+#  permit persons to whom the Software is furnished to do so, subject to
+#  the following conditions:
+#  
+#  The above copyright notice and this permission notice shall be
+#  included in all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+#  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+#  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+#  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__version__ = 'SPARK-0.7 (pre-alpha-5)'
+
+import re
+import sys
+import string
+
+def _namelist(instance):
+       namelist, namedict, classlist = [], {}, [instance.__class__]
+       for c in classlist:
+               for b in c.__bases__:
+                       classlist.append(b)
+               for name in c.__dict__.keys():
+                       if not namedict.has_key(name):
+                               namelist.append(name)
+                               namedict[name] = 1
+       return namelist
+
+class GenericScanner:
+       def __init__(self, flags=0):
+               pattern = self.reflect()
+               self.re = re.compile(pattern, re.VERBOSE|flags)
+
+               self.index2func = {}
+               for name, number in self.re.groupindex.items():
+                       self.index2func[number-1] = getattr(self, 't_' + name)
+
+       def makeRE(self, name):
+               doc = getattr(self, name).__doc__
+               rv = '(?P<%s>%s)' % (name[2:], doc)
+               return rv
+
+       def reflect(self):
+               rv = []
+               for name in _namelist(self):
+                       if name[:2] == 't_' and name != 't_default':
+                               rv.append(self.makeRE(name))
+
+               rv.append(self.makeRE('t_default'))
+               return string.join(rv, '|')
+
+       def error(self, s, pos):
+               print "Lexical error at position %s" % pos
+               raise SystemExit
+
+       def tokenize(self, s):
+               pos = 0
+               n = len(s)
+               while pos < n:
+                       m = self.re.match(s, pos)
+                       if m is None:
+                               self.error(s, pos)
+
+                       groups = m.groups()
+                       for i in range(len(groups)):
+                               if groups[i] and self.index2func.has_key(i):
+                                       self.index2func[i](groups[i])
+                       pos = m.end()
+
+       def t_default(self, s):
+               r'( . | \n )+'
+               print "Specification error: unmatched input"
+               raise SystemExit
+
+#
+#  Extracted from GenericParser and made global so that [un]picking works.
+#
+class _State:
+       def __init__(self, stateno, items):
+               self.T, self.complete, self.items = [], [], items
+               self.stateno = stateno
+
+class GenericParser:
+       #
+       #  An Earley parser, as per J. Earley, "An Efficient Context-Free
+       #  Parsing Algorithm", CACM 13(2), pp. 94-102.  Also J. C. Earley,
+       #  "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis,
+       #  Carnegie-Mellon University, August 1968.  New formulation of
+       #  the parser according to J. Aycock, "Practical Earley Parsing
+       #  and the SPARK Toolkit", Ph.D. thesis, University of Victoria,
+       #  2001, and J. Aycock and R. N. Horspool, "Practical Earley
+       #  Parsing", unpublished paper, 2001.
+       #
+
+       def __init__(self, start):
+               self.rules = {}
+               self.rule2func = {}
+               self.rule2name = {}
+               self.collectRules()
+               self.augment(start)
+               self.ruleschanged = 1
+
+       _NULLABLE = '\e_'
+       _START = 'START'
+       _BOF = '|-'
+
+       #
+       #  When pickling, take the time to generate the full state machine;
+       #  some information is then extraneous, too.  Unfortunately we
+       #  can't save the rule2func map.
+       #
+       def __getstate__(self):
+               if self.ruleschanged:
+                       #
+                       #  XXX - duplicated from parse()
+                       #
+                       self.computeNull()
+                       self.newrules = {}
+                       self.new2old = {}
+                       self.makeNewRules()
+                       self.ruleschanged = 0
+                       self.edges, self.cores = {}, {}
+                       self.states = { 0: self.makeState0() }
+                       self.makeState(0, self._BOF)
+               #
+               #  XXX - should find a better way to do this..
+               #
+               changes = 1
+               while changes:
+                       changes = 0
+                       for k, v in self.edges.items():
+                               if v is None:
+                                       state, sym = k
+                                       if self.states.has_key(state):
+                                               self.goto(state, sym)
+                                               changes = 1
+               rv = self.__dict__.copy()
+               for s in self.states.values():
+                       del s.items
+               del rv['rule2func']
+               del rv['nullable']
+               del rv['cores']
+               return rv
+
+       def __setstate__(self, D):
+               self.rules = {}
+               self.rule2func = {}
+               self.rule2name = {}
+               self.collectRules()
+               start = D['rules'][self._START][0][1][1]        # Blech.
+               self.augment(start)
+               D['rule2func'] = self.rule2func
+               D['makeSet'] = self.makeSet_fast
+               self.__dict__ = D
+
+       #
+       #  A hook for GenericASTBuilder and GenericASTMatcher.  Mess
+       #  thee not with this; nor shall thee toucheth the _preprocess
+       #  argument to addRule.
+       #
+       def preprocess(self, rule, func):       return rule, func
+
+       def addRule(self, doc, func, _preprocess=1):
+               fn = func
+               rules = string.split(doc)
+
+               index = []
+               for i in range(len(rules)):
+                       if rules[i] == '::=':
+                               index.append(i-1)
+               index.append(len(rules))
+
+               for i in range(len(index)-1):
+                       lhs = rules[index[i]]
+                       rhs = rules[index[i]+2:index[i+1]]
+                       rule = (lhs, tuple(rhs))
+
+                       if _preprocess:
+                               rule, fn = self.preprocess(rule, func)
+
+                       if self.rules.has_key(lhs):
+                               self.rules[lhs].append(rule)
+                       else:
+                               self.rules[lhs] = [ rule ]
+                       self.rule2func[rule] = fn
+                       self.rule2name[rule] = func.__name__[2:]
+               self.ruleschanged = 1
+
+       def collectRules(self):
+               for name in _namelist(self):
+                       if name[:2] == 'p_':
+                               func = getattr(self, name)
+                               doc = func.__doc__
+                               self.addRule(doc, func)
+
+       def augment(self, start):
+               rule = '%s ::= %s %s' % (self._START, self._BOF, start)
+               self.addRule(rule, lambda args: args[1], 0)
+
+       def computeNull(self):
+               self.nullable = {}
+               tbd = []
+
+               for rulelist in self.rules.values():
+                       lhs = rulelist[0][0]
+                       self.nullable[lhs] = 0
+                       for rule in rulelist:
+                               rhs = rule[1]
+                               if len(rhs) == 0:
+                                       self.nullable[lhs] = 1
+                                       continue
+                               #
+                               #  We only need to consider rules which
+                               #  consist entirely of nonterminal symbols.
+                               #  This should be a savings on typical
+                               #  grammars.
+                               #
+                               for sym in rhs:
+                                       if not self.rules.has_key(sym):
+                                               break
+                               else:
+                                       tbd.append(rule)
+               changes = 1
+               while changes:
+                       changes = 0
+                       for lhs, rhs in tbd:
+                               if self.nullable[lhs]:
+                                       continue
+                               for sym in rhs:
+                                       if not self.nullable[sym]:
+                                               break
+                               else:
+                                       self.nullable[lhs] = 1
+                                       changes = 1
+
+       def makeState0(self):
+               s0 = _State(0, [])
+               for rule in self.newrules[self._START]:
+                       s0.items.append((rule, 0))
+               return s0
+
+       def finalState(self, tokens):
+               #
+               #  Yuck.
+               #
+               if len(self.newrules[self._START]) == 2 and len(tokens) == 0:
+                       return 1
+               start = self.rules[self._START][0][1][1]
+               return self.goto(1, start)
+
+       def makeNewRules(self):
+               worklist = []
+               for rulelist in self.rules.values():
+                       for rule in rulelist:
+                               worklist.append((rule, 0, 1, rule))
+
+               for rule, i, candidate, oldrule in worklist:
+                       lhs, rhs = rule
+                       n = len(rhs)
+                       while i < n:
+                               sym = rhs[i]
+                               if not self.rules.has_key(sym) or \
+                                  not self.nullable[sym]:
+                                       candidate = 0
+                                       i = i + 1
+                                       continue
+
+                               newrhs = list(rhs)
+                               newrhs[i] = self._NULLABLE+sym
+                               newrule = (lhs, tuple(newrhs))
+                               worklist.append((newrule, i+1,
+                                                candidate, oldrule))
+                               candidate = 0
+                               i = i + 1
+                       else:
+                               if candidate:
+                                       lhs = self._NULLABLE+lhs
+                                       rule = (lhs, rhs)
+                               if self.newrules.has_key(lhs):
+                                       self.newrules[lhs].append(rule)
+                               else:
+                                       self.newrules[lhs] = [ rule ]
+                               self.new2old[rule] = oldrule
+       
+       def typestring(self, token):
+               return None
+
+       def error(self, token):
+               print "Syntax error at or near `%s' token" % token
+               raise SystemExit
+
+       def parse(self, tokens):
+               sets = [ [(1,0), (2,0)] ]
+               self.links = {}
+               
+               if self.ruleschanged:
+                       self.computeNull()
+                       self.newrules = {}
+                       self.new2old = {}
+                       self.makeNewRules()
+                       self.ruleschanged = 0
+                       self.edges, self.cores = {}, {}
+                       self.states = { 0: self.makeState0() }
+                       self.makeState(0, self._BOF)
+
+               for i in xrange(len(tokens)):
+                       sets.append([])
+
+                       if sets[i] == []:
+                               break                           
+                       self.makeSet(tokens[i], sets, i)
+               else:
+                       sets.append([])
+                       self.makeSet(None, sets, len(tokens))
+
+               #_dump(tokens, sets, self.states)
+
+               finalitem = (self.finalState(tokens), 0)
+               if finalitem not in sets[-2]:
+                       if len(tokens) > 0:
+                               self.error(tokens[i-1])
+                       else:
+                               self.error(None)
+
+               return self.buildTree(self._START, finalitem,
+                                     tokens, len(sets)-2)
+
+       def isnullable(self, sym):
+               #
+               #  For symbols in G_e only.  If we weren't supporting 1.5,
+               #  could just use sym.startswith().
+               #
+               return self._NULLABLE == sym[0:len(self._NULLABLE)]
+
+       def skip(self, (lhs, rhs), pos=0):
+               n = len(rhs)
+               while pos < n:
+                       if not self.isnullable(rhs[pos]):
+                               break
+                       pos = pos + 1
+               return pos
+
+       def makeState(self, state, sym):
+               assert sym is not None
+               #
+               #  Compute \epsilon-kernel state's core and see if
+               #  it exists already.
+               #
+               kitems = []
+               for rule, pos in self.states[state].items:
+                       lhs, rhs = rule
+                       if rhs[pos:pos+1] == (sym,):
+                               kitems.append((rule, self.skip(rule, pos+1)))
+               core = kitems
+
+               core.sort()
+               tcore = tuple(core)
+               if self.cores.has_key(tcore):
+                       return self.cores[tcore]
+               #
+               #  Nope, doesn't exist.  Compute it and the associated
+               #  \epsilon-nonkernel state together; we'll need it right away.
+               #
+               k = self.cores[tcore] = len(self.states)
+               K, NK = _State(k, kitems), _State(k+1, [])
+               self.states[k] = K
+               predicted = {}
+
+               edges = self.edges
+               rules = self.newrules
+               for X in K, NK:
+                       worklist = X.items
+                       for item in worklist:
+                               rule, pos = item
+                               lhs, rhs = rule
+                               if pos == len(rhs):
+                                       X.complete.append(rule)
+                                       continue
+
+                               nextSym = rhs[pos]
+                               key = (X.stateno, nextSym)
+                               if not rules.has_key(nextSym):
+                                       if not edges.has_key(key):
+                                               edges[key] = None
+                                               X.T.append(nextSym)
+                               else:
+                                       edges[key] = None
+                                       if not predicted.has_key(nextSym):
+                                               predicted[nextSym] = 1
+                                               for prule in rules[nextSym]:
+                                                       ppos = self.skip(prule)
+                                                       new = (prule, ppos)
+                                                       NK.items.append(new)
+                       #
+                       #  Problem: we know K needs generating, but we
+                       #  don't yet know about NK.  Can't commit anything
+                       #  regarding NK to self.edges until we're sure.  Should
+                       #  we delay committing on both K and NK to avoid this
+                       #  hacky code?  This creates other problems..
+                       #
+                       if X is K:
+                               edges = {}
+
+               if NK.items == []:
+                       return k
+
+               #
+               #  Check for \epsilon-nonkernel's core.  Unfortunately we
+               #  need to know the entire set of predicted nonterminals
+               #  to do this without accidentally duplicating states.
+               #
+               core = predicted.keys()
+               core.sort()
+               tcore = tuple(core)
+               if self.cores.has_key(tcore):
+                       self.edges[(k, None)] = self.cores[tcore]
+                       return k
+
+               nk = self.cores[tcore] = self.edges[(k, None)] = NK.stateno
+               self.edges.update(edges)
+               self.states[nk] = NK
+               return k
+
+       def goto(self, state, sym):
+               key = (state, sym)
+               if not self.edges.has_key(key):
+                       #
+                       #  No transitions from state on sym.
+                       #
+                       return None
+
+               rv = self.edges[key]
+               if rv is None:
+                       #
+                       #  Target state isn't generated yet.  Remedy this.
+                       #
+                       rv = self.makeState(state, sym)
+                       self.edges[key] = rv
+               return rv
+
+       def gotoT(self, state, t):
+               return [self.goto(state, t)]
+
+       def gotoST(self, state, st):
+               rv = []
+               for t in self.states[state].T:
+                       if st == t:
+                               rv.append(self.goto(state, t))
+               return rv
+
+       def add(self, set, item, i=None, predecessor=None, causal=None):
+               if predecessor is None:
+                       if item not in set:
+                               set.append(item)
+               else:
+                       key = (item, i)
+                       if item not in set:
+                               self.links[key] = []
+                               set.append(item)
+                       self.links[key].append((predecessor, causal))
+
+       def makeSet(self, token, sets, i):
+               cur, next = sets[i], sets[i+1]
+
+               ttype = token is not None and self.typestring(token) or None
+               if ttype is not None:
+                       fn, arg = self.gotoT, ttype
+               else:
+                       fn, arg = self.gotoST, token
+
+               for item in cur:
+                       ptr = (item, i)
+                       state, parent = item
+                       add = fn(state, arg)
+                       for k in add:
+                               if k is not None:
+                                       self.add(next, (k, parent), i+1, ptr)
+                                       nk = self.goto(k, None)
+                                       if nk is not None:
+                                               self.add(next, (nk, i+1))
+
+                       if parent == i:
+                               continue
+
+                       for rule in self.states[state].complete:
+                               lhs, rhs = rule
+                               for pitem in sets[parent]:
+                                       pstate, pparent = pitem
+                                       k = self.goto(pstate, lhs)
+                                       if k is not None:
+                                               why = (item, i, rule)
+                                               pptr = (pitem, parent)
+                                               self.add(cur, (k, pparent),
+                                                        i, pptr, why)
+                                               nk = self.goto(k, None)
+                                               if nk is not None:
+                                                       self.add(cur, (nk, i))
+
+       def makeSet_fast(self, token, sets, i):
+               #
+               #  Call *only* when the entire state machine has been built!
+               #  It relies on self.edges being filled in completely, and
+               #  then duplicates and inlines code to boost speed at the
+               #  cost of extreme ugliness.
+               #
+               cur, next = sets[i], sets[i+1]
+               ttype = token is not None and self.typestring(token) or None
+
+               for item in cur:
+                       ptr = (item, i)
+                       state, parent = item
+                       if ttype is not None:
+                               k = self.edges.get((state, ttype), None)
+                               if k is not None:
+                                       #self.add(next, (k, parent), i+1, ptr)
+                                       #INLINED --v
+                                       new = (k, parent)
+                                       key = (new, i+1)
+                                       if new not in next:
+                                               self.links[key] = []
+                                               next.append(new)
+                                       self.links[key].append((ptr, None))
+                                       #INLINED --^
+                                       #nk = self.goto(k, None)
+                                       nk = self.edges.get((k, None), None)
+                                       if nk is not None:
+                                               #self.add(next, (nk, i+1))
+                                               #INLINED --v
+                                               new = (nk, i+1)
+                                               if new not in next:
+                                                       next.append(new)
+                                               #INLINED --^
+                       else:
+                               add = self.gotoST(state, token)
+                               for k in add:
+                                       if k is not None:
+                                               self.add(next, (k, parent), i+1, ptr)
+                                               #nk = self.goto(k, None)
+                                               nk = self.edges.get((k, None), None)
+                                               if nk is not None:
+                                                       self.add(next, (nk, i+1))
+
+                       if parent == i:
+                               continue
+
+                       for rule in self.states[state].complete:
+                               lhs, rhs = rule
+                               for pitem in sets[parent]:
+                                       pstate, pparent = pitem
+                                       #k = self.goto(pstate, lhs)
+                                       k = self.edges.get((pstate, lhs), None)
+                                       if k is not None:
+                                               why = (item, i, rule)
+                                               pptr = (pitem, parent)
+                                               #self.add(cur, (k, pparent),
+                                               #        i, pptr, why)
+                                               #INLINED --v
+                                               new = (k, pparent)
+                                               key = (new, i)
+                                               if new not in cur:
+                                                       self.links[key] = []
+                                                       cur.append(new)
+                                               self.links[key].append((pptr, why))
+                                               #INLINED --^
+                                               #nk = self.goto(k, None)
+                                               nk = self.edges.get((k, None), None)
+                                               if nk is not None:
+                                                       #self.add(cur, (nk, i))
+                                                       #INLINED --v
+                                                       new = (nk, i)
+                                                       if new not in cur:
+                                                               cur.append(new)
+                                                       #INLINED --^
+
+       def predecessor(self, key, causal):
+               for p, c in self.links[key]:
+                       if c == causal:
+                               return p
+               assert 0
+
+       def causal(self, key):
+               links = self.links[key]
+               if len(links) == 1:
+                       return links[0][1]
+               choices = []
+               rule2cause = {}
+               for p, c in links:
+                       rule = c[2]
+                       choices.append(rule)
+                       rule2cause[rule] = c
+               return rule2cause[self.ambiguity(choices)]
+
+       def deriveEpsilon(self, nt):
+               if len(self.newrules[nt]) > 1:
+                       rule = self.ambiguity(self.newrules[nt])
+               else:
+                       rule = self.newrules[nt][0]
+               #print rule
+
+               rhs = rule[1]
+               attr = [None] * len(rhs)
+
+               for i in range(len(rhs)-1, -1, -1):
+                       attr[i] = self.deriveEpsilon(rhs[i])
+               return self.rule2func[self.new2old[rule]](attr)
+
+       def buildTree(self, nt, item, tokens, k):
+               state, parent = item
+
+               choices = []
+               for rule in self.states[state].complete:
+                       if rule[0] == nt:
+                               choices.append(rule)
+               rule = choices[0]
+               if len(choices) > 1:
+                       rule = self.ambiguity(choices)
+               #print rule
+
+               rhs = rule[1]
+               attr = [None] * len(rhs)
+
+               for i in range(len(rhs)-1, -1, -1):
+                       sym = rhs[i]
+                       if not self.newrules.has_key(sym):
+                               if sym != self._BOF:
+                                       attr[i] = tokens[k-1]
+                                       key = (item, k)
+                                       item, k = self.predecessor(key, None)
+                       #elif self.isnullable(sym):
+                       elif self._NULLABLE == sym[0:len(self._NULLABLE)]:
+                               attr[i] = self.deriveEpsilon(sym)
+                       else:
+                               key = (item, k)
+                               why = self.causal(key)
+                               attr[i] = self.buildTree(sym, why[0],
+                                                        tokens, why[1])
+                               item, k = self.predecessor(key, why)
+               return self.rule2func[self.new2old[rule]](attr)
+
+       def ambiguity(self, rules):
+               #
+               #  XXX - problem here and in collectRules() if the same rule
+               #        appears in >1 method.  Also undefined results if rules
+               #        causing the ambiguity appear in the same method.
+               #
+               sortlist = []
+               name2index = {}
+               for i in range(len(rules)):
+                       lhs, rhs = rule = rules[i]
+                       name = self.rule2name[self.new2old[rule]]
+                       sortlist.append((len(rhs), name))
+                       name2index[name] = i
+               sortlist.sort()
+               list = map(lambda (a,b): b, sortlist)
+               return rules[name2index[self.resolve(list)]]
+
+       def resolve(self, list):
+               #
+               #  Resolve ambiguity in favor of the shortest RHS.
+               #  Since we walk the tree from the top down, this
+               #  should effectively resolve in favor of a "shift".
+               #
+               return list[0]
+
+#
+#  GenericASTBuilder automagically constructs a concrete/abstract syntax tree
+#  for a given input.  The extra argument is a class (not an instance!)
+#  which supports the "__setslice__" and "__len__" methods.
+#
+#  XXX - silently overrides any user code in methods.
+#
+
+class GenericASTBuilder(GenericParser):
+       def __init__(self, AST, start):
+               GenericParser.__init__(self, start)
+               self.AST = AST
+
+       def preprocess(self, rule, func):
+               rebind = lambda lhs, self=self: \
+                               lambda args, lhs=lhs, self=self: \
+                                       self.buildASTNode(args, lhs)
+               lhs, rhs = rule
+               return rule, rebind(lhs)
+
+       def buildASTNode(self, args, lhs):
+               children = []
+               for arg in args:
+                       if isinstance(arg, self.AST):
+                               children.append(arg)
+                       else:
+                               children.append(self.terminal(arg))
+               return self.nonterminal(lhs, children)
+
+       def terminal(self, token):      return token
+
+       def nonterminal(self, type, args):
+               rv = self.AST(type)
+               rv[:len(args)] = args
+               return rv
+
+#
+#  GenericASTTraversal is a Visitor pattern according to Design Patterns.  For
+#  each node it attempts to invoke the method n_<node type>, falling
+#  back onto the default() method if the n_* can't be found.  The preorder
+#  traversal also looks for an exit hook named n_<node type>_exit (no default
+#  routine is called if it's not found).  To prematurely halt traversal
+#  of a subtree, call the prune() method -- this only makes sense for a
+#  preorder traversal.  Node type is determined via the typestring() method.
+#
+
+class GenericASTTraversalPruningException:
+       pass
+
+class GenericASTTraversal:
+       def __init__(self, ast):
+               self.ast = ast
+
+       def typestring(self, node):
+               return node.type
+
+       def prune(self):
+               raise GenericASTTraversalPruningException
+
+       def preorder(self, node=None):
+               if node is None:
+                       node = self.ast
+
+               try:
+                       name = 'n_' + self.typestring(node)
+                       if hasattr(self, name):
+                               func = getattr(self, name)
+                               func(node)
+                       else:
+                               self.default(node)
+               except GenericASTTraversalPruningException:
+                       return
+
+               for kid in node:
+                       self.preorder(kid)
+
+               name = name + '_exit'
+               if hasattr(self, name):
+                       func = getattr(self, name)
+                       func(node)
+
+       def postorder(self, node=None):
+               if node is None:
+                       node = self.ast
+
+               for kid in node:
+                       self.postorder(kid)
+
+               name = 'n_' + self.typestring(node)
+               if hasattr(self, name):
+                       func = getattr(self, name)
+                       func(node)
+               else:
+                       self.default(node)
+
+
+       def default(self, node):
+               pass
+
+#
+#  GenericASTMatcher.  AST nodes must have "__getitem__" and "__cmp__"
+#  implemented.
+#
+#  XXX - makes assumptions about how GenericParser walks the parse tree.
+#
+
+class GenericASTMatcher(GenericParser):
+       def __init__(self, start, ast):
+               GenericParser.__init__(self, start)
+               self.ast = ast
+
+       def preprocess(self, rule, func):
+               rebind = lambda func, self=self: \
+                               lambda args, func=func, self=self: \
+                                       self.foundMatch(args, func)
+               lhs, rhs = rule
+               rhslist = list(rhs)
+               rhslist.reverse()
+
+               return (lhs, tuple(rhslist)), rebind(func)
+
+       def foundMatch(self, args, func):
+               func(args[-1])
+               return args[-1]
+
+       def match_r(self, node):
+               self.input.insert(0, node)
+               children = 0
+
+               for child in node:
+                       if children == 0:
+                               self.input.insert(0, '(')
+                       children = children + 1
+                       self.match_r(child)
+
+               if children > 0:
+                       self.input.insert(0, ')')
+
+       def match(self, ast=None):
+               if ast is None:
+                       ast = self.ast
+               self.input = []
+
+               self.match_r(ast)
+               self.parse(self.input)
+
+       def resolve(self, list):
+               #
+               #  Resolve ambiguity in favor of the longest RHS.
+               #
+               return list[-1]
+
+def _dump(tokens, sets, states):
+       for i in range(len(sets)):
+               print 'set', i
+               for item in sets[i]:
+                       print '\t', item
+                       for (lhs, rhs), pos in states[item[0]].items:
+                               print '\t\t', lhs, '::=',
+                               print string.join(rhs[:pos]),
+                               print '.',
+                               print string.join(rhs[pos:])
+               if i < len(tokens):
+                       print
+                       print 'token', str(tokens[i])
+                       print
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
new file mode 100644 (file)
index 0000000..e82b61c
--- /dev/null
@@ -0,0 +1,2281 @@
+/* File automatically generated by ../Parser/asdl_c.py */
+
+#include "Python.h"
+#include "Python-ast.h"
+
+mod_ty
+Module(asdl_seq * body)
+{
+        mod_ty p;
+        p = (mod_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Module_kind;
+        p->v.Module.body = body;
+        return p;
+}
+
+mod_ty
+Interactive(asdl_seq * body)
+{
+        mod_ty p;
+        p = (mod_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Interactive_kind;
+        p->v.Interactive.body = body;
+        return p;
+}
+
+mod_ty
+Expression(expr_ty body)
+{
+        mod_ty p;
+        if (!body) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field body is required for Expression");
+                return NULL;
+        }
+        p = (mod_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Expression_kind;
+        p->v.Expression.body = body;
+        return p;
+}
+
+mod_ty
+Suite(asdl_seq * body)
+{
+        mod_ty p;
+        p = (mod_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Suite_kind;
+        p->v.Suite.body = body;
+        return p;
+}
+
+stmt_ty
+FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq *
+            decorators, int lineno)
+{
+        stmt_ty p;
+        if (!name) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field name is required for FunctionDef");
+                return NULL;
+        }
+        if (!args) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field args is required for FunctionDef");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = FunctionDef_kind;
+        p->v.FunctionDef.name = name;
+        p->v.FunctionDef.args = args;
+        p->v.FunctionDef.body = body;
+        p->v.FunctionDef.decorators = decorators;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int lineno)
+{
+        stmt_ty p;
+        if (!name) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field name is required for ClassDef");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = ClassDef_kind;
+        p->v.ClassDef.name = name;
+        p->v.ClassDef.bases = bases;
+        p->v.ClassDef.body = body;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Return(expr_ty value, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Return_kind;
+        p->v.Return.value = value;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Delete(asdl_seq * targets, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Delete_kind;
+        p->v.Delete.targets = targets;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Assign(asdl_seq * targets, expr_ty value, int lineno)
+{
+        stmt_ty p;
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for Assign");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Assign_kind;
+        p->v.Assign.targets = targets;
+        p->v.Assign.value = value;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno)
+{
+        stmt_ty p;
+        if (!target) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field target is required for AugAssign");
+                return NULL;
+        }
+        if (!op) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field op is required for AugAssign");
+                return NULL;
+        }
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for AugAssign");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = AugAssign_kind;
+        p->v.AugAssign.target = target;
+        p->v.AugAssign.op = op;
+        p->v.AugAssign.value = value;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Print(expr_ty dest, asdl_seq * values, bool nl, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Print_kind;
+        p->v.Print.dest = dest;
+        p->v.Print.values = values;
+        p->v.Print.nl = nl;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int
+    lineno)
+{
+        stmt_ty p;
+        if (!target) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field target is required for For");
+                return NULL;
+        }
+        if (!iter) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field iter is required for For");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = For_kind;
+        p->v.For.target = target;
+        p->v.For.iter = iter;
+        p->v.For.body = body;
+        p->v.For.orelse = orelse;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno)
+{
+        stmt_ty p;
+        if (!test) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field test is required for While");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = While_kind;
+        p->v.While.test = test;
+        p->v.While.body = body;
+        p->v.While.orelse = orelse;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno)
+{
+        stmt_ty p;
+        if (!test) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field test is required for If");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = If_kind;
+        p->v.If.test = test;
+        p->v.If.body = body;
+        p->v.If.orelse = orelse;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Raise_kind;
+        p->v.Raise.type = type;
+        p->v.Raise.inst = inst;
+        p->v.Raise.tback = tback;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = TryExcept_kind;
+        p->v.TryExcept.body = body;
+        p->v.TryExcept.handlers = handlers;
+        p->v.TryExcept.orelse = orelse;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = TryFinally_kind;
+        p->v.TryFinally.body = body;
+        p->v.TryFinally.finalbody = finalbody;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Assert(expr_ty test, expr_ty msg, int lineno)
+{
+        stmt_ty p;
+        if (!test) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field test is required for Assert");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Assert_kind;
+        p->v.Assert.test = test;
+        p->v.Assert.msg = msg;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Import(asdl_seq * names, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Import_kind;
+        p->v.Import.names = names;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+ImportFrom(identifier module, asdl_seq * names, int lineno)
+{
+        stmt_ty p;
+        if (!module) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field module is required for ImportFrom");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = ImportFrom_kind;
+        p->v.ImportFrom.module = module;
+        p->v.ImportFrom.names = names;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno)
+{
+        stmt_ty p;
+        if (!body) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field body is required for Exec");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Exec_kind;
+        p->v.Exec.body = body;
+        p->v.Exec.globals = globals;
+        p->v.Exec.locals = locals;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Global(asdl_seq * names, int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Global_kind;
+        p->v.Global.names = names;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Expr(expr_ty value, int lineno)
+{
+        stmt_ty p;
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for Expr");
+                return NULL;
+        }
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Expr_kind;
+        p->v.Expr.value = value;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Pass(int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Pass_kind;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Break(int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Break_kind;
+        p->lineno = lineno;
+        return p;
+}
+
+stmt_ty
+Continue(int lineno)
+{
+        stmt_ty p;
+        p = (stmt_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Continue_kind;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+BoolOp(boolop_ty op, asdl_seq * values, int lineno)
+{
+        expr_ty p;
+        if (!op) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field op is required for BoolOp");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = BoolOp_kind;
+        p->v.BoolOp.op = op;
+        p->v.BoolOp.values = values;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno)
+{
+        expr_ty p;
+        if (!left) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field left is required for BinOp");
+                return NULL;
+        }
+        if (!op) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field op is required for BinOp");
+                return NULL;
+        }
+        if (!right) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field right is required for BinOp");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = BinOp_kind;
+        p->v.BinOp.left = left;
+        p->v.BinOp.op = op;
+        p->v.BinOp.right = right;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+UnaryOp(unaryop_ty op, expr_ty operand, int lineno)
+{
+        expr_ty p;
+        if (!op) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field op is required for UnaryOp");
+                return NULL;
+        }
+        if (!operand) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field operand is required for UnaryOp");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = UnaryOp_kind;
+        p->v.UnaryOp.op = op;
+        p->v.UnaryOp.operand = operand;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Lambda(arguments_ty args, expr_ty body, int lineno)
+{
+        expr_ty p;
+        if (!args) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field args is required for Lambda");
+                return NULL;
+        }
+        if (!body) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field body is required for Lambda");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Lambda_kind;
+        p->v.Lambda.args = args;
+        p->v.Lambda.body = body;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Dict(asdl_seq * keys, asdl_seq * values, int lineno)
+{
+        expr_ty p;
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Dict_kind;
+        p->v.Dict.keys = keys;
+        p->v.Dict.values = values;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+ListComp(expr_ty elt, asdl_seq * generators, int lineno)
+{
+        expr_ty p;
+        if (!elt) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field elt is required for ListComp");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = ListComp_kind;
+        p->v.ListComp.elt = elt;
+        p->v.ListComp.generators = generators;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno)
+{
+        expr_ty p;
+        if (!elt) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field elt is required for GeneratorExp");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = GeneratorExp_kind;
+        p->v.GeneratorExp.elt = elt;
+        p->v.GeneratorExp.generators = generators;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Yield(expr_ty value, int lineno)
+{
+        expr_ty p;
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Yield_kind;
+        p->v.Yield.value = value;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Compare(expr_ty left, asdl_seq * ops, asdl_seq * comparators, int lineno)
+{
+        expr_ty p;
+        if (!left) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field left is required for Compare");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Compare_kind;
+        p->v.Compare.left = left;
+        p->v.Compare.ops = ops;
+        p->v.Compare.comparators = comparators;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty starargs,
+     expr_ty kwargs, int lineno)
+{
+        expr_ty p;
+        if (!func) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field func is required for Call");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Call_kind;
+        p->v.Call.func = func;
+        p->v.Call.args = args;
+        p->v.Call.keywords = keywords;
+        p->v.Call.starargs = starargs;
+        p->v.Call.kwargs = kwargs;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Repr(expr_ty value, int lineno)
+{
+        expr_ty p;
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for Repr");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Repr_kind;
+        p->v.Repr.value = value;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Num(object n, int lineno)
+{
+        expr_ty p;
+        if (!n) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field n is required for Num");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Num_kind;
+        p->v.Num.n = n;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Str(string s, int lineno)
+{
+        expr_ty p;
+        if (!s) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field s is required for Str");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Str_kind;
+        p->v.Str.s = s;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno)
+{
+        expr_ty p;
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for Attribute");
+                return NULL;
+        }
+        if (!attr) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field attr is required for Attribute");
+                return NULL;
+        }
+        if (!ctx) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field ctx is required for Attribute");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Attribute_kind;
+        p->v.Attribute.value = value;
+        p->v.Attribute.attr = attr;
+        p->v.Attribute.ctx = ctx;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int lineno)
+{
+        expr_ty p;
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for Subscript");
+                return NULL;
+        }
+        if (!slice) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field slice is required for Subscript");
+                return NULL;
+        }
+        if (!ctx) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field ctx is required for Subscript");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Subscript_kind;
+        p->v.Subscript.value = value;
+        p->v.Subscript.slice = slice;
+        p->v.Subscript.ctx = ctx;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Name(identifier id, expr_context_ty ctx, int lineno)
+{
+        expr_ty p;
+        if (!id) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field id is required for Name");
+                return NULL;
+        }
+        if (!ctx) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field ctx is required for Name");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Name_kind;
+        p->v.Name.id = id;
+        p->v.Name.ctx = ctx;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+List(asdl_seq * elts, expr_context_ty ctx, int lineno)
+{
+        expr_ty p;
+        if (!ctx) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field ctx is required for List");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = List_kind;
+        p->v.List.elts = elts;
+        p->v.List.ctx = ctx;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
+Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno)
+{
+        expr_ty p;
+        if (!ctx) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field ctx is required for Tuple");
+                return NULL;
+        }
+        p = (expr_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Tuple_kind;
+        p->v.Tuple.elts = elts;
+        p->v.Tuple.ctx = ctx;
+        p->lineno = lineno;
+        return p;
+}
+
+slice_ty
+Ellipsis()
+{
+        slice_ty p;
+        p = (slice_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Ellipsis_kind;
+        return p;
+}
+
+slice_ty
+Slice(expr_ty lower, expr_ty upper, expr_ty step)
+{
+        slice_ty p;
+        p = (slice_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Slice_kind;
+        p->v.Slice.lower = lower;
+        p->v.Slice.upper = upper;
+        p->v.Slice.step = step;
+        return p;
+}
+
+slice_ty
+ExtSlice(asdl_seq * dims)
+{
+        slice_ty p;
+        p = (slice_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = ExtSlice_kind;
+        p->v.ExtSlice.dims = dims;
+        return p;
+}
+
+slice_ty
+Index(expr_ty value)
+{
+        slice_ty p;
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for Index");
+                return NULL;
+        }
+        p = (slice_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->kind = Index_kind;
+        p->v.Index.value = value;
+        return p;
+}
+
+comprehension_ty
+comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs)
+{
+        comprehension_ty p;
+        if (!target) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field target is required for comprehension");
+                return NULL;
+        }
+        if (!iter) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field iter is required for comprehension");
+                return NULL;
+        }
+        p = (comprehension_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->target = target;
+        p->iter = iter;
+        p->ifs = ifs;
+        return p;
+}
+
+excepthandler_ty
+excepthandler(expr_ty type, expr_ty name, asdl_seq * body)
+{
+        excepthandler_ty p;
+        p = (excepthandler_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->type = type;
+        p->name = name;
+        p->body = body;
+        return p;
+}
+
+arguments_ty
+arguments(asdl_seq * args, identifier vararg, identifier kwarg, asdl_seq *
+          defaults)
+{
+        arguments_ty p;
+        p = (arguments_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->args = args;
+        p->vararg = vararg;
+        p->kwarg = kwarg;
+        p->defaults = defaults;
+        return p;
+}
+
+keyword_ty
+keyword(identifier arg, expr_ty value)
+{
+        keyword_ty p;
+        if (!arg) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field arg is required for keyword");
+                return NULL;
+        }
+        if (!value) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field value is required for keyword");
+                return NULL;
+        }
+        p = (keyword_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->arg = arg;
+        p->value = value;
+        return p;
+}
+
+alias_ty
+alias(identifier name, identifier asname)
+{
+        alias_ty p;
+        if (!name) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field name is required for alias");
+                return NULL;
+        }
+        p = (alias_ty)malloc(sizeof(*p));
+        if (!p) {
+                PyErr_SetString(PyExc_MemoryError, "no memory");
+                return NULL;
+        }
+        p->name = name;
+        p->asname = asname;
+        return p;
+}
+
+static void
+free_seq_exprs(asdl_seq *seq)
+{
+        int i, n;
+        n = asdl_seq_LEN(seq);
+        for (i = 0; i < n; i++)
+                free_expr((expr_ty)asdl_seq_GET(seq, i));
+        asdl_seq_free(seq);
+}
+
+static void
+free_seq_stmts(asdl_seq *seq)
+{
+        int i, n;
+        n = asdl_seq_LEN(seq);
+        for (i = 0; i < n; i++)
+                free_stmt((stmt_ty)asdl_seq_GET(seq, i));
+        asdl_seq_free(seq);
+}
+
+void
+free_mod(mod_ty o)
+{
+        if (!o)
+                return;
+
+        switch (o->kind) {
+        case Module_kind:
+                free_seq_stmts(o->v.Module.body);
+                break;
+        case Interactive_kind:
+                free_seq_stmts(o->v.Interactive.body);
+                break;
+        case Expression_kind:
+                free_expr((expr_ty)o->v.Expression.body);
+                break;
+        case Suite_kind:
+                free_seq_stmts(o->v.Suite.body);
+                break;
+        }
+
+        free(o);
+}
+
+void
+free_stmt(stmt_ty o)
+{
+        int i, n;
+        asdl_seq *seq;
+
+        if (!o)
+                return;
+
+        switch (o->kind) {
+        case FunctionDef_kind:
+                Py_DECREF((identifier)o->v.FunctionDef.name);
+                free_arguments((arguments_ty)o->v.FunctionDef.args);
+                free_seq_stmts(o->v.FunctionDef.body);
+                free_seq_exprs(o->v.FunctionDef.decorators);
+                break;
+        case ClassDef_kind:
+                Py_DECREF((identifier)o->v.ClassDef.name);
+                free_seq_exprs(o->v.ClassDef.bases);
+                free_seq_stmts(o->v.ClassDef.body);
+                break;
+        case Return_kind:
+                if (o->v.Return.value) {
+                        free_expr((expr_ty)o->v.Return.value);
+                }
+                break;
+        case Delete_kind:
+                free_seq_exprs(o->v.Delete.targets);
+                break;
+        case Assign_kind:
+                free_seq_exprs(o->v.Assign.targets);
+                free_expr((expr_ty)o->v.Assign.value);
+                break;
+        case AugAssign_kind:
+                free_expr((expr_ty)o->v.AugAssign.target);
+                free_operator((operator_ty)o->v.AugAssign.op);
+                free_expr((expr_ty)o->v.AugAssign.value);
+                break;
+        case Print_kind:
+                if (o->v.Print.dest) {
+                        free_expr((expr_ty)o->v.Print.dest);
+                }
+                free_seq_exprs(o->v.Print.values);
+                break;
+        case For_kind:
+                free_expr((expr_ty)o->v.For.target);
+                free_expr((expr_ty)o->v.For.iter);
+                free_seq_stmts(o->v.For.body);
+                free_seq_stmts(o->v.For.orelse);
+                break;
+        case While_kind:
+                free_expr((expr_ty)o->v.While.test);
+                free_seq_stmts(o->v.While.body);
+                free_seq_stmts(o->v.While.orelse);
+                break;
+        case If_kind:
+                free_expr((expr_ty)o->v.If.test);
+                free_seq_stmts(o->v.If.body);
+                free_seq_stmts(o->v.If.orelse);
+                break;
+        case Raise_kind:
+                if (o->v.Raise.type) {
+                        free_expr((expr_ty)o->v.Raise.type);
+                }
+                if (o->v.Raise.inst) {
+                        free_expr((expr_ty)o->v.Raise.inst);
+                }
+                if (o->v.Raise.tback) {
+                        free_expr((expr_ty)o->v.Raise.tback);
+                }
+                break;
+        case TryExcept_kind:
+                free_seq_stmts(o->v.TryExcept.body);
+                seq = o->v.TryExcept.handlers;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_excepthandler((excepthandler_ty)asdl_seq_GET(seq,
+                                           i));
+                asdl_seq_free(seq);
+                free_seq_stmts(o->v.TryExcept.orelse);
+                break;
+        case TryFinally_kind:
+                free_seq_stmts(o->v.TryFinally.body);
+                free_seq_stmts(o->v.TryFinally.finalbody);
+                break;
+        case Assert_kind:
+                free_expr((expr_ty)o->v.Assert.test);
+                if (o->v.Assert.msg) {
+                        free_expr((expr_ty)o->v.Assert.msg);
+                }
+                break;
+        case Import_kind:
+                seq = o->v.Import.names;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_alias((alias_ty)asdl_seq_GET(seq, i));
+                asdl_seq_free(seq);
+                break;
+        case ImportFrom_kind:
+                Py_DECREF((identifier)o->v.ImportFrom.module);
+                seq = o->v.ImportFrom.names;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_alias((alias_ty)asdl_seq_GET(seq, i));
+                asdl_seq_free(seq);
+                break;
+        case Exec_kind:
+                free_expr((expr_ty)o->v.Exec.body);
+                if (o->v.Exec.globals) {
+                        free_expr((expr_ty)o->v.Exec.globals);
+                }
+                if (o->v.Exec.locals) {
+                        free_expr((expr_ty)o->v.Exec.locals);
+                }
+                break;
+        case Global_kind:
+                seq = o->v.Global.names;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        Py_DECREF((identifier)asdl_seq_GET(seq, i));
+                asdl_seq_free(seq);
+                break;
+        case Expr_kind:
+                free_expr((expr_ty)o->v.Expr.value);
+                break;
+        case Pass_kind:
+                break;
+        case Break_kind:
+                break;
+        case Continue_kind:
+                break;
+        }
+
+        free(o);
+}
+
+void
+free_expr(expr_ty o)
+{
+        int i, n;
+        asdl_seq *seq;
+
+        if (!o)
+                return;
+
+        switch (o->kind) {
+        case BoolOp_kind:
+                free_boolop((boolop_ty)o->v.BoolOp.op);
+                free_seq_exprs(o->v.BoolOp.values);
+                break;
+        case BinOp_kind:
+                free_expr((expr_ty)o->v.BinOp.left);
+                free_operator((operator_ty)o->v.BinOp.op);
+                free_expr((expr_ty)o->v.BinOp.right);
+                break;
+        case UnaryOp_kind:
+                free_unaryop((unaryop_ty)o->v.UnaryOp.op);
+                free_expr((expr_ty)o->v.UnaryOp.operand);
+                break;
+        case Lambda_kind:
+                free_arguments((arguments_ty)o->v.Lambda.args);
+                free_expr((expr_ty)o->v.Lambda.body);
+                break;
+        case Dict_kind:
+                free_seq_exprs(o->v.Dict.keys);
+                free_seq_exprs(o->v.Dict.values);
+                break;
+        case ListComp_kind:
+                free_expr((expr_ty)o->v.ListComp.elt);
+                seq = o->v.ListComp.generators;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_comprehension((comprehension_ty)asdl_seq_GET(seq,
+                                           i));
+                asdl_seq_free(seq);
+                break;
+        case GeneratorExp_kind:
+                free_expr((expr_ty)o->v.GeneratorExp.elt);
+                seq = o->v.GeneratorExp.generators;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_comprehension((comprehension_ty)asdl_seq_GET(seq,
+                                           i));
+                asdl_seq_free(seq);
+                break;
+        case Yield_kind:
+                if (o->v.Yield.value) {
+                        free_expr((expr_ty)o->v.Yield.value);
+                }
+                break;
+        case Compare_kind:
+                free_expr((expr_ty)o->v.Compare.left);
+                seq = o->v.Compare.ops;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_cmpop((cmpop_ty)asdl_seq_GET(seq, i));
+                asdl_seq_free(seq);
+                free_seq_exprs(o->v.Compare.comparators);
+                break;
+        case Call_kind:
+                free_expr((expr_ty)o->v.Call.func);
+                free_seq_exprs(o->v.Call.args);
+                seq = o->v.Call.keywords;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_keyword((keyword_ty)asdl_seq_GET(seq, i));
+                asdl_seq_free(seq);
+                if (o->v.Call.starargs) {
+                        free_expr((expr_ty)o->v.Call.starargs);
+                }
+                if (o->v.Call.kwargs) {
+                        free_expr((expr_ty)o->v.Call.kwargs);
+                }
+                break;
+        case Repr_kind:
+                free_expr((expr_ty)o->v.Repr.value);
+                break;
+        case Num_kind:
+                Py_DECREF((object)o->v.Num.n);
+                break;
+        case Str_kind:
+                Py_DECREF((string)o->v.Str.s);
+                break;
+        case Attribute_kind:
+                free_expr((expr_ty)o->v.Attribute.value);
+                Py_DECREF((identifier)o->v.Attribute.attr);
+                free_expr_context((expr_context_ty)o->v.Attribute.ctx);
+                break;
+        case Subscript_kind:
+                free_expr((expr_ty)o->v.Subscript.value);
+                free_slice((slice_ty)o->v.Subscript.slice);
+                free_expr_context((expr_context_ty)o->v.Subscript.ctx);
+                break;
+        case Name_kind:
+                Py_DECREF((identifier)o->v.Name.id);
+                free_expr_context((expr_context_ty)o->v.Name.ctx);
+                break;
+        case List_kind:
+                free_seq_exprs(o->v.List.elts);
+                free_expr_context((expr_context_ty)o->v.List.ctx);
+                break;
+        case Tuple_kind:
+                free_seq_exprs(o->v.Tuple.elts);
+                free_expr_context((expr_context_ty)o->v.Tuple.ctx);
+                break;
+        }
+
+        free(o);
+}
+
+void
+free_expr_context(expr_context_ty o)
+{
+        if (!o)
+                return;
+
+}
+
+void
+free_slice(slice_ty o)
+{
+        int i, n;
+        asdl_seq *seq;
+
+        if (!o)
+                return;
+
+        switch (o->kind) {
+        case Ellipsis_kind:
+                break;
+        case Slice_kind:
+                if (o->v.Slice.lower) {
+                        free_expr((expr_ty)o->v.Slice.lower);
+                }
+                if (o->v.Slice.upper) {
+                        free_expr((expr_ty)o->v.Slice.upper);
+                }
+                if (o->v.Slice.step) {
+                        free_expr((expr_ty)o->v.Slice.step);
+                }
+                break;
+        case ExtSlice_kind:
+                seq = o->v.ExtSlice.dims;
+                n = asdl_seq_LEN(seq);
+                for (i = 0; i < n; i++)
+                        free_slice((slice_ty)asdl_seq_GET(seq, i));
+                asdl_seq_free(seq);
+                break;
+        case Index_kind:
+                free_expr((expr_ty)o->v.Index.value);
+                break;
+        }
+
+        free(o);
+}
+
+void
+free_boolop(boolop_ty o)
+{
+        if (!o)
+                return;
+
+}
+
+void
+free_operator(operator_ty o)
+{
+        if (!o)
+                return;
+
+}
+
+void
+free_unaryop(unaryop_ty o)
+{
+        if (!o)
+                return;
+
+}
+
+void
+free_cmpop(cmpop_ty o)
+{
+        if (!o)
+                return;
+
+}
+
+void
+free_comprehension(comprehension_ty o)
+{
+        if (!o)
+                return;
+
+        free_expr((expr_ty)o->target);
+        free_expr((expr_ty)o->iter);
+        free_seq_exprs(o->ifs);
+
+        free(o);
+}
+
+void
+free_excepthandler(excepthandler_ty o)
+{
+        if (!o)
+                return;
+
+        if (o->type) {
+                free_expr((expr_ty)o->type);
+        }
+        if (o->name) {
+                free_expr((expr_ty)o->name);
+        }
+        free_seq_stmts(o->body);
+
+        free(o);
+}
+
+void
+free_arguments(arguments_ty o)
+{
+        if (!o)
+                return;
+
+        free_seq_exprs(o->args);
+        if (o->vararg) {
+                Py_DECREF((identifier)o->vararg);
+        }
+        if (o->kwarg) {
+                Py_DECREF((identifier)o->kwarg);
+        }
+        free_seq_exprs(o->defaults);
+
+        free(o);
+}
+
+void
+free_keyword(keyword_ty o)
+{
+        if (!o)
+                return;
+
+        Py_DECREF((identifier)o->arg);
+        free_expr((expr_ty)o->value);
+
+        free(o);
+}
+
+void
+free_alias(alias_ty o)
+{
+        if (!o)
+                return;
+
+        Py_DECREF((identifier)o->name);
+        if (o->asname) {
+                Py_DECREF((identifier)o->asname);
+        }
+
+        free(o);
+}
+
+int
+marshal_write_mod(PyObject **buf, int *off, mod_ty o)
+{
+        int i;
+        switch (o->kind) {
+        case Module_kind:
+                marshal_write_int(buf, off, 1);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Module.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.Module.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.Module.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case Interactive_kind:
+                marshal_write_int(buf, off, 2);
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.Interactive.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.Interactive.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.Interactive.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case Expression_kind:
+                marshal_write_int(buf, off, 3);
+                marshal_write_expr(buf, off, o->v.Expression.body);
+                break;
+        case Suite_kind:
+                marshal_write_int(buf, off, 4);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Suite.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.Suite.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.Suite.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_stmt(PyObject **buf, int *off, stmt_ty o)
+{
+        int i;
+        switch (o->kind) {
+        case FunctionDef_kind:
+                marshal_write_int(buf, off, 1);
+                marshal_write_identifier(buf, off, o->v.FunctionDef.name);
+                marshal_write_arguments(buf, off, o->v.FunctionDef.args);
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.FunctionDef.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.FunctionDef.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.FunctionDef.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.FunctionDef.decorators));
+                for (i = 0; i < asdl_seq_LEN(o->v.FunctionDef.decorators); i++)
+                     {
+                        void *elt = asdl_seq_GET(o->v.FunctionDef.decorators,
+                                                 i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                break;
+        case ClassDef_kind:
+                marshal_write_int(buf, off, 2);
+                marshal_write_identifier(buf, off, o->v.ClassDef.name);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.ClassDef.bases));
+                for (i = 0; i < asdl_seq_LEN(o->v.ClassDef.bases); i++) {
+                        void *elt = asdl_seq_GET(o->v.ClassDef.bases, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.ClassDef.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.ClassDef.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.ClassDef.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case Return_kind:
+                marshal_write_int(buf, off, 3);
+                if (o->v.Return.value) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Return.value);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case Delete_kind:
+                marshal_write_int(buf, off, 4);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Delete.targets));
+                for (i = 0; i < asdl_seq_LEN(o->v.Delete.targets); i++) {
+                        void *elt = asdl_seq_GET(o->v.Delete.targets, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                break;
+        case Assign_kind:
+                marshal_write_int(buf, off, 5);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Assign.targets));
+                for (i = 0; i < asdl_seq_LEN(o->v.Assign.targets); i++) {
+                        void *elt = asdl_seq_GET(o->v.Assign.targets, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_expr(buf, off, o->v.Assign.value);
+                break;
+        case AugAssign_kind:
+                marshal_write_int(buf, off, 6);
+                marshal_write_expr(buf, off, o->v.AugAssign.target);
+                marshal_write_operator(buf, off, o->v.AugAssign.op);
+                marshal_write_expr(buf, off, o->v.AugAssign.value);
+                break;
+        case Print_kind:
+                marshal_write_int(buf, off, 7);
+                if (o->v.Print.dest) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Print.dest);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Print.values));
+                for (i = 0; i < asdl_seq_LEN(o->v.Print.values); i++) {
+                        void *elt = asdl_seq_GET(o->v.Print.values, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_bool(buf, off, o->v.Print.nl);
+                break;
+        case For_kind:
+                marshal_write_int(buf, off, 8);
+                marshal_write_expr(buf, off, o->v.For.target);
+                marshal_write_expr(buf, off, o->v.For.iter);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.For.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.For.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.For.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.For.orelse));
+                for (i = 0; i < asdl_seq_LEN(o->v.For.orelse); i++) {
+                        void *elt = asdl_seq_GET(o->v.For.orelse, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case While_kind:
+                marshal_write_int(buf, off, 9);
+                marshal_write_expr(buf, off, o->v.While.test);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.While.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.While.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.While.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.While.orelse));
+                for (i = 0; i < asdl_seq_LEN(o->v.While.orelse); i++) {
+                        void *elt = asdl_seq_GET(o->v.While.orelse, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case If_kind:
+                marshal_write_int(buf, off, 10);
+                marshal_write_expr(buf, off, o->v.If.test);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.If.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.If.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.If.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.If.orelse));
+                for (i = 0; i < asdl_seq_LEN(o->v.If.orelse); i++) {
+                        void *elt = asdl_seq_GET(o->v.If.orelse, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case Raise_kind:
+                marshal_write_int(buf, off, 11);
+                if (o->v.Raise.type) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Raise.type);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                if (o->v.Raise.inst) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Raise.inst);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                if (o->v.Raise.tback) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Raise.tback);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case TryExcept_kind:
+                marshal_write_int(buf, off, 12);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.TryExcept.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.TryExcept.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.TryExcept.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.TryExcept.handlers));
+                for (i = 0; i < asdl_seq_LEN(o->v.TryExcept.handlers); i++) {
+                        void *elt = asdl_seq_GET(o->v.TryExcept.handlers, i);
+                        marshal_write_excepthandler(buf, off,
+                                                    (excepthandler_ty)elt);
+                }
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.TryExcept.orelse));
+                for (i = 0; i < asdl_seq_LEN(o->v.TryExcept.orelse); i++) {
+                        void *elt = asdl_seq_GET(o->v.TryExcept.orelse, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case TryFinally_kind:
+                marshal_write_int(buf, off, 13);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.TryFinally.body));
+                for (i = 0; i < asdl_seq_LEN(o->v.TryFinally.body); i++) {
+                        void *elt = asdl_seq_GET(o->v.TryFinally.body, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.TryFinally.finalbody));
+                for (i = 0; i < asdl_seq_LEN(o->v.TryFinally.finalbody); i++) {
+                        void *elt = asdl_seq_GET(o->v.TryFinally.finalbody, i);
+                        marshal_write_stmt(buf, off, (stmt_ty)elt);
+                }
+                break;
+        case Assert_kind:
+                marshal_write_int(buf, off, 14);
+                marshal_write_expr(buf, off, o->v.Assert.test);
+                if (o->v.Assert.msg) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Assert.msg);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case Import_kind:
+                marshal_write_int(buf, off, 15);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Import.names));
+                for (i = 0; i < asdl_seq_LEN(o->v.Import.names); i++) {
+                        void *elt = asdl_seq_GET(o->v.Import.names, i);
+                        marshal_write_alias(buf, off, (alias_ty)elt);
+                }
+                break;
+        case ImportFrom_kind:
+                marshal_write_int(buf, off, 16);
+                marshal_write_identifier(buf, off, o->v.ImportFrom.module);
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.ImportFrom.names));
+                for (i = 0; i < asdl_seq_LEN(o->v.ImportFrom.names); i++) {
+                        void *elt = asdl_seq_GET(o->v.ImportFrom.names, i);
+                        marshal_write_alias(buf, off, (alias_ty)elt);
+                }
+                break;
+        case Exec_kind:
+                marshal_write_int(buf, off, 17);
+                marshal_write_expr(buf, off, o->v.Exec.body);
+                if (o->v.Exec.globals) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Exec.globals);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                if (o->v.Exec.locals) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Exec.locals);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case Global_kind:
+                marshal_write_int(buf, off, 18);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Global.names));
+                for (i = 0; i < asdl_seq_LEN(o->v.Global.names); i++) {
+                        void *elt = asdl_seq_GET(o->v.Global.names, i);
+                        marshal_write_identifier(buf, off, (identifier)elt);
+                }
+                break;
+        case Expr_kind:
+                marshal_write_int(buf, off, 19);
+                marshal_write_expr(buf, off, o->v.Expr.value);
+                break;
+        case Pass_kind:
+                marshal_write_int(buf, off, 20);
+                break;
+        case Break_kind:
+                marshal_write_int(buf, off, 21);
+                break;
+        case Continue_kind:
+                marshal_write_int(buf, off, 22);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_expr(PyObject **buf, int *off, expr_ty o)
+{
+        int i;
+        switch (o->kind) {
+        case BoolOp_kind:
+                marshal_write_int(buf, off, 1);
+                marshal_write_boolop(buf, off, o->v.BoolOp.op);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.BoolOp.values));
+                for (i = 0; i < asdl_seq_LEN(o->v.BoolOp.values); i++) {
+                        void *elt = asdl_seq_GET(o->v.BoolOp.values, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                break;
+        case BinOp_kind:
+                marshal_write_int(buf, off, 2);
+                marshal_write_expr(buf, off, o->v.BinOp.left);
+                marshal_write_operator(buf, off, o->v.BinOp.op);
+                marshal_write_expr(buf, off, o->v.BinOp.right);
+                break;
+        case UnaryOp_kind:
+                marshal_write_int(buf, off, 3);
+                marshal_write_unaryop(buf, off, o->v.UnaryOp.op);
+                marshal_write_expr(buf, off, o->v.UnaryOp.operand);
+                break;
+        case Lambda_kind:
+                marshal_write_int(buf, off, 4);
+                marshal_write_arguments(buf, off, o->v.Lambda.args);
+                marshal_write_expr(buf, off, o->v.Lambda.body);
+                break;
+        case Dict_kind:
+                marshal_write_int(buf, off, 5);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Dict.keys));
+                for (i = 0; i < asdl_seq_LEN(o->v.Dict.keys); i++) {
+                        void *elt = asdl_seq_GET(o->v.Dict.keys, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Dict.values));
+                for (i = 0; i < asdl_seq_LEN(o->v.Dict.values); i++) {
+                        void *elt = asdl_seq_GET(o->v.Dict.values, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                break;
+        case ListComp_kind:
+                marshal_write_int(buf, off, 6);
+                marshal_write_expr(buf, off, o->v.ListComp.elt);
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.ListComp.generators));
+                for (i = 0; i < asdl_seq_LEN(o->v.ListComp.generators); i++) {
+                        void *elt = asdl_seq_GET(o->v.ListComp.generators, i);
+                        marshal_write_comprehension(buf, off,
+                                                    (comprehension_ty)elt);
+                }
+                break;
+        case GeneratorExp_kind:
+                marshal_write_int(buf, off, 7);
+                marshal_write_expr(buf, off, o->v.GeneratorExp.elt);
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.GeneratorExp.generators));
+                for (i = 0; i < asdl_seq_LEN(o->v.GeneratorExp.generators);
+                     i++) {
+                        void *elt = asdl_seq_GET(o->v.GeneratorExp.generators,
+                                                 i);
+                        marshal_write_comprehension(buf, off,
+                                                    (comprehension_ty)elt);
+                }
+                break;
+        case Yield_kind:
+                marshal_write_int(buf, off, 8);
+                if (o->v.Yield.value) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Yield.value);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case Compare_kind:
+                marshal_write_int(buf, off, 9);
+                marshal_write_expr(buf, off, o->v.Compare.left);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Compare.ops));
+                for (i = 0; i < asdl_seq_LEN(o->v.Compare.ops); i++) {
+                        void *elt = asdl_seq_GET(o->v.Compare.ops, i);
+                        marshal_write_cmpop(buf, off, (cmpop_ty)elt);
+                }
+                marshal_write_int(buf, off,
+                                  asdl_seq_LEN(o->v.Compare.comparators));
+                for (i = 0; i < asdl_seq_LEN(o->v.Compare.comparators); i++) {
+                        void *elt = asdl_seq_GET(o->v.Compare.comparators, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                break;
+        case Call_kind:
+                marshal_write_int(buf, off, 10);
+                marshal_write_expr(buf, off, o->v.Call.func);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Call.args));
+                for (i = 0; i < asdl_seq_LEN(o->v.Call.args); i++) {
+                        void *elt = asdl_seq_GET(o->v.Call.args, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Call.keywords));
+                for (i = 0; i < asdl_seq_LEN(o->v.Call.keywords); i++) {
+                        void *elt = asdl_seq_GET(o->v.Call.keywords, i);
+                        marshal_write_keyword(buf, off, (keyword_ty)elt);
+                }
+                if (o->v.Call.starargs) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Call.starargs);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                if (o->v.Call.kwargs) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Call.kwargs);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case Repr_kind:
+                marshal_write_int(buf, off, 11);
+                marshal_write_expr(buf, off, o->v.Repr.value);
+                break;
+        case Num_kind:
+                marshal_write_int(buf, off, 12);
+                marshal_write_object(buf, off, o->v.Num.n);
+                break;
+        case Str_kind:
+                marshal_write_int(buf, off, 13);
+                marshal_write_string(buf, off, o->v.Str.s);
+                break;
+        case Attribute_kind:
+                marshal_write_int(buf, off, 14);
+                marshal_write_expr(buf, off, o->v.Attribute.value);
+                marshal_write_identifier(buf, off, o->v.Attribute.attr);
+                marshal_write_expr_context(buf, off, o->v.Attribute.ctx);
+                break;
+        case Subscript_kind:
+                marshal_write_int(buf, off, 15);
+                marshal_write_expr(buf, off, o->v.Subscript.value);
+                marshal_write_slice(buf, off, o->v.Subscript.slice);
+                marshal_write_expr_context(buf, off, o->v.Subscript.ctx);
+                break;
+        case Name_kind:
+                marshal_write_int(buf, off, 16);
+                marshal_write_identifier(buf, off, o->v.Name.id);
+                marshal_write_expr_context(buf, off, o->v.Name.ctx);
+                break;
+        case List_kind:
+                marshal_write_int(buf, off, 17);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.List.elts));
+                for (i = 0; i < asdl_seq_LEN(o->v.List.elts); i++) {
+                        void *elt = asdl_seq_GET(o->v.List.elts, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_expr_context(buf, off, o->v.List.ctx);
+                break;
+        case Tuple_kind:
+                marshal_write_int(buf, off, 18);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.Tuple.elts));
+                for (i = 0; i < asdl_seq_LEN(o->v.Tuple.elts); i++) {
+                        void *elt = asdl_seq_GET(o->v.Tuple.elts, i);
+                        marshal_write_expr(buf, off, (expr_ty)elt);
+                }
+                marshal_write_expr_context(buf, off, o->v.Tuple.ctx);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_expr_context(PyObject **buf, int *off, expr_context_ty o)
+{
+        int i;
+        switch (o) {
+        case Load:
+                marshal_write_int(buf, off, 1);
+                break;
+        case Store:
+                marshal_write_int(buf, off, 2);
+                break;
+        case Del:
+                marshal_write_int(buf, off, 3);
+                break;
+        case AugLoad:
+                marshal_write_int(buf, off, 4);
+                break;
+        case AugStore:
+                marshal_write_int(buf, off, 5);
+                break;
+        case Param:
+                marshal_write_int(buf, off, 6);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_slice(PyObject **buf, int *off, slice_ty o)
+{
+        int i;
+        switch (o->kind) {
+        case Ellipsis_kind:
+                marshal_write_int(buf, off, 1);
+                break;
+        case Slice_kind:
+                marshal_write_int(buf, off, 2);
+                if (o->v.Slice.lower) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Slice.lower);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                if (o->v.Slice.upper) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Slice.upper);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                if (o->v.Slice.step) {
+                        marshal_write_int(buf, off, 1);
+                        marshal_write_expr(buf, off, o->v.Slice.step);
+                }
+                else {
+                        marshal_write_int(buf, off, 0);
+                }
+                break;
+        case ExtSlice_kind:
+                marshal_write_int(buf, off, 3);
+                marshal_write_int(buf, off, asdl_seq_LEN(o->v.ExtSlice.dims));
+                for (i = 0; i < asdl_seq_LEN(o->v.ExtSlice.dims); i++) {
+                        void *elt = asdl_seq_GET(o->v.ExtSlice.dims, i);
+                        marshal_write_slice(buf, off, (slice_ty)elt);
+                }
+                break;
+        case Index_kind:
+                marshal_write_int(buf, off, 4);
+                marshal_write_expr(buf, off, o->v.Index.value);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_boolop(PyObject **buf, int *off, boolop_ty o)
+{
+        int i;
+        switch (o) {
+        case And:
+                marshal_write_int(buf, off, 1);
+                break;
+        case Or:
+                marshal_write_int(buf, off, 2);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_operator(PyObject **buf, int *off, operator_ty o)
+{
+        int i;
+        switch (o) {
+        case Add:
+                marshal_write_int(buf, off, 1);
+                break;
+        case Sub:
+                marshal_write_int(buf, off, 2);
+                break;
+        case Mult:
+                marshal_write_int(buf, off, 3);
+                break;
+        case Div:
+                marshal_write_int(buf, off, 4);
+                break;
+        case Mod:
+                marshal_write_int(buf, off, 5);
+                break;
+        case Pow:
+                marshal_write_int(buf, off, 6);
+                break;
+        case LShift:
+                marshal_write_int(buf, off, 7);
+                break;
+        case RShift:
+                marshal_write_int(buf, off, 8);
+                break;
+        case BitOr:
+                marshal_write_int(buf, off, 9);
+                break;
+        case BitXor:
+                marshal_write_int(buf, off, 10);
+                break;
+        case BitAnd:
+                marshal_write_int(buf, off, 11);
+                break;
+        case FloorDiv:
+                marshal_write_int(buf, off, 12);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_unaryop(PyObject **buf, int *off, unaryop_ty o)
+{
+        int i;
+        switch (o) {
+        case Invert:
+                marshal_write_int(buf, off, 1);
+                break;
+        case Not:
+                marshal_write_int(buf, off, 2);
+                break;
+        case UAdd:
+                marshal_write_int(buf, off, 3);
+                break;
+        case USub:
+                marshal_write_int(buf, off, 4);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_cmpop(PyObject **buf, int *off, cmpop_ty o)
+{
+        int i;
+        switch (o) {
+        case Eq:
+                marshal_write_int(buf, off, 1);
+                break;
+        case NotEq:
+                marshal_write_int(buf, off, 2);
+                break;
+        case Lt:
+                marshal_write_int(buf, off, 3);
+                break;
+        case LtE:
+                marshal_write_int(buf, off, 4);
+                break;
+        case Gt:
+                marshal_write_int(buf, off, 5);
+                break;
+        case GtE:
+                marshal_write_int(buf, off, 6);
+                break;
+        case Is:
+                marshal_write_int(buf, off, 7);
+                break;
+        case IsNot:
+                marshal_write_int(buf, off, 8);
+                break;
+        case In:
+                marshal_write_int(buf, off, 9);
+                break;
+        case NotIn:
+                marshal_write_int(buf, off, 10);
+                break;
+        }
+        return 1;
+}
+
+int
+marshal_write_comprehension(PyObject **buf, int *off, comprehension_ty o)
+{
+        int i;
+        marshal_write_expr(buf, off, o->target);
+        marshal_write_expr(buf, off, o->iter);
+        marshal_write_int(buf, off, asdl_seq_LEN(o->ifs));
+        for (i = 0; i < asdl_seq_LEN(o->ifs); i++) {
+                void *elt = asdl_seq_GET(o->ifs, i);
+                marshal_write_expr(buf, off, (expr_ty)elt);
+        }
+        return 1;
+}
+
+int
+marshal_write_excepthandler(PyObject **buf, int *off, excepthandler_ty o)
+{
+        int i;
+        if (o->type) {
+                marshal_write_int(buf, off, 1);
+                marshal_write_expr(buf, off, o->type);
+        }
+        else {
+                marshal_write_int(buf, off, 0);
+        }
+        if (o->name) {
+                marshal_write_int(buf, off, 1);
+                marshal_write_expr(buf, off, o->name);
+        }
+        else {
+                marshal_write_int(buf, off, 0);
+        }
+        marshal_write_int(buf, off, asdl_seq_LEN(o->body));
+        for (i = 0; i < asdl_seq_LEN(o->body); i++) {
+                void *elt = asdl_seq_GET(o->body, i);
+                marshal_write_stmt(buf, off, (stmt_ty)elt);
+        }
+        return 1;
+}
+
+int
+marshal_write_arguments(PyObject **buf, int *off, arguments_ty o)
+{
+        int i;
+        marshal_write_int(buf, off, asdl_seq_LEN(o->args));
+        for (i = 0; i < asdl_seq_LEN(o->args); i++) {
+                void *elt = asdl_seq_GET(o->args, i);
+                marshal_write_expr(buf, off, (expr_ty)elt);
+        }
+        if (o->vararg) {
+                marshal_write_int(buf, off, 1);
+                marshal_write_identifier(buf, off, o->vararg);
+        }
+        else {
+                marshal_write_int(buf, off, 0);
+        }
+        if (o->kwarg) {
+                marshal_write_int(buf, off, 1);
+                marshal_write_identifier(buf, off, o->kwarg);
+        }
+        else {
+                marshal_write_int(buf, off, 0);
+        }
+        marshal_write_int(buf, off, asdl_seq_LEN(o->defaults));
+        for (i = 0; i < asdl_seq_LEN(o->defaults); i++) {
+                void *elt = asdl_seq_GET(o->defaults, i);
+                marshal_write_expr(buf, off, (expr_ty)elt);
+        }
+        return 1;
+}
+
+int
+marshal_write_keyword(PyObject **buf, int *off, keyword_ty o)
+{
+        int i;
+        marshal_write_identifier(buf, off, o->arg);
+        marshal_write_expr(buf, off, o->value);
+        return 1;
+}
+
+int
+marshal_write_alias(PyObject **buf, int *off, alias_ty o)
+{
+        int i;
+        marshal_write_identifier(buf, off, o->name);
+        if (o->asname) {
+                marshal_write_int(buf, off, 1);
+                marshal_write_identifier(buf, off, o->asname);
+        }
+        else {
+                marshal_write_int(buf, off, 0);
+        }
+        return 1;
+}
+
diff --git a/Python/asdl.c b/Python/asdl.c
new file mode 100644 (file)
index 0000000..bb29857
--- /dev/null
@@ -0,0 +1,92 @@
+#include "Python.h"
+#include "asdl.h"
+
+asdl_seq *
+asdl_seq_new(int size)
+{
+       asdl_seq *seq = NULL;
+       size_t n = sizeof(asdl_seq) +
+                       (size ? (sizeof(void *) * (size - 1)) : 0);
+
+       seq = (asdl_seq *)PyObject_Malloc(n);
+       if (!seq) {
+               PyErr_SetString(PyExc_MemoryError, "no memory");
+               return NULL;
+       }
+       memset(seq, 0, n);
+       seq->size = size;
+       return seq;
+}
+
+void
+asdl_seq_free(asdl_seq *seq)
+{
+       PyObject_Free(seq);
+}
+
+#define CHECKSIZE(BUF, OFF, MIN) { \
+       int need = *(OFF) + MIN; \
+       if (need >= PyString_GET_SIZE(*(BUF))) { \
+               int newsize = PyString_GET_SIZE(*(BUF)) * 2; \
+               if (newsize < need) \
+                       newsize = need; \
+               if (_PyString_Resize((BUF), newsize) < 0) \
+                       return 0; \
+       } \
+} 
+
+int 
+marshal_write_int(PyObject **buf, int *offset, int x)
+{
+       char *s;
+
+       CHECKSIZE(buf, offset, 4)
+       s = PyString_AS_STRING(*buf) + (*offset);
+       s[0] = (x & 0xff);
+       s[1] = (x >> 8) & 0xff;
+       s[2] = (x >> 16) & 0xff;
+       s[3] = (x >> 24) & 0xff;
+       *offset += 4;
+       return 1;
+}
+
+int 
+marshal_write_bool(PyObject **buf, int *offset, bool b)
+{
+       if (b)
+               marshal_write_int(buf, offset, 1);
+       else
+               marshal_write_int(buf, offset, 0);
+       return 1;
+}
+
+int 
+marshal_write_identifier(PyObject **buf, int *offset, identifier id)
+{
+       int l = PyString_GET_SIZE(id);
+       marshal_write_int(buf, offset, l);
+       CHECKSIZE(buf, offset, l);
+       memcpy(PyString_AS_STRING(*buf) + *offset,
+              PyString_AS_STRING(id), l);
+       *offset += l;
+       return 1;
+}
+
+int 
+marshal_write_string(PyObject **buf, int *offset, string s)
+{
+       int len = PyString_GET_SIZE(s);
+       marshal_write_int(buf, offset, len);
+       CHECKSIZE(buf, offset, len);
+       memcpy(PyString_AS_STRING(*buf) + *offset,
+              PyString_AS_STRING(s), len);
+       *offset += len;
+       return 1;
+}
+
+int 
+marshal_write_object(PyObject **buf, int *offset, object s)
+{
+       /* XXX */
+       return 0;
+}
diff --git a/Python/ast.c b/Python/ast.c
new file mode 100644 (file)
index 0000000..475382c
--- /dev/null
@@ -0,0 +1,3114 @@
+/*
+ * This file includes functions to transform a concrete syntax tree (CST) to
+ * an abstract syntax tree (AST).  The main function is PyAST_FromNode().
+ *
+ */
+#include "Python.h"
+#include "Python-ast.h"
+#include "grammar.h"
+#include "node.h"
+#include "ast.h"
+#include "token.h"
+#include "parsetok.h"
+#include "graminit.h"
+
+#include <assert.h>
+
+#if 0
+#define fprintf if (0) fprintf
+#endif
+
+/* XXX TO DO
+   - re-indent this file (should be done)
+   - internal error checking (freeing memory, etc.)
+   - syntax errors
+*/
+
+
+/* Data structure used internally */
+struct compiling {
+       char *c_encoding; /* source encoding */
+};
+
+static asdl_seq *seq_for_testlist(struct compiling *, const node *);
+static expr_ty ast_for_expr(struct compiling *, const node *);
+static stmt_ty ast_for_stmt(struct compiling *, const node *);
+static asdl_seq *ast_for_suite(struct compiling *, const node *);
+static asdl_seq *ast_for_exprlist(struct compiling *, const node *, int);
+static expr_ty ast_for_testlist(struct compiling *, const node *, int);
+
+/* Note different signature for ast_for_call */
+static expr_ty ast_for_call(struct compiling *, const node *, expr_ty);
+
+static PyObject *parsenumber(const char *);
+static PyObject *parsestr(const char *s, const char *encoding);
+static PyObject *parsestrplus(struct compiling *, const node *n);
+
+extern grammar _PyParser_Grammar; /* From graminit.c */
+
+#ifndef LINENO
+#define LINENO(n)      ((n)->n_lineno)
+#endif
+
+#define NEW_IDENTIFIER(n) PyString_InternFromString(STR(n))
+
+static void
+asdl_stmt_seq_free(asdl_seq* seq)
+{
+    int n, i;
+
+    if (!seq)
+       return;
+             
+    n = asdl_seq_LEN(seq);
+    for (i = 0; i < n; i++)
+       free_stmt(asdl_seq_GET(seq, i));
+    asdl_seq_free(seq);
+}
+
+static void
+asdl_expr_seq_free(asdl_seq* seq)
+{
+    int n, i;
+
+    if (!seq)
+       return;
+             
+    n = asdl_seq_LEN(seq);
+    for (i = 0; i < n; i++)
+       free_expr(asdl_seq_GET(seq, i));
+    asdl_seq_free(seq);
+}
+
+/* This routine provides an invalid object for the syntax error.
+   The outermost routine must unpack this error and create the
+   proper object.  We do this so that we don't have to pass
+   the filename to everything function.
+
+   XXX Maybe we should just pass the filename...
+*/
+
+static int
+ast_error(const node *n, const char *errstr)
+{
+    PyObject *u = Py_BuildValue("zi", errstr, LINENO(n));
+    if (!u)
+       return 0;
+    PyErr_SetObject(PyExc_SyntaxError, u);
+    Py_DECREF(u);
+    return 0;
+}
+
+static void
+ast_error_finish(const char *filename)
+{
+    PyObject *type, *value, *tback, *errstr, *loc, *tmp;
+    int lineno;
+
+    assert(PyErr_Occurred());
+    if (!PyErr_ExceptionMatches(PyExc_SyntaxError))
+       return;
+
+    PyErr_Fetch(&type, &value, &tback);
+    errstr = PyTuple_GetItem(value, 0);
+    if (!errstr)
+       return;
+    Py_INCREF(errstr);
+    lineno = PyInt_AsLong(PyTuple_GetItem(value, 1));
+    if (lineno == -1)
+       return;
+    Py_DECREF(value);
+
+    loc = PyErr_ProgramText(filename, lineno);
+    if (!loc) {
+       Py_INCREF(Py_None);
+       loc = Py_None;
+    }
+    tmp = Py_BuildValue("(ziOO)", filename, lineno, Py_None, loc);
+    Py_DECREF(loc);
+    if (!tmp)
+       return;
+    value = Py_BuildValue("(OO)", errstr, tmp);
+    Py_DECREF(errstr);
+    Py_DECREF(tmp);
+    if (!value)
+       return;
+    PyErr_Restore(type, value, tback);
+}
+
+/* num_stmts() returns number of contained statements.
+
+   Use this routine to determine how big a sequence is needed for
+   the statements in a parse tree.  Its raison d'etre is this bit of
+   grammar:
+
+   stmt: simple_stmt | compound_stmt
+   simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
+
+   A simple_stmt can contain multiple small_stmt elements joined
+   by semicolons.  If the arg is a simple_stmt, the number of
+   small_stmt elements is returned.
+*/
+
+static int
+num_stmts(const node *n)
+{
+    int i, l;
+    node *ch;
+
+    switch (TYPE(n)) {
+        case single_input:
+            if (TYPE(CHILD(n, 0)) == NEWLINE)
+                return 0;
+            else
+                return num_stmts(CHILD(n, 0));
+        case file_input:
+            l = 0;
+            for (i = 0; i < NCH(n); i++) {
+                ch = CHILD(n, i);
+                if (TYPE(ch) == stmt)
+                    l += num_stmts(ch);
+            }
+            return l;
+        case stmt:
+            return num_stmts(CHILD(n, 0));
+        case compound_stmt:
+            return 1;
+        case simple_stmt:
+            return NCH(n) / 2; /* Divide by 2 to remove count of semi-colons */
+        case suite:
+            if (NCH(n) == 1)
+                return num_stmts(CHILD(n, 0));
+            else {
+                l = 0;
+                for (i = 2; i < (NCH(n) - 1); i++)
+                    l += num_stmts(CHILD(n, i));
+                return l;
+            }
+        default: {
+            char buf[128];
+
+            sprintf(buf, "Non-statement found: %d %d\n",
+                    TYPE(n), NCH(n));
+            Py_FatalError(buf);
+        }
+    }
+    assert(0);
+    return 0;
+}
+
+/* Transform the CST rooted at node * to the appropriate AST
+*/
+
+mod_ty
+PyAST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename)
+{
+    int i, j, num;
+    asdl_seq *stmts = NULL;
+    stmt_ty s;
+    node *ch;
+    struct compiling c;
+
+    if (flags && flags->cf_flags & PyCF_SOURCE_IS_UTF8) {
+            c.c_encoding = "utf-8";
+    } else if (TYPE(n) == encoding_decl) {
+        c.c_encoding = STR(n);
+        n = CHILD(n, 0);
+    } else {
+        c.c_encoding = NULL;
+    }
+
+    switch (TYPE(n)) {
+        case file_input:
+            stmts = asdl_seq_new(num_stmts(n));
+            if (!stmts)
+                    return NULL;
+            for (i = 0; i < NCH(n) - 1; i++) {
+                ch = CHILD(n, i);
+                if (TYPE(ch) == NEWLINE)
+                    continue;
+                REQ(ch, stmt);
+                num = num_stmts(ch);
+                if (num == 1) {
+                    s = ast_for_stmt(&c, ch);
+                    if (!s)
+                        goto error;
+                    asdl_seq_APPEND(stmts, s);
+                }
+                else {
+                    ch = CHILD(ch, 0);
+                    REQ(ch, simple_stmt);
+                    for (j = 0; j < num; j++) {
+                        s = ast_for_stmt(&c, CHILD(ch, j * 2));
+                        if (!s)
+                            goto error;
+                        asdl_seq_APPEND(stmts, s);
+                    }
+                }
+            }
+            return Module(stmts);
+        case eval_input: {
+            expr_ty testlist_ast;
+
+            /* XXX Why not gen_for here? */
+            testlist_ast = ast_for_testlist(&c, CHILD(n, 0), 0);
+            if (!testlist_ast)
+                goto error;
+            return Expression(testlist_ast);
+        }
+        case single_input:
+            if (TYPE(CHILD(n, 0)) == NEWLINE) {
+                stmts = asdl_seq_new(1);
+                if (!stmts)
+                   goto error;
+                asdl_seq_SET(stmts, 0, Pass(n->n_lineno));
+                return Interactive(stmts);
+            }
+            else {
+                n = CHILD(n, 0);
+                num = num_stmts(n);
+                stmts = asdl_seq_new(num);
+                if (!stmts)
+                   goto error;
+                if (num == 1) {
+                   stmt_ty s = ast_for_stmt(&c, n);
+                   if (!s)
+                       goto error;
+                    asdl_seq_SET(stmts, 0, s);
+                }
+                else {
+                    /* Only a simple_stmt can contain multiple statements. */
+                    REQ(n, simple_stmt);
+                    for (i = 0; i < NCH(n); i += 2) {
+                        stmt_ty s;
+                        if (TYPE(CHILD(n, i)) == NEWLINE)
+                            break;
+                        s = ast_for_stmt(&c, CHILD(n, i));
+                        if (!s)
+                            goto error;
+                        asdl_seq_SET(stmts, i / 2, s);
+                    }
+                }
+
+                return Interactive(stmts);
+            }
+        default:
+            goto error;
+    }
+ error:
+    if (stmts)
+       asdl_stmt_seq_free(stmts);
+    ast_error_finish(filename);
+    return NULL;
+}
+
+/* Return the AST repr. of the operator represented as syntax (|, ^, etc.)
+*/
+
+static operator_ty
+get_operator(const node *n)
+{
+    switch (TYPE(n)) {
+        case VBAR:
+            return BitOr;
+        case CIRCUMFLEX:
+            return BitXor;
+        case AMPER:
+            return BitAnd;
+        case LEFTSHIFT:
+            return LShift;
+        case RIGHTSHIFT:
+            return RShift;
+        case PLUS:
+            return Add;
+        case MINUS:
+            return Sub;
+        case STAR:
+            return Mult;
+        case SLASH:
+            return Div;
+        case DOUBLESLASH:
+            return FloorDiv;
+        case PERCENT:
+            return Mod;
+        default:
+            return 0;
+    }
+}
+
+/* Set the context ctx for expr_ty e returning 0 on success, -1 on error.
+
+   Only sets context for expr kinds that "can appear in assignment context"
+   (according to ../Parser/Python.asdl).  For other expr kinds, it sets
+   an appropriate syntax error and returns false.
+
+   If e is a sequential type, items in sequence will also have their context
+   set.
+
+*/
+
+static int
+set_context(expr_ty e, expr_context_ty ctx, const node *n)
+{
+    asdl_seq *s = NULL;
+
+    switch (e->kind) {
+        case Attribute_kind:
+           if (ctx == Store &&
+               !strcmp(PyString_AS_STRING(e->v.Attribute.attr), "None")) {
+                   return ast_error(n, "assignment to None");
+           }
+           e->v.Attribute.ctx = ctx;
+           break;
+        case Subscript_kind:
+           e->v.Subscript.ctx = ctx;
+           break;
+        case Name_kind:
+           if (ctx == Store &&
+               !strcmp(PyString_AS_STRING(e->v.Name.id), "None")) {
+                   return ast_error(n, "assignment to None");
+           }
+           e->v.Name.ctx = ctx;
+           break;
+        case List_kind:
+           e->v.List.ctx = ctx;
+           s = e->v.List.elts;
+           break;
+        case Tuple_kind:
+            if (asdl_seq_LEN(e->v.Tuple.elts) == 0) 
+                return ast_error(n, "can't assign to ()");
+           e->v.Tuple.ctx = ctx;
+           s = e->v.Tuple.elts;
+           break;
+        case Call_kind:
+           if (ctx == Store)
+               return ast_error(n, "can't assign to function call");
+           else if (ctx == Del)
+               return ast_error(n, "can't delete function call");
+           else
+               return ast_error(n, "unexpected operation on function call");
+           break;
+        case BinOp_kind:
+            return ast_error(n, "can't assign to operator");
+        case GeneratorExp_kind:
+            return ast_error(n, "assignment to generator expression "
+                             "not possible");
+        case Num_kind:
+        case Str_kind:
+           return ast_error(n, "can't assign to literal");
+        default: {
+          char buf[300];
+          PyOS_snprintf(buf, sizeof(buf), 
+                        "unexpected expression in assignment %d (line %d)", 
+                        e->kind, e->lineno);
+          return ast_error(n, buf);
+       }
+    }
+    /* If the LHS is a list or tuple, we need to set the assignment
+       context for all the tuple elements.  
+    */
+    if (s) {
+       int i;
+
+       for (i = 0; i < asdl_seq_LEN(s); i++) {
+           if (!set_context(asdl_seq_GET(s, i), ctx, n))
+               return 0;
+       }
+    }
+    return 1;
+}
+
+static operator_ty
+ast_for_augassign(const node *n)
+{
+    REQ(n, augassign);
+    n = CHILD(n, 0);
+    switch (STR(n)[0]) {
+        case '+':
+            return Add;
+        case '-':
+            return Sub;
+        case '/':
+            if (STR(n)[1] == '/')
+                return FloorDiv;
+            else
+                return Div;
+        case '%':
+            return Mod;
+        case '<':
+            return LShift;
+        case '>':
+            return RShift;
+        case '&':
+            return BitAnd;
+        case '^':
+            return BitXor;
+        case '|':
+            return BitOr;
+        case '*':
+            if (STR(n)[1] == '*')
+                return Pow;
+            else
+                return Mult;
+        default:
+            PyErr_Format(PyExc_Exception, "invalid augassign: %s", STR(n));
+            return 0;
+    }
+}
+
+static cmpop_ty
+ast_for_comp_op(const node *n)
+{
+    /* comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'
+               |'is' 'not'
+    */
+    REQ(n, comp_op);
+    if (NCH(n) == 1) {
+       n = CHILD(n, 0);
+       switch (TYPE(n)) {
+            case LESS:
+                return Lt;
+            case GREATER:
+                return Gt;
+            case EQEQUAL:                      /* == */
+            case EQUAL:
+                return Eq;
+            case LESSEQUAL:
+                return LtE;
+            case GREATEREQUAL:
+                return GtE;
+            case NOTEQUAL:
+                return NotEq;
+            case NAME:
+                if (strcmp(STR(n), "in") == 0)
+                    return In;
+                if (strcmp(STR(n), "is") == 0)
+                    return Is;
+            default:
+                PyErr_Format(PyExc_Exception, "invalid comp_op: %s",
+                             STR(n));
+                return 0;
+       }
+    }
+    else if (NCH(n) == 2) {
+       /* handle "not in" and "is not" */
+       switch (TYPE(CHILD(n, 0))) {
+            case NAME:
+                if (strcmp(STR(CHILD(n, 1)), "in") == 0)
+                    return NotIn;
+                if (strcmp(STR(CHILD(n, 0)), "is") == 0)
+                    return IsNot;
+            default:
+                PyErr_Format(PyExc_Exception, "invalid comp_op: %s %s",
+                             STR(CHILD(n, 0)), STR(CHILD(n, 1)));
+                return 0;
+       }
+    }
+    PyErr_Format(PyExc_Exception, "invalid comp_op: has %d children",
+                 NCH(n));
+    return 0;
+}
+
+static asdl_seq *
+seq_for_testlist(struct compiling *c, const node *n)
+{
+    /* testlist: test (',' test)* [','] */
+    assert(TYPE(n) == testlist
+          || TYPE(n) == listmaker
+          || TYPE(n) == testlist_gexp
+          || TYPE(n) == testlist_safe
+          );
+    asdl_seq *seq;
+    expr_ty expression;
+    int i;
+
+    seq = asdl_seq_new((NCH(n) + 1) / 2);
+    if (!seq)
+        return NULL;
+
+    for (i = 0; i < NCH(n); i += 2) {
+        REQ(CHILD(n, i), test);
+
+        expression = ast_for_expr(c, CHILD(n, i));
+        if (!expression) {
+            asdl_seq_free(seq);
+            return NULL;
+        }
+
+        assert(i / 2 < seq->size);
+        asdl_seq_SET(seq, i / 2, expression);
+    }
+    return seq;
+}
+
+static expr_ty
+compiler_complex_args(const node *n)
+{
+    int i, len = (NCH(n) + 1) / 2;
+    expr_ty result;
+    asdl_seq *args = asdl_seq_new(len);
+    if (!args)
+        return NULL;
+
+    REQ(n, fplist);
+
+    for (i = 0; i < len; i++) {
+        const node *child = CHILD(CHILD(n, 2*i), 0);
+        expr_ty arg;
+        if (TYPE(child) == NAME) {
+               if (!strcmp(STR(child), "None")) {
+                       ast_error(child, "assignment to None");
+                       return NULL;
+               }
+            arg = Name(NEW_IDENTIFIER(child), Store, LINENO(child));
+       }
+        else
+            arg = compiler_complex_args(CHILD(CHILD(n, 2*i), 1));
+       set_context(arg, Store, n);
+        asdl_seq_SET(args, i, arg);
+    }
+
+    result = Tuple(args, Store, LINENO(n));
+    set_context(result, Store, n);
+    return result;
+}
+
+/* Create AST for argument list.
+
+   XXX TO DO:
+       - check for invalid argument lists like normal after default
+*/
+
+static arguments_ty
+ast_for_arguments(struct compiling *c, const node *n)
+{
+    /* parameters: '(' [varargslist] ')'
+       varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME]
+            | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+    */
+    int i, n_args = 0, n_defaults = 0, found_default = 0;
+    asdl_seq *args, *defaults;
+    identifier vararg = NULL, kwarg = NULL;
+    node *ch;
+
+    if (TYPE(n) == parameters) {
+       if (NCH(n) == 2) /* () as argument list */
+           return arguments(NULL, NULL, NULL, NULL);
+       n = CHILD(n, 1);
+    }
+    REQ(n, varargslist);
+
+    /* first count the number of normal args & defaults */
+    for (i = 0; i < NCH(n); i++) {
+       ch = CHILD(n, i);
+       if (TYPE(ch) == fpdef) {
+           n_args++;
+       }
+       if (TYPE(ch) == EQUAL)
+           n_defaults++;
+    }
+    args = (n_args ? asdl_seq_new(n_args) : NULL);
+    if (!args && n_args)
+       return NULL; /* Don't need to go to NULL; nothing allocated */
+    defaults = (n_defaults ? asdl_seq_new(n_defaults) : NULL);
+    if (!defaults && n_defaults)
+        goto error;
+
+    /* fpdef: NAME | '(' fplist ')'
+       fplist: fpdef (',' fpdef)* [',']
+    */
+    i = 0;
+    while (i < NCH(n)) {
+       ch = CHILD(n, i);
+       switch (TYPE(ch)) {
+            case fpdef:
+                /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is
+                   anything other than EQUAL or a comma? */
+                /* XXX Should NCH(n) check be made a separate check? */
+                if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) {
+                    asdl_seq_APPEND(defaults, 
+                                   ast_for_expr(c, CHILD(n, i + 2)));
+                    i += 2;
+                   found_default = 1;
+                }
+               else if (found_default) {
+                   ast_error(n, 
+                            "non-default argument follows default argument");
+                   goto error;
+               }
+
+                if (NCH(ch) == 3) {
+                    asdl_seq_APPEND(args, 
+                                    compiler_complex_args(CHILD(ch, 1))); 
+               }
+                else if (TYPE(CHILD(ch, 0)) == NAME) {
+                   if (!strcmp(STR(CHILD(ch, 0)), "None")) {
+                           ast_error(CHILD(ch, 0), "assignment to None");
+                           goto error;
+                   }
+                    expr_ty name = Name(NEW_IDENTIFIER(CHILD(ch, 0)),
+                                        Param, LINENO(ch));
+                    if (!name)
+                        goto error;
+                    asdl_seq_APPEND(args, name);
+                                        
+               }
+                i += 2; /* the name and the comma */
+                break;
+            case STAR:
+               if (!strcmp(STR(CHILD(n, i+1)), "None")) {
+                       ast_error(CHILD(n, i+1), "assignment to None");
+                       goto error;
+               }
+                vararg = NEW_IDENTIFIER(CHILD(n, i+1));
+                i += 3;
+                break;
+            case DOUBLESTAR:
+               if (!strcmp(STR(CHILD(n, i+1)), "None")) {
+                       ast_error(CHILD(n, i+1), "assignment to None");
+                       goto error;
+               }
+                kwarg = NEW_IDENTIFIER(CHILD(n, i+1));
+                i += 3;
+                break;
+            default:
+                PyErr_Format(PyExc_Exception,
+                             "unexpected node in varargslist: %d @ %d",
+                             TYPE(ch), i);
+                goto error;
+       }
+    }
+
+    return arguments(args, vararg, kwarg, defaults);
+
+ error:
+    if (args)
+        asdl_seq_free(args);
+    if (defaults)
+        asdl_seq_free(defaults);
+    return NULL;
+}
+
+static expr_ty
+ast_for_dotted_name(struct compiling *c, const node *n)
+{
+    expr_ty e = NULL;
+    expr_ty attrib = NULL;
+    identifier id = NULL;
+    int i;
+
+    REQ(n, dotted_name);
+    
+    id = NEW_IDENTIFIER(CHILD(n, 0));
+    if (!id)
+        goto error;
+    e = Name(id, Load, LINENO(n));
+    if (!e)
+       goto error;
+    id = NULL;
+
+    for (i = 2; i < NCH(n); i+=2) {
+        id = NEW_IDENTIFIER(CHILD(n, i));
+       if (!id)
+           goto error;
+       attrib = Attribute(e, id, Load, LINENO(CHILD(n, i)));
+       if (!attrib)
+           goto error;
+       e = attrib;
+       attrib = NULL;
+    }
+
+    return e;
+    
+  error:
+    Py_XDECREF(id);
+    free_expr(e);
+    return NULL;
+}
+
+static expr_ty
+ast_for_decorator(struct compiling *c, const node *n)
+{
+    /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */
+    expr_ty d = NULL;
+    expr_ty name_expr = NULL;
+    
+    REQ(n, decorator);
+    
+    if ((NCH(n) < 3 && NCH(n) != 5 && NCH(n) != 6)
+       || TYPE(CHILD(n, 0)) != AT || TYPE(RCHILD(n, -1)) != NEWLINE) {
+       ast_error(n, "Invalid decorator node");
+       goto error;
+    }
+    
+    name_expr = ast_for_dotted_name(c, CHILD(n, 1));
+    if (!name_expr)
+       goto error;
+       
+    if (NCH(n) == 3) { /* No arguments */
+       d = name_expr;
+       name_expr = NULL;
+    }
+    else if (NCH(n) == 5) { /* Call with no arguments */
+       d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n));
+       if (!d)
+           goto error;
+       name_expr = NULL;
+    }
+    else {
+       d = ast_for_call(c, CHILD(n, 3), name_expr);
+       if (!d)
+           goto error;
+       name_expr = NULL;
+    }
+
+    return d;
+    
+  error:
+    free_expr(name_expr);
+    free_expr(d);
+    return NULL;
+}
+
+static asdl_seq*
+ast_for_decorators(struct compiling *c, const node *n)
+{
+    asdl_seq* decorator_seq = NULL;
+    expr_ty d = NULL;
+    int i;
+    
+    REQ(n, decorators);
+
+    decorator_seq = asdl_seq_new(NCH(n));
+    if (!decorator_seq)
+        return NULL;
+       
+    for (i = 0; i < NCH(n); i++) {
+       d = ast_for_decorator(c, CHILD(n, i));
+       if (!d)
+           goto error;
+       asdl_seq_APPEND(decorator_seq, d);
+       d = NULL;
+    }
+    return decorator_seq;
+  error:
+    asdl_expr_seq_free(decorator_seq);
+    free_expr(d);
+    return NULL;
+}
+
+static stmt_ty
+ast_for_funcdef(struct compiling *c, const node *n)
+{
+    /* funcdef: 'def' [decorators] NAME parameters ':' suite */
+    identifier name = NULL;
+    arguments_ty args = NULL;
+    asdl_seq *body = NULL;
+    asdl_seq *decorator_seq = NULL;
+    int name_i;
+
+    REQ(n, funcdef);
+
+    if (NCH(n) == 6) { /* decorators are present */
+       decorator_seq = ast_for_decorators(c, CHILD(n, 0));
+       if (!decorator_seq)
+           goto error;
+       name_i = 2;
+    }
+    else {
+       name_i = 1;
+    }
+
+    name = NEW_IDENTIFIER(CHILD(n, name_i));
+    if (!name)
+       goto error;
+    else if (!strcmp(STR(CHILD(n, name_i)), "None")) {
+           ast_error(CHILD(n, name_i), "assignment to None");
+           goto error;
+    }
+    args = ast_for_arguments(c, CHILD(n, name_i + 1));
+    if (!args)
+       goto error;
+    body = ast_for_suite(c, CHILD(n, name_i + 3));
+    if (!body)
+       goto error;
+
+    return FunctionDef(name, args, body, decorator_seq, LINENO(n));
+
+error:
+    asdl_stmt_seq_free(body);
+    asdl_expr_seq_free(decorator_seq);
+    free_arguments(args);
+    Py_XDECREF(name);
+    return NULL;
+}
+
+static expr_ty
+ast_for_lambdef(struct compiling *c, const node *n)
+{
+    /* lambdef: 'lambda' [varargslist] ':' test */
+    arguments_ty args;
+    expr_ty expression;
+
+    if (NCH(n) == 3) {
+        args = arguments(NULL, NULL, NULL, NULL);
+        if (!args)
+            return NULL;
+        expression = ast_for_expr(c, CHILD(n, 2));
+        if (!expression) {
+            free_arguments(args);
+            return NULL;
+        }
+    }
+    else {
+        args = ast_for_arguments(c, CHILD(n, 1));
+        if (!args)
+            return NULL;
+        expression = ast_for_expr(c, CHILD(n, 3));
+        if (!expression) {
+            free_arguments(args);
+            return NULL;
+        }
+    }
+
+    return Lambda(args, expression, LINENO(n));
+}
+
+/* Count the number of 'for' loop in a list comprehension.
+
+   Helper for ast_for_listcomp().
+*/
+
+static int
+count_list_fors(const node *n)
+{
+    int n_fors = 0;
+    node *ch = CHILD(n, 1);
+
+ count_list_for:
+    n_fors++;
+    REQ(ch, list_for);
+    if (NCH(ch) == 5)
+       ch = CHILD(ch, 4);
+    else
+       return n_fors;
+ count_list_iter:
+    REQ(ch, list_iter);
+    ch = CHILD(ch, 0);
+    if (TYPE(ch) == list_for)
+       goto count_list_for;
+    else if (TYPE(ch) == list_if) {
+        if (NCH(ch) == 3) {
+            ch = CHILD(ch, 2);
+            goto count_list_iter;
+        }
+        else
+            return n_fors;
+    }
+    else {
+        /* Should never be reached */
+        PyErr_SetString(PyExc_Exception, "logic error in count_list_fors");
+        return -1;
+    }
+}
+
+/* Count the number of 'if' statements in a list comprehension.
+
+   Helper for ast_for_listcomp().
+*/
+
+static int
+count_list_ifs(const node *n)
+{
+    int n_ifs = 0;
+
+ count_list_iter:
+    REQ(n, list_iter);
+    if (TYPE(CHILD(n, 0)) == list_for)
+       return n_ifs;
+    n = CHILD(n, 0);
+    REQ(n, list_if);
+    n_ifs++;
+    if (NCH(n) == 2)
+       return n_ifs;
+    n = CHILD(n, 2);
+    goto count_list_iter;
+}
+
+static expr_ty
+ast_for_listcomp(struct compiling *c, const node *n)
+{
+    /* listmaker: test ( list_for | (',' test)* [','] )
+       list_for: 'for' exprlist 'in' testlist_safe [list_iter]
+       list_iter: list_for | list_if
+       list_if: 'if' test [list_iter]
+       testlist_safe: test [(',' test)+ [',']]
+    */
+    expr_ty elt;
+    asdl_seq *listcomps;
+    int i, n_fors;
+    node *ch;
+
+    REQ(n, listmaker);
+    assert(NCH(n) > 1);
+
+    elt = ast_for_expr(c, CHILD(n, 0));
+    if (!elt)
+        return NULL;
+
+    n_fors = count_list_fors(n);
+    if (n_fors == -1)
+        return NULL;
+
+    listcomps = asdl_seq_new(n_fors);
+    if (!listcomps) {
+        free_expr(elt);
+       return NULL;
+    }
+    
+    ch = CHILD(n, 1);
+    for (i = 0; i < n_fors; i++) {
+       comprehension_ty lc;
+       asdl_seq *t;
+        expr_ty expression;
+
+       REQ(ch, list_for);
+
+       t = ast_for_exprlist(c, CHILD(ch, 1), Store);
+        if (!t) {
+            asdl_seq_free(listcomps);
+            free_expr(elt);
+            return NULL;
+        }
+        expression = ast_for_testlist(c, CHILD(ch, 3), 0);
+        if (!expression) {
+            asdl_seq_free(t);
+            asdl_seq_free(listcomps);
+            free_expr(elt);
+            return NULL;
+        }
+
+       if (asdl_seq_LEN(t) == 1)
+           lc = comprehension(asdl_seq_GET(t, 0), expression, NULL);
+       else
+           lc = comprehension(Tuple(t, Store, LINENO(ch)), expression, NULL);
+
+        if (!lc) {
+            asdl_seq_free(t);
+            asdl_seq_free(listcomps);
+            free_expr(expression);
+            free_expr(elt);
+            return NULL;
+        }
+
+       if (NCH(ch) == 5) {
+           int j, n_ifs;
+           asdl_seq *ifs;
+
+           ch = CHILD(ch, 4);
+           n_ifs = count_list_ifs(ch);
+            if (n_ifs == -1) {
+                asdl_seq_free(listcomps);
+                free_expr(elt);
+                return NULL;
+            }
+
+           ifs = asdl_seq_new(n_ifs);
+           if (!ifs) {
+               asdl_seq_free(listcomps);
+                free_expr(elt);
+               return NULL;
+           }
+
+           for (j = 0; j < n_ifs; j++) {
+               REQ(ch, list_iter);
+
+               ch = CHILD(ch, 0);
+               REQ(ch, list_if);
+
+               asdl_seq_APPEND(ifs, ast_for_expr(c, CHILD(ch, 1)));
+               if (NCH(ch) == 3)
+                   ch = CHILD(ch, 2);
+           }
+           /* on exit, must guarantee that ch is a list_for */
+           if (TYPE(ch) == list_iter)
+               ch = CHILD(ch, 0);
+            lc->ifs = ifs;
+       }
+       asdl_seq_APPEND(listcomps, lc);
+    }
+
+    return ListComp(elt, listcomps, LINENO(n));
+}
+
+/*
+   Count the number of 'for' loops in a generator expression.
+
+   Helper for ast_for_genexp().
+*/
+
+static int
+count_gen_fors(const node *n)
+{
+       int n_fors = 0;
+       node *ch = CHILD(n, 1);
+
+ count_gen_for:
+       n_fors++;
+       REQ(ch, gen_for);
+       if (NCH(ch) == 5)
+               ch = CHILD(ch, 4);
+       else
+               return n_fors;
+ count_gen_iter:
+       REQ(ch, gen_iter);
+       ch = CHILD(ch, 0);
+       if (TYPE(ch) == gen_for)
+               goto count_gen_for;
+       else if (TYPE(ch) == gen_if) {
+               if (NCH(ch) == 3) {
+                       ch = CHILD(ch, 2);
+                       goto count_gen_iter;
+               }
+               else
+                   return n_fors;
+       }
+       else {
+               /* Should never be reached */
+               PyErr_SetString(PyExc_Exception, "logic error in count_gen_fors");
+               return -1;
+       }
+}
+
+/* Count the number of 'if' statements in a generator expression.
+
+   Helper for ast_for_genexp().
+*/
+
+static int
+count_gen_ifs(const node *n)
+{
+       int n_ifs = 0;
+
+       while (1) {
+               REQ(n, gen_iter);
+               if (TYPE(CHILD(n, 0)) == gen_for)
+                       return n_ifs;
+               n = CHILD(n, 0);
+               REQ(n, gen_if);
+               n_ifs++;
+               if (NCH(n) == 2)
+                       return n_ifs;
+               n = CHILD(n, 2);
+       }
+}
+
+static expr_ty
+ast_for_genexp(struct compiling *c, const node *n)
+{
+    /* testlist_gexp: test ( gen_for | (',' test)* [','] )
+       argument: [test '='] test [gen_for]      # Really [keyword '='] test */
+    expr_ty elt;
+    asdl_seq *genexps;
+    int i, n_fors;
+    node *ch;
+    
+    assert(TYPE(n) == (testlist_gexp) || TYPE(n) == (argument));
+    assert(NCH(n) > 1);
+    
+    elt = ast_for_expr(c, CHILD(n, 0));
+    if (!elt)
+        return NULL;
+    
+    n_fors = count_gen_fors(n);
+    if (n_fors == -1)
+        return NULL;
+    
+    genexps = asdl_seq_new(n_fors);
+    if (!genexps) {
+        free_expr(elt);
+        return NULL;
+    }
+    
+    ch = CHILD(n, 1);
+    for (i = 0; i < n_fors; i++) {
+        comprehension_ty ge;
+        asdl_seq *t;
+        expr_ty expression;
+        
+        REQ(ch, gen_for);
+        
+        t = ast_for_exprlist(c, CHILD(ch, 1), Store);
+        if (!t) {
+            asdl_seq_free(genexps);
+            free_expr(elt);
+            return NULL;
+        }
+        expression = ast_for_testlist(c, CHILD(ch, 3), 1);
+        if (!expression) {
+            asdl_seq_free(genexps);
+            free_expr(elt);
+            return NULL;
+        }
+        
+        if (asdl_seq_LEN(t) == 1)
+            ge = comprehension(asdl_seq_GET(t, 0), expression,
+                               NULL);
+        else
+            ge = comprehension(Tuple(t, Store, LINENO(ch)),
+                               expression, NULL);
+        
+        if (!ge) {
+            asdl_seq_free(genexps);
+            free_expr(elt);
+            return NULL;
+        }
+        
+        if (NCH(ch) == 5) {
+            int j, n_ifs;
+            asdl_seq *ifs;
+            
+            ch = CHILD(ch, 4);
+            n_ifs = count_gen_ifs(ch);
+            if (n_ifs == -1) {
+                asdl_seq_free(genexps);
+                free_expr(elt);
+                return NULL;
+            }
+            
+            ifs = asdl_seq_new(n_ifs);
+            if (!ifs) {
+                asdl_seq_free(genexps);
+                free_expr(elt);
+                return NULL;
+            }
+            
+            for (j = 0; j < n_ifs; j++) {
+                REQ(ch, gen_iter);
+                ch = CHILD(ch, 0);
+                REQ(ch, gen_if);
+                
+                asdl_seq_APPEND(ifs, ast_for_expr(c, CHILD(ch, 1)));
+                if (NCH(ch) == 3)
+                    ch = CHILD(ch, 2);
+            }
+            /* on exit, must guarantee that ch is a gen_for */
+            if (TYPE(ch) == gen_iter)
+                ch = CHILD(ch, 0);
+            ge->ifs = ifs;
+        }
+        asdl_seq_APPEND(genexps, ge);
+    }
+    
+    return GeneratorExp(elt, genexps, LINENO(n));
+}
+
+static expr_ty
+ast_for_atom(struct compiling *c, const node *n)
+{
+    /* atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']'
+       | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
+    */
+    node *ch = CHILD(n, 0);
+    
+    switch (TYPE(ch)) {
+    case NAME:
+       /* All names start in Load context, but may later be
+          changed. */
+       return Name(NEW_IDENTIFIER(ch), Load, LINENO(n));
+    case STRING: {
+       PyObject *str = parsestrplus(c, n);
+       
+       if (!str)
+           return NULL;
+       
+       return Str(str, LINENO(n));
+    }
+    case NUMBER: {
+       PyObject *pynum = parsenumber(STR(ch));
+       
+       if (!pynum)
+           return NULL;
+       
+       return Num(pynum, LINENO(n));
+    }
+    case LPAR: /* some parenthesized expressions */
+       ch = CHILD(n, 1);
+       
+       if (TYPE(ch) == RPAR)
+           return Tuple(NULL, Load, LINENO(n));
+       
+       if (TYPE(ch) == yield_expr)
+           return ast_for_expr(c, ch);
+       
+       if ((NCH(ch) > 1) && (TYPE(CHILD(ch, 1)) == gen_for))
+           return ast_for_genexp(c, ch);
+       
+       return ast_for_testlist(c, ch, 1);
+    case LSQB: /* list (or list comprehension) */
+       ch = CHILD(n, 1);
+       
+       if (TYPE(ch) == RSQB)
+           return List(NULL, Load, LINENO(n));
+       
+       REQ(ch, listmaker);
+       if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) {
+           asdl_seq *elts = seq_for_testlist(c, ch);
+           
+           if (!elts)
+               return NULL;
+           
+           return List(elts, Load, LINENO(n));
+       }
+       else
+           return ast_for_listcomp(c, ch);
+    case LBRACE: {
+       /* dictmaker: test ':' test (',' test ':' test)* [','] */
+       int i, size;
+       asdl_seq *keys, *values;
+       
+       ch = CHILD(n, 1);
+       size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */
+       keys = asdl_seq_new(size);
+       if (!keys)
+           return NULL;
+       
+       values = asdl_seq_new(size);
+       if (!values) {
+           asdl_seq_free(keys);
+           return NULL;
+       }
+       
+       for (i = 0; i < NCH(ch); i += 4) {
+           expr_ty expression;
+           
+           expression = ast_for_expr(c, CHILD(ch, i));
+           if (!expression)
+               return NULL;
+           
+           asdl_seq_SET(keys, i / 4, expression);
+           
+           expression = ast_for_expr(c, CHILD(ch, i + 2));
+           if (!expression)
+               return NULL;
+           
+           asdl_seq_SET(values, i / 4, expression);
+       }
+       return Dict(keys, values, LINENO(n));
+    }
+    case BACKQUOTE: { /* repr */
+       expr_ty expression = ast_for_testlist(c, CHILD(n, 1), 0);
+       
+       if (!expression)
+           return NULL;
+       
+       return Repr(expression, LINENO(n));
+    }
+    default:
+       PyErr_Format(PyExc_Exception, "unhandled atom %d",
+                    TYPE(ch));
+       return NULL;
+    }
+}
+
+static slice_ty
+ast_for_slice(struct compiling *c, const node *n)
+{
+    node *ch;
+    expr_ty lower = NULL, upper = NULL, step = NULL;
+
+    REQ(n, subscript);
+
+    /*
+       subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
+       sliceop: ':' [test]
+    */
+    ch = CHILD(n, 0);
+    if (TYPE(ch) == DOT)
+       return Ellipsis();
+
+    if (NCH(n) == 1 && TYPE(ch) == test) {
+        /* 'step' variable hold no significance in terms of being used over
+           other vars */
+        step = ast_for_expr(c, ch); 
+        if (!step)
+            return NULL;
+            
+       return Index(step);
+    }
+
+    if (TYPE(ch) == test) {
+       lower = ast_for_expr(c, ch);
+        if (!lower)
+            return NULL;
+    }
+
+    /* If there's an upper bound it's in the second or third position. */
+    if (TYPE(ch) == COLON) {
+       if (NCH(n) > 1) {
+           node *n2 = CHILD(n, 1);
+
+           if (TYPE(n2) == test) {
+               upper = ast_for_expr(c, n2);
+                if (!upper)
+                    return NULL;
+            }
+       }
+    } else if (NCH(n) > 2) {
+       node *n2 = CHILD(n, 2);
+
+       if (TYPE(n2) == test) {
+           upper = ast_for_expr(c, n2);
+            if (!upper)
+                return NULL;
+        }
+    }
+
+    ch = CHILD(n, NCH(n) - 1);
+    if (TYPE(ch) == sliceop) {
+       if (NCH(ch) == 1)
+            /* XXX: If only 1 child, then should just be a colon.  Should we
+               just skip assigning and just get to the return? */
+           ch = CHILD(ch, 0);
+       else
+           ch = CHILD(ch, 1);
+       if (TYPE(ch) == test) {
+           step = ast_for_expr(c, ch);
+            if (!step)
+                return NULL;
+        }
+    }
+
+    return Slice(lower, upper, step);
+}
+
+static expr_ty
+ast_for_binop(struct compiling *c, const node *n)
+{
+       /* Must account for a sequence of expressions.
+          How should A op B op C by represented?  
+          BinOp(BinOp(A, op, B), op, C).
+       */
+
+       int i, nops;
+       expr_ty expr1, expr2, result;
+        operator_ty operator;
+
+        expr1 = ast_for_expr(c, CHILD(n, 0));
+        if (!expr1)
+            return NULL;
+
+        expr2 = ast_for_expr(c, CHILD(n, 2));
+        if (!expr2)
+            return NULL;
+
+        operator = get_operator(CHILD(n, 1));
+        if (!operator)
+            return NULL;
+
+       result = BinOp(expr1, operator, expr2, LINENO(n));
+       if (!result)
+            return NULL;
+
+       nops = (NCH(n) - 1) / 2;
+       for (i = 1; i < nops; i++) {
+               expr_ty tmp_result, tmp;
+               const node* next_oper = CHILD(n, i * 2 + 1);
+
+               operator = get_operator(next_oper);
+                if (!operator)
+                    return NULL;
+
+                tmp = ast_for_expr(c, CHILD(n, i * 2 + 2));
+                if (!tmp)
+                    return NULL;
+
+                tmp_result = BinOp(result, operator, tmp, 
+                                  LINENO(next_oper));
+               if (!tmp) 
+                       return NULL;
+               result = tmp_result;
+       }
+       return result;
+}
+
+/* Do not name a variable 'expr'!  Will cause a compile error.
+*/
+
+static expr_ty
+ast_for_expr(struct compiling *c, const node *n)
+{
+    /* handle the full range of simple expressions
+       test: and_test ('or' and_test)* | lambdef
+       and_test: not_test ('and' not_test)*
+       not_test: 'not' not_test | comparison
+       comparison: expr (comp_op expr)*
+       expr: xor_expr ('|' xor_expr)*
+       xor_expr: and_expr ('^' and_expr)*
+       and_expr: shift_expr ('&' shift_expr)*
+       shift_expr: arith_expr (('<<'|'>>') arith_expr)*
+       arith_expr: term (('+'|'-') term)*
+       term: factor (('*'|'/'|'%'|'//') factor)*
+       factor: ('+'|'-'|'~') factor | power
+       power: atom trailer* ('**' factor)*
+    */
+
+    asdl_seq *seq;
+    int i;
+
+ loop:
+    switch (TYPE(n)) {
+        case test:
+            if (TYPE(CHILD(n, 0)) == lambdef)
+                return ast_for_lambdef(c, CHILD(n, 0));
+            /* Fall through to and_test */
+        case and_test:
+            if (NCH(n) == 1) {
+                n = CHILD(n, 0);
+                goto loop;
+            }
+            seq = asdl_seq_new((NCH(n) + 1) / 2);
+            if (!seq)
+                return NULL;
+            for (i = 0; i < NCH(n); i += 2) {
+                expr_ty e = ast_for_expr(c, CHILD(n, i));
+                if (!e)
+                    return NULL;
+                asdl_seq_SET(seq, i / 2, e);
+            }
+            if (!strcmp(STR(CHILD(n, 1)), "and"))
+                return BoolOp(And, seq, LINENO(n));
+            else {
+                assert(!strcmp(STR(CHILD(n, 1)), "or"));
+                return BoolOp(Or, seq, LINENO(n));
+            }
+            break;
+        case not_test:
+            if (NCH(n) == 1) {
+                n = CHILD(n, 0);
+                goto loop;
+            }
+            else {
+                expr_ty expression = ast_for_expr(c, CHILD(n, 1));
+                if (!expression)
+                    return NULL;
+
+                return UnaryOp(Not, expression, LINENO(n));
+            }
+        case comparison:
+            if (NCH(n) == 1) {
+                n = CHILD(n, 0);
+                goto loop;
+            }
+            else {
+                expr_ty expression;
+                asdl_seq *ops, *cmps;
+                ops = asdl_seq_new(NCH(n) / 2);
+                if (!ops)
+                    return NULL;
+                cmps = asdl_seq_new(NCH(n) / 2);
+                if (!cmps) {
+                    asdl_seq_free(ops);
+                    return NULL;
+                }
+                for (i = 1; i < NCH(n); i += 2) {
+                    /* XXX cmpop_ty is just an enum */
+                    cmpop_ty operator;
+
+                    operator = ast_for_comp_op(CHILD(n, i));
+                    if (!operator)
+                        return NULL;
+
+                    expression = ast_for_expr(c, CHILD(n, i + 1));
+                    if (!expression)
+                        return NULL;
+                        
+                    asdl_seq_SET(ops, i / 2, (void *)operator);
+                    asdl_seq_SET(cmps, i / 2, expression);
+                }
+                expression = ast_for_expr(c, CHILD(n, 0));
+                if (!expression)
+                    return NULL;
+                    
+                return Compare(expression, ops, cmps, LINENO(n));
+            }
+            break;
+
+        /* The next five cases all handle BinOps.  The main body of code
+           is the same in each case, but the switch turned inside out to
+           reuse the code for each type of operator.
+         */
+        case expr:
+        case xor_expr:
+        case and_expr:
+        case shift_expr:
+        case arith_expr:
+        case term:
+            if (NCH(n) == 1) {
+                n = CHILD(n, 0);
+                goto loop;
+            }
+            return ast_for_binop(c, n);
+        case yield_expr: {
+           expr_ty exp = NULL;
+           if (NCH(n) == 2) {
+               exp = ast_for_testlist(c, CHILD(n, 1), 0);
+               if (!exp)
+                   return NULL;
+           }
+           return Yield(exp, LINENO(n));
+       }
+        case factor: {
+            expr_ty expression;
+            
+            if (NCH(n) == 1) {
+                n = CHILD(n, 0);
+                goto loop;
+            }
+
+            expression = ast_for_expr(c, CHILD(n, 1));
+            if (!expression)
+                return NULL;
+
+            switch (TYPE(CHILD(n, 0))) {
+                case PLUS:
+                    return UnaryOp(UAdd, expression, LINENO(n));
+                case MINUS:
+                    return UnaryOp(USub, expression, LINENO(n));
+                case TILDE:
+                    return UnaryOp(Invert, expression, LINENO(n));
+            }
+            break;
+        }
+        case power: {
+            expr_ty e = ast_for_atom(c, CHILD(n, 0));
+           if (!e)
+               return NULL;
+            if (NCH(n) == 1)
+                return e;
+            /* power: atom trailer* ('**' factor)*
+               trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME 
+
+               XXX What about atom trailer trailer ** factor?
+            */
+            for (i = 1; i < NCH(n); i++) {
+                expr_ty new = e;
+                node *ch = CHILD(n, i);
+                if (ch->n_str && strcmp(ch->n_str, "**") == 0)
+                    break;
+                if (TYPE(CHILD(ch, 0)) == LPAR) {
+                    if (NCH(ch) == 2)
+                        new = Call(new, NULL, NULL, NULL, NULL, LINENO(ch));
+                    else
+                        new = ast_for_call(c, CHILD(ch, 1), new);
+
+                    if (!new) {
+                       free_expr(e);
+                        return NULL;
+                   }
+                }
+                else if (TYPE(CHILD(ch, 0)) == LSQB) {
+                    REQ(CHILD(ch, 2), RSQB);
+                    ch = CHILD(ch, 1);
+                    if (NCH(ch) <= 2) {
+                        slice_ty slc = ast_for_slice(c, CHILD(ch, 0));
+                        if (!slc) {
+                           free_expr(e);
+                            return NULL;
+                       }
+
+                        new = Subscript(e, slc, Load, LINENO(ch));
+                        if (!new) {
+                           free_expr(e);
+                            free_slice(slc);
+                            return NULL;
+                       }
+                    }
+                    else {
+                        int j;
+                        slice_ty slc;
+                        asdl_seq *slices = asdl_seq_new((NCH(ch) + 1) / 2);
+                        if (!slices) {
+                           free_expr(e);
+                            return NULL;
+                       }
+
+                        for (j = 0; j < NCH(ch); j += 2) {
+                            slc = ast_for_slice(c, CHILD(ch, j));
+                            if (!slc) {
+                               free_expr(e);
+                               asdl_seq_free(slices);
+                                return NULL;
+                           }
+                            asdl_seq_SET(slices, j / 2, slc);
+                        }
+                        new = Subscript(e, ExtSlice(slices), Load, LINENO(ch));
+                        if (!new) {
+                           free_expr(e);
+                           asdl_seq_free(slices);
+                            return NULL;
+                       }
+                    }
+                }
+                else {
+                    assert(TYPE(CHILD(ch, 0)) == DOT);
+                    new = Attribute(e, NEW_IDENTIFIER(CHILD(ch, 1)), Load,
+                                   LINENO(ch));
+                    if (!new) {
+                       free_expr(e);
+                        return NULL;
+                   }
+                }
+                e = new;
+            }
+            if (TYPE(CHILD(n, NCH(n) - 1)) == factor) {
+                expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1));
+                if (!f) {
+                   free_expr(e);
+                    return NULL;
+               }
+                return BinOp(e, Pow, f, LINENO(n));
+            }
+            return e;
+        }
+        default:
+           abort();
+            PyErr_Format(PyExc_Exception, "unhandled expr: %d", TYPE(n));
+            return NULL;
+    }
+    /* should never get here */
+    return NULL;
+}
+
+static expr_ty
+ast_for_call(struct compiling *c, const node *n, expr_ty func)
+{
+    /*
+      arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
+               | '**' test)
+      argument: [test '='] test [gen_for]       # Really [keyword '='] test
+    */
+
+    int i, nargs, nkeywords, ngens;
+    asdl_seq *args = NULL;
+    asdl_seq *keywords = NULL;
+    expr_ty vararg = NULL, kwarg = NULL;
+
+    REQ(n, arglist);
+
+    nargs = 0;
+    nkeywords = 0;
+    ngens = 0;
+    for (i = 0; i < NCH(n); i++) {
+       node *ch = CHILD(n, i);
+       if (TYPE(ch) == argument) {
+           if (NCH(ch) == 1)
+               nargs++;
+           else if (TYPE(CHILD(ch, 1)) == gen_for)
+               ngens++;
+            else
+               nkeywords++;
+       }
+    }
+    if (ngens > 1 || (ngens && (nargs || nkeywords))) {
+        ast_error(n, "Generator expression must be parenthesised "
+                 "if not sole argument");
+       return NULL;
+    }
+
+    if (nargs + nkeywords + ngens > 255) {
+      ast_error(n, "more than 255 arguments");
+      return NULL;
+    }
+
+    args = asdl_seq_new(nargs + ngens);
+    if (!args)
+        goto error;
+    keywords = asdl_seq_new(nkeywords);
+    if (!keywords)
+        goto error;
+    nargs = 0;
+    nkeywords = 0;
+    for (i = 0; i < NCH(n); i++) {
+       node *ch = CHILD(n, i);
+       if (TYPE(ch) == argument) {
+           expr_ty e;
+           if (NCH(ch) == 1) {
+               e = ast_for_expr(c, CHILD(ch, 0));
+                if (!e)
+                    goto error;
+               asdl_seq_SET(args, nargs++, e);
+           }  
+           else if (TYPE(CHILD(ch, 1)) == gen_for) {
+               e = ast_for_genexp(c, ch);
+                if (!e)
+                    goto error;
+               asdl_seq_SET(args, nargs++, e);
+            }
+           else {
+               keyword_ty kw;
+               identifier key;
+
+               /* CHILD(ch, 0) is test, but must be an identifier? */ 
+               e = ast_for_expr(c, CHILD(ch, 0));
+                if (!e)
+                    goto error;
+                /* f(lambda x: x[0] = 3) ends up getting parsed with
+                 * LHS test = lambda x: x[0], and RHS test = 3.
+                 * SF bug 132313 points out that complaining about a keyword
+                 * then is very confusing.
+                 */
+                if (e->kind == Lambda_kind) {
+                  ast_error(CHILD(ch, 0), "lambda cannot contain assignment");
+                  goto error;
+                } else if (e->kind != Name_kind) {
+                  ast_error(CHILD(ch, 0), "keyword can't be an expression");
+                  goto error;
+                }
+               key = e->v.Name.id;
+               free(e);
+               e = ast_for_expr(c, CHILD(ch, 2));
+                if (!e)
+                    goto error;
+               kw = keyword(key, e);
+                if (!kw)
+                    goto error;
+               asdl_seq_SET(keywords, nkeywords++, kw);
+           }
+       }
+       else if (TYPE(ch) == STAR) {
+           vararg = ast_for_expr(c, CHILD(n, i+1));
+           i++;
+       }
+       else if (TYPE(ch) == DOUBLESTAR) {
+           kwarg = ast_for_expr(c, CHILD(n, i+1));
+           i++;
+       }
+    }
+
+    return Call(func, args, keywords, vararg, kwarg, LINENO(n));
+
+ error:
+    if (args)
+        asdl_seq_free(args);
+    if (keywords)
+        asdl_seq_free(keywords);
+    return NULL;
+}
+
+/* Unlike other ast_for_XXX() functions, this takes a flag that
+   indicates whether generator expressions are allowed.  If gexp is
+   non-zero, check for testlist_gexp instead of plain testlist.
+*/
+
+static expr_ty
+ast_for_testlist(struct compiling *c, const node* n, int gexp)
+{
+  /* testlist_gexp: test ( gen_for | (',' test)* [','] )
+     testlist: test (',' test)* [',']
+  */
+
+    assert(NCH(n) > 0);
+    if (NCH(n) == 1)
+       return ast_for_expr(c, CHILD(n, 0));
+    if (TYPE(CHILD(n, 1)) == gen_for) {
+       if (!gexp) {
+           ast_error(n, "illegal generator expression");
+           return NULL;
+       }
+       return ast_for_genexp(c, n);
+    }
+    else {
+        asdl_seq *tmp = seq_for_testlist(c, n);
+        if (!tmp)
+            return NULL;
+
+       return Tuple(tmp, Load, LINENO(n));
+    }
+    return NULL;  /* unreachable */
+}
+
+static stmt_ty
+ast_for_expr_stmt(struct compiling *c, const node *n)
+{
+    REQ(n, expr_stmt);
+    /* expr_stmt: testlist (augassign (yield_expr|testlist) 
+                | ('=' (yield_expr|testlist))*)
+       testlist: test (',' test)* [',']
+       augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
+               | '<<=' | '>>=' | '**=' | '//='
+       test: ... here starts the operator precendence dance
+     */
+
+    if (NCH(n) == 1) {
+       expr_ty e = ast_for_testlist(c, CHILD(n, 0), 0);
+        if (!e)
+            return NULL;
+
+       return Expr(e, LINENO(n));
+    }
+    else if (TYPE(CHILD(n, 1)) == augassign) {
+        expr_ty expr1, expr2;
+        operator_ty operator;
+       node *ch = CHILD(n, 0);
+
+       if (TYPE(ch) == testlist)
+           expr1 = ast_for_testlist(c, ch, 0);
+       else
+           expr1 = Yield(ast_for_expr(c, CHILD(ch, 0)), LINENO(ch));
+
+        if (!expr1)
+            return NULL;
+        if (expr1->kind == GeneratorExp_kind) {
+           ast_error(ch, "augmented assignment to generator "
+                     "expression not possible");
+           return NULL;
+        }
+       if (expr1->kind == Name_kind) {
+               char *var_name = PyString_AS_STRING(expr1->v.Name.id);
+               if (var_name[0] == 'N' && !strcmp(var_name, "None")) {
+                       ast_error(ch, "assignment to None");
+                       return NULL;
+               }
+       }
+
+       ch = CHILD(n, 2);
+       if (TYPE(ch) == testlist)
+           expr2 = ast_for_testlist(c, ch, 0);
+       else
+           expr2 = Yield(ast_for_expr(c, ch), LINENO(ch));
+        if (!expr2)
+            return NULL;
+
+        operator = ast_for_augassign(CHILD(n, 1));
+        if (!operator)
+            return NULL;
+
+       return AugAssign(expr1, operator, expr2, LINENO(n));
+    }
+    else {
+       int i;
+       asdl_seq *targets;
+       node *value;
+        expr_ty expression;
+
+       /* a normal assignment */
+       REQ(CHILD(n, 1), EQUAL);
+       targets = asdl_seq_new(NCH(n) / 2);
+       if (!targets)
+           return NULL;
+       for (i = 0; i < NCH(n) - 2; i += 2) {
+           node *ch = CHILD(n, i);
+           if (TYPE(ch) == yield_expr) {
+               ast_error(ch, "assignment to yield expression not possible");
+               goto error;
+           }
+           expr_ty e = ast_for_testlist(c, ch, 0);
+
+           /* set context to assign */
+           if (!e) 
+             goto error;
+
+           if (!set_context(e, Store, CHILD(n, i))) {
+              free_expr(e);
+             goto error;
+            }
+
+           asdl_seq_SET(targets, i / 2, e);
+       }
+       value = CHILD(n, NCH(n) - 1);
+       if (TYPE(value) == testlist)
+           expression = ast_for_testlist(c, value, 0);
+       else
+           expression = ast_for_expr(c, value);
+       if (!expression)
+           return NULL;
+       return Assign(targets, expression, LINENO(n));
+    error:
+        for (i = i / 2; i >= 0; i--)
+            free_expr((expr_ty)asdl_seq_GET(targets, i));
+        asdl_seq_free(targets);
+        return NULL;
+    }
+    return NULL;
+}
+
+static stmt_ty
+ast_for_print_stmt(struct compiling *c, const node *n)
+{
+    /* print_stmt: 'print' ( [ test (',' test)* [','] ]
+                             | '>>' test [ (',' test)+ [','] ] )
+     */
+    expr_ty dest = NULL, expression;
+    asdl_seq *seq;
+    bool nl;
+    int i, start = 1;
+
+    REQ(n, print_stmt);
+    if (NCH(n) >= 2 && TYPE(CHILD(n, 1)) == RIGHTSHIFT) {
+       dest = ast_for_expr(c, CHILD(n, 2));
+        if (!dest)
+            return NULL;
+       start = 4;
+    }
+    seq = asdl_seq_new((NCH(n) + 1 - start) / 2);
+    if (!seq)
+       return NULL;
+    for (i = start; i < NCH(n); i += 2) {
+        expression = ast_for_expr(c, CHILD(n, i));
+        if (!expression) {
+           asdl_seq_free(seq);
+            return NULL;
+       }
+
+       asdl_seq_APPEND(seq, expression);
+    }
+    nl = (TYPE(CHILD(n, NCH(n) - 1)) == COMMA) ? false : true;
+    return Print(dest, seq, nl, LINENO(n));
+}
+
+static asdl_seq *
+ast_for_exprlist(struct compiling *c, const node *n, int context)
+{
+    asdl_seq *seq;
+    int i;
+    expr_ty e;
+
+    REQ(n, exprlist);
+
+    seq = asdl_seq_new((NCH(n) + 1) / 2);
+    if (!seq)
+       return NULL;
+    for (i = 0; i < NCH(n); i += 2) {
+       e = ast_for_expr(c, CHILD(n, i));
+       if (!e) {
+           asdl_seq_free(seq);
+           return NULL;
+       }
+       if (context) {
+           if (!set_context(e, context, CHILD(n, i)))
+                return NULL;
+        }
+       asdl_seq_SET(seq, i / 2, e);
+    }
+    return seq;
+}
+
+static stmt_ty
+ast_for_del_stmt(struct compiling *c, const node *n)
+{
+    asdl_seq *expr_list;
+    
+    /* del_stmt: 'del' exprlist */
+    REQ(n, del_stmt);
+
+    expr_list = ast_for_exprlist(c, CHILD(n, 1), Del);
+    if (!expr_list)
+        return NULL;
+    return Delete(expr_list, LINENO(n));
+}
+
+static stmt_ty
+ast_for_flow_stmt(struct compiling *c, const node *n)
+{
+    /*
+      flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt
+                 | yield_stmt
+      break_stmt: 'break'
+      continue_stmt: 'continue'
+      return_stmt: 'return' [testlist]
+      yield_stmt: yield_expr
+      yield_expr: 'yield' testlist
+      raise_stmt: 'raise' [test [',' test [',' test]]]
+    */
+    node *ch;
+
+    REQ(n, flow_stmt);
+    ch = CHILD(n, 0);
+    switch (TYPE(ch)) {
+        case break_stmt:
+            return Break(LINENO(n));
+        case continue_stmt:
+            return Continue(LINENO(n));
+        case yield_stmt: { /* will reduce to yield_expr */
+           expr_ty exp = ast_for_expr(c, CHILD(ch, 0));
+           if (!exp)
+               return NULL;
+            return Expr(exp, LINENO(n));
+        }
+        case return_stmt:
+            if (NCH(ch) == 1)
+                return Return(NULL, LINENO(n));
+            else {
+                expr_ty expression = ast_for_testlist(c, CHILD(ch, 1), 0);
+                if (!expression)
+                    return NULL;
+                return Return(expression, LINENO(n));
+            }
+        case raise_stmt:
+            if (NCH(ch) == 1)
+                return Raise(NULL, NULL, NULL, LINENO(n));
+            else if (NCH(ch) == 2) {
+                expr_ty expression = ast_for_expr(c, CHILD(ch, 1));
+                if (!expression)
+                    return NULL;
+                return Raise(expression, NULL, NULL, LINENO(n));
+            }
+            else if (NCH(ch) == 4) {
+                expr_ty expr1, expr2;
+
+                expr1 = ast_for_expr(c, CHILD(ch, 1));
+                if (!expr1)
+                    return NULL;
+                expr2 = ast_for_expr(c, CHILD(ch, 3));
+                if (!expr2)
+                    return NULL;
+
+                return Raise(expr1, expr2, NULL, LINENO(n));
+            }
+            else if (NCH(ch) == 6) {
+                expr_ty expr1, expr2, expr3;
+
+                expr1 = ast_for_expr(c, CHILD(ch, 1));
+                if (!expr1)
+                    return NULL;
+                expr2 = ast_for_expr(c, CHILD(ch, 3));
+                if (!expr2)
+                    return NULL;
+                expr3 = ast_for_expr(c, CHILD(ch, 5));
+                if (!expr3)
+                    return NULL;
+                    
+                return Raise(expr1, expr2, expr3, LINENO(n));
+            }
+        default:
+            PyErr_Format(PyExc_Exception,
+                         "unexpected flow_stmt: %d", TYPE(ch));
+            return NULL;
+    }
+}
+
+static alias_ty
+alias_for_import_name(const node *n)
+{
+    /*
+      import_as_name: NAME [NAME NAME]
+      dotted_as_name: dotted_name [NAME NAME]
+      dotted_name: NAME ('.' NAME)*
+    */
+ loop:
+    switch (TYPE(n)) {
+        case import_as_name:
+            if (NCH(n) == 3)
+                return alias(NEW_IDENTIFIER(CHILD(n, 0)),
+                             NEW_IDENTIFIER(CHILD(n, 2)));
+            else
+                return alias(NEW_IDENTIFIER(CHILD(n, 0)),
+                             NULL);
+            break;
+        case dotted_as_name:
+            if (NCH(n) == 1) {
+                n = CHILD(n, 0);
+                goto loop;
+            }
+            else {
+                alias_ty a = alias_for_import_name(CHILD(n, 0));
+                assert(!a->asname);
+                a->asname = NEW_IDENTIFIER(CHILD(n, 2));
+                return a;
+            }
+            break;
+        case dotted_name:
+            if (NCH(n) == 1)
+                return alias(NEW_IDENTIFIER(CHILD(n, 0)), NULL);
+            else {
+                /* Create a string of the form "a.b.c" */
+                int i, len;
+                PyObject *str;
+                char *s;
+
+                len = 0;
+                for (i = 0; i < NCH(n); i += 2)
+                    /* length of string plus one for the dot */
+                    len += strlen(STR(CHILD(n, i))) + 1;
+                len--; /* the last name doesn't have a dot */
+                str = PyString_FromStringAndSize(NULL, len);
+                if (!str)
+                    return NULL;
+                s = PyString_AS_STRING(str);
+                if (!s)
+                    return NULL;
+                for (i = 0; i < NCH(n); i += 2) {
+                    char *sch = STR(CHILD(n, i));
+                    strcpy(s, STR(CHILD(n, i)));
+                    s += strlen(sch);
+                    *s++ = '.';
+                }
+                --s;
+                *s = '\0';
+                PyString_InternInPlace(&str);
+                return alias(str, NULL);
+            }
+            break;
+        case STAR:
+            return alias(PyString_InternFromString("*"), NULL);
+        default:
+            PyErr_Format(PyExc_Exception,
+                         "unexpected import name: %d", TYPE(n));
+            return NULL;
+    }
+    return NULL;
+}
+
+static stmt_ty
+ast_for_import_stmt(struct compiling *c, const node *n)
+{
+    /*
+      import_stmt: import_name | import_from
+      import_name: 'import' dotted_as_names
+      import_from: 'from' dotted_name 'import' ('*' | 
+                                                '(' import_as_names ')' | 
+                                                import_as_names)
+    */
+    int i;
+    asdl_seq *aliases;
+
+    REQ(n, import_stmt);
+    n = CHILD(n, 0);
+    if (STR(CHILD(n, 0))[0] == 'i') { /* import */
+        n = CHILD(n, 1);
+       aliases = asdl_seq_new((NCH(n) + 1) / 2);
+       if (!aliases)
+               return NULL;
+       for (i = 0; i < NCH(n); i += 2) {
+            alias_ty import_alias = alias_for_import_name(CHILD(n, i));
+            if (!import_alias) {
+                asdl_seq_free(aliases);
+                return NULL;
+            }
+           asdl_seq_SET(aliases, i / 2, import_alias);
+        }
+       return Import(aliases, LINENO(n));
+    }
+    else if (STR(CHILD(n, 0))[0] == 'f') { /* from */
+       stmt_ty import;
+        int n_children;
+        const char *from_modules;
+       int lineno = LINENO(n);
+       alias_ty mod = alias_for_import_name(CHILD(n, 1));
+       if (!mod)
+            return NULL;
+
+        /* XXX this needs to be cleaned up */
+
+        from_modules = STR(CHILD(n, 3));
+        if (!from_modules) {
+            n = CHILD(n, 3);                  /* from ... import x, y, z */
+            if (NCH(n) % 2 == 0) {
+                /* it ends with a comma, not valid but the parser allows it */
+                ast_error(n, "trailing comma not allowed without"
+                             " surrounding parentheses");
+                return NULL;
+            }
+        }
+        else if (from_modules[0] == '*') {
+            n = CHILD(n, 3); /* from ... import * */
+        }
+        else if (from_modules[0] == '(')
+            n = CHILD(n, 4);                  /* from ... import (x, y, z) */
+        else
+            return NULL;
+
+        n_children = NCH(n);
+        if (from_modules && from_modules[0] == '*')
+            n_children = 1;
+
+       aliases = asdl_seq_new((n_children + 1) / 2);
+       if (!aliases) {
+            free_alias(mod);
+            return NULL;
+       }
+
+        /* handle "from ... import *" special b/c there's no children */
+        if (from_modules && from_modules[0] == '*') {
+            alias_ty import_alias = alias_for_import_name(n);
+            if (!import_alias) {
+                asdl_seq_free(aliases);
+                free_alias(mod);
+                return NULL;
+            }
+           asdl_seq_APPEND(aliases, import_alias);
+        }
+
+       for (i = 0; i < NCH(n); i += 2) {
+            alias_ty import_alias = alias_for_import_name(CHILD(n, i));
+            if (!import_alias) {
+                asdl_seq_free(aliases);
+                free_alias(mod);
+                return NULL;
+            }
+           asdl_seq_APPEND(aliases, import_alias);
+        }
+        Py_INCREF(mod->name);
+       import = ImportFrom(mod->name, aliases, lineno);
+       free_alias(mod);
+       return import;
+    }
+    PyErr_Format(PyExc_Exception,
+                 "unknown import statement: starts with command '%s'",
+                 STR(CHILD(n, 0)));
+    return NULL;
+}
+
+static stmt_ty
+ast_for_global_stmt(struct compiling *c, const node *n)
+{
+    /* global_stmt: 'global' NAME (',' NAME)* */
+    identifier name;
+    asdl_seq *s;
+    int i;
+
+    REQ(n, global_stmt);
+    s = asdl_seq_new(NCH(n) / 2);
+    if (!s)
+       return NULL;
+    for (i = 1; i < NCH(n); i += 2) {
+       name = NEW_IDENTIFIER(CHILD(n, i));
+       if (!name) {
+           asdl_seq_free(s);
+           return NULL;
+       }
+       asdl_seq_SET(s, i / 2, name);
+    }
+    return Global(s, LINENO(n));
+}
+
+static stmt_ty
+ast_for_exec_stmt(struct compiling *c, const node *n)
+{
+    expr_ty expr1, globals = NULL, locals = NULL;
+    int n_children = NCH(n);
+    if (n_children != 2 && n_children != 4 && n_children != 6) {
+        PyErr_Format(PyExc_Exception,
+                     "poorly formed 'exec' statement: %d parts to statement",
+                     n_children);
+        return NULL;
+    }
+
+    /* exec_stmt: 'exec' expr ['in' test [',' test]] */
+    REQ(n, exec_stmt);
+    expr1 = ast_for_expr(c, CHILD(n, 1));
+    if (!expr1)
+        return NULL;
+    if (n_children >= 4) {
+        globals = ast_for_expr(c, CHILD(n, 3));
+        if (!globals)
+            return NULL;
+    }
+    if (n_children == 6) {
+        locals = ast_for_expr(c, CHILD(n, 5));
+        if (!locals)
+            return NULL;
+    }
+
+    return Exec(expr1, globals, locals, LINENO(n));
+}
+
+static stmt_ty
+ast_for_assert_stmt(struct compiling *c, const node *n)
+{
+    /* assert_stmt: 'assert' test [',' test] */
+    REQ(n, assert_stmt);
+    if (NCH(n) == 2) {
+        expr_ty expression = ast_for_expr(c, CHILD(n, 1));
+        if (!expression)
+            return NULL;
+       return Assert(expression, NULL, LINENO(n));
+    }
+    else if (NCH(n) == 4) {
+        expr_ty expr1, expr2;
+
+        expr1 = ast_for_expr(c, CHILD(n, 1));
+        if (!expr1)
+            return NULL;
+        expr2 = ast_for_expr(c, CHILD(n, 3));
+        if (!expr2)
+            return NULL;
+            
+       return Assert(expr1, expr2, LINENO(n));
+    }
+    PyErr_Format(PyExc_Exception,
+                 "improper number of parts to 'assert' statement: %d",
+                 NCH(n));
+    return NULL;
+}
+
+static asdl_seq *
+ast_for_suite(struct compiling *c, const node *n)
+{
+    /* suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT */
+    asdl_seq *seq = NULL;
+    stmt_ty s;
+    int i, total, num, end, pos = 0;
+    node *ch;
+
+    REQ(n, suite);
+
+    total = num_stmts(n);
+    seq = asdl_seq_new(total);
+    if (!seq)
+       return NULL;
+    if (TYPE(CHILD(n, 0)) == simple_stmt) {
+       n = CHILD(n, 0);
+       /* simple_stmt always ends with a NEWLINE,
+          and may have a trailing SEMI 
+       */
+       end = NCH(n) - 1;
+       if (TYPE(CHILD(n, end - 1)) == SEMI)
+           end--;
+        /* loop by 2 to skip semi-colons */
+       for (i = 0; i < end; i += 2) {
+           ch = CHILD(n, i);
+           s = ast_for_stmt(c, ch);
+           if (!s)
+               goto error;
+           asdl_seq_SET(seq, pos++, s);
+       }
+    }
+    else {
+       for (i = 2; i < (NCH(n) - 1); i++) {
+           ch = CHILD(n, i);
+           REQ(ch, stmt);
+           num = num_stmts(ch);
+           if (num == 1) {
+               /* small_stmt or compound_stmt with only one child */
+               s = ast_for_stmt(c, ch);
+               if (!s)
+                   goto error;
+               asdl_seq_SET(seq, pos++, s);
+           }
+           else {
+               int j;
+               ch = CHILD(ch, 0);
+               REQ(ch, simple_stmt);
+               for (j = 0; j < NCH(ch); j += 2) {
+                   s = ast_for_stmt(c, CHILD(ch, j));
+                   if (!s)
+                       goto error;
+                   asdl_seq_SET(seq, pos++, s);
+               }
+           }
+       }
+    }
+    assert(pos == seq->size);
+    return seq;
+ error:
+    if (seq)
+       asdl_seq_free(seq);
+    return NULL;
+}
+
+static stmt_ty
+ast_for_if_stmt(struct compiling *c, const node *n)
+{
+    /* if_stmt: 'if' test ':' suite ('elif' test ':' suite)*
+       ['else' ':' suite]
+    */
+    char *s;
+
+    REQ(n, if_stmt);
+
+    if (NCH(n) == 4) {
+        expr_ty expression;
+        asdl_seq *suite_seq;
+
+        expression = ast_for_expr(c, CHILD(n, 1));
+        if (!expression)
+            return NULL;
+        suite_seq = ast_for_suite(c, CHILD(n, 3)); 
+        if (!suite_seq)
+            return NULL;
+            
+       return If(expression, suite_seq, NULL, LINENO(n));
+    }
+    s = STR(CHILD(n, 4));
+    /* s[2], the third character in the string, will be
+       's' for el_s_e, or
+       'i' for el_i_f
+    */
+    if (s[2] == 's') {
+        expr_ty expression;
+        asdl_seq *seq1, *seq2;
+
+        expression = ast_for_expr(c, CHILD(n, 1));
+        if (!expression)
+            return NULL;
+        seq1 = ast_for_suite(c, CHILD(n, 3));
+        if (!seq1)
+            return NULL;
+        seq2 = ast_for_suite(c, CHILD(n, 6));
+        if (!seq2)
+            return NULL;
+
+       return If(expression, seq1, seq2, LINENO(n));
+    }
+    else if (s[2] == 'i') {
+       int i, n_elif, has_else = 0;
+       asdl_seq *orelse = NULL;
+       n_elif = NCH(n) - 4;
+        /* must reference the child n_elif+1 since 'else' token is third,
+           not fourth, child from the end. */
+       if (TYPE(CHILD(n, (n_elif + 1))) == NAME
+           && STR(CHILD(n, (n_elif + 1)))[2] == 's') {
+           has_else = 1;
+           n_elif -= 3;
+       }
+       n_elif /= 4;
+
+       if (has_else) {
+            expr_ty expression;
+            asdl_seq *seq1, *seq2;
+
+           orelse = asdl_seq_new(1);
+           if (!orelse)
+               return NULL;
+            expression = ast_for_expr(c, CHILD(n, NCH(n) - 6));
+            if (!expression) {
+                asdl_seq_free(orelse);
+                return NULL;
+            }
+            seq1 = ast_for_suite(c, CHILD(n, NCH(n) - 4));
+            if (!seq1) {
+                asdl_seq_free(orelse);
+                return NULL;
+            }
+            seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1));
+            if (!seq2) {
+                asdl_seq_free(orelse);
+                return NULL;
+            }
+
+           asdl_seq_SET(orelse, 0, If(expression, seq1, seq2, 
+                                      LINENO(CHILD(n, NCH(n) - 6))));
+           /* the just-created orelse handled the last elif */
+           n_elif--;
+       }
+        else
+            orelse  = NULL;
+
+       for (i = 0; i < n_elif; i++) {
+           int off = 5 + (n_elif - i - 1) * 4;
+            expr_ty expression;
+            asdl_seq *suite_seq;
+           asdl_seq *new = asdl_seq_new(1);
+           if (!new)
+               return NULL;
+            expression = ast_for_expr(c, CHILD(n, off));
+            if (!expression) {
+                asdl_seq_free(new);
+                return NULL;
+            }
+            suite_seq = ast_for_suite(c, CHILD(n, off + 2));
+            if (!suite_seq) {
+                asdl_seq_free(new);
+                return NULL;
+            }
+
+           asdl_seq_SET(new, 0,
+                        If(expression, suite_seq, orelse, 
+                           LINENO(CHILD(n, off))));
+           orelse = new;
+       }
+       return If(ast_for_expr(c, CHILD(n, 1)),
+                 ast_for_suite(c, CHILD(n, 3)),
+                 orelse, LINENO(n));
+    }
+    else {
+        PyErr_Format(PyExc_Exception,
+                     "unexpected token in 'if' statement: %s", s);
+        return NULL;
+    }
+}
+
+static stmt_ty
+ast_for_while_stmt(struct compiling *c, const node *n)
+{
+    /* while_stmt: 'while' test ':' suite ['else' ':' suite] */
+    REQ(n, while_stmt);
+
+    if (NCH(n) == 4) {
+        expr_ty expression;
+        asdl_seq *suite_seq;
+
+        expression = ast_for_expr(c, CHILD(n, 1));
+        if (!expression)
+            return NULL;
+        suite_seq = ast_for_suite(c, CHILD(n, 3));
+        if (!suite_seq)
+            return NULL;
+       return While(expression, suite_seq, NULL, LINENO(n));
+    }
+    else if (NCH(n) == 7) {
+        expr_ty expression;
+        asdl_seq *seq1, *seq2;
+
+        expression = ast_for_expr(c, CHILD(n, 1));
+        if (!expression)
+            return NULL;
+        seq1 = ast_for_suite(c, CHILD(n, 3));
+        if (!seq1)
+            return NULL;
+        seq2 = ast_for_suite(c, CHILD(n, 6));
+        if (!seq2)
+            return NULL;
+
+       return While(expression, seq1, seq2, LINENO(n));
+    }
+    else {
+        PyErr_Format(PyExc_Exception,
+                     "wrong number of tokens for 'while' statement: %d",
+                     NCH(n));
+        return NULL;
+    }
+}
+
+static stmt_ty
+ast_for_for_stmt(struct compiling *c, const node *n)
+{
+    asdl_seq *_target = NULL, *seq = NULL, *suite_seq = NULL;
+    expr_ty expression;
+    expr_ty target;
+    /* for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] */
+    REQ(n, for_stmt);
+
+    if (NCH(n) == 9) {
+       seq = ast_for_suite(c, CHILD(n, 8));
+        if (!seq)
+            return NULL;
+    }
+
+    _target = ast_for_exprlist(c, CHILD(n, 1), Store);
+    if (!_target)
+        return NULL;
+    if (asdl_seq_LEN(_target) == 1) {
+       target = asdl_seq_GET(_target, 0);
+       asdl_seq_free(_target);
+    }
+    else
+       target = Tuple(_target, Store, LINENO(n));
+
+    expression = ast_for_testlist(c, CHILD(n, 3), 0);
+    if (!expression)
+        return NULL;
+    suite_seq = ast_for_suite(c, CHILD(n, 5));
+    if (!suite_seq)
+        return NULL;
+
+    return For(target, expression, suite_seq, seq, LINENO(n));
+}
+
+static excepthandler_ty
+ast_for_except_clause(struct compiling *c, const node *exc, node *body)
+{
+    /* except_clause: 'except' [test [',' test]] */
+    REQ(exc, except_clause);
+    REQ(body, suite);
+
+    if (NCH(exc) == 1) {
+        asdl_seq *suite_seq = ast_for_suite(c, body);
+        if (!suite_seq)
+            return NULL;
+
+       return excepthandler(NULL, NULL, suite_seq);
+    }
+    else if (NCH(exc) == 2) {
+        expr_ty expression;
+        asdl_seq *suite_seq;
+
+        expression = ast_for_expr(c, CHILD(exc, 1));
+        if (!expression)
+            return NULL;
+        suite_seq = ast_for_suite(c, body);
+        if (!suite_seq)
+            return NULL;
+
+       return excepthandler(expression, NULL, suite_seq);
+    }
+    else if (NCH(exc) == 4) {
+        asdl_seq *suite_seq;
+        expr_ty expression;
+       expr_ty e = ast_for_expr(c, CHILD(exc, 3));
+       if (!e)
+            return NULL;
+       if (!set_context(e, Store, CHILD(exc, 3)))
+            return NULL;
+        expression = ast_for_expr(c, CHILD(exc, 1));
+        if (!expression)
+            return NULL;
+        suite_seq = ast_for_suite(c, body);
+        if (!suite_seq)
+            return NULL;
+
+       return excepthandler(expression, e, suite_seq);
+    }
+    else {
+        PyErr_Format(PyExc_Exception,
+                     "wrong number of children for 'except' clause: %d",
+                     NCH(exc));
+        return NULL;
+    }
+}
+
+static stmt_ty
+ast_for_try_stmt(struct compiling *c, const node *n)
+{
+    REQ(n, try_stmt);
+
+    if (TYPE(CHILD(n, 3)) == NAME) {/* must be 'finally' */
+       /* try_stmt: 'try' ':' suite 'finally' ':' suite) */
+        asdl_seq *s1, *s2;
+        s1 = ast_for_suite(c, CHILD(n, 2));
+        if (!s1)
+            return NULL;
+        s2 = ast_for_suite(c, CHILD(n, 5));
+        if (!s2)
+            return NULL;
+            
+       return TryFinally(s1, s2, LINENO(n));
+    }
+    else if (TYPE(CHILD(n, 3)) == except_clause) {
+       /* try_stmt: ('try' ':' suite (except_clause ':' suite)+
+           ['else' ':' suite]
+       */
+        asdl_seq *suite_seq1, *suite_seq2;
+       asdl_seq *handlers;
+       int i, has_else = 0, n_except = NCH(n) - 3;
+       if (TYPE(CHILD(n, NCH(n) - 3)) == NAME) {
+           has_else = 1;
+           n_except -= 3;
+       }
+       n_except /= 3;
+       handlers = asdl_seq_new(n_except);
+       if (!handlers)
+               return NULL;
+       for (i = 0; i < n_except; i++) {
+            excepthandler_ty e = ast_for_except_clause(c,
+                                                       CHILD(n, 3 + i * 3),
+                                                       CHILD(n, 5 + i * 3));
+            if (!e)
+                return NULL;
+           asdl_seq_SET(handlers, i, e);
+        }
+
+        suite_seq1 = ast_for_suite(c, CHILD(n, 2));
+        if (!suite_seq1)
+            return NULL;
+        if (has_else) {
+            suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1));
+            if (!suite_seq2)
+                return NULL;
+        }
+        else
+            suite_seq2 = NULL;
+
+       return TryExcept(suite_seq1, handlers, suite_seq2, LINENO(n));
+    }
+    else {
+        PyErr_SetString(PyExc_Exception, "malformed 'try' statement");
+        return NULL;
+    }
+}
+
+static stmt_ty
+ast_for_classdef(struct compiling *c, const node *n)
+{
+    /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
+    expr_ty _bases;
+    asdl_seq *bases, *s;
+    
+    REQ(n, classdef);
+
+    if (!strcmp(STR(CHILD(n, 1)), "None")) {
+           ast_error(n, "assignment to None");
+           return NULL;
+    }
+
+    if (NCH(n) == 4) {
+        s = ast_for_suite(c, CHILD(n, 3));
+        if (!s)
+            return NULL;
+       return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n));
+    }
+    /* check for empty base list */
+    if (TYPE(CHILD(n,3)) == RPAR) {
+       s = ast_for_suite(c, CHILD(n,5));
+       if (!s)
+               return NULL;
+       return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n));
+    }
+
+    /* else handle the base class list */
+    _bases = ast_for_testlist(c, CHILD(n, 3), 0);
+    if (!_bases)
+        return NULL;
+    /* XXX: I don't think we can set to diff types here, how to free???
+
+       Here's the allocation chain:
+               Tuple (Python-ast.c:907)
+               ast_for_testlist (ast.c:1782)
+               ast_for_classdef (ast.c:2677)
+     */
+    if (_bases->kind == Tuple_kind)
+       bases = _bases->v.Tuple.elts;
+    else {
+       bases = asdl_seq_new(1);
+       if (!bases) {
+            free_expr(_bases);
+           /* XXX: free _bases */
+            return NULL;
+       }
+       asdl_seq_SET(bases, 0, _bases);
+    }
+
+    s = ast_for_suite(c, CHILD(n, 6));
+    if (!s) {
+       /* XXX: I think this free is correct, but needs to change see above */
+        if (_bases->kind == Tuple_kind)
+               free_expr(_bases);
+       else {
+               free_expr(_bases);
+               asdl_seq_free(bases);
+       }
+        return NULL;
+    }
+    return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), bases, s, LINENO(n));
+}
+
+static stmt_ty
+ast_for_stmt(struct compiling *c, const node *n)
+{
+    if (TYPE(n) == stmt) {
+       assert(NCH(n) == 1);
+       n = CHILD(n, 0);
+    }
+    if (TYPE(n) == simple_stmt) {
+       assert(num_stmts(n) == 1);
+       n = CHILD(n, 0);
+    }
+    if (TYPE(n) == small_stmt) {
+       REQ(n, small_stmt);
+       n = CHILD(n, 0);
+       /* small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt
+                    | flow_stmt | import_stmt | global_stmt | exec_stmt
+                     | assert_stmt
+       */
+       switch (TYPE(n)) {
+            case expr_stmt:
+                return ast_for_expr_stmt(c, n);
+            case print_stmt:
+                return ast_for_print_stmt(c, n);
+            case del_stmt:
+                return ast_for_del_stmt(c, n);
+            case pass_stmt:
+                return Pass(LINENO(n));
+            case flow_stmt:
+                return ast_for_flow_stmt(c, n);
+            case import_stmt:
+                return ast_for_import_stmt(c, n);
+            case global_stmt:
+                return ast_for_global_stmt(c, n);
+            case exec_stmt:
+                return ast_for_exec_stmt(c, n);
+            case assert_stmt:
+                return ast_for_assert_stmt(c, n);
+            default:
+                PyErr_Format(PyExc_Exception,
+                             "unhandled small_stmt: TYPE=%d NCH=%d\n",
+                             TYPE(n), NCH(n));
+                return NULL;
+        }
+    }
+    else {
+        /* compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt
+                       | funcdef | classdef
+       */
+       node *ch = CHILD(n, 0);
+       REQ(n, compound_stmt);
+       switch (TYPE(ch)) {
+            case if_stmt:
+                return ast_for_if_stmt(c, ch);
+            case while_stmt:
+                return ast_for_while_stmt(c, ch);
+            case for_stmt:
+                return ast_for_for_stmt(c, ch);
+            case try_stmt:
+                return ast_for_try_stmt(c, ch);
+            case funcdef:
+                return ast_for_funcdef(c, ch);
+            case classdef:
+                return ast_for_classdef(c, ch);
+            default:
+                PyErr_Format(PyExc_Exception,
+                             "unhandled small_stmt: TYPE=%d NCH=%d\n",
+                             TYPE(n), NCH(n));
+                return NULL;
+       }
+    }
+}
+
+static PyObject *
+parsenumber(const char *s)
+{
+       const char *end;
+       long x;
+       double dx;
+#ifndef WITHOUT_COMPLEX
+       Py_complex c;
+       int imflag;
+#endif
+
+       errno = 0;
+       end = s + strlen(s) - 1;
+#ifndef WITHOUT_COMPLEX
+       imflag = *end == 'j' || *end == 'J';
+#endif
+       if (*end == 'l' || *end == 'L')
+               return PyLong_FromString((char *)s, (char **)0, 0);
+       if (s[0] == '0') {
+               x = (long) PyOS_strtoul((char *)s, (char **)&end, 0);
+               if (x < 0 && errno == 0) {
+                               return PyLong_FromString((char *)s,
+                                                        (char **)0,
+                                                        0);
+               }
+       }
+       else
+               x = PyOS_strtol((char *)s, (char **)&end, 0);
+       if (*end == '\0') {
+               if (errno != 0)
+                       return PyLong_FromString((char *)s, (char **)0, 0);
+               return PyInt_FromLong(x);
+       }
+       /* XXX Huge floats may silently fail */
+#ifndef WITHOUT_COMPLEX
+       if (imflag) {
+               c.real = 0.;
+               PyFPE_START_PROTECT("atof", return 0)
+               c.imag = atof(s);
+               PyFPE_END_PROTECT(c)
+               return PyComplex_FromCComplex(c);
+       }
+       else
+#endif
+       {
+               PyFPE_START_PROTECT("atof", return 0)
+               dx = atof(s);
+               PyFPE_END_PROTECT(dx)
+               return PyFloat_FromDouble(dx);
+       }
+}
+
+static PyObject *
+decode_utf8(const char **sPtr, const char *end, char* encoding)
+{
+#ifndef Py_USING_UNICODE
+       Py_FatalError("decode_utf8 should not be called in this build.");
+        return NULL;
+#else
+       PyObject *u, *v;
+       char *s, *t;
+       t = s = (char *)*sPtr;
+       /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */
+       while (s < end && (*s & 0x80)) s++;
+       *sPtr = s;
+       u = PyUnicode_DecodeUTF8(t, s - t, NULL);
+       if (u == NULL)
+               return NULL;
+       v = PyUnicode_AsEncodedString(u, encoding, NULL);
+       Py_DECREF(u);
+       return v;
+#endif
+}
+
+static PyObject *
+decode_unicode(const char *s, size_t len, int rawmode, const char *encoding)
+{
+       PyObject *v, *u;
+       char *buf;
+       char *p;
+       const char *end;
+       if (encoding == NULL) {
+               buf = (char *)s;
+               u = NULL;
+       } else if (strcmp(encoding, "iso-8859-1") == 0) {
+               buf = (char *)s;
+               u = NULL;
+       } else {
+               /* "\XX" may become "\u005c\uHHLL" (12 bytes) */
+               u = PyString_FromStringAndSize((char *)NULL, len * 4);
+               if (u == NULL)
+                       return NULL;
+               p = buf = PyString_AsString(u);
+               end = s + len;
+               while (s < end) {
+                       if (*s == '\\') {
+                               *p++ = *s++;
+                               if (*s & 0x80) {
+                                       strcpy(p, "u005c");
+                                       p += 5;
+                               }
+                       }
+                       if (*s & 0x80) { /* XXX inefficient */
+                               PyObject *w;
+                               char *r;
+                               int rn, i;
+                               w = decode_utf8(&s, end, "utf-16-be");
+                               if (w == NULL) {
+                                       Py_DECREF(u);
+                                       return NULL;
+                               }
+                               r = PyString_AsString(w);
+                               rn = PyString_Size(w);
+                               assert(rn % 2 == 0);
+                               for (i = 0; i < rn; i += 2) {
+                                       sprintf(p, "\\u%02x%02x",
+                                               r[i + 0] & 0xFF,
+                                               r[i + 1] & 0xFF);
+                                       p += 6;
+                               }
+                               Py_DECREF(w);
+                       } else {
+                               *p++ = *s++;
+                       }
+               }
+               len = p - buf;
+               s = buf;
+       }
+       if (rawmode)
+               v = PyUnicode_DecodeRawUnicodeEscape(s, len, NULL);
+       else
+               v = PyUnicode_DecodeUnicodeEscape(s, len, NULL);
+       Py_XDECREF(u);
+       return v;
+}
+
+/* s is a Python string literal, including the bracketing quote characters,
+ * and r &/or u prefixes (if any), and embedded escape sequences (if any).
+ * parsestr parses it, and returns the decoded Python string object.
+ */
+static PyObject *
+parsestr(const char *s, const char *encoding)
+{
+       PyObject *v;
+       size_t len;
+       int quote = *s;
+       int rawmode = 0;
+       int need_encoding;
+       int unicode = 0;
+
+       if (isalpha(quote) || quote == '_') {
+               if (quote == 'u' || quote == 'U') {
+                       quote = *++s;
+                       unicode = 1;
+               }
+               if (quote == 'r' || quote == 'R') {
+                       quote = *++s;
+                       rawmode = 1;
+               }
+       }
+       if (quote != '\'' && quote != '\"') {
+               PyErr_BadInternalCall();
+               return NULL;
+       }
+       s++;
+       len = strlen(s);
+       if (len > INT_MAX) {
+               PyErr_SetString(PyExc_OverflowError, 
+                               "string to parse is too long");
+               return NULL;
+       }
+       if (s[--len] != quote) {
+               PyErr_BadInternalCall();
+               return NULL;
+       }
+       if (len >= 4 && s[0] == quote && s[1] == quote) {
+               s += 2;
+               len -= 2;
+               if (s[--len] != quote || s[--len] != quote) {
+                       PyErr_BadInternalCall();
+                       return NULL;
+               }
+       }
+#ifdef Py_USING_UNICODE
+       if (unicode || Py_UnicodeFlag) {
+               return decode_unicode(s, len, rawmode, encoding);
+       }
+#endif
+       need_encoding = (encoding != NULL &&
+                        strcmp(encoding, "utf-8") != 0 &&
+                        strcmp(encoding, "iso-8859-1") != 0);
+       if (rawmode || strchr(s, '\\') == NULL) {
+               if (need_encoding) {
+#ifndef Py_USING_UNICODE
+                       /* This should not happen - we never see any other
+                          encoding. */
+                       Py_FatalError("cannot deal with encodings in this build.");
+#else
+                       PyObject* u = PyUnicode_DecodeUTF8(s, len, NULL);
+                       if (u == NULL)
+                               return NULL;
+                       v = PyUnicode_AsEncodedString(u, encoding, NULL);
+                       Py_DECREF(u);
+                       return v;
+#endif
+               } else {
+                       return PyString_FromStringAndSize(s, len);
+               }
+       }
+
+       v = PyString_DecodeEscape(s, len, NULL, unicode,
+                                 need_encoding ? encoding : NULL);
+       return v;
+}
+
+/* Build a Python string object out of a STRING atom.  This takes care of
+ * compile-time literal catenation, calling parsestr() on each piece, and
+ * pasting the intermediate results together.
+ */
+static PyObject *
+parsestrplus(struct compiling *c, const node *n)
+{
+       PyObject *v;
+       int i;
+       REQ(CHILD(n, 0), STRING);
+       if ((v = parsestr(STR(CHILD(n, 0)), c->c_encoding)) != NULL) {
+               /* String literal concatenation */
+               for (i = 1; i < NCH(n); i++) {
+                       PyObject *s;
+                       s = parsestr(STR(CHILD(n, i)), c->c_encoding);
+                       if (s == NULL)
+                               goto onError;
+                       if (PyString_Check(v) && PyString_Check(s)) {
+                               PyString_ConcatAndDel(&v, s);
+                               if (v == NULL)
+                                   goto onError;
+                       }
+#ifdef Py_USING_UNICODE
+                       else {
+                               PyObject *temp;
+                               temp = PyUnicode_Concat(v, s);
+                               Py_DECREF(s);
+                               if (temp == NULL)
+                                       goto onError;
+                               Py_DECREF(v);
+                               v = temp;
+                       }
+#endif
+               }
+       }
+       return v;
+
+ onError:
+       Py_XDECREF(v);
+       return NULL;
+}
index 3e5f4ebfefa609120e437662d431d006d88f33f1..2d51531f19c35442dca30db74de22acc1949d2c8 100644 (file)
@@ -1,9 +1,9 @@
-
 /* Built-in functions */
 
 #include "Python.h"
 
 #include "node.h"
+#include "code.h"
 #include "compile.h"
 #include "eval.h"
 
index 38b1328f5ded4c52bc62bf9de90ebffc34de8006..fdfe83e0e4510f5c1a9cba076795dddac91b1cf3 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "Python.h"
 
-#include "compile.h"
+#include "code.h"
 #include "frameobject.h"
 #include "eval.h"
 #include "opcode.h"
@@ -543,7 +543,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
 #ifdef LLTRACE
        int lltrace;
 #endif
-#if defined(Py_DEBUG) || defined(LLTRACE)
+#if defined(Py_DEBUG)
        /* Make it easier to find out where we are with a debugger */
        char *filename;
 #endif
@@ -743,9 +743,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
        f->f_stacktop = NULL;   /* remains NULL unless yield suspends frame */
 
 #ifdef LLTRACE
-       lltrace = PyDict_GetItemString(f->f_globals,"__lltrace__") != NULL;
+       lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL;
 #endif
-#if defined(Py_DEBUG) || defined(LLTRACE)
+#if defined(Py_DEBUG)
        filename = PyString_AsString(co->co_filename);
 #endif
 
@@ -2257,23 +2257,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
 
                case MAKE_CLOSURE:
                {
-                       int nfree;
                        v = POP(); /* code object */
                        x = PyFunction_New(v, f->f_globals);
-                       nfree = PyCode_GetNumFree((PyCodeObject *)v);
                        Py_DECREF(v);
-                       /* XXX Maybe this should be a separate opcode? */
-                       if (x != NULL && nfree > 0) {
-                               v = PyTuple_New(nfree);
-                               if (v == NULL) {
-                                       Py_DECREF(x);
-                                       x = NULL;
-                                       break;
-                               }
-                               while (--nfree >= 0) {
-                                       w = POP();
-                                       PyTuple_SET_ITEM(v, nfree, w);
-                               }
+                       if (x != NULL) {
+                               v = POP();
                                err = PyFunction_SetClosure(x, v);
                                Py_DECREF(v);
                        }
@@ -2695,12 +2683,18 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
                if (co->co_flags & CO_VARKEYWORDS)
                        nargs++;
 
-               /* Check for cells that shadow args */
-               for (i = 0; i < f->f_ncells && j < nargs; ++i) {
+               /* Initialize each cell var, taking into account
+                  cell vars that are initialized from arguments.
+
+                  Should arrange for the compiler to put cellvars
+                  that are arguments at the beginning of the cellvars
+                  list so that we can march over it more efficiently?
+               */
+               for (i = 0; i < f->f_ncells; ++i) {
                        cellname = PyString_AS_STRING(
                                PyTuple_GET_ITEM(co->co_cellvars, i));
                        found = 0;
-                       while (j < nargs) {
+                       for (j = 0; j < nargs; j++) {
                                argname = PyString_AS_STRING(
                                        PyTuple_GET_ITEM(co->co_varnames, j));
                                if (strcmp(cellname, argname) == 0) {
@@ -2711,7 +2705,6 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
                                        found = 1;
                                        break;
                                }
-                               j++;
                        }
                        if (found == 0) {
                                c = PyCell_New(NULL);
@@ -2720,14 +2713,6 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
                                SETLOCAL(f->f_nlocals + i, c);
                        }
                }
-               /* Initialize any that are left */
-               while (i < f->f_ncells) {
-                       c = PyCell_New(NULL);
-                       if (c == NULL)
-                               goto fail;
-                       SETLOCAL(f->f_nlocals + i, c);
-                       i++;
-               }
        }
        if (f->f_nfreevars) {
                int i;
index 99ccf292529f4591f16344cfa65acc7a3fa3c754..10c94e7fc0f534555a410a8d93b0bed004eca3b2 100644 (file)
-/* Compile an expression node to intermediate code */
-
-/* XXX TO DO:
-   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 finally clause of try-finally
-   XXX New opcode for loading the initial index for a for loop
-   XXX other JAR tricks?
-*/
+/*
+ * This file compiles an abstract syntax tree (AST) into Python bytecode.
+ *
+ * The primary entry point is PyAST_Compile(), which returns a
+ * PyCodeObject.  The compiler makes several passes to build the code
+ * object:
+ *   1. Checks for future statements.  See future.c
+ *   2. Builds a symbol table.  See symtable.c.
+ *   3. Generate code for basic blocks.  See compiler_mod() in this file.
+ *   4. Assemble the basic blocks into final code.  See assemble() in
+ *   this file.  
+ *
+ * Note that compiler_mod() suggests module, but the module ast type
+ * (mod_ty) has cases for expressions and interactive statements.
+ */
 
 #include "Python.h"
 
+#include "Python-ast.h"
 #include "node.h"
-#include "token.h"
-#include "graminit.h"
+#include "ast.h"
+#include "code.h"
 #include "compile.h"
 #include "symtable.h"
 #include "opcode.h"
-#include "structmember.h"
-
-#include <ctype.h>
-
-/* Three symbols from graminit.h are also defined in Python.h, with
-   Py_ prefixes to their names.  Python.h can't include graminit.h
-   (which defines too many confusing symbols), but we can check here
-   that they haven't changed (which is very unlikely, but possible). */
-#if Py_single_input != single_input
-  #error "single_input has changed -- update Py_single_input in Python.h"
-#endif
-#if Py_file_input != file_input
-  #error "file_input has changed -- update Py_file_input in Python.h"
-#endif
-#if Py_eval_input != eval_input
-  #error "eval_input has changed -- update Py_eval_input in Python.h"
-#endif
 
 int Py_OptimizeFlag = 0;
 
-#define OP_DELETE 0
-#define OP_ASSIGN 1
-#define OP_APPLY 2
+/*
+    ISSUES:
 
-#define VAR_LOAD 0
-#define VAR_STORE 1
-#define VAR_DELETE 2
+     character encodings aren't handled
 
-#define DEL_CLOSURE_ERROR \
-"can not delete variable '%.400s' referenced in nested scope"
+     ref leaks in interpreter when press return on empty line
 
-#define DUPLICATE_ARGUMENT \
-"duplicate argument '%s' in function definition"
+     opcode_stack_effect() function should be reviewed since stack depth bugs
+     could be really hard to find later.
 
-#define GLOBAL_AFTER_ASSIGN \
-"name '%.400s' is assigned to before global declaration"
-
-#define GLOBAL_AFTER_USE \
-"name '%.400s' is used prior to global declaration"
+     Dead code is being generated (i.e. after unconditional jumps).
+*/
 
-#define PARAM_GLOBAL \
-"name '%.400s' is a function parameter and declared global"
+#define DEFAULT_BLOCK_SIZE 16
+#define DEFAULT_BLOCKS 8
+#define DEFAULT_CODE_SIZE 128
+#define DEFAULT_LNOTAB_SIZE 16
+
+struct instr {
+       int i_jabs : 1;
+       int i_jrel : 1;
+       int i_hasarg : 1;
+       unsigned char i_opcode;
+       int i_oparg;
+       struct basicblock_ *i_target; /* target block (if jump instruction) */
+       int i_lineno;
+};
 
-#define LATE_FUTURE \
-"from __future__ imports must occur at the beginning of the file"
+typedef struct basicblock_ {
+       /* next block in the list of blocks for a unit (don't confuse with
+        * b_next) */
+       struct basicblock_ *b_list;
+       /* number of instructions used */
+       int b_iused;
+       /* length of instruction array (b_instr) */
+       int b_ialloc;
+       /* pointer to an array of instructions, initially NULL */
+       struct instr *b_instr;
+       /* If b_next is non-NULL, it is a pointer to the next
+          block reached by normal control flow. */
+       struct basicblock_ *b_next;
+       /* b_seen is used to perform a DFS of basicblocks. */
+       int b_seen : 1;
+       /* b_return is true if a RETURN_VALUE opcode is inserted. */
+       int b_return : 1;
+       /* depth of stack upon entry of block, computed by stackdepth() */
+       int b_startdepth;
+       /* instruction offset for block, computed by assemble_jump_offsets() */
+        int b_offset;
+} basicblock;
+
+/* fblockinfo tracks the current frame block.
+
+   A frame block is used to handle loops, try/except, and try/finally.
+   It's called a frame block to distinguish it from a basic block in the
+   compiler IR.
+*/
 
-#define ASSIGN_DEBUG \
-"can not assign to __debug__"
+enum fblocktype { LOOP, EXCEPT, FINALLY_TRY, FINALLY_END };
 
-#define MANGLE_LEN 256
+struct fblockinfo {
+        enum fblocktype fb_type;
+       basicblock *fb_block;
+};
 
-#define OFF(x) offsetof(PyCodeObject, x)
+/* The following items change on entry and exit of code blocks.
+   They must be saved and restored when returning to a block.
+*/
+struct compiler_unit {
+       PySTEntryObject *u_ste;
 
-static PyMemberDef 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},
-       {"co_names",    T_OBJECT,       OFF(co_names),          READONLY},
-       {"co_varnames", T_OBJECT,       OFF(co_varnames),       READONLY},
-       {"co_freevars", T_OBJECT,       OFF(co_freevars),       READONLY},
-       {"co_cellvars", T_OBJECT,       OFF(co_cellvars),       READONLY},
-       {"co_filename", T_OBJECT,       OFF(co_filename),       READONLY},
-       {"co_name",     T_OBJECT,       OFF(co_name),           READONLY},
-       {"co_firstlineno", T_INT,       OFF(co_firstlineno),    READONLY},
-       {"co_lnotab",   T_OBJECT,       OFF(co_lnotab),         READONLY},
-       {NULL}  /* Sentinel */
+       PyObject *u_name;
+       /* The following fields are dicts that map objects to
+          the index of them in co_XXX.  The index is used as
+          the argument for opcodes that refer to those collections.
+       */
+       PyObject *u_consts;    /* all constants */
+       PyObject *u_names;     /* all names */
+       PyObject *u_varnames;  /* local variables */
+       PyObject *u_cellvars;  /* cell variables */
+       PyObject *u_freevars;  /* free variables */
+
+       PyObject *u_private;    /* for private name mangling */
+
+       int u_argcount;    /* number of arguments for block */ 
+       basicblock *u_blocks; /* pointer to list of blocks */
+       basicblock *u_curblock; /* pointer to current block */
+       int u_tmpname;     /* temporary variables for list comps */
+
+       int u_nfblocks;
+       struct fblockinfo u_fblock[CO_MAXBLOCKS];
+
+       int u_firstlineno; /* the first lineno of the block */
+       int u_lineno;      /* the lineno for the current stmt */
+       bool u_lineno_set; /* boolean to indicate whether instr
+                             has been generated with current lineno */
 };
 
-/* Helper for code_new: return a shallow copy of a tuple that is
-   guaranteed to contain exact strings, by converting string subclasses
-   to exact strings and complaining if a non-string is found. */
-static PyObject*
-validate_and_copy_tuple(PyObject *tup)
-{
-       PyObject *newtuple;
-       PyObject *item;
-       int i, len;
+/* This struct captures the global state of a compilation.  
 
-       len = PyTuple_GET_SIZE(tup);
-       newtuple = PyTuple_New(len);
-       if (newtuple == NULL)
-               return NULL;
+   The u pointer points to the current compilation unit, while units
+   for enclosing blocks are stored in c_stack.  The u and c_stack are
+   managed by compiler_enter_scope() and compiler_exit_scope().
+*/
 
-       for (i = 0; i < len; i++) {
-               item = PyTuple_GET_ITEM(tup, i);
-               if (PyString_CheckExact(item)) {
-                       Py_INCREF(item);
-               }
-               else if (!PyString_Check(item)) {
-                       PyErr_Format(
-                               PyExc_TypeError,
-                               "name tuples must contain only "
-                               "strings, not '%.500s'",
-                               item->ob_type->tp_name);
-                       Py_DECREF(newtuple);
-                       return NULL;
-               }
-               else {
-                       item = PyString_FromStringAndSize(
-                               PyString_AS_STRING(item),
-                               PyString_GET_SIZE(item));
-                       if (item == NULL) {
-                               Py_DECREF(newtuple);
-                               return NULL;
-                       }
-               }
-               PyTuple_SET_ITEM(newtuple, i, item);
-       }
+struct compiler {
+       const char *c_filename;
+       struct symtable *c_st;
+        PyFutureFeatures *c_future; /* pointer to module's __future__ */
+       PyCompilerFlags *c_flags;
 
-       return newtuple;
-}
+       int c_interactive;
+        int c_nestlevel;
 
-PyDoc_STRVAR(code_doc,
-"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\
-      varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\
-\n\
-Create a code object.  Not for the faint of heart.");
+        struct compiler_unit *u; /* compiler state for current block */
+       PyObject *c_stack;       /* Python list holding compiler_unit ptrs */
+       char *c_encoding;        /* source encoding (a borrowed reference) */
+};
 
-static PyObject *
-code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+struct assembler {
+       PyObject *a_bytecode;  /* string containing bytecode */
+       int a_offset;          /* offset into bytecode */
+       int a_nblocks;         /* number of reachable blocks */
+       basicblock **a_postorder; /* list of blocks in dfs postorder */
+       PyObject *a_lnotab;    /* string containing lnotab */
+       int a_lnotab_off;      /* offset into lnotab */
+       int a_lineno;          /* last lineno of emitted instruction */
+       int a_lineno_off;      /* bytecode offset of last lineno */
+};
+
+static int compiler_enter_scope(struct compiler *, identifier, void *, int);
+static void compiler_free(struct compiler *);
+static basicblock *compiler_new_block(struct compiler *);
+static int compiler_next_instr(struct compiler *, basicblock *);
+static int compiler_addop(struct compiler *, int);
+static int compiler_addop_o(struct compiler *, int, PyObject *, PyObject *);
+static int compiler_addop_i(struct compiler *, int, int);
+static int compiler_addop_j(struct compiler *, int, basicblock *, int);
+static void compiler_use_block(struct compiler *, basicblock *);
+static basicblock *compiler_use_new_block(struct compiler *);
+static int compiler_error(struct compiler *, const char *);
+static int compiler_nameop(struct compiler *, identifier, expr_context_ty);
+
+static PyCodeObject *compiler_mod(struct compiler *, mod_ty);
+static int compiler_visit_stmt(struct compiler *, stmt_ty);
+static int compiler_visit_keyword(struct compiler *, keyword_ty);
+static int compiler_visit_expr(struct compiler *, expr_ty);
+static int compiler_augassign(struct compiler *, stmt_ty);
+static int compiler_visit_slice(struct compiler *, slice_ty,
+                               expr_context_ty);
+
+static int compiler_push_fblock(struct compiler *, enum fblocktype,
+                               basicblock *);
+static void compiler_pop_fblock(struct compiler *, enum fblocktype,
+                               basicblock *);
+
+static int inplace_binop(struct compiler *, operator_ty);
+static int expr_constant(expr_ty e);
+
+static PyCodeObject *assemble(struct compiler *, int addNone);
+static PyObject *__doc__;
+
+PyObject *
+_Py_Mangle(PyObject *private, PyObject *ident)
 {
-       int argcount;
-       int nlocals;
-       int stacksize;
-       int flags;
-       PyObject *co = NULL;
-       PyObject *code;
-       PyObject *consts;
-       PyObject *names, *ournames = NULL;
-       PyObject *varnames, *ourvarnames = NULL;
-       PyObject *freevars = NULL, *ourfreevars = NULL;
-       PyObject *cellvars = NULL, *ourcellvars = NULL;
-       PyObject *filename;
-       PyObject *name;
-       int firstlineno;
-       PyObject *lnotab;
-
-       if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code",
-                             &argcount, &nlocals, &stacksize, &flags,
-                             &code,
-                             &PyTuple_Type, &consts,
-                             &PyTuple_Type, &names,
-                             &PyTuple_Type, &varnames,
-                             &filename, &name,
-                             &firstlineno, &lnotab,
-                             &PyTuple_Type, &freevars,
-                             &PyTuple_Type, &cellvars))
-               return NULL;
+       /* Name mangling: __private becomes _classname__private.
+          This is independent from how the name is used. */
+        const char *p, *name = PyString_AsString(ident);
+        char *buffer;
+       size_t nlen, plen;
+       if (private == NULL || name == NULL || name[0] != '_' || name[1] != '_') {
+                Py_INCREF(ident);
+               return ident;
+        }
+        p = PyString_AsString(private);
+       nlen = strlen(name);
+       if (name[nlen-1] == '_' && name[nlen-2] == '_') {
+                Py_INCREF(ident);
+               return ident; /* Don't mangle __whatever__ */
+        }
+       /* Strip leading underscores from class name */
+       while (*p == '_')
+               p++;
+       if (*p == '\0') {
+                Py_INCREF(ident);
+               return ident; /* Don't mangle if class is just underscores */
+        }
+       plen = strlen(p);
+        ident = PyString_FromStringAndSize(NULL, 1 + nlen + plen);
+        if (!ident)
+            return 0;
+       /* ident = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */
+        buffer = PyString_AS_STRING(ident);
+        buffer[0] = '_';
+       strncpy(buffer+1, p, plen);
+       strcpy(buffer+1+plen, name);
+       return ident;
+}
 
-       if (argcount < 0) {
-               PyErr_SetString(
-                       PyExc_ValueError, 
-                       "code: argcount must not be negative");
-               goto cleanup;
-       }
+static int
+compiler_init(struct compiler *c)
+{
+       memset(c, 0, sizeof(struct compiler));
+
+       c->c_stack = PyList_New(0);
+       if (!c->c_stack)
+               return 0;
+
+       return 1;
+}
 
-       if (nlocals < 0) {
-               PyErr_SetString(
-                       PyExc_ValueError, 
-                       "code: nlocals must not be negative");
-               goto cleanup;
+PyCodeObject *
+PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags)
+{
+       struct compiler c;
+       PyCodeObject *co = NULL;
+        PyCompilerFlags local_flags;
+        int merged;
+
+        if (!__doc__) {
+            __doc__ = PyString_InternFromString("__doc__");
+            if (!__doc__)
+                goto error;
+        }
+
+       if (!compiler_init(&c))
+               goto error;
+       c.c_filename = filename;
+       c.c_future = PyFuture_FromAST(mod, filename);
+       if (c.c_future == NULL)
+               goto error;
+       if (!flags) {
+            local_flags.cf_flags = 0;
+            flags = &local_flags;
+        }
+        merged = c.c_future->ff_features | flags->cf_flags;
+        c.c_future->ff_features = merged;
+        flags->cf_flags = merged;
+        c.c_flags = flags;
+        c.c_nestlevel = 0;
+
+       c.c_st = PySymtable_Build(mod, filename, c.c_future);
+       if (c.c_st == NULL) {
+               if (!PyErr_Occurred())
+                       PyErr_SetString(PyExc_SystemError, "no symtable");
+               goto error;
        }
 
-       ournames = validate_and_copy_tuple(names);
-       if (ournames == NULL)
-               goto cleanup;
-       ourvarnames = validate_and_copy_tuple(varnames);
-       if (ourvarnames == NULL)
-               goto cleanup;
-       if (freevars)
-               ourfreevars = validate_and_copy_tuple(freevars);
-       else
-               ourfreevars = PyTuple_New(0);
-       if (ourfreevars == NULL)
-               goto cleanup;
-       if (cellvars)
-               ourcellvars = validate_and_copy_tuple(cellvars);
-       else
-               ourcellvars = PyTuple_New(0);
-       if (ourcellvars == NULL)
-               goto cleanup;
-
-       co = (PyObject *) PyCode_New(argcount, nlocals, stacksize, flags,
-                                    code, consts, ournames, ourvarnames,
-                                    ourfreevars, ourcellvars, filename,
-                                    name, firstlineno, lnotab);
-  cleanup:
-       Py_XDECREF(ournames);
-       Py_XDECREF(ourvarnames);
-       Py_XDECREF(ourfreevars);
-       Py_XDECREF(ourcellvars);
+       /* XXX initialize to NULL for now, need to handle */
+       c.c_encoding = NULL;
+
+       co = compiler_mod(&c, mod);
+
+ error:
+       compiler_free(&c);
        return co;
 }
 
-static void
-code_dealloc(PyCodeObject *co)
+PyCodeObject *
+PyNode_Compile(struct _node *n, const char *filename)
 {
-       Py_XDECREF(co->co_code);
-       Py_XDECREF(co->co_consts);
-       Py_XDECREF(co->co_names);
-       Py_XDECREF(co->co_varnames);
-       Py_XDECREF(co->co_freevars);
-       Py_XDECREF(co->co_cellvars);
-       Py_XDECREF(co->co_filename);
-       Py_XDECREF(co->co_name);
-       Py_XDECREF(co->co_lnotab);
-       PyObject_DEL(co);
+       PyCodeObject *co;
+       mod_ty mod = PyAST_FromNode(n, NULL, filename);
+       if (!mod)
+               return NULL;
+       co = PyAST_Compile(mod, filename, NULL);
+       free_mod(mod);
+       return co;
 }
 
-static PyObject *
-code_repr(PyCodeObject *co)
+static void
+compiler_free(struct compiler *c)
 {
-       char buf[500];
-       int lineno = -1;
-       char *filename = "???";
-       char *name = "???";
-
-       if (co->co_firstlineno != 0)
-               lineno = co->co_firstlineno;
-       if (co->co_filename && PyString_Check(co->co_filename))
-               filename = PyString_AS_STRING(co->co_filename);
-       if (co->co_name && PyString_Check(co->co_name))
-               name = PyString_AS_STRING(co->co_name);
-       PyOS_snprintf(buf, sizeof(buf),
-                     "<code object %.100s at %p, file \"%.300s\", line %d>",
-                     name, co, filename, lineno);
-       return PyString_FromString(buf);
+       if (c->c_st)
+               PySymtable_Free(c->c_st);
+       if (c->c_future)
+               PyObject_Free((void *)c->c_future);
+       Py_DECREF(c->c_stack);
 }
 
-static int
-code_compare(PyCodeObject *co, PyCodeObject *cp)
+static PyObject *
+list2dict(PyObject *list)
 {
-       int cmp;
-       cmp = PyObject_Compare(co->co_name, cp->co_name);
-       if (cmp) return cmp;
-       cmp = co->co_argcount - cp->co_argcount;
-       if (cmp) return (cmp<0)?-1:1;
-       cmp = co->co_nlocals - cp->co_nlocals;
-       if (cmp) return (cmp<0)?-1:1;
-       cmp = co->co_flags - cp->co_flags;
-       if (cmp) return (cmp<0)?-1:1;
-       cmp = co->co_firstlineno - cp->co_firstlineno;
-       if (cmp) return (cmp<0)?-1:1;
-       cmp = PyObject_Compare(co->co_code, cp->co_code);
-       if (cmp) return cmp;
-       cmp = PyObject_Compare(co->co_consts, cp->co_consts);
-       if (cmp) return cmp;
-       cmp = PyObject_Compare(co->co_names, cp->co_names);
-       if (cmp) return cmp;
-       cmp = PyObject_Compare(co->co_varnames, cp->co_varnames);
-       if (cmp) return cmp;
-       cmp = PyObject_Compare(co->co_freevars, cp->co_freevars);
-       if (cmp) return cmp;
-       cmp = PyObject_Compare(co->co_cellvars, cp->co_cellvars);
-       return cmp;
-}
+       int i, n;
+       PyObject *v, *k, *dict = PyDict_New();
 
-static long
-code_hash(PyCodeObject *co)
-{
-       long h, h0, h1, h2, h3, h4, h5, h6;
-       h0 = PyObject_Hash(co->co_name);
-       if (h0 == -1) return -1;
-       h1 = PyObject_Hash(co->co_code);
-       if (h1 == -1) return -1;
-       h2 = PyObject_Hash(co->co_consts);
-       if (h2 == -1) return -1;
-       h3 = PyObject_Hash(co->co_names);
-       if (h3 == -1) return -1;
-       h4 = PyObject_Hash(co->co_varnames);
-       if (h4 == -1) return -1;
-       h5 = PyObject_Hash(co->co_freevars);
-       if (h5 == -1) return -1;
-       h6 = PyObject_Hash(co->co_cellvars);
-       if (h6 == -1) return -1;
-       h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
-               co->co_argcount ^ co->co_nlocals ^ co->co_flags;
-       if (h == -1) h = -2;
-       return h;
+       n = PyList_Size(list);
+       for (i = 0; i < n; i++) {
+               v = PyInt_FromLong(i);
+               if (!v) {
+                       Py_DECREF(dict);
+                       return NULL;
+               }
+                k = PyList_GET_ITEM(list, i);
+                k = Py_BuildValue("(OO)", k, k->ob_type);
+               if (k == NULL || PyDict_SetItem(dict, k, v) < 0) {
+                       Py_XDECREF(k);
+                       Py_DECREF(v);
+                       Py_DECREF(dict);
+                       return NULL;
+               }
+               Py_DECREF(v);
+       }
+       return dict;
 }
 
-/* XXX code objects need to participate in GC? */
-
-PyTypeObject PyCode_Type = {
-       PyObject_HEAD_INIT(&PyType_Type)
-       0,
-       "code",
-       sizeof(PyCodeObject),
-       0,
-       (destructor)code_dealloc,       /* tp_dealloc */
-       0,                              /* tp_print */
-       0,                              /* tp_getattr */
-       0,                              /* tp_setattr */
-       (cmpfunc)code_compare,          /* tp_compare */
-       (reprfunc)code_repr,            /* tp_repr */
-       0,                              /* tp_as_number */
-       0,                              /* tp_as_sequence */
-       0,                              /* tp_as_mapping */
-       (hashfunc)code_hash,            /* tp_hash */
-       0,                              /* tp_call */
-       0,                              /* tp_str */
-       PyObject_GenericGetAttr,        /* tp_getattro */
-       0,                              /* tp_setattro */
-       0,                              /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT,             /* tp_flags */
-       code_doc,                       /* tp_doc */
-       0,                              /* tp_traverse */
-       0,                              /* tp_clear */
-       0,                              /* tp_richcompare */
-       0,                              /* tp_weaklistoffset */
-       0,                              /* tp_iter */
-       0,                              /* tp_iternext */
-       0,                              /* tp_methods */
-       code_memberlist,                /* tp_members */
-       0,                              /* tp_getset */
-       0,                              /* tp_base */
-       0,                              /* tp_dict */
-       0,                              /* tp_descr_get */
-       0,                              /* tp_descr_set */
-       0,                              /* tp_dictoffset */
-       0,                              /* tp_init */
-       0,                              /* tp_alloc */
-       code_new,                       /* tp_new */
-};
-
-#define NAME_CHARS \
-       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
+/* Return new dict containing names from src that match scope(s).
 
-/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */
+   src is a symbol table dictionary.  If the scope of a name matches
+   either scope_type or flag is set, insert it into the new dict.  The
+   values are integers, starting at offset and increasing by one for
+   each key.
+*/
 
-static int
-all_name_chars(unsigned char *s)
+static PyObject *
+dictbytype(PyObject *src, int scope_type, int flag, int offset)
 {
-       static char ok_name_char[256];
-       static unsigned char *name_chars = (unsigned char *)NAME_CHARS;
+       int pos = 0, i = offset, scope;
+       PyObject *k, *v, *dest = PyDict_New();
 
-       if (ok_name_char[*name_chars] == 0) {
-               unsigned char *p;
-               for (p = name_chars; *p; p++)
-                       ok_name_char[*p] = 1;
-       }
-       while (*s) {
-               if (ok_name_char[*s++] == 0)
-                       return 0;
-       }
-       return 1;
-}
+        assert(offset >= 0);
+        if (dest == NULL)
+            return NULL;
 
-static void
-intern_strings(PyObject *tuple)
-{
-       int i;
+       while (PyDict_Next(src, &pos, &k, &v)) {
+            /* XXX this should probably be a macro in symtable.h */
+            assert(PyInt_Check(v));
+            scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK;
 
-       for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
-               PyObject *v = PyTuple_GET_ITEM(tuple, i);
-               if (v == NULL || !PyString_CheckExact(v)) {
-                       Py_FatalError("non-string found in code slot");
+            if (scope == scope_type || PyInt_AS_LONG(v) & flag) {
+                PyObject *tuple, *item = PyInt_FromLong(i);
+                if (item == NULL) {
+                       Py_DECREF(dest);
+                       return NULL;
+               }
+                i++;
+                tuple = Py_BuildValue("(OO)", k, k->ob_type);
+               if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) {
+                       Py_DECREF(item);
+                       Py_DECREF(dest);
+                       Py_XDECREF(tuple);
+                       return NULL;
                }
-               PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
+               Py_DECREF(item);
+               Py_DECREF(tuple);
+            }
        }
+       return dest;
 }
 
 /* Begin: Peephole optimizations ----------------------------------------- */
@@ -974,5849 +968,3122 @@ exitUnchanged:
 
 /* End: Peephole optimizations ----------------------------------------- */
 
-PyCodeObject *
-PyCode_New(int argcount, int nlocals, int stacksize, int flags,
-          PyObject *code, PyObject *consts, PyObject *names,
-          PyObject *varnames, PyObject *freevars, PyObject *cellvars,
-          PyObject *filename, PyObject *name, int firstlineno,
-          PyObject *lnotab) 
-{
-       PyCodeObject *co;
-       int i;
-       /* Check argument types */
-       if (argcount < 0 || nlocals < 0 ||
-           code == NULL ||
-           consts == NULL || !PyTuple_Check(consts) ||
-           names == NULL || !PyTuple_Check(names) ||
-           varnames == NULL || !PyTuple_Check(varnames) ||
-           freevars == NULL || !PyTuple_Check(freevars) ||
-           cellvars == NULL || !PyTuple_Check(cellvars) ||
-           name == NULL || !PyString_Check(name) ||
-           filename == NULL || !PyString_Check(filename) ||
-           lnotab == NULL || !PyString_Check(lnotab) ||
-           !PyObject_CheckReadBuffer(code)) {
-               PyErr_BadInternalCall();
-               return NULL;
-       }
-       intern_strings(names);
-       intern_strings(varnames);
-       intern_strings(freevars);
-       intern_strings(cellvars);
-       /* Intern selected string constants */
-       for (i = PyTuple_Size(consts); --i >= 0; ) {
-               PyObject *v = PyTuple_GetItem(consts, i);
-               if (!PyString_Check(v))
-                       continue;
-               if (!all_name_chars((unsigned char *)PyString_AS_STRING(v)))
-                       continue;
-               PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i));
-       }
-       co = PyObject_NEW(PyCodeObject, &PyCode_Type);
-       if (co != NULL) {
-               co->co_argcount = argcount;
-               co->co_nlocals = nlocals;
-               co->co_stacksize = stacksize;
-               co->co_flags = flags;
-               Py_INCREF(code);
-               co->co_code = code;
-               Py_INCREF(consts);
-               co->co_consts = consts;
-               Py_INCREF(names);
-               co->co_names = names;
-               Py_INCREF(varnames);
-               co->co_varnames = varnames;
-               Py_INCREF(freevars);
-               co->co_freevars = freevars;
-               Py_INCREF(cellvars);
-               co->co_cellvars = cellvars;
-               Py_INCREF(filename);
-               co->co_filename = filename;
-               Py_INCREF(name);
-               co->co_name = name;
-               co->co_firstlineno = firstlineno;
-               Py_INCREF(lnotab);
-               co->co_lnotab = lnotab;
-               if (PyTuple_GET_SIZE(freevars) == 0 &&
-                   PyTuple_GET_SIZE(cellvars) == 0)
-                   co->co_flags |= CO_NOFREE;
+/*
+
+Leave this debugging code for just a little longer.
+
+static void
+compiler_display_symbols(PyObject *name, PyObject *symbols)
+{
+       PyObject *key, *value;
+       int flags, pos = 0;
+
+       fprintf(stderr, "block %s\n", PyString_AS_STRING(name));
+       while (PyDict_Next(symbols, &pos, &key, &value)) {
+               flags = PyInt_AsLong(value);
+               fprintf(stderr, "var %s:", PyString_AS_STRING(key));
+               if (flags & DEF_GLOBAL)
+                       fprintf(stderr, " declared_global");
+               if (flags & DEF_LOCAL)
+                       fprintf(stderr, " local");
+               if (flags & DEF_PARAM)
+                       fprintf(stderr, " param");
+               if (flags & DEF_STAR)
+                       fprintf(stderr, " stararg");
+               if (flags & DEF_DOUBLESTAR)
+                       fprintf(stderr, " starstar");
+               if (flags & DEF_INTUPLE)
+                       fprintf(stderr, " tuple");
+               if (flags & DEF_FREE)
+                       fprintf(stderr, " free");
+               if (flags & DEF_FREE_GLOBAL)
+                       fprintf(stderr, " global");
+               if (flags & DEF_FREE_CLASS)
+                       fprintf(stderr, " free/class");
+               if (flags & DEF_IMPORT)
+                       fprintf(stderr, " import");
+               fprintf(stderr, "\n");
        }
-       return co;
+       fprintf(stderr, "\n");
 }
-
-
-/* Data structure used internally */
-
-/* The compiler uses two passes to generate bytecodes.  The first pass
-   builds the symbol table.  The second pass generates the bytecode.
-
-   The first pass uses a single symtable struct.  The second pass uses
-   a compiling struct for each code block.  The compiling structs
-   share a reference to the symtable.
-
-   The two passes communicate via symtable_load_symbols() and via
-   is_local() and is_global().  The former initializes several slots
-   in the compiling struct: c_varnames, c_locals, c_nlocals,
-   c_argcount, c_globals, and c_flags.
-*/
-
-/* All about c_lnotab.
-
-c_lnotab is an array of unsigned bytes disguised as a Python string.  Since
-version 2.3, SET_LINENO opcodes are never generated and bytecode offsets are
-mapped to source code line #s via c_lnotab instead.
-
-The array is conceptually a list of
-    (bytecode offset increment, line number increment)
-pairs.  The details are important and delicate, best illustrated by example:
-
-    byte code offset    source code line number
-        0                  1
-        6                  2
-       50                  7
-      350                 307
-      361                 308
-
-The first trick is that these numbers aren't stored, only the increments
-from one row to the next (this doesn't really work, but it's a start):
-
-    0, 1,  6, 1,  44, 5,  300, 300,  11, 1
-
-The second trick is that an unsigned byte can't hold negative values, or
-values larger than 255, so (a) there's a deep assumption that byte code
-offsets and their corresponding line #s both increase monotonically, and (b)
-if at least one column jumps by more than 255 from one row to the next, more
-than one pair is written to the table. In case #b, there's no way to know
-from looking at the table later how many were written.  That's the delicate
-part.  A user of c_lnotab desiring to find the source line number
-corresponding to a bytecode address A should do something like this
-
-    lineno = addr = 0
-    for addr_incr, line_incr in c_lnotab:
-        addr += addr_incr
-        if addr > A:
-            return lineno
-        lineno += line_incr
-
-In order for this to work, when the addr field increments by more than 255,
-the line # increment in each pair generated must be 0 until the remaining addr
-increment is < 256.  So, in the example above, com_set_lineno should not (as
-was actually done until 2.2) expand 300, 300 to 255, 255,  45, 45, but to
-255, 0,  45, 255,  0, 45.
 */
 
-struct compiling {
-       PyObject *c_code;       /* string */
-       PyObject *c_consts;     /* list of objects */
-       PyObject *c_const_dict; /* inverse of c_consts */
-       PyObject *c_names;      /* list of strings (names) */
-       PyObject *c_name_dict;  /* inverse of c_names */
-       PyObject *c_globals;    /* dictionary (value=None or True) */
-       PyObject *c_locals;     /* dictionary (value=localID) */
-       PyObject *c_varnames;   /* list (inverse of c_locals) */
-       PyObject *c_freevars;   /* dictionary (value=None) */
-       PyObject *c_cellvars;   /* dictionary */
-       int c_nlocals;          /* index of next local */
-       int c_argcount;         /* number of top-level arguments */
-       int c_flags;            /* same as co_flags */
-       int c_nexti;            /* index into c_code */
-       int c_errors;           /* counts errors occurred */
-       int c_infunction;       /* set when compiling a function */
-       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[CO_MAXBLOCKS]; /* stack of block types */
-       int c_nblocks;          /* current block stack level */
-       const 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 */
-       int c_firstlineno;
-       PyObject *c_lnotab;     /* Table mapping address to line number */
-       int c_last_addr;        /* last op addr seen and recorded in lnotab */
-       int c_last_line;        /* last line seen and recorded in lnotab */
-       int c_lnotab_next;      /* current length of lnotab */
-       int c_lnotab_last;      /* start of last lnotab record added */
-       char *c_private;        /* for private name mangling */
-       int c_tmpname;          /* temporary local name counter */
-       int c_nested;           /* Is block nested funcdef or lamdef? */
-       int c_closure;          /* Is nested w/freevars? */
-       struct symtable *c_symtable; /* pointer to module symbol table */
-        PyFutureFeatures *c_future; /* pointer to module's __future__ */
-       char *c_encoding;       /* source encoding (a borrowed reference) */
-};
-
-static int
-is_free(int v)
+static void
+compiler_unit_check(struct compiler_unit *u)
 {
-       if ((v & (USE | DEF_FREE))
-           && !(v & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)))
-               return 1;
-       if (v & DEF_FREE_CLASS)
-               return 1;
-       return 0;
+       basicblock *block;
+       for (block = u->u_blocks; block != NULL; block = block->b_list) {
+               assert(block != (void *)0xcbcbcbcb);
+               assert(block != (void *)0xfbfbfbfb);
+               assert(block != (void *)0xdbdbdbdb);
+               if (block->b_instr != NULL) {
+                       assert(block->b_ialloc > 0);
+                       assert(block->b_iused > 0);
+                       assert(block->b_ialloc >= block->b_iused);
+               }
+               else {
+                       assert (block->b_iused == 0);
+                       assert (block->b_ialloc == 0);
+               }
+       }
 }
 
 static void
-com_error(struct compiling *c, PyObject *exc, char *msg)
+compiler_unit_free(struct compiler_unit *u)
 {
-       PyObject *t = NULL, *v = NULL, *w = NULL, *line = NULL;
-
-       if (c == NULL) {
-               /* Error occurred via symtable call to
-                  is_constant_false */
-               PyErr_SetString(exc, msg);
-               return;
-       }
-       c->c_errors++;
-       if (c->c_lineno < 1 || c->c_interactive) { 
-               /* Unknown line number or interactive input */
-               PyErr_SetString(exc, msg);
-               return;
-       }
-       v = PyString_FromString(msg);
-       if (v == NULL)
-               return; /* MemoryError, too bad */
+       basicblock *b, *next;
 
-       line = PyErr_ProgramText(c->c_filename, c->c_lineno);
-       if (line == NULL) {
-               Py_INCREF(Py_None);
-               line = Py_None;
+       compiler_unit_check(u);
+       b = u->u_blocks;
+       while (b != NULL) {
+               if (b->b_instr)
+                       PyObject_Free((void *)b->b_instr);
+               next = b->b_list;
+               PyObject_Free((void *)b);
+               b = next;
        }
-       if (exc == PyExc_SyntaxError) {
-               t = Py_BuildValue("(ziOO)", c->c_filename, c->c_lineno,
-                                 Py_None, line);
-               if (t == NULL)
-                       goto exit;
-               w = PyTuple_Pack(2, v, t);
-               if (w == NULL)
-                       goto exit;
-               PyErr_SetObject(exc, w);
-       } else {
-               /* Make sure additional exceptions are printed with
-                  file and line, also. */
-               PyErr_SetObject(exc, v);
-               PyErr_SyntaxLocation(c->c_filename, c->c_lineno);
-       }
- exit:
-       Py_XDECREF(t);
-       Py_XDECREF(v);
-       Py_XDECREF(w);
-       Py_XDECREF(line);
+       Py_XDECREF(u->u_ste);
+       Py_XDECREF(u->u_name);
+       Py_XDECREF(u->u_consts);
+       Py_XDECREF(u->u_names);
+       Py_XDECREF(u->u_varnames);
+       Py_XDECREF(u->u_freevars);
+       Py_XDECREF(u->u_cellvars);
+       Py_XDECREF(u->u_private);
+       PyObject_Free(u);
 }
 
-/* Interface to the block stack */
-
-static void
-block_push(struct compiling *c, int type)
+static int
+compiler_enter_scope(struct compiler *c, identifier name, void *key,
+                    int lineno)
 {
-       if (c->c_nblocks >= CO_MAXBLOCKS) {
-               com_error(c, PyExc_SystemError,
-                         "too many statically nested blocks");
+       struct compiler_unit *u;
+
+       u = PyObject_Malloc(sizeof(struct compiler_unit));
+        memset(u, 0, sizeof(struct compiler_unit));
+       u->u_argcount = 0;
+       u->u_ste = PySymtable_Lookup(c->c_st, key);
+       if (!u->u_ste) {
+                compiler_unit_free(u);
+               return 0;
        }
-       else {
-               c->c_block[c->c_nblocks++] = type;
+       Py_INCREF(name);
+       u->u_name = name;
+       u->u_varnames = list2dict(u->u_ste->ste_varnames);
+       u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0);
+       u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS,
+                                   PyDict_Size(u->u_cellvars));
+
+       u->u_blocks = NULL;
+       u->u_tmpname = 0;
+       u->u_nfblocks = 0;
+       u->u_firstlineno = lineno;
+       u->u_lineno = 0;
+       u->u_lineno_set = false;
+       u->u_consts = PyDict_New();
+       if (!u->u_consts) {
+                compiler_unit_free(u);
+               return 0;
+       }
+       u->u_names = PyDict_New();
+       if (!u->u_names) {
+                compiler_unit_free(u);
+               return 0;
        }
-}
 
-static void
-block_pop(struct compiling *c, int type)
-{
-       if (c->c_nblocks > 0)
-               c->c_nblocks--;
-       if (c->c_block[c->c_nblocks] != type && c->c_errors == 0) {
-               com_error(c, PyExc_SystemError, "bad block pop");
+        u->u_private = NULL;
+
+       /* Push the old compiler_unit on the stack. */
+       if (c->u) {
+               PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL);
+               if (PyList_Append(c->c_stack, wrapper) < 0) {
+                        compiler_unit_free(u);
+                       return 0;
+               }
+               Py_DECREF(wrapper);
+                u->u_private = c->u->u_private;
+                Py_XINCREF(u->u_private);
        }
-}
+       c->u = u;
 
-/* Prototype forward declarations */
-
-static int issue_warning(const char *, const char *, int);
-static int com_init(struct compiling *, const char *);
-static void com_free(struct compiling *);
-static void com_push(struct compiling *, int);
-static void com_pop(struct compiling *, int);
-static void com_done(struct compiling *);
-static void com_node(struct compiling *, node *);
-static void com_factor(struct compiling *, node *);
-static void com_addbyte(struct compiling *, int);
-static void com_addint(struct compiling *, int);
-static void com_addoparg(struct compiling *, int, int);
-static void com_addfwref(struct compiling *, int, int *);
-static void com_backpatch(struct compiling *, int);
-static int com_add(struct compiling *, PyObject *, PyObject *, PyObject *);
-static int com_addconst(struct compiling *, PyObject *);
-static int com_addname(struct compiling *, PyObject *);
-static void com_addopname(struct compiling *, int, node *);
-static void com_test(struct compiling *c, node *n);
-static void com_list(struct compiling *, node *, int);
-static void com_list_iter(struct compiling *, node *, node *, char *);
-static void com_gen_iter(struct compiling *, node *, node *);
-static int com_argdefs(struct compiling *, node *);
-static void com_assign(struct compiling *, node *, int, node *);
-static void com_assign_name(struct compiling *, node *, int);
-static int com_make_closure(struct compiling *c, PyCodeObject *co);
-
-static PyCodeObject *icompile(node *, struct compiling *);
-static PyCodeObject *jcompile(node *, const char *, struct compiling *,
-                             PyCompilerFlags *);
-static PyObject *parsestrplus(struct compiling*, node *);
-static PyObject *parsestr(struct compiling *, char *);
-static node *get_rawdocstring(node *);
-
-static int get_ref_type(struct compiling *, char *);
-
-/* symtable operations */
-static int symtable_lookup(struct symtable *st, char *name);
-static struct symtable *symtable_build(node *, PyFutureFeatures *,
-                                      const char *filename);
-static int symtable_load_symbols(struct compiling *);
-static struct symtable *symtable_init(void);
-static void symtable_enter_scope(struct symtable *, char *, int, int);
-static int symtable_exit_scope(struct symtable *);
-static int symtable_add_def(struct symtable *, char *, int);
-static int symtable_add_def_o(struct symtable *, PyObject *, PyObject *, int);
-
-static void symtable_node(struct symtable *, node *);
-static void symtable_funcdef(struct symtable *, node *);
-static void symtable_default_args(struct symtable *, node *);
-static void symtable_params(struct symtable *, node *);
-static void symtable_params_fplist(struct symtable *, node *n);
-static void symtable_global(struct symtable *, node *);
-static void symtable_import(struct symtable *, node *);
-static void symtable_assign(struct symtable *, node *, int);
-static void symtable_list_comprehension(struct symtable *, node *);
-static void symtable_generator_expression(struct symtable *, node *);
-static void symtable_list_for(struct symtable *, node *);
-static void symtable_gen_for(struct symtable *, node *, int);
-static void symtable_gen_iter(struct symtable *, node *);
-
-static int symtable_update_free_vars(struct symtable *);
-static int symtable_undo_free(struct symtable *, PyObject *, PyObject *);
-static int symtable_check_global(struct symtable *, PyObject *, PyObject *);
-
-/* helper */
-static void
-do_pad(int pad)
-{
-       int i;
-       for (i = 0; i < pad; ++i)
-               fprintf(stderr, "  ");
-}
+        c->c_nestlevel++;
+       if (compiler_use_new_block(c) < 0)
+               return 0;
 
-static void
-dump(node *n, int pad, int depth)
-{
-       int i;
-       if (depth == 0)
-           return;
-       do_pad(pad);
-       fprintf(stderr, "%d: %s\n", TYPE(n), STR(n));
-       if (depth > 0)
-           depth--;
-       for (i = 0; i < NCH(n); ++i)
-               dump(CHILD(n, i), pad + 1, depth);
+       return 1;
 }
 
 static int
-com_init(struct compiling *c, const char *filename)
-{
-       memset((void *)c, '\0', sizeof(struct compiling));
-       if ((c->c_code = PyString_FromStringAndSize((char *)NULL,
-                                                   1000)) == NULL)
-               goto fail;
-       if ((c->c_consts = PyList_New(0)) == NULL)
-               goto fail;
-       if ((c->c_const_dict = PyDict_New()) == NULL)
-               goto fail;
-       if ((c->c_names = PyList_New(0)) == NULL)
-               goto fail;
-       if ((c->c_name_dict = PyDict_New()) == NULL)
-               goto fail;
-       if ((c->c_locals = PyDict_New()) == NULL)
-               goto fail;
-       if ((c->c_lnotab = PyString_FromStringAndSize((char *)NULL,
-                                                     1000)) == NULL)
-               goto fail;
-       c->c_globals = NULL;
-       c->c_varnames = NULL;
-       c->c_freevars = NULL;
-       c->c_cellvars = NULL;
-       c->c_nlocals = 0;
-       c->c_argcount = 0;
-       c->c_flags = 0;
-       c->c_nexti = 0;
-       c->c_errors = 0;
-       c->c_infunction = 0;
-       c->c_interactive = 0;
-       c->c_loops = 0;
-       c->c_begin = 0;
-       c->c_nblocks = 0;
-       c->c_filename = filename;
-       c->c_name = "?";
-       c->c_lineno = 0;
-       c->c_stacklevel = 0;
-       c->c_maxstacklevel = 0;
-       c->c_firstlineno = 0;
-       c->c_last_addr = 0;
-       c->c_last_line = 0;
-       c->c_lnotab_next = 0;
-       c->c_lnotab_last = 0;
-       c->c_tmpname = 0;
-       c->c_nested = 0;
-       c->c_closure = 0;
-       c->c_symtable = NULL;
-       return 1;
-       
-  fail:
-       com_free(c);
-       return 0;
-}
+compiler_exit_scope(struct compiler *c)
+{
+       int n;
+       PyObject *wrapper;
+
+        c->c_nestlevel--;
+       compiler_unit_free(c->u);
+       /* Restore c->u to the parent unit. */
+       n = PyList_GET_SIZE(c->c_stack) - 1;
+       if (n >= 0) {
+               wrapper = PyList_GET_ITEM(c->c_stack, n);
+               c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper);
+               if (PySequence_DelItem(c->c_stack, n) < 0)
+                       return 0;
+               compiler_unit_check(c->u);
+       }
+       else
+               c->u = NULL;
 
-static void
-com_free(struct compiling *c)
-{
-       Py_XDECREF(c->c_code);
-       Py_XDECREF(c->c_consts);
-       Py_XDECREF(c->c_const_dict);
-       Py_XDECREF(c->c_names);
-       Py_XDECREF(c->c_name_dict);
-       Py_XDECREF(c->c_globals);
-       Py_XDECREF(c->c_locals);
-       Py_XDECREF(c->c_varnames);
-       Py_XDECREF(c->c_freevars);
-       Py_XDECREF(c->c_cellvars);
-       Py_XDECREF(c->c_lnotab);
-       if (c->c_future)
-               PyObject_FREE((void *)c->c_future);
+       return 1; /* XXX void? */
 }
 
-static void
-com_push(struct compiling *c, int n)
-{
-       c->c_stacklevel += n;
-       if (c->c_stacklevel > c->c_maxstacklevel) {
-               c->c_maxstacklevel = c->c_stacklevel;
-               /*
-               fprintf(stderr, "%s:%s:%d max stack nexti=%d level=%d n=%d\n",
-                       c->c_filename, c->c_name, c->c_lineno,
-                       c->c_nexti, c->c_stacklevel, n);
-               */
-       }
-}
+/* Allocate a new block and return a pointer to it.
+   Returns NULL on error.
+*/
 
-static void
-com_pop(struct compiling *c, int n)
+static basicblock *
+compiler_new_block(struct compiler *c)
 {
-       if (c->c_stacklevel < n) 
-               c->c_stacklevel = 0;
-       else
-               c->c_stacklevel -= n;
+       basicblock *b;
+       struct compiler_unit *u;
+
+       u = c->u;
+       b = (basicblock *)PyObject_Malloc(sizeof(basicblock));
+       if (b == NULL)
+               return NULL;
+       memset((void *)b, 0, sizeof(basicblock));
+       assert (b->b_next == NULL);
+       b->b_list = u->u_blocks;
+       u->u_blocks = b;
+       return b;
 }
 
 static void
-com_done(struct compiling *c)
+compiler_use_block(struct compiler *c, basicblock *block)
 {
-       if (c->c_code != NULL)
-               _PyString_Resize(&c->c_code, c->c_nexti);
-       if (c->c_lnotab != NULL)
-               _PyString_Resize(&c->c_lnotab, c->c_lnotab_next);
+        assert (block != NULL);
+       c->u->u_curblock = block;
 }
 
-static int
-com_check_size(PyObject **s, int offset)
+static basicblock *
+compiler_use_new_block(struct compiler *c)
 {
-       int len = PyString_GET_SIZE(*s);
-       if (offset >= len) 
-               return _PyString_Resize(s, len * 2);
-       return 0;
+       basicblock *block = compiler_new_block(c);
+       if (block == NULL)
+               return NULL;
+       c->u->u_curblock = block;
+       return block;
 }
 
-static void
-com_addbyte(struct compiling *c, int byte)
+static basicblock *
+compiler_next_block(struct compiler *c)
 {
-       /*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
-       assert(byte >= 0 && byte <= 255);
-       assert(c->c_code != 0);
-       if (com_check_size(&c->c_code, c->c_nexti)) {
-               c->c_errors++;
-               return;
-       }
-       PyString_AS_STRING(c->c_code)[c->c_nexti++] = byte;
+       basicblock *block = compiler_new_block(c);
+       if (block == NULL)
+               return NULL;
+       c->u->u_curblock->b_next = block;
+       c->u->u_curblock = block;
+       return block;
 }
 
-static void
-com_addint(struct compiling *c, int x)
+static basicblock *
+compiler_use_next_block(struct compiler *c, basicblock *block)
 {
-       com_addbyte(c, x & 0xff);
-       com_addbyte(c, x >> 8); /* XXX x should be positive */
+       assert(block != NULL);
+       c->u->u_curblock->b_next = block;
+       c->u->u_curblock = block;
+       return block;
 }
 
-static void
-com_add_lnotab(struct compiling *c, int addr, int line)
-{
-       char *p;
-       if (c->c_lnotab == NULL)
-               return;
-       if (com_check_size(&c->c_lnotab, c->c_lnotab_next + 2)) {
-               c->c_errors++;
-               return;
-       }
-       p = PyString_AS_STRING(c->c_lnotab) + c->c_lnotab_next;
-       *p++ = addr;
-       *p++ = line;
-       c->c_lnotab_next += 2;
-}
+/* Returns the offset of the next instruction in the current block's
+   b_instr array.  Resizes the b_instr as necessary.
+   Returns -1 on failure.
+ */
 
-static void
-com_set_lineno(struct compiling *c, int lineno)
-{
-       c->c_lineno = lineno;
-       if (c->c_firstlineno == 0) {
-               c->c_firstlineno = c->c_last_line = lineno;
-       }
-       else {
-               int incr_addr = c->c_nexti - c->c_last_addr;
-               int incr_line = lineno - c->c_last_line;
-               c->c_lnotab_last = c->c_lnotab_next;
-               while (incr_addr > 255) {
-                       com_add_lnotab(c, 255, 0);
-                       incr_addr -= 255;
+static int
+compiler_next_instr(struct compiler *c, basicblock *b)
+{
+       assert(b != NULL);
+        if (b->b_instr == NULL) {
+               b->b_instr = PyObject_Malloc(sizeof(struct instr) *
+                                            DEFAULT_BLOCK_SIZE);
+               if (b->b_instr == NULL) {
+                       PyErr_NoMemory();
+                       return -1;
                }
-               while (incr_line > 255) {
-                       com_add_lnotab(c, incr_addr, 255);
-                       incr_line -=255;
-                       incr_addr = 0;
+               b->b_ialloc = DEFAULT_BLOCK_SIZE;
+               memset((char *)b->b_instr, 0,
+                      sizeof(struct instr) * DEFAULT_BLOCK_SIZE);
+        }
+       else if (b->b_iused == b->b_ialloc) {
+               size_t oldsize, newsize;
+               oldsize = b->b_ialloc * sizeof(struct instr);
+               newsize = oldsize << 1;
+               if (newsize == 0) {
+                       PyErr_NoMemory();
+                       return -1;
                }
-               if (incr_addr > 0 || incr_line > 0)
-                       com_add_lnotab(c, incr_addr, incr_line);
-               c->c_last_addr = c->c_nexti;
-               c->c_last_line = lineno;
-       }
-}
-
-static void
-com_strip_lnotab(struct compiling *c)
-{
-       /* strip the last lnotab entry if no opcode were emitted.
-        * This prevents a line number to be generated on a final
-        * pass, like in the following example:
-        *
-        *    if a:
-        *        print 5
-        *    else:
-        *        pass
-        *
-        * Without the fix, a line trace event would be generated
-        * on the pass even if a is true (because of the implicit
-        * return).
-        */
-       if (c->c_nexti == c->c_last_addr && c->c_lnotab_last > 0) {
-               c->c_lnotab_next = c->c_lnotab_last;
+               b->b_ialloc <<= 1;
+               b->b_instr = PyObject_Realloc((void *)b->b_instr, newsize);
+               if (b->b_instr == NULL)
+                       return -1;
+               memset((char *)b->b_instr + oldsize, 0, newsize - oldsize);
        }
+       return b->b_iused++;
 }
 
 static void
-com_addoparg(struct compiling *c, int op, int arg)
+compiler_set_lineno(struct compiler *c, int off)
 {
-       int extended_arg = arg >> 16;
-       if (extended_arg){
-               com_addbyte(c, EXTENDED_ARG);
-               com_addint(c, extended_arg);
-               arg &= 0xffff;
-       }
-       com_addbyte(c, op);
-       com_addint(c, arg);
+       basicblock *b;
+       if (c->u->u_lineno_set)
+               return;
+       c->u->u_lineno_set = true;
+       b = c->u->u_curblock;
+       b->b_instr[off].i_lineno = c->u->u_lineno;
 }
 
-static void
-com_addfwref(struct compiling *c, int op, int *p_anchor)
+static int
+opcode_stack_effect(int opcode, int oparg)
 {
-       /* 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);
-}
+       switch (opcode) {
+               case POP_TOP:
+                       return -1;
+               case ROT_TWO:
+               case ROT_THREE:
+                       return 0;
+               case DUP_TOP:
+                       return 1;
+               case ROT_FOUR:
+                       return 0;
 
-static void
-com_backpatch(struct compiling *c, int anchor)
-{
-       unsigned char *code = (unsigned char *) PyString_AS_STRING(c->c_code);
-       int target = c->c_nexti;
-       int dist;
-       int prev;
-       for (;;) {
-               /* Make the JUMP instruction at anchor point to target */
-               prev = code[anchor] + (code[anchor+1] << 8);
-               dist = target - (anchor+2);
-               code[anchor] = dist & 0xff;
-               dist >>= 8;
-               code[anchor+1] = dist;
-               dist >>= 8;
-               if (dist) {
-                       com_error(c, PyExc_SystemError,
-                                 "com_backpatch: offset too large");
-                       break;
-               }
-               if (!prev)
-                       break;
-               anchor -= prev;
-       }
-}
-
-/* Handle literals and names uniformly */
-
-static int
-com_add(struct compiling *c, PyObject *list, PyObject *dict, PyObject *v)
-{
-       PyObject *w, *t, *np=NULL;
-       long n;
-       
-       t = PyTuple_Pack(2, v, v->ob_type);
-       if (t == NULL)
-           goto fail;
-       w = PyDict_GetItem(dict, t);
-       if (w != NULL) {
-               n = PyInt_AsLong(w);
-       } else {
-               n = PyList_Size(list);
-               np = PyInt_FromLong(n);
-               if (np == NULL)
-                   goto fail;
-               if (PyList_Append(list, v) != 0)
-                   goto fail;
-               if (PyDict_SetItem(dict, t, np) != 0)
-                   goto fail;
-               Py_DECREF(np);
-       }
-       Py_DECREF(t);
-       return n;
-  fail:
-       Py_XDECREF(np);
-       Py_XDECREF(t);
-       c->c_errors++;
-       return 0;
-}
-
-static int
-com_addconst(struct compiling *c, PyObject *v)
-{
-       return com_add(c, c->c_consts, c->c_const_dict, v);
-}
-
-static int
-com_addname(struct compiling *c, PyObject *v)
-{
-       return com_add(c, c->c_names, c->c_name_dict, v);
-}
-
-int
-_Py_Mangle(char *p, char *name, char *buffer, size_t maxlen)
-{
-       /* Name mangling: __private becomes _classname__private.
-          This is independent from how the name is used. */
-       size_t nlen, plen;
-       if (p == NULL || name == NULL || name[0] != '_' || name[1] != '_')
-               return 0;
-       nlen = strlen(name);
-       if (nlen+2 >= maxlen)
-               return 0; /* Don't mangle __extremely_long_names */
-       if (name[nlen-1] == '_' && name[nlen-2] == '_')
-               return 0; /* Don't mangle __whatever__ */
-       /* Strip leading underscores from class name */
-       while (*p == '_')
-               p++;
-       if (*p == '\0')
-               return 0; /* Don't mangle if class is just underscores */
-       plen = strlen(p);
-       if (plen + nlen >= maxlen)
-               plen = maxlen-nlen-2; /* Truncate class name if too long */
-       /* buffer = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */
-       buffer[0] = '_';
-       strncpy(buffer+1, p, plen);
-       strcpy(buffer+1+plen, name);
-       return 1;
-}
-
-static void
-com_addop_name(struct compiling *c, int op, char *name)
-{
-       PyObject *v;
-       int i;
-       char buffer[MANGLE_LEN];
-
-       if (_Py_Mangle(c->c_private, name, buffer, sizeof(buffer)))
-               name = buffer;
-       if (name == NULL || (v = PyString_InternFromString(name)) == NULL) {
-               c->c_errors++;
-               i = 255;
-       }
-       else {
-               i = com_addname(c, v);
-               Py_DECREF(v);
-       }
-       com_addoparg(c, op, i);
-}
-
-#define NAME_LOCAL 0
-#define NAME_GLOBAL 1
-#define NAME_DEFAULT 2
-#define NAME_CLOSURE 3
-
-static int
-com_lookup_arg(PyObject *dict, PyObject *name)
-{
-       PyObject *v = PyDict_GetItem(dict, name);
-       if (v == NULL)
-               return -1;
-       else
-               return PyInt_AS_LONG(v);
-}
-
-static int
-none_assignment_check(struct compiling *c, char *name, int assigning)
-{
-       if (name[0] == 'N' && strcmp(name, "None") == 0) {
-               char *msg;
-               if (assigning)
-                       msg = "assignment to None";
-               else
-                       msg = "deleting None";
-               com_error(c, PyExc_SyntaxError, msg);
-               return -1;
-       }
-       return 0;
-}
-
-static void
-com_addop_varname(struct compiling *c, int kind, char *name)
-{
-       PyObject *v;
-       int i, reftype;
-       int scope = NAME_DEFAULT;
-       int op = STOP_CODE;
-       char buffer[MANGLE_LEN];
-
-       if (kind != VAR_LOAD &&
-           none_assignment_check(c, name, kind == VAR_STORE))
-       {
-               i = 255;
-               goto done;
-       }
-       if (_Py_Mangle(c->c_private, name, buffer, sizeof(buffer)))
-               name = buffer;
-       if (name == NULL || (v = PyString_InternFromString(name)) == NULL) {
-               c->c_errors++;
-               i = 255;
-               goto done;
-       }
-
-       reftype = get_ref_type(c, name);
-       switch (reftype) {
-       case LOCAL:
-               if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION)
-                       scope = NAME_LOCAL;
-               break;
-       case GLOBAL_EXPLICIT:
-               scope = NAME_GLOBAL;
-               break;
-       case GLOBAL_IMPLICIT:
-               if (c->c_flags & CO_OPTIMIZED)
-                       scope = NAME_GLOBAL;
-               break;
-       case FREE:
-       case CELL:
-               scope = NAME_CLOSURE;
-               break;
-       }
-
-       i = com_addname(c, v);
-       if (scope == NAME_LOCAL)
-               i = com_lookup_arg(c->c_locals, v);
-       else if (reftype == FREE)
-               i = com_lookup_arg(c->c_freevars, v);
-       else if (reftype == CELL)
-               i = com_lookup_arg(c->c_cellvars, v);
-       if (i == -1) {
-               c->c_errors++; /* XXX no exception set */
-               i = 255;
-               goto done;
-       }
-       Py_DECREF(v);
-
-       switch (kind) {
-       case VAR_LOAD:
-               switch (scope) {
-               case NAME_LOCAL:
-                       op = LOAD_FAST;
-                       break;
-               case NAME_GLOBAL:
-                       op = LOAD_GLOBAL;
-                       break;
-               case NAME_DEFAULT:
-                       op = LOAD_NAME;
-                       break;
-               case NAME_CLOSURE:
-                       op = LOAD_DEREF;
-                       break;
-               }
-               break;
-       case VAR_STORE:
-               switch (scope) {
-               case NAME_LOCAL:
-                       op = STORE_FAST;
-                       break;
-               case NAME_GLOBAL:
-                       op = STORE_GLOBAL;
-                       break;
-               case NAME_DEFAULT:
-                       op = STORE_NAME;
-                       break;
-               case NAME_CLOSURE:
-                       op = STORE_DEREF;
-                       break;
-               }
-               break;
-       case VAR_DELETE:
-               switch (scope) {
-               case NAME_LOCAL:
-                       op = DELETE_FAST;
-                       break;
-               case NAME_GLOBAL:
-                       op = DELETE_GLOBAL;
-                       break;
-               case NAME_DEFAULT:
-                       op = DELETE_NAME;
-                       break;
-               case NAME_CLOSURE: {
-                       char buf[500];
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     DEL_CLOSURE_ERROR, name);
-                       com_error(c, PyExc_SyntaxError, buf);
-                       i = 255;
-                       break;
-               }
-               }
-               break;
-       }
-done:
-       com_addoparg(c, op, i);
-}
-
-static void
-com_addopname(struct compiling *c, int op, node *n)
-{
-       char *name;
-       char buffer[1000];
-       /* XXX it is possible to write this code without the 1000
-          chars on the total length of dotted names, I just can't be
-          bothered right now */
-       if (TYPE(n) == STAR)
-               name = "*";
-       else if (TYPE(n) == dotted_name) {
-               char *p = buffer;
-               int i;
-               name = buffer;
-               for (i = 0; i < NCH(n); i += 2) {
-                       char *s = STR(CHILD(n, i));
-                       if (p + strlen(s) > buffer + (sizeof buffer) - 2) {
-                               com_error(c, PyExc_MemoryError,
-                                         "dotted_name too long");
-                               name = NULL;
-                               break;
-                       }
-                       if (p != buffer)
-                               *p++ = '.';
-                       strcpy(p, s);
-                       p = strchr(p, '\0');
-               }
-       }
-       else {
-               REQ(n, NAME);
-               name = STR(n);
-       }
-       com_addop_name(c, op, name);
-}
-
-static PyObject *
-parsenumber(struct compiling *c, char *s)
-{
-       char *end;
-       long x;
-       double dx;
-#ifndef WITHOUT_COMPLEX
-       int imflag;
-#endif
-
-       errno = 0;
-       end = s + strlen(s) - 1;
-#ifndef WITHOUT_COMPLEX
-       imflag = *end == 'j' || *end == 'J';
-#endif
-       if (*end == 'l' || *end == 'L')
-               return PyLong_FromString(s, (char **)0, 0);
-       if (s[0] == '0') {
-               x = (long) PyOS_strtoul(s, &end, 0);
-               if (x < 0 && errno == 0) {
-                       return PyLong_FromString(s, (char **)0, 0);
-               }
-       }
-       else
-               x = PyOS_strtol(s, &end, 0);
-       if (*end == '\0') {
-               if (errno != 0)
-                       return PyLong_FromString(s, (char **)0, 0);
-               return PyInt_FromLong(x);
-       }
-       /* XXX Huge floats may silently fail */
-#ifndef WITHOUT_COMPLEX
-       if (imflag) {
-               Py_complex z;
-               z.real = 0.;
-               PyFPE_START_PROTECT("atof", return 0)
-               z.imag = PyOS_ascii_atof(s);
-               PyFPE_END_PROTECT(z)
-               return PyComplex_FromCComplex(z);
-       }
-       else
-#endif
-       {
-               PyFPE_START_PROTECT("atof", return 0)
-               dx = PyOS_ascii_atof(s);
-               PyFPE_END_PROTECT(dx)
-               return PyFloat_FromDouble(dx);
-       }
-}
-
-static PyObject *
-decode_utf8(char **sPtr, char *end, char* encoding)
-{
-#ifndef Py_USING_UNICODE
-       Py_FatalError("decode_utf8 should not be called in this build.");
-        return NULL;
-#else
-       PyObject *u, *v;
-       char *s, *t;
-       t = s = *sPtr;
-       /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */
-       while (s < end && (*s & 0x80)) s++;
-       *sPtr = s;
-       u = PyUnicode_DecodeUTF8(t, s - t, NULL);
-       if (u == NULL)
-               return NULL;
-       v = PyUnicode_AsEncodedString(u, encoding, NULL);
-       Py_DECREF(u);
-       return v;
-#endif
-}
-
-/* compiler.transformer.Transformer.decode_literal depends on what 
-   might seem like minor details of this function -- changes here 
-   must be reflected there. */
-static PyObject *
-parsestr(struct compiling *c, char *s)
-{
-       PyObject *v;
-       size_t len;
-       int quote = *s;
-       int rawmode = 0;
-       char* encoding = ((c == NULL) ? NULL : c->c_encoding);
-       int need_encoding;
-       int unicode = 0;
-
-       if (isalpha(quote) || quote == '_') {
-               if (quote == 'u' || quote == 'U') {
-                       quote = *++s;
-                       unicode = 1;
-               }
-               if (quote == 'r' || quote == 'R') {
-                       quote = *++s;
-                       rawmode = 1;
-               }
-       }
-       if (quote != '\'' && quote != '\"') {
-               PyErr_BadInternalCall();
-               return NULL;
-       }
-       s++;
-       len = strlen(s);
-       if (len > INT_MAX) {
-               com_error(c, PyExc_OverflowError, 
-                         "string to parse is too long");
-               return NULL;
-       }
-       if (s[--len] != quote) {
-               PyErr_BadInternalCall();
-               return NULL;
-       }
-       if (len >= 4 && s[0] == quote && s[1] == quote) {
-               s += 2;
-               len -= 2;
-               if (s[--len] != quote || s[--len] != quote) {
-                       PyErr_BadInternalCall();
-                       return NULL;
-               }
-       }
-#ifdef Py_USING_UNICODE
-       if (unicode || Py_UnicodeFlag) {
-               PyObject *u, *w;
-               char *buf;
-               char *p;
-               char *end;
-               if (encoding == NULL) {
-                       buf = s;
-                       u = NULL;
-               } else if (strcmp(encoding, "iso-8859-1") == 0) {
-                       buf = s;
-                       u = NULL;
-               } else {
-                       /* "\XX" may become "\u005c\uHHLL" (12 bytes) */
-                       u = PyString_FromStringAndSize((char *)NULL, len * 4);
-                       if (u == NULL)
-                               return NULL;
-                       p = buf = PyString_AsString(u);
-                       end = s + len;
-                       while (s < end) {
-                               if (*s == '\\') {
-                                       *p++ = *s++;
-                                       if (*s & 0x80) {
-                                               strcpy(p, "u005c");
-                                               p += 5;
-                                       }
-                               }
-                               if (*s & 0x80) { /* XXX inefficient */
-                                       char *r;
-                                       int rn, i;
-                                       w = decode_utf8(&s, end, "utf-16-be");
-                                       if (w == NULL) {
-                                               Py_DECREF(u);
-                                               return NULL;
-                                       }
-                                       r = PyString_AsString(w);
-                                       rn = PyString_Size(w);
-                                       assert(rn % 2 == 0);
-                                       for (i = 0; i < rn; i += 2) {
-                                               sprintf(p, "\\u%02x%02x",
-                                                       r[i + 0] & 0xFF,
-                                                       r[i + 1] & 0xFF);
-                                               p += 6;
-                                       }
-                                       Py_DECREF(w);
-                               } else {
-                                       *p++ = *s++;
-                               }
-                       }
-                       len = p - buf;
-               }
-               if (rawmode)
-                       v = PyUnicode_DecodeRawUnicodeEscape(buf, len, NULL);
-               else
-                       v = PyUnicode_DecodeUnicodeEscape(buf, len, NULL);
-               Py_XDECREF(u);
-               if (v == NULL)
-                       PyErr_SyntaxLocation(c->c_filename, c->c_lineno);
-               return v;
-                       
-       }
-#endif
-       need_encoding = (encoding != NULL &&
-                        strcmp(encoding, "utf-8") != 0 &&
-                        strcmp(encoding, "iso-8859-1") != 0);
-       if (rawmode || strchr(s, '\\') == NULL) {
-               if (need_encoding) {
-#ifndef Py_USING_UNICODE
-                       /* This should not happen - we never see any other
-                          encoding. */
-                       Py_FatalError("cannot deal with encodings in this build.");
-#else
-                       PyObject* u = PyUnicode_DecodeUTF8(s, len, NULL);
-                       if (u == NULL)
-                               return NULL;
-                       v = PyUnicode_AsEncodedString(u, encoding, NULL);
-                       Py_DECREF(u);
-                       return v;
-#endif
-               } else {
-                       return PyString_FromStringAndSize(s, len);
-               }
-       }
-
-       v = PyString_DecodeEscape(s, len, NULL, unicode,
-                                 need_encoding ? encoding : NULL);
-       if (v == NULL)
-               PyErr_SyntaxLocation(c->c_filename, c->c_lineno);
-       return v;
-}
-
-static PyObject *
-parsestrplus(struct compiling* c, node *n)
-{
-       PyObject *v;
-       int i;
-       REQ(CHILD(n, 0), STRING);
-       if ((v = parsestr(c, STR(CHILD(n, 0)))) != NULL) {
-               /* String literal concatenation */
-               for (i = 1; i < NCH(n); i++) {
-                   PyObject *s;
-                   s = parsestr(c, STR(CHILD(n, i)));
-                   if (s == NULL)
-                       goto onError;
-                   if (PyString_Check(v) && PyString_Check(s)) {
-                       PyString_ConcatAndDel(&v, s);
-                       if (v == NULL)
-                           goto onError;
-                   }
-#ifdef Py_USING_UNICODE
-                   else {
-                       PyObject *temp;
-                       temp = PyUnicode_Concat(v, s);
-                       Py_DECREF(s);
-                       if (temp == NULL)
-                           goto onError;
-                       Py_DECREF(v);
-                       v = temp;
-                   }
-#endif
-               }
-       }
-       return v;
-
- onError:
-       Py_XDECREF(v);
-       return NULL;
-}
-
-static void
-com_list_for(struct compiling *c, node *n, node *e, char *t)
-{
-       int anchor = 0;
-       int save_begin = c->c_begin;
-
-       /* list_for: for v in expr [list_iter] */
-       com_node(c, CHILD(n, 3)); /* expr */
-       com_addbyte(c, GET_ITER);
-       c->c_begin = c->c_nexti;
-       com_addfwref(c, FOR_ITER, &anchor);
-       com_push(c, 1);
-       com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
-       c->c_loops++;
-       com_list_iter(c, n, e, t);
-       c->c_loops--;
-       com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
-       c->c_begin = save_begin;
-       com_backpatch(c, anchor);
-       com_pop(c, 1); /* FOR_ITER has popped this */
-}  
-
-static void
-com_gen_for(struct compiling *c, node *n, node *t, int is_outmost)
-{
-       int break_anchor = 0;
-       int anchor = 0;
-       int save_begin = c->c_begin;
-
-       REQ(n, gen_for);
-       /* gen_for: for v in test [gen_iter] */
-
-       com_addfwref(c, SETUP_LOOP, &break_anchor);
-       block_push(c, SETUP_LOOP);
-
-       if (is_outmost) {
-               com_addop_varname(c, VAR_LOAD, "[outmost-iterable]");
-               com_push(c, 1);
-       }
-       else {
-               com_node(c, CHILD(n, 3));
-               com_addbyte(c, GET_ITER); 
-       }
-
-       c->c_begin = c->c_nexti;
-       com_set_lineno(c, c->c_last_line);
-       com_addfwref(c, FOR_ITER, &anchor);
-       com_push(c, 1);
-       com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
-
-       if (NCH(n) == 5) 
-               com_gen_iter(c, CHILD(n, 4), t);
-       else {
-               com_test(c, t);
-               com_addbyte(c, YIELD_VALUE);
-               com_addbyte(c, POP_TOP);
-               com_pop(c, 1);
-       }
-
-       com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
-       c->c_begin = save_begin;
-
-       com_backpatch(c, anchor);
-       com_pop(c, 1); /* FOR_ITER has popped this */
-       com_addbyte(c, POP_BLOCK);
-       block_pop(c, SETUP_LOOP);
-       com_backpatch(c, break_anchor);
-}
-
-static void
-com_list_if(struct compiling *c, node *n, node *e, char *t)
-{
-       int anchor = 0;
-       int a = 0;
-       /* list_iter: 'if' test [list_iter] */
-       com_node(c, CHILD(n, 1));
-       com_addfwref(c, JUMP_IF_FALSE, &a);
-       com_addbyte(c, POP_TOP);
-       com_pop(c, 1);
-       com_list_iter(c, n, e, t);
-       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);
-       com_backpatch(c, anchor);
-}
-
-static void
-com_gen_if(struct compiling *c, node *n, node *t)
-{
-       /* gen_if: 'if' test [gen_iter] */
-       int anchor = 0;
-       int a=0;
-
-       com_node(c, CHILD(n, 1));
-       com_addfwref(c, JUMP_IF_FALSE, &a);
-       com_addbyte(c, POP_TOP);
-       com_pop(c, 1);
-
-       if (NCH(n) == 3)
-               com_gen_iter(c, CHILD(n, 2), t);
-       else {
-               com_test(c, t);
-               com_addbyte(c, YIELD_VALUE);
-               com_addbyte(c, POP_TOP);
-               com_pop(c, 1);
-       }
-       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);
-       com_backpatch(c, anchor);
-}
-
-static void
-com_list_iter(struct compiling *c,
-             node *p,          /* parent of list_iter node */
-             node *e,          /* element expression node */
-             char *t           /* name of result list temp local */)
-{
-       /* list_iter is the last child in a listmaker, list_for, or list_if */
-       node *n = CHILD(p, NCH(p)-1);
-       if (TYPE(n) == list_iter) {
-               n = CHILD(n, 0);
-               switch (TYPE(n)) {
-               case list_for: 
-                       com_list_for(c, n, e, t);
-                       break;
-               case list_if:
-                       com_list_if(c, n, e, t);
-                       break;
-               default:
-                       com_error(c, PyExc_SystemError,
-                                 "invalid list_iter node type");
-               }
-       }
-       else {
-               com_addop_varname(c, VAR_LOAD, t);
-               com_push(c, 1);
-               com_node(c, e);
-               com_addbyte(c, LIST_APPEND);
-               com_pop(c, 2);
-       }
-}
-
-static void
-com_gen_iter(struct compiling *c, node *n, node *t)
-{
-       /* gen_iter: gen_for | gen_if */
-       node *ch;
-       REQ(n, gen_iter);
-
-       ch = CHILD(n, 0);
-
-       switch (TYPE(ch)) {
-       case gen_for:
-               com_gen_for(c, ch, t, 0);
-               break;
-       case gen_if:
-               com_gen_if(c, ch, t);
-               break;
-       default:
-               com_error(c, PyExc_SystemError,
-                         "invalid gen_iter node type");
-       }
-}
-
-static void
-com_list_comprehension(struct compiling *c, node *n)
-{
-       /* listmaker: test list_for */
-       char tmpname[30];
-
-       REQ(n, listmaker);
-       PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->c_tmpname);
-       com_addoparg(c, BUILD_LIST, 0);
-       com_addbyte(c, DUP_TOP); /* leave the result on the stack */
-       com_push(c, 2);
-       com_addop_varname(c, VAR_STORE, tmpname);
-       com_pop(c, 1);
-       com_list_for(c, CHILD(n, 1), CHILD(n, 0), tmpname);
-       com_addop_varname(c, VAR_DELETE, tmpname);
-       --c->c_tmpname;
-}
-
-static void
-com_listmaker(struct compiling *c, node *n)
-{
-       /* listmaker: test ( list_for | (',' test)* [','] ) */
-       if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for)
-               com_list_comprehension(c, n);
-       else {
-               int len = 0;
-               int i;
-               for (i = 0; i < NCH(n); i += 2, len++)
-                       com_node(c, CHILD(n, i));
-               com_addoparg(c, BUILD_LIST, len);
-               com_pop(c, len-1);
-       }
-}
-
-static void
-com_generator_expression(struct compiling *c, node *n)
-{
-       /* testlist_gexp: test gen_for */
-       /* argument: test gen_for */
-       PyCodeObject *co;
-
-       REQ(CHILD(n, 0), test); 
-       REQ(CHILD(n, 1), gen_for); 
-
-       symtable_enter_scope(c->c_symtable, "<genexpr>", TYPE(n),
-                            n->n_lineno);
-       co = icompile(n, c);
-       symtable_exit_scope(c->c_symtable);
-
-       if (co == NULL)
-               c->c_errors++;
-       else {
-               int closure = com_make_closure(c, co);
-               int i = com_addconst(c, (PyObject *)co);
-
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               if (closure)
-                       com_addoparg(c, MAKE_CLOSURE, 0);
-               else
-                       com_addoparg(c, MAKE_FUNCTION, 0);
-
-               com_test(c, CHILD(CHILD(n, 1), 3));
-               com_addbyte(c, GET_ITER);
-               com_addoparg(c, CALL_FUNCTION, 1);
-               com_pop(c, 1);
-
-               Py_DECREF(co);
-       }
-}
-
-static void
-com_testlist_gexp(struct compiling *c, node *n)
-{
-       /* testlist_gexp: test ( gen_for | (',' test)* [','] ) */
-       if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for)
-               com_generator_expression(c, n);
-       else com_list(c, n, 0);
-}
-
-
-static void
-com_dictmaker(struct compiling *c, node *n)
-{
-       int i;
-       /* dictmaker: test ':' test (',' test ':' value)* [','] */
-       for (i = 0; i+2 < NCH(n); i += 4) {
-               /* 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)); /* key */
-               com_node(c, CHILD(n, i+2)); /* value */
-               com_addbyte(c, ROT_THREE);
-               com_addbyte(c, STORE_SUBSCR);
-               com_pop(c, 3);
-       }
-}
-
-
-/* forward reference */
-static void com_yield_expr(struct compiling *c, node *n);
-
-static void
-com_atom(struct compiling *c, node *n)
-{
-       node *ch;
-       PyObject *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);
-                       com_push(c, 1);
-               }
-               else
-                       if (TYPE(CHILD(n, 1)) == yield_expr)
-                               com_yield_expr(c, CHILD(n, 1));
-                       else
-                               com_testlist_gexp(c, CHILD(n, 1));
-               break;
-       case LSQB: /* '[' [listmaker] ']' */
-               if (TYPE(CHILD(n, 1)) == RSQB) {
-                       com_addoparg(c, BUILD_LIST, 0);
-                       com_push(c, 1);
-               }
-               else
-                       com_listmaker(c, CHILD(n, 1));
-               break;
-       case LBRACE: /* '{' [dictmaker] '}' */
-               com_addoparg(c, BUILD_MAP, 0);
-               com_push(c, 1);
-               if (TYPE(CHILD(n, 1)) == dictmaker)
-                       com_dictmaker(c, CHILD(n, 1));
-               break;
-       case BACKQUOTE:
-               com_node(c, CHILD(n, 1));
-               com_addbyte(c, UNARY_CONVERT);
-               break;
-       case NUMBER:
-               if ((v = parsenumber(c, STR(ch))) == NULL) {
-                       i = 255;
-               }
-               else {
-                       i = com_addconst(c, v);
-                       Py_DECREF(v);
-               }
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               break;
-       case STRING:
-               v = parsestrplus(c, n);
-               if (v == NULL) {
-                       c->c_errors++;
-                       i = 255;
-               }
-               else {
-                       i = com_addconst(c, v);
-                       Py_DECREF(v);
-               }
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               break;
-       case NAME:
-               com_addop_varname(c, VAR_LOAD, STR(ch));
-               com_push(c, 1);
-               break;
-       default:
-               com_error(c, PyExc_SystemError,
-                         "com_atom: unexpected node type");
-       }
-}
-
-static void
-com_slice(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);
-               }
-               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);
-       }
-}
-
-static void
-com_augassign_slice(struct compiling *c, node *n, int opcode, node *augn)
-{
-       if (NCH(n) == 1) {
-               com_addbyte(c, DUP_TOP);
-               com_push(c, 1);
-               com_addbyte(c, SLICE);
-               com_node(c, augn);
-               com_addbyte(c, opcode);
-               com_pop(c, 1);
-               com_addbyte(c, ROT_TWO);
-               com_addbyte(c, STORE_SLICE);
-               com_pop(c, 2);
-       } else if (NCH(n) == 2 && TYPE(CHILD(n, 0)) != COLON) {
-               com_node(c, CHILD(n, 0));
-               com_addoparg(c, DUP_TOPX, 2);
-               com_push(c, 2);
-               com_addbyte(c, SLICE+1);
-               com_pop(c, 1);
-               com_node(c, augn);
-               com_addbyte(c, opcode);
-               com_pop(c, 1);
-               com_addbyte(c, ROT_THREE);
-               com_addbyte(c, STORE_SLICE+1);
-               com_pop(c, 3);
-       } else if (NCH(n) == 2) {
-               com_node(c, CHILD(n, 1));
-               com_addoparg(c, DUP_TOPX, 2);
-               com_push(c, 2);
-               com_addbyte(c, SLICE+2);
-               com_pop(c, 1);
-               com_node(c, augn);
-               com_addbyte(c, opcode);
-               com_pop(c, 1);
-               com_addbyte(c, ROT_THREE);
-               com_addbyte(c, STORE_SLICE+2);
-               com_pop(c, 3);
-       } else {
-               com_node(c, CHILD(n, 0));
-               com_node(c, CHILD(n, 2));
-               com_addoparg(c, DUP_TOPX, 3);
-               com_push(c, 3);
-               com_addbyte(c, SLICE+3);
-               com_pop(c, 2);
-               com_node(c, augn);
-               com_addbyte(c, opcode);
-               com_pop(c, 1);
-               com_addbyte(c, ROT_FOUR);
-               com_addbyte(c, STORE_SLICE+3);
-               com_pop(c, 4);
-       }
-}
-
-static void
-com_argument(struct compiling *c, node *n, PyObject **pkeywords)
-{
-       node *m;
-       REQ(n, argument); /* [test '='] test [gen_for]; really [keyword '='] test */
-       if (NCH(n) == 1) {
-               if (*pkeywords != NULL) {
-                       com_error(c, PyExc_SyntaxError,
-                                 "non-keyword arg after keyword arg");
-               }
-               else {
-                       com_node(c, CHILD(n, 0));
-               }
-               return;
-       }
-       if (NCH(n) == 2) {
-               com_generator_expression(c, n);
-               return;
-       }
-
-       m = n;
-       do {
-               m = CHILD(m, 0);
-       } while (NCH(m) == 1);
-       if (TYPE(m) != NAME) {
-               /* f(lambda x: x[0] = 3) ends up getting parsed with
-                * LHS test = lambda x: x[0], and RHS test = 3.
-                * SF bug 132313 points out that complaining about a keyword
-                * then is very confusing.
-                */
-               com_error(c, PyExc_SyntaxError,
-                         TYPE(m) == lambdef ?
-                                 "lambda cannot contain assignment" :
-                                 "keyword can't be an expression");
-       }
-       else {
-               PyObject *v = PyString_InternFromString(STR(m));
-               (void) none_assignment_check(c, STR(m), 1);
-               if (v != NULL && *pkeywords == NULL)
-                       *pkeywords = PyDict_New();
-               if (v == NULL)
-                       c->c_errors++;
-               else if (*pkeywords == NULL) {
-                       c->c_errors++;
-                       Py_DECREF(v);
-               } else {
-                       if (PyDict_GetItem(*pkeywords, v) != NULL)
-                               com_error(c, PyExc_SyntaxError,
-                                         "duplicate keyword argument");
-                       else
-                               if (PyDict_SetItem(*pkeywords, v, v) != 0)
-                                       c->c_errors++;
-                       com_addoparg(c, LOAD_CONST, com_addconst(c, v));
-                       com_push(c, 1);
-                       Py_DECREF(v);
-               }
-       }
-       com_node(c, CHILD(n, 2));
-}
-
-static void
-com_call_function(struct compiling *c, node *n)
-{
-       if (TYPE(n) == RPAR) {
-               com_addoparg(c, CALL_FUNCTION, 0);
-       }
-       else {
-               PyObject *keywords = NULL;
-               int i, na, nk;
-               int lineno = n->n_lineno;
-               int star_flag = 0;
-               int starstar_flag = 0;
-               int opcode;
-               REQ(n, arglist);
-               na = 0;
-               nk = 0;
-               for (i = 0; i < NCH(n); i += 2) {
-                       node *ch = CHILD(n, i);
-                       if (TYPE(ch) == STAR ||
-                           TYPE(ch) == DOUBLESTAR)
-                         break;
-                       if (ch->n_lineno != lineno) {
-                               lineno = ch->n_lineno;
-                               com_set_lineno(c, lineno);
-                       }
-                       com_argument(c, ch, &keywords);
-                       if (keywords == NULL)
-                               na++;
-                       else
-                               nk++;
-               }
-               Py_XDECREF(keywords);
-               while (i < NCH(n)) {
-                   node *tok = CHILD(n, i);
-                   node *ch = CHILD(n, i+1);
-                   i += 3;
-                   switch (TYPE(tok)) {
-                   case STAR:       star_flag = 1;     break;
-                   case DOUBLESTAR: starstar_flag = 1; break;
-                   }
-                   com_node(c, ch);
-               }
-               if (na > 255 || nk > 255) {
-                       com_error(c, PyExc_SyntaxError,
-                                 "more than 255 arguments");
-               }
-               if (star_flag || starstar_flag)
-                   opcode = CALL_FUNCTION_VAR - 1 + 
-                       star_flag + (starstar_flag << 1);
-               else
-                   opcode = CALL_FUNCTION;
-               com_addoparg(c, opcode, na | (nk << 8));
-               com_pop(c, na + 2*nk + star_flag + starstar_flag);
-       }
-}
-
-static void
-com_select_member(struct compiling *c, node *n)
-{
-       com_addopname(c, LOAD_ATTR, n);
-}
-
-static void
-com_sliceobj(struct compiling *c, node *n)
-{
-       int i=0;
-       int ns=2; /* number of slice arguments */
-       node *ch;
-
-       /* first argument */
-       if (TYPE(CHILD(n,i)) == COLON) {
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-               com_push(c, 1);
-               i++;
-       }
-       else {
-               com_node(c, CHILD(n,i));
-               i++;
-               REQ(CHILD(n,i),COLON);
-               i++;
-       }
-       /* second argument */
-       if (i < NCH(n) && TYPE(CHILD(n,i)) == test) {
-               com_node(c, CHILD(n,i));
-               i++;
-       }
-       else {
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-               com_push(c, 1);
-       }
-       /* remaining arguments */
-       for (; i < NCH(n); i++) {
-               ns++;
-               ch=CHILD(n,i);
-               REQ(ch, sliceop);
-               if (NCH(ch) == 1) {
-                       /* right argument of ':' missing */
-                       com_addoparg(c, LOAD_CONST, com_addconst(c, Py_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
-com_subscript(struct compiling *c, node *n)
-{
-       node *ch;
-       REQ(n, subscript);
-       ch = CHILD(n,0);
-       /* check for rubber index */
-       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))
-                       com_sliceobj(c, n);
-               else {
-                       REQ(ch, test);
-                       com_node(c, ch);
-               }
-       }
-}
-
-static void
-com_subscriptlist(struct compiling *c, node *n, int assigning, node *augn)
-{
-       int i, op;
-       REQ(n, subscriptlist);
-       /* Check to make backward compatible slice behavior for '[i:j]' */
-       if (NCH(n) == 1) {
-               node *sub = CHILD(n, 0); /* subscript */
-               /* 'Basic' slice, 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))
-               {
-                       switch (assigning) {
-                       case OP_DELETE:
-                               op = DELETE_SLICE;
-                               break;
-                       case OP_ASSIGN:
-                               op = STORE_SLICE;
-                               break;
-                       case OP_APPLY:
-                               op = SLICE;
-                               break;
-                       default:
-                               com_augassign_slice(c, sub, assigning, augn);
-                               return;
-                       }
-                       com_slice(c, sub, op);
-                       if (op == STORE_SLICE)
-                               com_pop(c, 2);
-                       else if (op == DELETE_SLICE)
-                               com_pop(c, 1);
-                       return;
-               }
-       }
-       /* Else normal subscriptlist.  Compile each subscript. */
-       for (i = 0; i < NCH(n); i += 2)
-               com_subscript(c, CHILD(n, i));
-       /* Put multiple subscripts into a tuple */
-       if (NCH(n) > 1) {
-               i = (NCH(n)+1) / 2;
-               com_addoparg(c, BUILD_TUPLE, i);
-               com_pop(c, i-1);
-       }
-       switch (assigning) {
-       case OP_DELETE:
-               op = DELETE_SUBSCR;
-               i = 2;
-               break;
-       default:
-       case OP_ASSIGN:
-               op = STORE_SUBSCR;
-               i = 3;
-               break;
-       case OP_APPLY:
-               op = BINARY_SUBSCR;
-               i = 1;
-               break;
-       }
-       if (assigning > OP_APPLY) {
-               com_addoparg(c, DUP_TOPX, 2);
-               com_push(c, 2);
-               com_addbyte(c, BINARY_SUBSCR);
-               com_pop(c, 1);
-               com_node(c, augn);
-               com_addbyte(c, assigning);
-               com_pop(c, 1);
-               com_addbyte(c, ROT_THREE);
-       }
-       com_addbyte(c, op);
-       com_pop(c, i);
-}
-
-static void
-com_apply_trailer(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_subscriptlist(c, CHILD(n, 1), OP_APPLY, NULL);
-               break;
-       default:
-               com_error(c, PyExc_SystemError,
-                         "com_apply_trailer: unknown trailer type");
-       }
-}
-
-static void
-com_power(struct compiling *c, node *n)
-{
-       int i;
-       REQ(n, power);
-       com_atom(c, CHILD(n, 0));
-       for (i = 1; i < NCH(n); i++) {
-               if (TYPE(CHILD(n, i)) == DOUBLESTAR) {
-                       com_factor(c, CHILD(n, i+1));
-                       com_addbyte(c, BINARY_POWER);
-                       com_pop(c, 1);
-                       break;
-               }
-               else
-                       com_apply_trailer(c, CHILD(n, i));
-       }
-}
-
-static void
-com_invert_constant(struct compiling *c, node *n)
-{
-       /* Compute the inverse of int and longs and use them directly,
-          but be prepared to generate code for all other
-          possibilities (invalid numbers, floats, complex).
-       */
-       PyObject *num, *inv = NULL;
-       int i;
-
-       REQ(n, NUMBER);
-       num = parsenumber(c, STR(n));
-       if (num == NULL) 
-               i = 255;
-       else {
-               inv = PyNumber_Invert(num);
-               if (inv == NULL) {
-                       PyErr_Clear();
-                       i = com_addconst(c, num);
-               } else {
-                       i = com_addconst(c, inv);
-                       Py_DECREF(inv);
-               }
-               Py_DECREF(num);
-       }
-       com_addoparg(c, LOAD_CONST, i);
-       com_push(c, 1);
-       if (num != NULL && inv == NULL)
-               com_addbyte(c, UNARY_INVERT);
-}
-
-static int
-is_float_zero(const char *p)
-{
-       int found_radix_point = 0;
-       int ch;
-       while ((ch = Py_CHARMASK(*p++)) != '\0') {
-               switch (ch) {
-               case '0':
-                       /* no reason to believe it's not 0 -- continue */
-                       break;
-
-               case 'e': case 'E': case 'j': case 'J':
-                       /* If this was a hex constant, we already would have
-                          returned 0 due to the 'x' or 'X', so 'e' or 'E'
-                          must be an exponent marker, and we haven't yet
-                          seen a non-zero digit, and it doesn't matter what
-                          the exponent is then.  For 'j' or 'J' similarly,
-                          except that this is an imaginary 0 then. */
-                       return 1;
-
-               case '.':
-                       found_radix_point = 1;
-                       break;
-
-               default:
-                       return 0;
-               }
-       }
-       return found_radix_point;
-}
-
-static void
-com_factor(struct compiling *c, node *n)
-{
-       int childtype = TYPE(CHILD(n, 0));
-       node *pfactor, *ppower, *patom, *pnum;
-       REQ(n, factor);
-       /* If the unary +, -, or ~ operator is applied to a constant,
-          don't generate a UNARY_xxx opcode.  Just store the
-          approriate value as a constant.  If the value is negative,
-          extend the string containing the constant and insert a
-          negative in the 0th position -- unless we're doing unary minus
-          of a floating zero!  In that case the sign is significant, but
-          the const dict can't distinguish +0.0 from -0.0.
-        */
-       if ((childtype == PLUS || childtype == MINUS || childtype == TILDE)
-           && NCH(n) == 2
-           && TYPE((pfactor = CHILD(n, 1))) == factor
-           && NCH(pfactor) == 1
-           && TYPE((ppower = CHILD(pfactor, 0))) == power
-           && NCH(ppower) == 1
-           && TYPE((patom = CHILD(ppower, 0))) == atom
-           && TYPE((pnum = CHILD(patom, 0))) == NUMBER
-           && !(childtype == MINUS &&
-                (STR(pnum)[0] == '0' || is_float_zero(STR(pnum))))) {
-               if (childtype == TILDE) {
-                       com_invert_constant(c, pnum);
-                       return;
-               }
-               if (childtype == MINUS) {
-                       char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2);
-                       if (s == NULL) {
-                               com_error(c, PyExc_MemoryError, "");
-                               com_addbyte(c, 255);
-                               return;
-                       }
-                       s[0] = '-';
-                       strcpy(s + 1, STR(pnum));
-                       PyObject_FREE(STR(pnum));
-                       STR(pnum) = s;
-               }
-               com_atom(c, patom);
-       }
-       else if (childtype == PLUS) {
-               com_factor(c, CHILD(n, 1));
-               com_addbyte(c, UNARY_POSITIVE);
-       }
-       else if (childtype == MINUS) {
-               com_factor(c, CHILD(n, 1));
-               com_addbyte(c, UNARY_NEGATIVE);
-       }
-       else if (childtype == TILDE) {
-               com_factor(c, CHILD(n, 1));
-               com_addbyte(c, UNARY_INVERT);
-       }
-       else {
-               com_power(c, CHILD(n, 0));
-       }
-}
-
-static void
-com_term(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:
-                       if (c->c_flags & CO_FUTURE_DIVISION)
-                               op = BINARY_TRUE_DIVIDE;
-                       else
-                               op = BINARY_DIVIDE;
-                       break;
-               case PERCENT:
-                       op = BINARY_MODULO;
-                       break;
-               case DOUBLESLASH:
-                       op = BINARY_FLOOR_DIVIDE;
-                       break;
-               default:
-                       com_error(c, PyExc_SystemError,
-                                 "com_term: operator not *, /, // or %");
-                       op = 255;
-               }
-               com_addbyte(c, op);
-               com_pop(c, 1);
-       }
-}
-
-static void
-com_arith_expr(struct compiling *c, node *n)
-{
-       int i;
-       int op;
-       REQ(n, arith_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:
-                       com_error(c, PyExc_SystemError,
-                                 "com_arith_expr: operator not + or -");
-                       op = 255;
-               }
-               com_addbyte(c, op);
-               com_pop(c, 1);
-       }
-}
-
-static void
-com_shift_expr(struct compiling *c, node *n)
-{
-       int i;
-       int op;
-       REQ(n, shift_expr);
-       com_arith_expr(c, CHILD(n, 0));
-       for (i = 2; i < NCH(n); i += 2) {
-               com_arith_expr(c, CHILD(n, i));
-               switch (TYPE(CHILD(n, i-1))) {
-               case LEFTSHIFT:
-                       op = BINARY_LSHIFT;
-                       break;
-               case RIGHTSHIFT:
-                       op = BINARY_RSHIFT;
-                       break;
-               default:
-                       com_error(c, PyExc_SystemError,
-                                 "com_shift_expr: operator not << or >>");
-                       op = 255;
-               }
-               com_addbyte(c, op);
-               com_pop(c, 1);
-       }
-}
-
-static void
-com_and_expr(struct compiling *c, node *n)
-{
-       int i;
-       int op;
-       REQ(n, and_expr);
-       com_shift_expr(c, CHILD(n, 0));
-       for (i = 2; i < NCH(n); i += 2) {
-               com_shift_expr(c, CHILD(n, i));
-               if (TYPE(CHILD(n, i-1)) == AMPER) {
-                       op = BINARY_AND;
-               }
-               else {
-                       com_error(c, PyExc_SystemError,
-                                 "com_and_expr: operator not &");
-                       op = 255;
-               }
-               com_addbyte(c, op);
-               com_pop(c, 1);
-       }
-}
-
-static void
-com_xor_expr(struct compiling *c, node *n)
-{
-       int i;
-       int op;
-       REQ(n, xor_expr);
-       com_and_expr(c, CHILD(n, 0));
-       for (i = 2; i < NCH(n); i += 2) {
-               com_and_expr(c, CHILD(n, i));
-               if (TYPE(CHILD(n, i-1)) == CIRCUMFLEX) {
-                       op = BINARY_XOR;
-               }
-               else {
-                       com_error(c, PyExc_SystemError,
-                                 "com_xor_expr: operator not ^");
-                       op = 255;
-               }
-               com_addbyte(c, op);
-               com_pop(c, 1);
-       }
-}
-
-static void
-com_expr(struct compiling *c, node *n)
-{
-       int i;
-       int op;
-       REQ(n, expr);
-       com_xor_expr(c, CHILD(n, 0));
-       for (i = 2; i < NCH(n); i += 2) {
-               com_xor_expr(c, CHILD(n, i));
-               if (TYPE(CHILD(n, i-1)) == VBAR) {
-                       op = BINARY_OR;
-               }
-               else {
-                       com_error(c, PyExc_SystemError,
-                                 "com_expr: expr operator not |");
-                       op = 255;
-               }
-               com_addbyte(c, op);
-               com_pop(c, 1);
-       }
-}
-
-static enum cmp_op
-cmp_type(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 PyCmp_LT;
-               case GREATER:   return PyCmp_GT;
-               case EQEQUAL:   return PyCmp_EQ;
-               case LESSEQUAL: return PyCmp_LE;
-               case GREATEREQUAL: return PyCmp_GE;
-               case NOTEQUAL:  return PyCmp_NE;        /* <> or != */
-               case NAME:      if (strcmp(STR(n), "in") == 0) return PyCmp_IN;
-                               if (strcmp(STR(n), "is") == 0) return PyCmp_IS;
-               }
-       }
-       else if (NCH(n) == 2) {
-               switch (TYPE(CHILD(n, 0))) {
-               case NAME:      if (strcmp(STR(CHILD(n, 1)), "in") == 0)
-                                       return PyCmp_NOT_IN;
-                               if (strcmp(STR(CHILD(n, 0)), "is") == 0)
-                                       return PyCmp_IS_NOT;
-               }
-       }
-       return PyCmp_BAD;
-}
-
-static void
-com_comparison(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:          0-or-1
-       ****************************************************************/
-       
-       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_push(c, 1);
-                       com_addbyte(c, ROT_THREE);
-               }
-               op = cmp_type(CHILD(n, i-1));
-               if (op == PyCmp_BAD) {
-                       com_error(c, PyExc_SystemError,
-                                 "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);
-               }
-       }
-       
-       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(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(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);
-               com_pop(c, 1);
-       }
-       if (anchor)
-               com_backpatch(c, anchor);
-}
-
-static int
-com_make_closure(struct compiling *c, PyCodeObject *co)
-{
-       int i, free = PyCode_GetNumFree(co);
-       if (free == 0)
-               return 0;
-       for (i = 0; i < free; ++i) {
-               /* Bypass com_addop_varname because it will generate
-                  LOAD_DEREF but LOAD_CLOSURE is needed. 
-               */
-               PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
-               int arg, reftype;
-
-               /* Special case: If a class contains a method with a
-                  free variable that has the same name as a method,
-                  the name will be considered free *and* local in the
-                  class.  It should be handled by the closure, as
-                  well as by the normal name loookup logic.
-               */
-               reftype = get_ref_type(c, PyString_AS_STRING(name));    
-               if (reftype == CELL)
-                       arg = com_lookup_arg(c->c_cellvars, name);
-               else /* (reftype == FREE) */
-                       arg = com_lookup_arg(c->c_freevars, name);
-               if (arg == -1) {
-                       fprintf(stderr, "lookup %s in %s %d %d\n"
-                               "freevars of %s: %s\n",
-                               PyObject_REPR(name), 
-                               c->c_name, 
-                               reftype, arg,
-                               PyString_AS_STRING(co->co_name),
-                               PyObject_REPR(co->co_freevars));
-                       Py_FatalError("com_make_closure()");
-               }
-               com_addoparg(c, LOAD_CLOSURE, arg);
-
-       }
-       com_push(c, free);
-       return 1;
-}
-
-static void
-com_test(struct compiling *c, node *n)
-{
-       REQ(n, test); /* and_test ('or' and_test)* | lambdef */
-       if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
-               PyCodeObject *co;
-               int i, closure;
-               int ndefs = com_argdefs(c, CHILD(n, 0));
-               symtable_enter_scope(c->c_symtable, "lambda", lambdef,
-                                    n->n_lineno);
-               co = icompile(CHILD(n, 0), c);
-               if (co == NULL) {
-                       c->c_errors++;
-                       return;
-               }
-               symtable_exit_scope(c->c_symtable);
-               i = com_addconst(c, (PyObject *)co);
-               closure = com_make_closure(c, co);
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               if (closure) {
-                       com_addoparg(c, MAKE_CLOSURE, ndefs);
-                       com_pop(c, PyCode_GetNumFree(co));
-               } else
-                       com_addoparg(c, MAKE_FUNCTION, ndefs);
-               Py_DECREF(co);
-               com_pop(c, ndefs);
-       }
-       else {
-               int anchor = 0;
-               int 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);
-                       com_pop(c, 1);
-               }
-               if (anchor)
-                       com_backpatch(c, anchor);
-       }
-}
-
-static void
-com_list(struct compiling *c, node *n, int toplevel)
-{
-       /* exprlist: expr (',' expr)* [',']; likewise for testlist */
-       if (NCH(n) == 1 && !toplevel) {
-               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);
-               com_pop(c, len-1);
-       }
-}
-
-
-/* Begin of assignment compilation */
-
-
-static void
-com_augassign_attr(struct compiling *c, node *n, int opcode, node *augn)
-{
-       com_addbyte(c, DUP_TOP);
-       com_push(c, 1);
-       com_addopname(c, LOAD_ATTR, n);
-       com_node(c, augn);
-       com_addbyte(c, opcode);
-       com_pop(c, 1);
-       com_addbyte(c, ROT_TWO);
-       com_addopname(c, STORE_ATTR, n);
-       com_pop(c, 2);
-}
-
-static void
-com_assign_attr(struct compiling *c, node *n, int assigning)
-{
-       if (none_assignment_check(c, STR(n), assigning))
-               return;
-       com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n);
-       com_pop(c, assigning ? 2 : 1);
-}
-
-static void
-com_assign_trailer(struct compiling *c, node *n, int assigning, node *augn)
-{
-       REQ(n, trailer);
-       switch (TYPE(CHILD(n, 0))) {
-       case LPAR: /* '(' [exprlist] ')' */
-               if (assigning == OP_DELETE)
-                       com_error(c, PyExc_SyntaxError,
-                                 "can't delete function call");
-               else
-                       com_error(c, PyExc_SyntaxError,
-                                 "can't assign to function call");
-               break;
-       case DOT: /* '.' NAME */
-               if (assigning > OP_APPLY)
-                       com_augassign_attr(c, CHILD(n, 1), assigning, augn);
-               else
-                       com_assign_attr(c, CHILD(n, 1), assigning);
-               break;
-       case LSQB: /* '[' subscriptlist ']' */
-               com_subscriptlist(c, CHILD(n, 1), assigning, augn);
-               break;
-       default:
-               com_error(c, PyExc_SystemError, "unknown trailer type");
-       }
-}
-
-static void
-com_assign_sequence(struct compiling *c, node *n, int assigning)
-{
-       int i;
-       if (TYPE(n) != testlist && TYPE(n) != testlist_gexp &&
-           TYPE(n) != listmaker)
-               REQ(n, exprlist);
-       if (assigning) {
-               i = (NCH(n)+1)/2;
-               com_addoparg(c, UNPACK_SEQUENCE, i);
-               com_push(c, i-1);
-       }
-       for (i = 0; i < NCH(n); i += 2)
-               com_assign(c, CHILD(n, i), assigning, NULL);
-}
-
-static void
-com_augassign_name(struct compiling *c, node *n, int opcode, node *augn)
-{
-       REQ(n, NAME);
-       com_addop_varname(c, VAR_LOAD, STR(n));
-       com_push(c, 1);
-       com_node(c, augn);
-       com_addbyte(c, opcode);
-       com_pop(c, 1);
-       com_assign_name(c, n, OP_ASSIGN);
-}
-
-static void
-com_assign_name(struct compiling *c, node *n, int assigning)
-{
-       REQ(n, NAME);
-       com_addop_varname(c, assigning ? VAR_STORE : VAR_DELETE, STR(n));
-       if (assigning)
-               com_pop(c, 1);
-}
-
-static void
-com_assign(struct compiling *c, node *n, int assigning, node *augn)
-{
-       /* Loop to avoid trivial recursion */
-       for (;;) {
-               switch (TYPE(n)) {
-               
-               case exprlist:
-               case testlist:
-               case testlist1:
-               case testlist_gexp:
-                       if (NCH(n) > 1) {
-                               if (TYPE(CHILD(n, 1)) == gen_for) {
-                                       com_error(c, PyExc_SyntaxError,
-                                 "assign to generator expression not possible");
-                                       return;
-                               }
-                               if (assigning > OP_APPLY) {
-                                       com_error(c, PyExc_SyntaxError,
-                                 "augmented assign to generator expression not possible");
-                                       return;
-                               }
-                               com_assign_sequence(c, n, assigning);
-                               return;
-                       }
-                       n = CHILD(n, 0);
-                       break;
-               case yield_expr:
-                       com_error(c, PyExc_SyntaxError,
-                         "assignment to yield expression not possible");
-                       return;
-                                       
-               case test:
-               case and_test:
-               case not_test:
-               case comparison:
-               case expr:
-               case xor_expr:
-               case and_expr:
-               case shift_expr:
-               case arith_expr:
-               case term:
-               case factor:
-                       if (NCH(n) > 1) {
-                               com_error(c, PyExc_SyntaxError,
-                                         "can't assign to operator");
-                               return;
-                       }
-                       n = CHILD(n, 0);
-                       break;
-               
-               case power: /* atom trailer* ('**' power)*
-                              ('+'|'-'|'~') factor | atom trailer* */
-                       if (TYPE(CHILD(n, 0)) != atom) {
-                               com_error(c, PyExc_SyntaxError,
-                                         "can't assign to operator");
-                               return;
-                       }
-                       if (NCH(n) > 1) { /* trailer or exponent present */
-                               int i;
-                               com_node(c, CHILD(n, 0));
-                               for (i = 1; i+1 < NCH(n); i++) {
-                                       if (TYPE(CHILD(n, i)) == DOUBLESTAR) {
-                                               com_error(c, PyExc_SyntaxError,
-                                                 "can't assign to operator");
-                                               return;
-                                       }
-                                       com_apply_trailer(c, CHILD(n, i));
-                               } /* NB i is still alive */
-                               com_assign_trailer(c,
-                                               CHILD(n, i), assigning, augn);
-                               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 () = () ??? */
-                                       com_error(c, PyExc_SyntaxError,
-                                                 "can't assign to ()");
-                                       return;
-                               }
-                               if (assigning > OP_APPLY) {
-                                       com_error(c, PyExc_SyntaxError,
-                                 "augmented assign to tuple literal, yield, or generator expression not possible");
-                                       return;
-                               }
-                               break;
-                       case LSQB:
-                               n = CHILD(n, 1);
-                               if (TYPE(n) == RSQB) {
-                                       com_error(c, PyExc_SyntaxError,
-                                                 "can't assign to []");
-                                       return;
-                               }
-                               if (assigning > OP_APPLY) {
-                                       com_error(c, PyExc_SyntaxError,
-                                 "augmented assign to list literal or comprehension not possible");
-                                       return;
-                               }
-                               if (NCH(n) > 1 
-                                   && TYPE(CHILD(n, 1)) == list_for) {
-                                       com_error(c, PyExc_SyntaxError,
-                                 "can't assign to list comprehension");
-                                       return;
-                               }
-                               com_assign_sequence(c, n, assigning);
-                               return;
-                       case NAME:
-                               if (assigning > OP_APPLY)
-                                       com_augassign_name(c, CHILD(n, 0),
-                                                          assigning, augn);
-                               else
-                                       com_assign_name(c, CHILD(n, 0),
-                                                       assigning);
-                               return;
-                       default:
-                               com_error(c, PyExc_SyntaxError,
-                                         "can't assign to literal");
-                               return;
-                       }
-                       break;
-
-               case lambdef:
-                       com_error(c, PyExc_SyntaxError,
-                                 "can't assign to lambda");
-                       return;
-               
-               default:
-                       com_error(c, PyExc_SystemError,
-                                 "com_assign: bad node");
-                       return;
-               
-               }
-       }
-}
-
-static void
-com_augassign(struct compiling *c, node *n)
-{
-       int opcode;
-
-       switch (STR(CHILD(CHILD(n, 1), 0))[0]) {
-       case '+': opcode = INPLACE_ADD; break;
-       case '-': opcode = INPLACE_SUBTRACT; break;
-       case '/':
-               if (STR(CHILD(CHILD(n, 1), 0))[1] == '/')
-                       opcode = INPLACE_FLOOR_DIVIDE;
-               else if (c->c_flags & CO_FUTURE_DIVISION)
-                       opcode = INPLACE_TRUE_DIVIDE;
-               else
-                       opcode = INPLACE_DIVIDE;
-               break;
-       case '%': opcode = INPLACE_MODULO; break;
-       case '<': opcode = INPLACE_LSHIFT; break;
-       case '>': opcode = INPLACE_RSHIFT; break;
-       case '&': opcode = INPLACE_AND; break;
-       case '^': opcode = INPLACE_XOR; break;
-       case '|': opcode = INPLACE_OR; break;
-       case '*':
-               if (STR(CHILD(CHILD(n, 1), 0))[1] == '*')
-                       opcode = INPLACE_POWER;
-               else
-                       opcode = INPLACE_MULTIPLY;
-               break;
-       default:
-               com_error(c, PyExc_SystemError, "com_augassign: bad operator");
-               return;
-       }
-       com_assign(c, CHILD(n, 0), opcode, CHILD(n, 2));
-}
-
-static void
-com_expr_stmt(struct compiling *c, node *n)
-{
-       REQ(n, expr_stmt);
-       /* testlist (('=' testlist)* | augassign testlist) */
-       /* Forget it if we have just a doc string here */
-       if (!c->c_interactive && NCH(n) == 1 && get_rawdocstring(n) != NULL)
-               return;
-       if (NCH(n) == 1) {
-               com_node(c, CHILD(n, NCH(n)-1));
-               if (c->c_interactive)
-                       com_addbyte(c, PRINT_EXPR);
-               else
-                       com_addbyte(c, POP_TOP);
-               com_pop(c, 1);
-       }
-       else if (TYPE(CHILD(n,1)) == augassign)
-               com_augassign(c, n);
-       else {
-               int i;
-               com_node(c, CHILD(n, NCH(n)-1));
-               for (i = 0; i < NCH(n)-2; i+=2) {
-                       if (i+2 < NCH(n)-2) {
-                               com_addbyte(c, DUP_TOP);
-                               com_push(c, 1);
-                       }
-                       com_assign(c, CHILD(n, i), OP_ASSIGN, NULL);
-               }
-       }
-}
-
-static void
-com_assert_stmt(struct compiling *c, node *n)
-{
-       int a = 0;
-       int i;
-       REQ(n, assert_stmt); /* 'assert' test [',' test] */
-       if (Py_OptimizeFlag)
-               return;
-       /* Generate code like
-          
-            if not <test>:
-                raise AssertionError [, <message>]
-
-          where <message> is the second test, if present.
-       */
-       com_node(c, CHILD(n, 1));
-       com_addfwref(c, JUMP_IF_TRUE, &a);
-       com_addbyte(c, POP_TOP);
-       com_pop(c, 1);
-       /* Raise that exception! */
-       com_addop_name(c, LOAD_GLOBAL, "AssertionError");
-       com_push(c, 1);
-       i = NCH(n)/2; /* Either 2 or 4 */
-       if (i > 1)
-               com_node(c, CHILD(n, 3));
-       com_addoparg(c, RAISE_VARARGS, i);
-       com_pop(c, i);
-       /* The interpreter does not fall through */
-       /* Jump ends up here */
-       com_backpatch(c, a);
-       com_addbyte(c, POP_TOP);
-}
-
-static void
-com_print_stmt(struct compiling *c, node *n)
-{
-       int i = 1;
-       node* stream = NULL;
-
-       REQ(n, print_stmt); /* 'print' (test ',')* [test] */
-
-       /* are we using the extended print form? */
-       if (NCH(n) >= 2 && TYPE(CHILD(n, 1)) == RIGHTSHIFT) {
-               stream = CHILD(n, 2);
-               com_node(c, stream);
-               /* stack: [...] => [... stream] */
-               com_push(c, 1);
-               if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == COMMA)
-                       i = 4;
-               else
-                       i = 3;
-       }
-       for (; i < NCH(n); i += 2) {
-               if (stream != NULL) {
-                       com_addbyte(c, DUP_TOP);
-                       /* stack: [stream] => [stream stream] */
-                       com_push(c, 1);
-                       com_node(c, CHILD(n, i));
-                       /* stack: [stream stream] => [stream stream obj] */
-                       com_addbyte(c, ROT_TWO);
-                       /* stack: [stream stream obj] => [stream obj stream] */
-                       com_addbyte(c, PRINT_ITEM_TO);
-                       /* stack: [stream obj stream] => [stream] */
-                       com_pop(c, 2);
-               }
-               else {
-                       com_node(c, CHILD(n, i));
-                       /* stack: [...] => [... obj] */
-                       com_addbyte(c, PRINT_ITEM);
-                       com_pop(c, 1);
-               }
-       }
-       /* XXX Alternatively, LOAD_CONST '\n' and then PRINT_ITEM */
-       if (TYPE(CHILD(n, NCH(n)-1)) == COMMA) {
-               if (stream != NULL) {
-                       /* must pop the extra stream object off the stack */
-                       com_addbyte(c, POP_TOP);
-                       /* stack: [... stream] => [...] */
-                       com_pop(c, 1);
-               }
-       }
-       else {
-               if (stream != NULL) {
-                       /* this consumes the last stream object on stack */
-                       com_addbyte(c, PRINT_NEWLINE_TO);
-                       /* stack: [... stream] => [...] */
-                       com_pop(c, 1);
-               }
-               else
-                       com_addbyte(c, PRINT_NEWLINE);
-       }
-}
-
-static void
-com_return_stmt(struct compiling *c, node *n)
-{
-       REQ(n, return_stmt); /* 'return' [testlist] */
-       if (!c->c_infunction) {
-               com_error(c, PyExc_SyntaxError, "'return' outside function");
-       }
-       if (c->c_flags & CO_GENERATOR) {
-               if (NCH(n) > 1) {
-                       com_error(c, PyExc_SyntaxError,
-                                 "'return' with argument inside generator");
-               }
-       }
-       if (NCH(n) < 2) {
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-               com_push(c, 1);
-       }
-       else
-               com_node(c, CHILD(n, 1));
-       com_addbyte(c, RETURN_VALUE);
-       com_pop(c, 1);
-}
-
-static void
-com_yield_expr(struct compiling *c, node *n)
-{
-       REQ(n, yield_expr); /* 'yield' testlist */
-       if (!c->c_infunction) {
-               com_error(c, PyExc_SyntaxError, "'yield' outside function");
-       }
-       
-       /* for (i = 0; i < c->c_nblocks; ++i) {
-               if (c->c_block[i] == SETUP_FINALLY) {
-                       com_error(c, PyExc_SyntaxError,
-                                 "'yield' not allowed in a 'try' block "
-                                 "with a 'finally' clause");
-                       return;
-               }
-       } */
-
-       if (NCH(n) < 2) {
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-               com_push(c, 1);
-       }
-       else
-               com_node(c, CHILD(n, 1));
-       com_addbyte(c, YIELD_VALUE);
-}
-
-static void
-com_yield_stmt(struct compiling *c, node *n)
-{
-       REQ(n, yield_stmt); /* yield_expr */
-       com_node(c, CHILD(n, 0));
-       com_addbyte(c, POP_TOP);
-       com_pop(c, 1);
-}
-
-
-static void
-com_raise_stmt(struct compiling *c, node *n)
-{
-       int i;
-       REQ(n, raise_stmt); /* 'raise' [test [',' test [',' test]]] */
-       if (NCH(n) > 1) {
-               com_node(c, CHILD(n, 1));
-               if (NCH(n) > 3) {
-                       com_node(c, CHILD(n, 3));
-                       if (NCH(n) > 5)
-                               com_node(c, CHILD(n, 5));
-               }
-       }
-       i = NCH(n)/2;
-       com_addoparg(c, RAISE_VARARGS, i);
-       com_pop(c, i);
-}
-
-static void
-com_from_import(struct compiling *c, node *n)
-{
-       com_addopname(c, IMPORT_FROM, CHILD(n, 0));
-       com_push(c, 1);
-       if (NCH(n) > 1) {
-               if (strcmp(STR(CHILD(n, 1)), "as") != 0) {
-                       com_error(c, PyExc_SyntaxError, "invalid syntax");
-                       return;
-               }
-               com_addop_varname(c, VAR_STORE, STR(CHILD(n, 2)));
-       } else
-               com_addop_varname(c, VAR_STORE, STR(CHILD(n, 0)));
-       com_pop(c, 1);
-}
+               case UNARY_POSITIVE:
+               case UNARY_NEGATIVE:
+               case UNARY_NOT:
+               case UNARY_CONVERT:
+               case UNARY_INVERT:
+                       return 0;
 
-static void
-com_import_stmt(struct compiling *c, node *n)
-{
-       node *nn;
-       int i;
-       REQ(n, import_stmt);
-       n = CHILD(n, 0);
-       /* import_stmt: import_name | import_from */
-       if (TYPE(n) == import_from) {
-               /* 'from' dotted_name 'import' ('*' |
-                    '(' import_as_names ')' | import_as_names) */
-               PyObject *tup;
-               REQ(CHILD(n, 1), dotted_name);
-               nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR));
-               if (TYPE(nn) == STAR)
-                       tup = Py_BuildValue("(s)", "*");
-               else {
-                       if (TYPE(CHILD(nn, NCH(nn) - 1)) == COMMA &&
-                           TYPE(CHILD(n, 3)) != LPAR) {
-                               com_error(c, PyExc_SyntaxError,
-                                   "trailing comma not allowed "
-                                   "without surrounding parentheses");
-                               return;
-                       }
-                       REQ(nn, import_as_names);
-                       tup = PyTuple_New((NCH(nn) + 1) / 2);
-            for (i = 0; i < NCH(nn); i += 2) {
-                PyObject *s = PyString_FromString(
-                    STR(CHILD(CHILD(nn, i), 0)));
-                if (s == NULL) {
-                    Py_CLEAR(tup);
-                    break;
-                } else
-                    PyTuple_SET_ITEM(tup, i / 2, s);
-            }
-            if (tup == NULL) {
-                /* Assume that failue above was MemoryError */
-                com_error(c, PyExc_MemoryError, "");
-                return;
-            }
-               }
-               com_addoparg(c, LOAD_CONST, com_addconst(c, tup));
-               Py_DECREF(tup);
-               com_push(c, 1);
-               com_addopname(c, IMPORT_NAME, CHILD(n, 1));
-               if (TYPE(nn) == STAR)
-                       com_addbyte(c, IMPORT_STAR);
-               else {
-                       for (i = 0; i < NCH(nn); i += 2)
-                               com_from_import(c, CHILD(nn, i));
-                       com_addbyte(c, POP_TOP);
-               }
-               com_pop(c, 1);
-       }
-       else {
-               /* 'import' dotted_as_names */
-               nn = CHILD(n, 1);
-               REQ(nn, dotted_as_names);
-               for (i = 0; i < NCH(nn); i += 2) {
-                       node *subn = CHILD(nn, i);
-                       REQ(subn, dotted_as_name);
-                       com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-                       com_push(c, 1);
-                       com_addopname(c, IMPORT_NAME, CHILD(subn, 0));
-                       if (NCH(subn) > 1) {
-                               int j;
-                               if (strcmp(STR(CHILD(subn, 1)), "as") != 0) {
-                                       com_error(c, PyExc_SyntaxError,
-                                                 "invalid syntax");
-                                       return;
-                               }
-                               for (j=2 ; j < NCH(CHILD(subn, 0)); j += 2)
-                                       com_addopname(c, LOAD_ATTR,
-                                                     CHILD(CHILD(subn, 0),
-                                                           j));
-                               com_addop_varname(c, VAR_STORE,
-                                                 STR(CHILD(subn, 2)));
-                       } else
-                               com_addop_varname(c, VAR_STORE,
-                                                 STR(CHILD(CHILD(subn, 0),
-                                                           0))); 
-                       com_pop(c, 1);
-               }
-       }
-}
+               case BINARY_POWER:
+               case BINARY_MULTIPLY:
+               case BINARY_DIVIDE:
+               case BINARY_MODULO:
+               case BINARY_ADD:
+               case BINARY_SUBTRACT:
+               case BINARY_SUBSCR:
+               case BINARY_FLOOR_DIVIDE:
+               case BINARY_TRUE_DIVIDE:
+                       return -1;
+               case INPLACE_FLOOR_DIVIDE:
+               case INPLACE_TRUE_DIVIDE:
+                       return -1;
 
-static void
-com_exec_stmt(struct compiling *c, node *n)
-{
-       REQ(n, exec_stmt);
-       /* exec_stmt: 'exec' expr ['in' expr [',' expr]] */
-       com_node(c, CHILD(n, 1));
-       if (NCH(n) >= 4)
-               com_node(c, CHILD(n, 3));
-       else {
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-               com_push(c, 1);
-       }
-       if (NCH(n) >= 6)
-               com_node(c, CHILD(n, 5));
-       else {
-               com_addbyte(c, DUP_TOP);
-               com_push(c, 1);
-       }
-       com_addbyte(c, EXEC_STMT);
-       com_pop(c, 3);
-}
+               case SLICE+0:
+                       return 1;
+               case SLICE+1:
+                       return 0;
+               case SLICE+2:
+                       return 0;
+               case SLICE+3:
+                       return -1;
 
-static int
-is_constant_false(struct compiling *c, node *n)
-{
-       PyObject *v;
-       int i;
-       /* argument c will be NULL when called from symtable_node() */
+               case STORE_SLICE+0:
+                       return -2;
+               case STORE_SLICE+1:
+                       return -3;
+               case STORE_SLICE+2:
+                       return -3;
+               case STORE_SLICE+3:
+                       return -4;
 
-  /* Label to avoid tail recursion */
-  next:
-       switch (TYPE(n)) {
+               case DELETE_SLICE+0:
+                       return -1;
+               case DELETE_SLICE+1:
+                       return -2;
+               case DELETE_SLICE+2:
+                       return -2;
+               case DELETE_SLICE+3:
+                       return -3;
+
+               case INPLACE_ADD:
+               case INPLACE_SUBTRACT:
+               case INPLACE_MULTIPLY:
+               case INPLACE_DIVIDE:
+               case INPLACE_MODULO:
+                       return -1;
+               case STORE_SUBSCR:
+                       return -3;
+               case DELETE_SUBSCR:
+                       return -2;
 
-       case suite:
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto next;
-               }
-               /* Fall through */
-       case file_input:
-               for (i = 0; i < NCH(n); i++) {
-                       node *ch = CHILD(n, i);
-                       if (TYPE(ch) == stmt) {
-                               n = ch;
-                               goto next;
-                       }
-               }
-               break;
+               case BINARY_LSHIFT:
+               case BINARY_RSHIFT:
+               case BINARY_AND:
+               case BINARY_XOR:
+               case BINARY_OR:
+                       return -1;
+               case INPLACE_POWER:
+                       return -1;
+               case GET_ITER:
+                       return 0;
 
-       case stmt:
-       case simple_stmt:
-       case small_stmt:
-               n = CHILD(n, 0);
-               goto next;
-
-       case expr_stmt:
-       case testlist:
-       case testlist1:
-       case test:
-       case and_test:
-       case not_test:
-       case comparison:
-       case expr:
-       case xor_expr:
-       case and_expr:
-       case shift_expr:
-       case arith_expr:
-       case term:
-       case factor:
-       case power:
-       case atom:
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto next;
-               }
-               break;
+               case PRINT_EXPR:
+                       return -1;
+               case PRINT_ITEM:
+                       return -1;
+               case PRINT_NEWLINE:
+                       return 0;
+               case PRINT_ITEM_TO:
+                       return -2;
+               case PRINT_NEWLINE_TO:
+                       return -1;
+               case INPLACE_LSHIFT:
+               case INPLACE_RSHIFT:
+               case INPLACE_AND:
+               case INPLACE_XOR:
+               case INPLACE_OR:
+                       return -1;
+               case BREAK_LOOP:
+                       return 0;
 
-       case NAME:
-               if (Py_OptimizeFlag && strcmp(STR(n), "__debug__") == 0)
+               case LOAD_LOCALS:
                        return 1;
-               break;
-
-       case NUMBER:
-               v = parsenumber(c, STR(n));
-               if (v == NULL) {
-                       PyErr_Clear();
-                       break;
-               }
-               i = PyObject_IsTrue(v);
-               Py_DECREF(v);
-               return i == 0;
+               case RETURN_VALUE:
+                       return -1;
+               case IMPORT_STAR:
+                       return -1;
+               case EXEC_STMT:
+                       return -3;
+               case YIELD_VALUE:
+                       return 0;
 
-       case STRING:
-               v = parsestr(c, STR(n));
-               if (v == NULL) {
-                       PyErr_Clear();
-                       break;
-               }
-               i = PyObject_IsTrue(v);
-               Py_DECREF(v);
-               return i == 0;
+               case POP_BLOCK:
+                       return 0;
+               case END_FINALLY:
+                       return -1; /* or -2 or -3 if exception occurred */
+               case BUILD_CLASS:
+                       return -2;
 
-       }
-       return 0;
-}
+               case STORE_NAME:
+                       return -1;
+               case DELETE_NAME:
+                       return 0;
+               case UNPACK_SEQUENCE:
+                       return oparg-1;
+               case FOR_ITER:
+                       return 1;
 
+               case STORE_ATTR:
+                       return -2;
+               case DELETE_ATTR:
+                       return -1;
+               case STORE_GLOBAL:
+                       return -1;
+               case DELETE_GLOBAL:
+                       return 0;
+               case DUP_TOPX:
+                       return oparg;
+               case LOAD_CONST:
+                       return 1;
+               case LOAD_NAME:
+                       return 1;
+               case BUILD_TUPLE:
+               case BUILD_LIST:
+                       return 1-oparg;
+               case BUILD_MAP:
+                       return 1;
+               case LOAD_ATTR:
+                       return 0;
+               case COMPARE_OP:
+                       return -1;
+               case IMPORT_NAME:
+                       return 0;
+               case IMPORT_FROM:
+                       return 1;
 
-/* Look under n for a return stmt with an expression.
- * This hack is used to find illegal returns under "if 0:" blocks in
- * functions already known to be generators (as determined by the symtable
- * pass).
- * Return the offending return node if found, else NULL.
- */
-static node *
-look_for_offending_return(node *n)
-{
-       int i;
+               case JUMP_FORWARD:
+               case JUMP_IF_FALSE:
+               case JUMP_IF_TRUE:
+               case JUMP_ABSOLUTE:
+                       return 0;
 
-       for (i = 0; i < NCH(n); ++i) {
-               node *kid = CHILD(n, i);
+               case LOAD_GLOBAL:
+                       return 1;
 
-               switch (TYPE(kid)) {
-                       case classdef:
-                       case funcdef:
-                       case lambdef:
-                               /* Stuff in nested functions & classes doesn't
-                                  affect the code block we started in. */
-                               return NULL;
+               case CONTINUE_LOOP:
+                       return 0;
+               case SETUP_LOOP:
+                       return 0;
+               case SETUP_EXCEPT:
+               case SETUP_FINALLY:
+                       return 3; /* actually pushed by an exception */
 
-                       case return_stmt:
-                               if (NCH(kid) > 1)
-                                       return kid;
-                               break;
+               case LOAD_FAST:
+                       return 1;
+               case STORE_FAST:
+                       return -1;
+               case DELETE_FAST:
+                       return 0;
 
-                       default: {
-                               node *bad = look_for_offending_return(kid);
-                               if (bad != NULL)
-                                       return bad;
-                       }
-               }
-       }
+               case RAISE_VARARGS:
+                       return -oparg;
+#define NARGS(o) (((o) % 256) + 2*((o) / 256))
+               case CALL_FUNCTION:
+                       return -NARGS(oparg);
+               case CALL_FUNCTION_VAR:
+               case CALL_FUNCTION_KW:
+                       return -NARGS(oparg)-1;
+               case CALL_FUNCTION_VAR_KW:
+                       return -NARGS(oparg)-2;
+#undef NARGS
+               case MAKE_FUNCTION:
+                       return -oparg;
+               case BUILD_SLICE:
+                       if (oparg == 3)
+                               return -2;
+                       else
+                               return -1;
 
-       return NULL;
-}                      
+               case MAKE_CLOSURE:
+                       return -oparg;
+               case LOAD_CLOSURE:
+                       return 1;
+               case LOAD_DEREF:
+                       return 1;
+               case STORE_DEREF:
+                       return -1;
+               default:
+                       fprintf(stderr, "opcode = %d\n", opcode);
+                       Py_FatalError("opcode_stack_effect()");
 
-static void
-com_if_stmt(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;
-               node *ch = CHILD(n, i+1);
-               if (is_constant_false(c, ch)) {
-                       /* We're going to skip this block.  However, if this
-                          is a generator, we have to check the dead code
-                          anyway to make sure there aren't any return stmts
-                          with expressions, in the same scope. */
-                       if (c->c_flags & CO_GENERATOR) {
-                               node *p = look_for_offending_return(n);
-                               if (p != NULL) {
-                                       int savelineno = c->c_lineno;
-                                       c->c_lineno = p->n_lineno;
-                                       com_error(c, PyExc_SyntaxError,
-                                               "'return' with argument "
-                                               "inside generator");
-                                       c->c_lineno = savelineno;
-                               }
-                       }
-                       continue;
-               }
-               if (i > 0)
-                       com_set_lineno(c, ch->n_lineno);
-               com_node(c, ch);
-               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))
-               com_node(c, CHILD(n, i+2));
-       if (anchor)
-               com_backpatch(c, anchor);
-}
-
-static void
-com_while_stmt(struct compiling *c, node *n)
-{
-       int break_anchor = 0;
-       int anchor = 0;
-       int save_begin = c->c_begin;
-       REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */
-       com_addfwref(c, SETUP_LOOP, &break_anchor);
-       block_push(c, SETUP_LOOP);
-       c->c_begin = c->c_nexti;
-       com_set_lineno(c, n->n_lineno);
-       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);
-       if (NCH(n) > 4)
-               com_node(c, CHILD(n, 6));
-       com_backpatch(c, break_anchor);
-}
-
-static void
-com_for_stmt(struct compiling *c, node *n)
-{
-       int break_anchor = 0;
-       int anchor = 0;
-       int save_begin = c->c_begin;
-       REQ(n, for_stmt);
-       /* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */
-       com_addfwref(c, SETUP_LOOP, &break_anchor);
-       block_push(c, SETUP_LOOP);
-       com_node(c, CHILD(n, 3));
-       com_addbyte(c, GET_ITER);
-       c->c_begin = c->c_nexti;
-       com_set_lineno(c, c->c_last_line);
-       com_addfwref(c, FOR_ITER, &anchor);
-       com_push(c, 1);
-       com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
-       c->c_loops++;
-       com_node(c, CHILD(n, 5));
-       c->c_loops--;
-       com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
-       c->c_begin = save_begin;
-       com_backpatch(c, anchor);
-       com_pop(c, 1); /* FOR_ITER has popped this */
-       com_addbyte(c, POP_BLOCK);
-       block_pop(c, SETUP_LOOP);
-       if (NCH(n) > 8)
-               com_node(c, CHILD(n, 8));
-       com_backpatch(c, break_anchor);
+       return 0; /* not reachable */
 }
 
-/* Code generated for "try: S finally: Sf" is as follows:
-   
-               SETUP_FINALLY   L
-               <code for S>
-               POP_BLOCK
-               LOAD_CONST      <nil>
-       L:      <code for Sf>
-               END_FINALLY
-   
-   The special instructions use the block stack.  Each block
-   stack entry contains the instruction that created it (here
-   SETUP_FINALLY), the level of the value stack at the time the
-   block stack entry was created, and a label (here L).
-   
-   SETUP_FINALLY:
-       Pushes the current value stack level and the label
-       onto the block stack.
-   POP_BLOCK:
-       Pops en entry from the block stack, and pops the value
-       stack until its level is the same as indicated on the
-       block stack.  (The label is ignored.)
-   END_FINALLY:
-       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
-   onto the value stack (and the exception condition is cleared),
-   and the interpreter jumps to the label gotten from the block
-   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
-   []                          <code for S>
-   []                          POP_BLOCK
-   []                          JUMP_FORWARD    L0
-   
-   [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
-   
-   [tb, val, exc, 0]   L2:     POP
-   [tb, val, exc]              DUP
-   .............................etc.......................
-
-   [tb, val, exc, 0]   Ln+1:   POP
-   [tb, val, exc]              END_FINALLY     # re-raise exception
-   
-   []                  L0:     <next statement>
-   
-   Of course, parts are not generated if Vi or Ei is not present.
+/* Add an opcode with no argument.
+   Returns 0 on failure, 1 on success.
 */
 
-static void
-com_try_except(struct compiling *c, node *n)
-{
-       int except_anchor = 0;
-       int end_anchor = 0;
-       int else_anchor = 0;
-       int i;
-       node *ch;
-
-       com_addfwref(c, SETUP_EXCEPT, &except_anchor);
-       block_push(c, SETUP_EXCEPT);
-       com_node(c, CHILD(n, 2));
-       com_addbyte(c, POP_BLOCK);
-       block_pop(c, SETUP_EXCEPT);
-       com_addfwref(c, JUMP_FORWARD, &else_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 [',' var]] */
-               if (except_anchor == 0) {
-                       com_error(c, PyExc_SyntaxError,
-                                 "default 'except:' must be last");
-                       break;
-               }
-               except_anchor = 0;
-               com_push(c, 3); /* tb, val, exc pushed by exception */
-               com_set_lineno(c, 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, PyCmp_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, NULL);
-               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))
-               com_node(c, CHILD(n, i+2));
-       com_backpatch(c, end_anchor);
-}
-
-static void
-com_try_finally(struct compiling *c, node *n)
-{
-       int finally_anchor = 0;
-       node *ch;
-
-       com_addfwref(c, SETUP_FINALLY, &finally_anchor);
-       block_push(c, SETUP_FINALLY);
-       com_node(c, CHILD(n, 2));
-       com_addbyte(c, POP_BLOCK);
-       block_pop(c, SETUP_FINALLY);
-       block_push(c, END_FINALLY);
-       com_addoparg(c, LOAD_CONST, com_addconst(c, Py_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_set_lineno(c, 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
-com_try_stmt(struct compiling *c, node *n)
-{
-       REQ(n, try_stmt);
-       /* 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
-        | 'try' ':' suite 'finally' ':' suite */
-       if (TYPE(CHILD(n, 3)) != except_clause)
-               com_try_finally(c, n);
-       else
-               com_try_except(c, n);
-}
-
-static node *
-get_rawdocstring(node *n)
-{
-       int i;
-
-  /* Label to avoid tail recursion */
-  next:
-       switch (TYPE(n)) {
-
-       case suite:
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto next;
-               }
-               /* Fall through */
-       case file_input:
-               for (i = 0; i < NCH(n); i++) {
-                       node *ch = CHILD(n, i);
-                       if (TYPE(ch) == stmt) {
-                               n = ch;
-                               goto next;
-                       }
-               }
-               break;
-
-       case stmt:
-       case simple_stmt:
-       case small_stmt:
-               n = CHILD(n, 0);
-               goto next;
-
-       case expr_stmt:
-       case testlist:
-       case testlist1:
-       case test:
-       case and_test:
-       case not_test:
-       case comparison:
-       case expr:
-       case xor_expr:
-       case and_expr:
-       case shift_expr:
-       case arith_expr:
-       case term:
-       case factor:
-       case power:
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto next;
-               }
-               break;
-
-       case atom:
-               if (TYPE(CHILD(n, 0)) == STRING)
-                       return n;
-               break;
-
-       }
-       return NULL;
-}
-
-static PyObject *
-get_docstring(struct compiling *c, node *n)
-{
-       /* Don't generate doc-strings if run with -OO */
-       if (Py_OptimizeFlag > 1)
-               return NULL;
-       n = get_rawdocstring(n);
-       if (n == NULL)
-               return NULL;
-       return parsestrplus(c, n);
-}
-
-static void
-com_suite(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) && c->c_errors == 0; i++) {
-                       node *ch = CHILD(n, i);
-                       if (TYPE(ch) == stmt)
-                               com_node(c, ch);
-               }
-       }
+static int
+compiler_addop(struct compiler *c, int opcode)
+{
+       basicblock *b;
+       struct instr *i;
+       int off;
+       off = compiler_next_instr(c, c->u->u_curblock);
+       if (off < 0)
+               return 0;
+       b = c->u->u_curblock;
+       i = &b->b_instr[off];
+       i->i_opcode = opcode;
+       i->i_hasarg = 0;
+       if (opcode == RETURN_VALUE)
+               b->b_return = 1;
+       compiler_set_lineno(c, off);
+       return 1;
 }
 
-/* ARGSUSED */
-static void
-com_continue_stmt(struct compiling *c, node *n)
-{
-       int i = c->c_nblocks;
-       if (i-- > 0 && c->c_block[i] == SETUP_LOOP) {
-               com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
-       }
-       else if (i <= 0) {
-               /* at the outer level */
-               com_error(c, PyExc_SyntaxError,
-                         "'continue' not properly in loop");
-       }
-       else {
-               int j;
-               for (j = i-1; j >= 0; --j) {
-                       if (c->c_block[j] == SETUP_LOOP)
-                               break;
-               }
-               if (j >= 0) {
-                       /* there is a loop, but something interferes */
-                       for (; i > j; --i) {
-                               if (c->c_block[i] == SETUP_EXCEPT ||
-                                   c->c_block[i] == SETUP_FINALLY) {
-                                       com_addoparg(c, CONTINUE_LOOP,
-                                                    c->c_begin);
-                                       return;
-                               }
-                               if (c->c_block[i] == END_FINALLY) {
-                                       com_error(c, PyExc_SyntaxError,
-                         "'continue' not supported inside 'finally' clause");
-                                       return;
-                               }
-                       }
+static int
+compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
+{
+       PyObject *t, *v;
+       int arg;
+
+        /* necessary to make sure types aren't coerced (e.g., int and long) */
+        /* XXX should use: t = PyTuple_Pack(2, o, o->ob_type); */
+        t = Py_BuildValue("(OO)", o, o->ob_type);
+        if (t == NULL)
+            return -1;
+
+       v = PyDict_GetItem(dict, t);
+       if (!v) {
+               arg = PyDict_Size(dict);
+               v = PyInt_FromLong(arg);
+               if (!v) {
+                       Py_DECREF(t);
+                       return -1;
+                }
+               if (PyDict_SetItem(dict, t, v) < 0) {
+                       Py_DECREF(t);
+                       Py_DECREF(v);
+                       return -1;
                }
-               com_error(c, PyExc_SyntaxError,
-                         "'continue' not properly in loop");
+               Py_DECREF(v);
        }
-       /* XXX Could allow it inside a 'finally' clause
-          XXX if we could pop the exception still on the stack */
+       else
+               arg = PyInt_AsLong(v);
+       Py_DECREF(t);
+        return arg;
 }
 
-/* Return the number of default values in the argument list.
+static int
+compiler_addop_o(struct compiler *c, int opcode, PyObject *dict,
+                    PyObject *o)
+{
+    int arg = compiler_add_o(c, dict, o);
+    if (arg < 0)
+        return 0;
+    return compiler_addop_i(c, opcode, arg);
+}
 
-   If a non-default argument follows a default argument, set an
-   exception and return -1.
+static int
+compiler_addop_name(struct compiler *c, int opcode, PyObject *dict,
+                    PyObject *o)
+{
+    int arg;
+    PyObject *mangled = _Py_Mangle(c->u->u_private, o);
+    if (!mangled)
+        return 0;
+    arg = compiler_add_o(c, dict, mangled);
+    Py_DECREF(mangled);
+    if (arg < 0)
+        return 0;
+    return compiler_addop_i(c, opcode, arg);
+}
+
+/* Add an opcode with an integer argument.
+   Returns 0 on failure, 1 on success.
 */
 
 static int
-com_argdefs(struct compiling *c, node *n)
+compiler_addop_i(struct compiler *c, int opcode, int oparg)
 {
-       int i, nch, ndefs;
-       if (TYPE(n) == lambdef) {
-               /* lambdef: 'lambda' [varargslist] ':' test */
-               n = CHILD(n, 1);
-       }
-       else {
-               REQ(n, funcdef);
-               /* funcdef: [decorators] 'def' NAME parameters ':' suite */
-               n = RCHILD(n, -3);
-               REQ(n, parameters); /* parameters: '(' [varargslist] ')' */
-               n = CHILD(n, 1);
-       }
-       if (TYPE(n) != varargslist)
-                   return 0;
-       /* varargslist:
-               (fpdef ['=' test] ',')* '*' ....... |
-               fpdef ['=' test] (',' fpdef ['=' test])* [','] */
-       nch = NCH(n);
-       ndefs = 0;
-       for (i = 0; i < nch; i++) {
-               int t;
-               if (TYPE(CHILD(n, i)) == STAR ||
-                   TYPE(CHILD(n, i)) == DOUBLESTAR)
-                       break;
-               i++;
-               if (i >= nch)
-                       t = RPAR; /* Anything except EQUAL or COMMA */
-               else
-                       t = TYPE(CHILD(n, i));
-               if (t == EQUAL) {
-                       i++;
-                       ndefs++;
-                       com_node(c, CHILD(n, i));
-                       i++;
-                       if (i >= nch)
-                               break;
-                       t = TYPE(CHILD(n, i));
-               }
-               else {
-                       /* Treat "(a=1, b)" as an error */
-                       if (ndefs) {
-                               com_error(c, PyExc_SyntaxError,
-                           "non-default argument follows default argument");
-                               return -1;
-                       }
-               }
-               if (t != COMMA)
-                       break;
-       }
-       return ndefs;
+       struct instr *i;
+       int off;
+       off = compiler_next_instr(c, c->u->u_curblock);
+       if (off < 0)
+               return 0;
+       i = &c->u->u_curblock->b_instr[off];
+       i->i_opcode = opcode;
+       i->i_oparg = oparg;
+       i->i_hasarg = 1;
+       compiler_set_lineno(c, off);
+       return 1;
 }
 
-static void
-com_decorator_name(struct compiling *c, node *n)
+static int
+compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
 {
-       /* dotted_name: NAME ('.' NAME)* */
-       
-       int i, nch;
-       node *varname;
+       struct instr *i;
+       int off;
 
-       REQ(n, dotted_name);
-       nch = NCH(n);
-       assert(nch >= 1 && nch % 2 == 1);
+       assert(b != NULL);
+       off = compiler_next_instr(c, c->u->u_curblock);
+       if (off < 0)
+               return 0;
+       compiler_set_lineno(c, off);
+       i = &c->u->u_curblock->b_instr[off];
+       i->i_opcode = opcode;
+       i->i_target = b;
+       i->i_hasarg = 1;
+       if (absolute)
+               i->i_jabs = 1;
+       else
+               i->i_jrel = 1;
+       return 1;
+}
 
-       varname = CHILD(n, 0);
-       REQ(varname, NAME);
-       com_addop_varname(c, VAR_LOAD, STR(varname));
-       com_push(c, 1);
-               
-       for (i = 1; i < nch; i += 2) {
-               node *attrname;
-               
-               REQ(CHILD(n, i), DOT);
+/* The distinction between NEW_BLOCK and NEXT_BLOCK is subtle.  (I'd
+   like to find better names.)  NEW_BLOCK() creates a new block and sets
+   it as the current block.  NEXT_BLOCK() also creates an implicit jump
+   from the current block to the new block.
+*/
 
-               attrname = CHILD(n, i + 1);
-               REQ(attrname, NAME);
-               com_addop_name(c, LOAD_ATTR, STR(attrname));
-       }
+/* XXX The returns inside these macros make it impossible to decref
+   objects created in the local function.
+*/
+
+
+#define NEW_BLOCK(C) { \
+        if (compiler_use_new_block((C)) == NULL) \
+               return 0; \
 }
 
-static void
-com_decorator(struct compiling *c, node *n)
-{
-       /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */
-       int nch = NCH(n);
-       assert(nch >= 3);
-       REQ(CHILD(n, 0), AT);
-       REQ(RCHILD(n, -1), NEWLINE);
-       com_decorator_name(c, CHILD(n, 1));
-
-       if (nch > 3) {
-               assert(nch == 5 || nch == 6);
-               REQ(CHILD(n, 2), LPAR);
-               REQ(RCHILD(n, -2), RPAR);
-               com_call_function(c, CHILD(n, 3));
-       }
+#define NEXT_BLOCK(C) { \
+        if (compiler_next_block((C)) == NULL) \
+               return 0; \
 }
 
-static int
-com_decorators(struct compiling *c, node *n)
-{
-       int i, nch;
-       
-       /* decorator+ */
-       nch = NCH(n);
-       assert(nch >= 1);
+#define ADDOP(C, OP) { \
+       if (!compiler_addop((C), (OP))) \
+               return 0; \
+}
 
-       for (i = 0; i < nch; ++i) {
-               node *ch = CHILD(n, i);
-               REQ(ch, decorator);
+#define ADDOP_O(C, OP, O, TYPE) { \
+       if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) \
+               return 0; \
+}
 
-               com_decorator(c, ch);
-       }
+#define ADDOP_NAME(C, OP, O, TYPE) { \
+       if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \
+               return 0; \
+}
 
-       return nch;
+#define ADDOP_I(C, OP, O) { \
+       if (!compiler_addop_i((C), (OP), (O))) \
+               return 0; \
 }
 
-static void
-com_funcdef(struct compiling *c, node *n)
-{
-       PyObject *co;
-       int ndefs, ndecorators;
-       
-       REQ(n, funcdef);
-       /*          -6            -5   -4   -3         -2  -1
-          funcdef: [decorators] 'def' NAME parameters ':' suite */
+#define ADDOP_JABS(C, OP, O) { \
+       if (!compiler_addop_j((C), (OP), (O), 1)) \
+               return 0; \
+}
 
-       if (NCH(n) == 6)
-               ndecorators = com_decorators(c, CHILD(n, 0));
-       else
-               ndecorators = 0;
+#define ADDOP_JREL(C, OP, O) { \
+       if (!compiler_addop_j((C), (OP), (O), 0)) \
+               return 0; \
+}
 
-       ndefs = com_argdefs(c, n);
-       if (ndefs < 0)
-               return;
-       symtable_enter_scope(c->c_symtable, STR(RCHILD(n, -4)), TYPE(n),
-                            n->n_lineno);
-       co = (PyObject *)icompile(n, c);
-       symtable_exit_scope(c->c_symtable);
-       if (co == NULL)
-               c->c_errors++;
-       else {
-               int closure = com_make_closure(c, (PyCodeObject *)co);
-               int i = com_addconst(c, co);
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               if (closure)
-                       com_addoparg(c, MAKE_CLOSURE, ndefs);
-               else
-                       com_addoparg(c, MAKE_FUNCTION, ndefs);
-               com_pop(c, ndefs);
+/* VISIT and VISIT_SEQ takes an ASDL type as their second argument.  They use
+   the ASDL name to synthesize the name of the C type and the visit function.
+*/
 
-               while (ndecorators > 0) {
-                       com_addoparg(c, CALL_FUNCTION, 1);
-                       com_pop(c, 1);
-                       --ndecorators;
-               }
+#define VISIT(C, TYPE, V) {\
+       if (!compiler_visit_ ## TYPE((C), (V))) \
+               return 0; \
+}
 
-               com_addop_varname(c, VAR_STORE, STR(RCHILD(n, -4)));
-               com_pop(c, 1);
-               Py_DECREF(co);
-       }
+#define VISIT_SLICE(C, V, CTX) {\
+       if (!compiler_visit_slice((C), (V), (CTX))) \
+               return 0; \
 }
 
-static void
-com_bases(struct compiling *c, node *n)
+#define VISIT_SEQ(C, TYPE, SEQ) { \
+       int i; \
+       asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+       for (i = 0; i < asdl_seq_LEN(seq); i++) { \
+               TYPE ## _ty elt = asdl_seq_GET(seq, i); \
+               if (!compiler_visit_ ## TYPE((C), elt)) \
+                       return 0; \
+       } \
+}
+
+static int
+compiler_isdocstring(stmt_ty s)
 {
-       int i;
-       REQ(n, testlist);
-       /* testlist: test (',' test)* [','] */
-       for (i = 0; i < NCH(n); i += 2)
-               com_node(c, CHILD(n, i));
-       i = (NCH(n)+1) / 2;
-       com_addoparg(c, BUILD_TUPLE, i);
-       com_pop(c, i-1);
+    if (s->kind != Expr_kind)
+        return 0;
+    return s->v.Expr.value->kind == Str_kind;
 }
 
-static void
-com_classdef(struct compiling *c, node *n)
+/* Compile a sequence of statements, checking for a docstring. */
+
+static int
+compiler_body(struct compiler *c, asdl_seq *stmts)
 {
-       int i;
-       PyObject *v;
-       PyCodeObject *co;
-       char *name;
+       int i = 0;
+       stmt_ty st;
 
-       REQ(n, classdef);
-       /* classdef: class NAME ['(' [testlist] ')'] ':' suite */
-       if ((v = PyString_InternFromString(STR(CHILD(n, 1)))) == NULL) {
-               c->c_errors++;
-               return;
-       }
-       /* Push the class name on the stack */
-       i = com_addconst(c, v);
-       com_addoparg(c, LOAD_CONST, i);
-       com_push(c, 1);
-       Py_DECREF(v);
-       /* Push the tuple of base classes on the stack */
-       if (TYPE(CHILD(n, 2)) != LPAR ||
-                       TYPE(CHILD(n, 3)) == RPAR) {
-               com_addoparg(c, BUILD_TUPLE, 0);
-               com_push(c, 1);
-       }
-       else
-               com_bases(c, CHILD(n, 3));
-       name = STR(CHILD(n, 1));
-       symtable_enter_scope(c->c_symtable, name, TYPE(n), n->n_lineno);
-       co = icompile(n, c);
-       symtable_exit_scope(c->c_symtable);
-       if (co == NULL)
-               c->c_errors++;
-       else {
-               int closure = com_make_closure(c, co);
-               i = com_addconst(c, (PyObject *)co);
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               if (closure) {
-                       com_addoparg(c, MAKE_CLOSURE, 0);
-                       com_pop(c, PyCode_GetNumFree(co));
-               } else
-                       com_addoparg(c, MAKE_FUNCTION, 0);
-               com_addoparg(c, CALL_FUNCTION, 0);
-               com_addbyte(c, BUILD_CLASS);
-               com_pop(c, 2);
-               com_addop_varname(c, VAR_STORE, STR(CHILD(n, 1)));
-               com_pop(c, 1);
-               Py_DECREF(co);
+       if (!asdl_seq_LEN(stmts))
+               return 1;
+       st = asdl_seq_GET(stmts, 0);
+       if (compiler_isdocstring(st)) {
+               i = 1;
+               VISIT(c, expr, st->v.Expr.value);
+               if (!compiler_nameop(c, __doc__, Store))
+                       return 0;
        }
+        for (; i < asdl_seq_LEN(stmts); i++)
+            VISIT(c, stmt, asdl_seq_GET(stmts, i));
+       return 1;
 }
 
-static void
-com_node(struct compiling *c, node *n)
+static PyCodeObject *
+compiler_mod(struct compiler *c, mod_ty mod)
 {
- loop:
-       if (c->c_errors)
-               return;
-       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 small_stmt:
-       case flow_stmt:
-               n = CHILD(n, 0);
-               goto loop;
-
-       case simple_stmt:
-               /* small_stmt (';' small_stmt)* [';'] NEWLINE */
-               com_set_lineno(c, n->n_lineno);
-               {
-                       int i;
-                       for (i = 0; i < NCH(n)-1; i += 2)
-                               com_node(c, CHILD(n, i));
-               }
-               break;
-       
-       case compound_stmt:
-               com_set_lineno(c, n->n_lineno);
-               n = CHILD(n, 0);
-               goto loop;
-
-       /* 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 */
-               com_assign(c, CHILD(n, 1), OP_DELETE, NULL);
-               break;
-       case pass_stmt:
-               break;
-       case break_stmt:
-               if (c->c_loops == 0) {
-                       com_error(c, PyExc_SyntaxError,
-                                 "'break' outside loop");
-               }
-               com_addbyte(c, BREAK_LOOP);
-               break;
-       case continue_stmt:
-               com_continue_stmt(c, n);
-               break;
-       case return_stmt:
-               com_return_stmt(c, n);
-               break;
-       case yield_stmt:
-               com_yield_stmt(c, n);
-               break;
-       case raise_stmt:
-               com_raise_stmt(c, n);
-               break;
-       case import_stmt:
-               com_import_stmt(c, n);
-               break;
-       case global_stmt:
-               break;
-       case exec_stmt:
-               com_exec_stmt(c, n);
-               break;
-       case assert_stmt:
-               com_assert_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 yield_expr:
-               com_yield_expr(c, n);
-               break;
-
-       case testlist:
-       case testlist1:
-       case testlist_safe:
-               com_list(c, n, 0);
-               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, 0);
-               break;
-       case expr:
-               com_expr(c, n);
-               break;
-       case xor_expr:
-               com_xor_expr(c, n);
-               break;
-       case and_expr:
-               com_and_expr(c, n);
-               break;
-       case shift_expr:
-               com_shift_expr(c, n);
-               break;
-       case arith_expr:
-               com_arith_expr(c, n);
-               break;
-       case term:
-               com_term(c, n);
+       PyCodeObject *co;
+        int addNone = 1;
+       static PyObject *module;
+       if (!module) {
+               module = PyString_FromString("<module>");
+               if (!module)
+                       return NULL;
+       }
+       if (!compiler_enter_scope(c, module, mod, 1))
+               return NULL;
+       switch (mod->kind) {
+       case Module_kind: 
+               if (!compiler_body(c, mod->v.Module.body))
+                       return 0;
                break;
-       case factor:
-               com_factor(c, n);
+       case Interactive_kind:
+               c->c_interactive = 1;
+               VISIT_SEQ(c, stmt, mod->v.Interactive.body);
                break;
-       case power:
-               com_power(c, n);
+       case Expression_kind:
+               VISIT(c, expr, mod->v.Expression.body);
+                addNone = 0;
                break;
-       case atom:
-               com_atom(c, n);
+       case Suite_kind:
+               assert(0);      /* XXX: what should we do here? */
+               VISIT_SEQ(c, stmt, mod->v.Suite.body);
                break;
-       
-       default:
-               com_error(c, PyExc_SystemError,
-                         "com_node: unexpected node type");
+        default:
+            assert(0);
        }
+       co = assemble(c, addNone);
+       compiler_exit_scope(c);
+       return co;
 }
 
-static void com_fplist(struct compiling *, node *);
+/* The test for LOCAL must come before the test for FREE in order to
+   handle classes where name is both local and free.  The local var is
+   a method and the free var is a free var referenced within a method.
+*/
 
-static void
-com_fpdef(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_addop_varname(c, VAR_STORE, STR(CHILD(n, 0)));
-               com_pop(c, 1);
-       }
+static int
+get_ref_type(struct compiler *c, PyObject *name)
+{
+       int scope = PyST_GetScope(c->u->u_ste, name);
+        if (scope == 0) {
+            char buf[350];
+            PyOS_snprintf(buf, sizeof(buf),
+                          "unknown scope for %.100s in %.100s(%s) in %s\n"
+                          "symbols: %s\nlocals: %s\nglobals: %s\n",
+                          PyString_AS_STRING(name), 
+                          PyString_AS_STRING(c->u->u_name), 
+                          PyObject_REPR(c->u->u_ste->ste_id),
+                          c->c_filename,
+                          PyObject_REPR(c->u->u_ste->ste_symbols),
+                          PyObject_REPR(c->u->u_varnames),
+                          PyObject_REPR(c->u->u_names)
+               );
+            Py_FatalError(buf);
+        }
+
+        return scope;
 }
 
-static void
-com_fplist(struct compiling *c, node *n)
+static int
+compiler_lookup_arg(PyObject *dict, PyObject *name)
 {
-       REQ(n, fplist); /* fplist: fpdef (',' fpdef)* [','] */
-       if (NCH(n) == 1) {
-               com_fpdef(c, CHILD(n, 0));
-       }
-       else {
-               int i = (NCH(n)+1)/2;
-               com_addoparg(c, UNPACK_SEQUENCE, i);
-               com_push(c, i-1);
-               for (i = 0; i < NCH(n); i += 2)
-                       com_fpdef(c, CHILD(n, i));
-       }
+    PyObject *k, *v;
+    k = Py_BuildValue("(OO)", name, name->ob_type);
+    if (k == NULL)
+        return -1;
+    v = PyDict_GetItem(dict, k);
+    if (v == NULL)
+        return -1;
+    return PyInt_AS_LONG(v);
 }
 
-static void
-com_arglist(struct compiling *c, node *n)
+static int
+compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
 {
-       int nch, i, narg;
-       int complex = 0;
-       char nbuf[30];
-       REQ(n, varargslist);
-       /* varargslist:
-               (fpdef ['=' test] ',')* (fpdef ['=' test] | '*' .....) */
-       nch = NCH(n);
-       /* Enter all arguments in table of locals */
-       for (i = 0, narg = 0; i < nch; i++) {
-               node *ch = CHILD(n, i);
-               node *fp;
-               if (TYPE(ch) == STAR || TYPE(ch) == DOUBLESTAR)
-                       break;
-               REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
-               fp = CHILD(ch, 0);
-               if (TYPE(fp) != NAME) {
-                       PyOS_snprintf(nbuf, sizeof(nbuf), ".%d", i);
-                       complex = 1;
-               }
-               narg++;
-               /* all name updates handled by symtable */
-               if (++i >= nch)
-                       break;
-               ch = CHILD(n, i);
-               if (TYPE(ch) == EQUAL)
-                       i += 2;
-               else
-                       REQ(ch, COMMA);
-       }
-       if (complex) {
-               /* Generate code for complex arguments only after
-                  having counted the simple arguments */
-               int ilocal = 0;
-               for (i = 0; i < nch; i++) {
-                       node *ch = CHILD(n, i);
-                       node *fp;
-                       if (TYPE(ch) == STAR || TYPE(ch) == DOUBLESTAR)
-                               break;
-                       REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
-                       fp = CHILD(ch, 0);
-                       if (TYPE(fp) != NAME) {
-                               com_addoparg(c, LOAD_FAST, ilocal);
-                               com_push(c, 1);
-                               com_fpdef(c, ch);
-                       }
-                       ilocal++;
-                       if (++i >= nch)
-                               break;
-                       ch = CHILD(n, i);
-                       if (TYPE(ch) == EQUAL)
-                               i += 2;
-                       else
-                               REQ(ch, COMMA);
+       int i, free = PyCode_GetNumFree(co);
+       if (free == 0) {
+            ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+            ADDOP_I(c, MAKE_FUNCTION, args);
+            return 1;
+        }
+       for (i = 0; i < free; ++i) {
+               /* Bypass com_addop_varname because it will generate
+                  LOAD_DEREF but LOAD_CLOSURE is needed. 
+               */
+               PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
+               int arg, reftype;
+
+               /* Special case: If a class contains a method with a
+                  free variable that has the same name as a method,
+                  the name will be considered free *and* local in the
+                  class.  It should be handled by the closure, as
+                  well as by the normal name loookup logic.
+               */
+               reftype = get_ref_type(c, name);
+               if (reftype == CELL)
+                       arg = compiler_lookup_arg(c->u->u_cellvars, name);
+               else /* (reftype == FREE) */
+                       arg = compiler_lookup_arg(c->u->u_freevars, name);
+               if (arg == -1) {
+                       printf("lookup %s in %s %d %d\n"
+                               "freevars of %s: %s\n",
+                               PyObject_REPR(name), 
+                               PyString_AS_STRING(c->u->u_name), 
+                               reftype, arg,
+                               PyString_AS_STRING(co->co_name),
+                               PyObject_REPR(co->co_freevars));
+                       Py_FatalError("compiler_make_closure()");
                }
+               ADDOP_I(c, LOAD_CLOSURE, arg);
        }
+        ADDOP_I(c, BUILD_TUPLE, free);
+       ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+        ADDOP_I(c, MAKE_CLOSURE, args);
+        return 1;
 }
 
-static void
-com_file_input(struct compiling *c, node *n)
+static int
+compiler_decorators(struct compiler *c, asdl_seq* decos)
 {
        int i;
-       PyObject *doc;
-       REQ(n, file_input); /* (NEWLINE | stmt)* ENDMARKER */
-       doc = get_docstring(c, n);
-       if (doc != NULL) {
-               int i = com_addconst(c, doc);
-               Py_DECREF(doc);
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               com_addop_name(c, STORE_NAME, "__doc__");
-               com_pop(c, 1);
-       }
-       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 */
+       if (!decos)
+               return 1;
 
-static void
-compile_funcdef(struct compiling *c, node *n)
-{
-       PyObject *doc;
-       node *ch;
-       REQ(n, funcdef);
-       /*          -6            -5   -4   -3         -2  -1
-          funcdef: [decorators] 'def' NAME parameters ':' suite */
-       c->c_name = STR(RCHILD(n, -4));
-       doc = get_docstring(c, RCHILD(n, -1));
-       if (doc != NULL) {
-               (void) com_addconst(c, doc);
-               Py_DECREF(doc);
+       for (i = 0; i < asdl_seq_LEN(decos); i++) {
+               VISIT(c, expr, asdl_seq_GET(decos, i));
        }
-       else
-               (void) com_addconst(c, Py_None); /* No docstring */
-       ch = RCHILD(n, -3); /* parameters: '(' [varargslist] ')' */
-       ch = CHILD(ch, 1); /* ')' | varargslist */
-       if (TYPE(ch) == varargslist)
-               com_arglist(c, ch);
-       c->c_infunction = 1;
-       com_node(c, RCHILD(n, -1));
-       c->c_infunction = 0;
-       com_strip_lnotab(c);
-       com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-       com_push(c, 1);
-       com_addbyte(c, RETURN_VALUE);
-       com_pop(c, 1);
+       return 1;
 }
 
-static void
-compile_lambdef(struct compiling *c, node *n)
+static int
+compiler_arguments(struct compiler *c, arguments_ty args)
 {
-       node *ch;
-       REQ(n, lambdef); /* lambdef: 'lambda' [varargslist] ':' test */
-       c->c_name = "<lambda>";
-
-       ch = CHILD(n, 1);
-       (void) com_addconst(c, Py_None); /* No docstring */
-       if (TYPE(ch) == varargslist) {
-               com_arglist(c, ch);
-               ch = CHILD(n, 3);
+       int i;
+       int n = asdl_seq_LEN(args->args);
+       /* Correctly handle nested argument lists */
+       for (i = 0; i < n; i++) {
+               expr_ty arg = asdl_seq_GET(args->args, i);
+               if (arg->kind == Tuple_kind) {
+                       PyObject *id = PyString_FromFormat(".%d", i);
+                       if (id == NULL) {
+                               return 0;
+                       }
+                       if (!compiler_nameop(c, id, Load)) {
+                               Py_DECREF(id);
+                               return 0;
+                       }
+                       Py_DECREF(id);
+                       VISIT(c, expr, arg);
+               }
        }
-       else
-               ch = CHILD(n, 2);
-       com_node(c, ch);
-       com_addbyte(c, RETURN_VALUE);
-       com_pop(c, 1);
+       return 1;
 }
 
-static void
-compile_classdef(struct compiling *c, node *n)
+static int
+compiler_function(struct compiler *c, stmt_ty s)
 {
-       node *ch;
-       PyObject *doc;
-       REQ(n, classdef);
-       /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
-       c->c_name = STR(CHILD(n, 1));
-       c->c_private = c->c_name;
-       /* Initialize local __module__ from global __name__ */
-       com_addop_name(c, LOAD_GLOBAL, "__name__");
-       com_addop_name(c, STORE_NAME, "__module__");
-       ch = CHILD(n, NCH(n)-1); /* The suite */
-       doc = get_docstring(c, ch);
-       if (doc != NULL) {
-               int i = com_addconst(c, doc);
-               Py_DECREF(doc);
-               com_addoparg(c, LOAD_CONST, i);
-               com_push(c, 1);
-               com_addop_name(c, STORE_NAME, "__doc__");
-               com_pop(c, 1);
+       PyCodeObject *co;
+        PyObject *first_const = Py_None;
+       arguments_ty args = s->v.FunctionDef.args;
+       asdl_seq* decos = s->v.FunctionDef.decorators;
+        stmt_ty st;
+       int i, n, docstring;
+
+       assert(s->kind == FunctionDef_kind);
+
+       if (!compiler_decorators(c, decos))
+               return 0;
+       if (args->defaults)
+               VISIT_SEQ(c, expr, args->defaults);
+       if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s,
+                                 s->lineno))
+               return 0;
+
+        st = asdl_seq_GET(s->v.FunctionDef.body, 0);
+        docstring = compiler_isdocstring(st);
+        if (docstring)
+            first_const = st->v.Expr.value->v.Str.s;
+        if (compiler_add_o(c, c->u->u_consts, first_const) < 0)
+            return 0;
+
+        /* unpack nested arguments */
+       compiler_arguments(c, args);
+
+       c->u->u_argcount = asdl_seq_LEN(args->args);
+       n = asdl_seq_LEN(s->v.FunctionDef.body);
+        /* if there was a docstring, we need to skip the first statement */
+       for (i = docstring; i < n; i++) {
+               stmt_ty s2 = asdl_seq_GET(s->v.FunctionDef.body, i);
+               if (i == 0 && s2->kind == Expr_kind &&
+                   s2->v.Expr.value->kind == Str_kind)
+                       continue;
+               VISIT(c, stmt, s2);
        }
-       else
-               (void) com_addconst(c, Py_None);
-       com_node(c, ch);
-       com_strip_lnotab(c);
-       com_addbyte(c, LOAD_LOCALS);
-       com_push(c, 1);
-       com_addbyte(c, RETURN_VALUE);
-       com_pop(c, 1);
-}
+       co = assemble(c, 1);
+       if (co == NULL)
+               return 0;
+       compiler_exit_scope(c);
 
-static void
-compile_generator_expression(struct compiling *c, node *n)
-{
-       /* testlist_gexp: test gen_for */
-       /* argument: test gen_for */
-       REQ(CHILD(n, 0), test); 
-       REQ(CHILD(n, 1), gen_for); 
-
-       c->c_name = "<generator expression>";
-       c->c_infunction = 1;
-       com_gen_for(c, CHILD(n, 1), CHILD(n, 0), 1);
-       c->c_infunction = 0;
-
-       com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
-       com_push(c, 1);
-       com_addbyte(c, RETURN_VALUE);
-       com_pop(c, 1);
+        compiler_make_closure(c, co, asdl_seq_LEN(args->defaults));
+
+       for (i = 0; i < asdl_seq_LEN(decos); i++) {
+               ADDOP_I(c, CALL_FUNCTION, 1);
+       }
+
+       return compiler_nameop(c, s->v.FunctionDef.name, Store);
 }
 
-static void
-compile_node(struct compiling *c, node *n)
+static int
+compiler_class(struct compiler *c, stmt_ty s)
 {
-       com_set_lineno(c, n->n_lineno);
-       
-       switch (TYPE(n)) {
-       
-       case single_input: /* One interactive command */
-               /* NEWLINE | simple_stmt | compound_stmt NEWLINE */
-               c->c_interactive++;
-               n = CHILD(n, 0);
-               if (TYPE(n) != NEWLINE)
-                       com_node(c, n);
-               com_strip_lnotab(c);
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_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_strip_lnotab(c);
-               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_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 */
-               compile_lambdef(c, n);
-               break;
+       int n;
+       PyCodeObject *co;
+        PyObject *str;
+       /* push class name on stack, needed by BUILD_CLASS */
+       ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts);
+       /* push the tuple of base classes on the stack */
+       n = asdl_seq_LEN(s->v.ClassDef.bases);
+       if (n > 0)
+               VISIT_SEQ(c, expr, s->v.ClassDef.bases);
+       ADDOP_I(c, BUILD_TUPLE, n);
+       if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s,
+                                 s->lineno))
+               return 0;
+        c->u->u_private = s->v.ClassDef.name;
+        Py_INCREF(c->u->u_private);
+        str = PyString_InternFromString("__name__");
+       if (!str || !compiler_nameop(c, str, Load)) {
+               Py_XDECREF(str);
+               return 0;
+        }
+        
+        Py_DECREF(str);
+        str = PyString_InternFromString("__module__");
+       if (!str || !compiler_nameop(c, str, Store)) {
+               Py_XDECREF(str);
+               return 0;
+        }
+        Py_DECREF(str);
+
+       if (!compiler_body(c, s->v.ClassDef.body))
+               return 0;
 
-       case funcdef: /* A function definition */
-               compile_funcdef(c, n);
-               break;
-       
-       case classdef: /* A class definition */
-               compile_classdef(c, n);
-               break;
-       
-       case testlist_gexp: /* A generator expression */
-       case argument:      /* A generator expression */
-               compile_generator_expression(c, n);
-               break;
+       ADDOP(c, LOAD_LOCALS);
+       ADDOP(c, RETURN_VALUE);
+       co = assemble(c, 1);
+       if (co == NULL)
+               return 0;
+       compiler_exit_scope(c);
 
-       default:
-               com_error(c, PyExc_SystemError,
-                         "compile_node: unexpected node type");
-       }
+        compiler_make_closure(c, co, 0);
+       ADDOP_I(c, CALL_FUNCTION, 0);
+       ADDOP(c, BUILD_CLASS);
+       if (!compiler_nameop(c, s->v.ClassDef.name, Store))
+               return 0;
+       return 1;
 }
 
-static PyObject *
-dict_keys_inorder(PyObject *dict, int offset)
+static int
+compiler_lambda(struct compiler *c, expr_ty e)
 {
-       PyObject *tuple, *k, *v;
-       int i, pos = 0, size = PyDict_Size(dict);
+       PyCodeObject *co;
+       identifier name;
+       arguments_ty args = e->v.Lambda.args;
+       assert(e->kind == Lambda_kind);
 
-       tuple = PyTuple_New(size);
-       if (tuple == NULL)
-               return NULL;
-       while (PyDict_Next(dict, &pos, &k, &v)) {
-               i = PyInt_AS_LONG(v);
-               Py_INCREF(k);
-               assert((i - offset) < size);
-               PyTuple_SET_ITEM(tuple, i - offset, k);
-       }
-       return tuple;
-}
+       name = PyString_InternFromString("lambda");
+       if (!name)
+               return 0;
 
-PyCodeObject *
-PyNode_Compile(node *n, const char *filename)
-{
-       return PyNode_CompileFlags(n, filename, NULL);
+       if (args->defaults)
+               VISIT_SEQ(c, expr, args->defaults);
+       if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
+               return 0;
+               
+        /* unpack nested arguments */
+       compiler_arguments(c, args);
+       
+       c->u->u_argcount = asdl_seq_LEN(args->args);
+       VISIT(c, expr, e->v.Lambda.body);
+       ADDOP(c, RETURN_VALUE);
+       co = assemble(c, 1);
+       if (co == NULL)
+               return 0;
+       compiler_exit_scope(c);
+
+        compiler_make_closure(c, co, asdl_seq_LEN(args->defaults));
+       Py_DECREF(name);
+
+       return 1;
 }
 
-PyCodeObject *
-PyNode_CompileFlags(node *n, const char *filename, PyCompilerFlags *flags)
-{
-       return jcompile(n, filename, NULL, flags);
+static int
+compiler_print(struct compiler *c, stmt_ty s)
+{
+       int i, n;
+       bool dest;
+
+       assert(s->kind == Print_kind);
+       n = asdl_seq_LEN(s->v.Print.values);
+       dest = false;
+       if (s->v.Print.dest) {
+               VISIT(c, expr, s->v.Print.dest);
+               dest = true;
+       }
+       for (i = 0; i < n; i++) {
+               expr_ty e = (expr_ty)asdl_seq_GET(s->v.Print.values, i);
+               if (dest) {
+                       ADDOP(c, DUP_TOP);
+                       VISIT(c, expr, e);
+                       ADDOP(c, ROT_TWO);
+                       ADDOP(c, PRINT_ITEM_TO);
+               }
+               else {
+                       VISIT(c, expr, e);
+                       ADDOP(c, PRINT_ITEM);
+               }
+       }
+       if (s->v.Print.nl) {
+               if (dest)
+                       ADDOP(c, PRINT_NEWLINE_TO)
+               else
+                       ADDOP(c, PRINT_NEWLINE)
+       }
+       else if (dest)
+               ADDOP(c, POP_TOP);
+       return 1;
 }
 
-struct symtable *
-PyNode_CompileSymtable(node *n, const char *filename)
+static int
+compiler_if(struct compiler *c, stmt_ty s)
 {
-       struct symtable *st;
-       PyFutureFeatures *ff;
+       basicblock *end, *next;
 
-       ff = PyNode_Future(n, filename);
-       if (ff == NULL)
-               return NULL;
-       st = symtable_build(n, ff, filename);
-       if (st == NULL) {
-               PyObject_FREE((void *)ff);
-               return NULL;
-       }
-       return st;
+       assert(s->kind == If_kind);
+       end = compiler_new_block(c);
+       if (end == NULL)
+               return 0;
+        next = compiler_new_block(c);
+        if (next == NULL)
+            return 0;
+        VISIT(c, expr, s->v.If.test);
+        ADDOP_JREL(c, JUMP_IF_FALSE, next);
+        ADDOP(c, POP_TOP);
+        VISIT_SEQ(c, stmt, s->v.If.body);
+        ADDOP_JREL(c, JUMP_FORWARD, end);
+        compiler_use_next_block(c, next);
+        ADDOP(c, POP_TOP);
+        if (s->v.If.orelse)
+            VISIT_SEQ(c, stmt, s->v.If.orelse);
+       compiler_use_next_block(c, end);
+       return 1;
 }
 
-static PyCodeObject *
-icompile(node *n, struct compiling *base)
+static int
+compiler_for(struct compiler *c, stmt_ty s)
 {
-       return jcompile(n, base->c_filename, base, NULL);
+       basicblock *start, *cleanup, *end;
+
+       start = compiler_new_block(c);
+       cleanup = compiler_new_block(c);
+       end = compiler_new_block(c);
+       if (start == NULL || end == NULL || cleanup == NULL)
+               return 0;
+       ADDOP_JREL(c, SETUP_LOOP, end);
+       if (!compiler_push_fblock(c, LOOP, start))
+               return 0;
+       VISIT(c, expr, s->v.For.iter);
+       ADDOP(c, GET_ITER);
+       compiler_use_next_block(c, start);
+       ADDOP_JREL(c, FOR_ITER, cleanup);
+       VISIT(c, expr, s->v.For.target);
+       VISIT_SEQ(c, stmt, s->v.For.body);
+       ADDOP_JABS(c, JUMP_ABSOLUTE, start);
+       compiler_use_next_block(c, cleanup);
+       ADDOP(c, POP_BLOCK);
+       compiler_pop_fblock(c, LOOP, start);
+       VISIT_SEQ(c, stmt, s->v.For.orelse);
+       compiler_use_next_block(c, end);
+       return 1;
 }
 
-static PyCodeObject *
-jcompile(node *n, const char *filename, struct compiling *base,
-        PyCompilerFlags *flags)
+static int
+compiler_while(struct compiler *c, stmt_ty s)
 {
-       struct compiling sc;
-       PyCodeObject *co;
-       if (!com_init(&sc, filename))
-               return NULL;
-       if (flags && flags->cf_flags & PyCF_SOURCE_IS_UTF8) {
-               sc.c_encoding = "utf-8";
-       } else if (TYPE(n) == encoding_decl) {
-               sc.c_encoding = STR(n);
-               n = CHILD(n, 0);
-       } else {
-               sc.c_encoding = NULL;
-       }
-       if (base) {
-               sc.c_private = base->c_private;
-               sc.c_symtable = base->c_symtable;
-               /* c_symtable still points to parent's symbols */
-               if (base->c_nested 
-                   || (sc.c_symtable->st_cur->ste_type == TYPE_FUNCTION))
-                       sc.c_nested = 1;
-               sc.c_flags |= base->c_flags & PyCF_MASK;
-               if (base->c_encoding != NULL) {
-                       assert(sc.c_encoding == NULL);
-                       sc.c_encoding = base->c_encoding;
-               }
-       } else {
-               sc.c_private = NULL;
-               sc.c_future = PyNode_Future(n, filename);
-               if (sc.c_future == NULL) {
-                       com_free(&sc);
-                       return NULL;
-               }
-               if (flags) {
-                       int merged = sc.c_future->ff_features |
-                               flags->cf_flags;
-                       sc.c_future->ff_features = merged;
-                       flags->cf_flags = merged;
-               }
-               sc.c_symtable = symtable_build(n, sc.c_future, sc.c_filename);
-               if (sc.c_symtable == NULL) {
-                       com_free(&sc);
-                       return NULL;
-               }
-               /* reset symbol table for second pass */
-               sc.c_symtable->st_nscopes = 1;
-               sc.c_symtable->st_pass = 2;
-       }
-       co = NULL;
-       if (symtable_load_symbols(&sc) < 0) {
-               sc.c_errors++;
-               goto exit;
+       basicblock *loop, *orelse, *end, *anchor = NULL;
+       int constant = expr_constant(s->v.While.test);
+
+       if (constant == 0)
+               return 1;
+       loop = compiler_new_block(c);
+       end = compiler_new_block(c);
+       if (constant == -1) {
+               anchor = compiler_new_block(c);
+               if (anchor == NULL)
+                       return 0;
        }
-       compile_node(&sc, n);
-       com_done(&sc);
-       if (sc.c_errors == 0) {
-               PyObject *consts, *names, *varnames, *filename, *name,
-                       *freevars, *cellvars, *code;
-               names = PyList_AsTuple(sc.c_names);
-               varnames = PyList_AsTuple(sc.c_varnames);
-               cellvars = dict_keys_inorder(sc.c_cellvars, 0);
-               freevars = dict_keys_inorder(sc.c_freevars,
-                                            PyTuple_GET_SIZE(cellvars));
-               filename = PyString_InternFromString(sc.c_filename);
-               name = PyString_InternFromString(sc.c_name);
-               code = optimize_code(sc.c_code, sc.c_consts, names, sc.c_lnotab);
-               consts = PyList_AsTuple(sc.c_consts);
-               if (!PyErr_Occurred())
-                       co = PyCode_New(sc.c_argcount,
-                                       sc.c_nlocals,
-                                       sc.c_maxstacklevel,
-                                       sc.c_flags,
-                                       code,
-                                       consts,
-                                       names,
-                                       varnames,
-                                       freevars,
-                                       cellvars,
-                                       filename,
-                                       name,
-                                       sc.c_firstlineno,
-                                       sc.c_lnotab);
-               Py_XDECREF(consts);
-               Py_XDECREF(names);
-               Py_XDECREF(varnames);
-               Py_XDECREF(freevars);
-               Py_XDECREF(cellvars);
-               Py_XDECREF(filename);
-               Py_XDECREF(name);
-               Py_XDECREF(code);
+       if (loop == NULL || end == NULL)
+               return 0;
+       if (s->v.While.orelse) {
+               orelse = compiler_new_block(c);
+               if (orelse == NULL)
+                       return 0;
        }
-       else if (!PyErr_Occurred()) {
-               /* This could happen if someone called PyErr_Clear() after an
-                  error was reported above.  That's not supposed to happen,
-                  but I just plugged one case and I'm not sure there can't be
-                  others.  In that case, raise SystemError so that at least
-                  it gets reported instead dumping core. */
-               PyErr_SetString(PyExc_SystemError, "lost syntax error");
+       else
+               orelse = NULL;
+
+       ADDOP_JREL(c, SETUP_LOOP, end);
+       compiler_use_next_block(c, loop);
+       if (!compiler_push_fblock(c, LOOP, loop))
+               return 0;
+       if (constant == -1) {
+               VISIT(c, expr, s->v.While.test);
+               ADDOP_JREL(c, JUMP_IF_FALSE, anchor);
+               ADDOP(c, POP_TOP);
        }
- exit:
-       if (base == NULL) {
-               PySymtable_Free(sc.c_symtable);
-               sc.c_symtable = NULL;
+       VISIT_SEQ(c, stmt, s->v.While.body);
+       ADDOP_JABS(c, JUMP_ABSOLUTE, loop);
+
+       /* XXX should the two POP instructions be in a separate block
+          if there is no else clause ?
+       */
+
+       if (constant == -1) {
+               compiler_use_next_block(c, anchor);
+               ADDOP(c, POP_TOP);
+               ADDOP(c, POP_BLOCK);
        }
-       com_free(&sc);
-       return co;
+       compiler_pop_fblock(c, LOOP, loop);
+       if (orelse != NULL)
+               VISIT_SEQ(c, stmt, s->v.While.orelse);
+       compiler_use_next_block(c, end);
+
+       return 1;
 }
 
-int
-PyCode_Addr2Line(PyCodeObject *co, int addrq)
+static int
+compiler_continue(struct compiler *c)
 {
-       int size = PyString_Size(co->co_lnotab) / 2;
-       unsigned char *p = (unsigned char*)PyString_AsString(co->co_lnotab);
-       int line = co->co_firstlineno;
-       int addr = 0;
-       while (--size >= 0) {
-               addr += *p++;
-               if (addr > addrq)
-                       break;
-               line += *p++;
+       static const char LOOP_ERROR_MSG[] = "'continue' not properly in loop";
+       int i;
+
+       if (!c->u->u_nfblocks)
+               return compiler_error(c, LOOP_ERROR_MSG);
+       i = c->u->u_nfblocks - 1;
+       switch (c->u->u_fblock[i].fb_type) {
+       case LOOP:
+               ADDOP_JABS(c, JUMP_ABSOLUTE, c->u->u_fblock[i].fb_block);
+               break;
+       case EXCEPT:
+       case FINALLY_TRY:
+               while (--i >= 0 && c->u->u_fblock[i].fb_type != LOOP)
+                       ;
+               if (i == -1)
+                       return compiler_error(c, LOOP_ERROR_MSG);
+               ADDOP_JABS(c, CONTINUE_LOOP, c->u->u_fblock[i].fb_block);
+               break;
+       case FINALLY_END:
+               return compiler_error(c,
+                       "'continue' not supported inside 'finally' clause");
        }
-       return line;
+
+       return 1;
 }
 
-/* The test for LOCAL must come before the test for FREE in order to
-   handle classes where name is both local and free.  The local var is
-   a method and the free var is a free var referenced within a method.
+/* Code generated for "try: <body> finally: <finalbody>" is as follows:
+   
+               SETUP_FINALLY   L
+               <code for body>
+               POP_BLOCK
+               LOAD_CONST      <None>
+       L:      <code for finalbody>
+               END_FINALLY
+   
+   The special instructions use the block stack.  Each block
+   stack entry contains the instruction that created it (here
+   SETUP_FINALLY), the level of the value stack at the time the
+   block stack entry was created, and a label (here L).
+   
+   SETUP_FINALLY:
+       Pushes the current value stack level and the label
+       onto the block stack.
+   POP_BLOCK:
+       Pops en entry from the block stack, and pops the value
+       stack until its level is the same as indicated on the
+       block stack.  (The label is ignored.)
+   END_FINALLY:
+       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
+   onto the value stack (and the exception condition is cleared),
+   and the interpreter jumps to the label gotten from the block
+   stack.
 */
 
 static int
-get_ref_type(struct compiling *c, char *name)
+compiler_try_finally(struct compiler *c, stmt_ty s)
 {
-       char buf[350];
-       PyObject *v;
-
-       if (PyDict_GetItemString(c->c_cellvars, name) != NULL)
-               return CELL;
-       if (PyDict_GetItemString(c->c_locals, name) != NULL)
-               return LOCAL;
-       if (PyDict_GetItemString(c->c_freevars, name) != NULL)
-               return FREE;
-       v = PyDict_GetItemString(c->c_globals, name);
-       if (v) {
-               if (v == Py_None)
-                       return GLOBAL_EXPLICIT;
-               else {
-                       return GLOBAL_IMPLICIT;
-               }
-       }
-       PyOS_snprintf(buf, sizeof(buf),
-               "unknown scope for %.100s in %.100s(%s) "
-               "in %s\nsymbols: %s\nlocals: %s\nglobals: %s\n",
-               name, c->c_name, 
-               PyObject_REPR(c->c_symtable->st_cur->ste_id),
-               c->c_filename,
-               PyObject_REPR(c->c_symtable->st_cur->ste_symbols),
-               PyObject_REPR(c->c_locals),
-               PyObject_REPR(c->c_globals)
-               );
+       basicblock *body, *end;
+       body = compiler_new_block(c);
+       end = compiler_new_block(c);
+       if (body == NULL || end == NULL)
+               return 0;
+
+       ADDOP_JREL(c, SETUP_FINALLY, end);
+       compiler_use_next_block(c, body);
+       if (!compiler_push_fblock(c, FINALLY_TRY, body))
+               return 0;
+       VISIT_SEQ(c, stmt, s->v.TryFinally.body);
+       ADDOP(c, POP_BLOCK);
+       compiler_pop_fblock(c, FINALLY_TRY, body);
 
-       Py_FatalError(buf);
-       return -1;
+       ADDOP_O(c, LOAD_CONST, Py_None, consts);
+       compiler_use_next_block(c, end);
+       if (!compiler_push_fblock(c, FINALLY_END, end))
+               return 0;
+       VISIT_SEQ(c, stmt, s->v.TryFinally.finalbody);
+       ADDOP(c, END_FINALLY);
+       compiler_pop_fblock(c, FINALLY_END, end);
+
+       return 1;
 }
 
-/* Helper functions to issue warnings */
+/*
+   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
+   []                          <code for S>
+   []                          POP_BLOCK
+   []                          JUMP_FORWARD    L0
+   
+   [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
+   
+   [tb, val, exc, 0]   L2:     POP
+   [tb, val, exc]              DUP
+   .............................etc.......................
 
+   [tb, val, exc, 0]   Ln+1:   POP
+   [tb, val, exc]              END_FINALLY     # re-raise exception
+   
+   []                  L0:     <next statement>
+   
+   Of course, parts are not generated if Vi or Ei is not present.
+*/
 static int
-issue_warning(const char *msg, const char *filename, int lineno)
+compiler_try_except(struct compiler *c, stmt_ty s)
 {
-       if (PyErr_Occurred()) {
-               /* This can happen because symtable_node continues
-                  processing even after raising a SyntaxError.
-                  Calling PyErr_WarnExplicit now would clobber the
-                  pending exception; instead we fail and let that
-                  exception propagate.
-               */
-               return -1;
-       }
-       if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, filename,
-                              lineno, NULL, NULL) < 0) {
-               if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
-                       PyErr_SetString(PyExc_SyntaxError, msg);
-                       PyErr_SyntaxLocation(filename, lineno);
+        basicblock *body, *orelse, *except, *end;
+       int i, n;
+
+       body = compiler_new_block(c);
+       except = compiler_new_block(c);
+       orelse = compiler_new_block(c);
+       end = compiler_new_block(c);
+       if (body == NULL || except == NULL || orelse == NULL || end == NULL)
+               return 0;
+       ADDOP_JREL(c, SETUP_EXCEPT, except);
+       compiler_use_next_block(c, body);
+       if (!compiler_push_fblock(c, EXCEPT, body))
+               return 0;
+       VISIT_SEQ(c, stmt, s->v.TryExcept.body);
+       ADDOP(c, POP_BLOCK);
+       compiler_pop_fblock(c, EXCEPT, body);
+       ADDOP_JREL(c, JUMP_FORWARD, orelse);
+       n = asdl_seq_LEN(s->v.TryExcept.handlers);
+       compiler_use_next_block(c, except);
+       for (i = 0; i < n; i++) {
+               excepthandler_ty handler = asdl_seq_GET(
+                                               s->v.TryExcept.handlers, i);
+               if (!handler->type && i < n-1)
+                   return compiler_error(c, "default 'except:' must be last");
+               except = compiler_new_block(c);
+               if (except == NULL)
+                       return 0;
+               if (handler->type) {
+                       ADDOP(c, DUP_TOP);
+                       VISIT(c, expr, handler->type);
+                       ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH);
+                       ADDOP_JREL(c, JUMP_IF_FALSE, except);
+                       ADDOP(c, POP_TOP);
                }
-               return -1;
-       }
-       return 0;
+               ADDOP(c, POP_TOP);
+               if (handler->name) {
+                       VISIT(c, expr, handler->name);
+               }
+               else {
+                       ADDOP(c, POP_TOP);
+               }
+               ADDOP(c, POP_TOP);
+               VISIT_SEQ(c, stmt, handler->body);
+               ADDOP_JREL(c, JUMP_FORWARD, end);
+               compiler_use_next_block(c, except);
+               if (handler->type)
+                       ADDOP(c, POP_TOP);
+       }
+       ADDOP(c, END_FINALLY);
+       compiler_use_next_block(c, orelse);
+       VISIT_SEQ(c, stmt, s->v.TryExcept.orelse);
+       compiler_use_next_block(c, end);
+       return 1;
 }
 
 static int
-symtable_warn(struct symtable *st, char *msg)
+compiler_import_as(struct compiler *c, identifier name, identifier asname)
 {
-       if (issue_warning(msg, st->st_filename, st->st_cur->ste_lineno) < 0) {
-               st->st_errors++;
-               return -1;
+       /* The IMPORT_NAME opcode was already generated.  This function
+          merely needs to bind the result to a name.
+
+          If there is a dot in name, we need to split it and emit a 
+          LOAD_ATTR for each name.
+       */
+       const char *src = PyString_AS_STRING(name);
+       const char *dot = strchr(src, '.');
+       if (dot) {
+               /* Consume the base module name to get the first attribute */
+               src = dot + 1;
+               while (dot) {
+                       /* NB src is only defined when dot != NULL */
+                       dot = strchr(src, '.');
+                       PyObject *attr = PyString_FromStringAndSize(src, 
+                                           dot ? dot - src : strlen(src));
+                       ADDOP_O(c, LOAD_ATTR, attr, names);
+                       src = dot + 1;
+               }
        }
-       return 0;
+       return compiler_nameop(c, asname, Store);
 }
 
-/* Helper function for setting lineno and filename */
-
-static struct symtable *
-symtable_build(node *n, PyFutureFeatures *ff, const char *filename)
-{
-       struct symtable *st;
-
-       st = symtable_init();
-       if (st == NULL)
-               return NULL;
-       st->st_future = ff;
-       st->st_filename = filename;
-       symtable_enter_scope(st, TOP, TYPE(n), n->n_lineno);
-       if (st->st_errors > 0)
-               goto fail;
-       symtable_node(st, n);
-       if (st->st_errors > 0)
-               goto fail;
-       return st;
- fail:
-       if (!PyErr_Occurred()) {
-               /* This could happen because after a syntax error is
-                  detected, the symbol-table-building continues for
-                  a while, and PyErr_Clear() might erroneously be
-                  called during that process.  One such case has been
-                  fixed, but there might be more (now or later).
-               */
-               PyErr_SetString(PyExc_SystemError, "lost exception");
+static int
+compiler_import(struct compiler *c, stmt_ty s)
+{
+       /* The Import node stores a module name like a.b.c as a single
+          string.  This is convenient for all cases except
+            import a.b.c as d
+          where we need to parse that string to extract the individual
+          module names.  
+          XXX Perhaps change the representation to make this case simpler?
+        */
+       int i, n = asdl_seq_LEN(s->v.Import.names);
+       for (i = 0; i < n; i++) {
+               alias_ty alias = asdl_seq_GET(s->v.Import.names, i);
+               int r;
+
+               ADDOP_O(c, LOAD_CONST, Py_None, consts);
+               ADDOP_NAME(c, IMPORT_NAME, alias->name, names);
+
+               if (alias->asname) {
+                       return compiler_import_as(c, 
+                                                 alias->name, alias->asname);
+                }
+                else {
+                       identifier tmp = alias->name;
+                       const char *base = PyString_AS_STRING(alias->name);
+                       char *dot = strchr(base, '.');
+                       if (dot)
+                               tmp = PyString_FromStringAndSize(base, 
+                                                                dot - base);
+                       r = compiler_nameop(c, tmp, Store);
+                       if (dot) {
+                               Py_DECREF(tmp);
+                       }
+                       if (!r)
+                               return r;
+               }
        }
-       st->st_future = NULL;
-       st->st_filename = NULL;
-       PySymtable_Free(st);
-       return NULL;
+       return 1;
 }
 
 static int
-symtable_init_compiling_symbols(struct compiling *c)
+compiler_from_import(struct compiler *c, stmt_ty s)
 {
-       PyObject *varnames;
+       int i, n = asdl_seq_LEN(s->v.ImportFrom.names);
+       int star = 0;
 
-       varnames = c->c_symtable->st_cur->ste_varnames;
-       if (varnames == NULL) {
-               varnames = PyList_New(0);
-               if (varnames == NULL)
-                       return -1;
-               c->c_symtable->st_cur->ste_varnames = varnames;
-               Py_INCREF(varnames);
-       } else
-               Py_INCREF(varnames);
-       c->c_varnames = varnames;
-
-       c->c_globals = PyDict_New();
-       if (c->c_globals == NULL)
-               return -1;
-       c->c_freevars = PyDict_New();
-       if (c->c_freevars == NULL)
-               return -1;
-       c->c_cellvars = PyDict_New();
-       if (c->c_cellvars == NULL)
-               return -1;
-       return 0;
-}
+       PyObject *names = PyTuple_New(n);
+       if (!names)
+               return 0;
 
-struct symbol_info {
-       int si_nlocals;
-       int si_ncells;
-       int si_nfrees;
-       int si_nimplicit;
-};
+       /* build up the names */
+       for (i = 0; i < n; i++) {
+               alias_ty alias = asdl_seq_GET(s->v.ImportFrom.names, i);
+               Py_INCREF(alias->name);
+               PyTuple_SET_ITEM(names, i, alias->name);
+       }
 
-static void
-symtable_init_info(struct symbol_info *si)
-{
-       si->si_nlocals = 0;
-       si->si_ncells = 0;
-       si->si_nfrees = 0;
-       si->si_nimplicit = 0;
+       if (s->lineno > c->c_future->ff_lineno) {
+               if (!strcmp(PyString_AS_STRING(s->v.ImportFrom.module),
+                           "__future__")) {
+                       Py_DECREF(names);
+                       return compiler_error(c, 
+                                     "from __future__ imports must occur "
+                                      "at the beginning of the file");
+
+               }
+       }
+
+       ADDOP_O(c, LOAD_CONST, names, consts);
+       ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names);
+       for (i = 0; i < n; i++) {
+               alias_ty alias = asdl_seq_GET(s->v.ImportFrom.names, i);
+               identifier store_name;
+
+               if (i == 0 && *PyString_AS_STRING(alias->name) == '*') {
+                       assert(n == 1);
+                       ADDOP(c, IMPORT_STAR);
+                       star = 1;
+                       break;
+               }
+                   
+               ADDOP_NAME(c, IMPORT_FROM, alias->name, names);
+               store_name = alias->name;
+               if (alias->asname)
+                       store_name = alias->asname;
+
+               if (!compiler_nameop(c, store_name, Store)) {
+                       Py_DECREF(names);
+                       return 0;
+               }
+       }
+       if (!star) 
+               /* remove imported module */
+               ADDOP(c, POP_TOP);
+       return 1;
 }
 
 static int
-symtable_resolve_free(struct compiling *c, PyObject *name, int flags,
-                     struct symbol_info *si)
+compiler_assert(struct compiler *c, stmt_ty s)
 {
-       PyObject *dict, *v;
+       static PyObject *assertion_error = NULL;
+       basicblock *end;
 
-       /* Seperate logic for DEF_FREE.  If it occurs in a function,
-          it indicates a local that we must allocate storage for (a
-          cell var).  If it occurs in a class, then the class has a
-          method and a free variable with the same name.
-       */
-       if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION) {
-               /* If it isn't declared locally, it can't be a cell. */
-               if (!(flags & (DEF_LOCAL | DEF_PARAM)))
-                       return 0;
-               v = PyInt_FromLong(si->si_ncells++);
-               dict = c->c_cellvars;
-       } else {
-               /* If it is free anyway, then there is no need to do
-                  anything here.
-               */
-               if (is_free(flags ^ DEF_FREE_CLASS) 
-                   || (flags == DEF_FREE_CLASS))
+       if (Py_OptimizeFlag)
+               return 1;
+       if (assertion_error == NULL) {
+               assertion_error = PyString_FromString("AssertionError");
+               if (assertion_error == NULL)
                        return 0;
-               v = PyInt_FromLong(si->si_nfrees++);
-               dict = c->c_freevars;
        }
-       if (v == NULL)
-               return -1;
-       if (PyDict_SetItem(dict, name, v) < 0) {
-               Py_DECREF(v);
-               return -1;
+       VISIT(c, expr, s->v.Assert.test);
+       end = compiler_new_block(c);
+       if (end == NULL)
+               return 0;
+       ADDOP_JREL(c, JUMP_IF_TRUE, end);
+       ADDOP(c, POP_TOP);
+       ADDOP_O(c, LOAD_GLOBAL, assertion_error, names);
+       if (s->v.Assert.msg) {
+               VISIT(c, expr, s->v.Assert.msg);
+               ADDOP_I(c, RAISE_VARARGS, 2);
        }
-       Py_DECREF(v);
-       return 0;
+       else {
+               ADDOP_I(c, RAISE_VARARGS, 1);
+       }
+       compiler_use_block(c, end);
+       ADDOP(c, POP_TOP);
+       return 1;
 }
 
-/* If a variable is a cell and an argument, make sure that appears in
-   co_cellvars before any variable to its right in varnames. 
-*/
-
-
 static int
-symtable_cellvar_offsets(PyObject **cellvars, int argcount, 
-                        PyObject *varnames, int flags) 
-{
-       PyObject *v = NULL;
-       PyObject *w, *d, *list = NULL;
-       int i, pos;
-
-       if (flags & CO_VARARGS)
-               argcount++;
-       if (flags & CO_VARKEYWORDS)
-               argcount++;
-       for (i = argcount; --i >= 0; ) {
-               v = PyList_GET_ITEM(varnames, i);
-               if (PyDict_GetItem(*cellvars, v)) {
-                       if (list == NULL) {
-                               list = PyList_New(1);
-                               if (list == NULL)
-                                       return -1;
-                               PyList_SET_ITEM(list, 0, v);
-                               Py_INCREF(v);
-                       } else {
-                               if (PyList_Insert(list, 0, v) < 0) {
-                                       Py_DECREF(list);
-                                       return -1;
+compiler_visit_stmt(struct compiler *c, stmt_ty s)
+{
+       int i, n;
+
+       c->u->u_lineno = s->lineno;
+       c->u->u_lineno_set = false;
+       switch (s->kind) {
+        case FunctionDef_kind:
+               return compiler_function(c, s);
+        case ClassDef_kind:
+               return compiler_class(c, s);
+        case Return_kind:
+               if (c->u->u_ste->ste_type != FunctionBlock)
+                       return compiler_error(c, "'return' outside function");
+               if (s->v.Return.value) {
+                       if (c->u->u_ste->ste_generator) {
+                               return compiler_error(c,
+                                   "'return' with argument inside generator");
+                       }
+                       VISIT(c, expr, s->v.Return.value);
+               }
+               else
+                       ADDOP_O(c, LOAD_CONST, Py_None, consts);
+               ADDOP(c, RETURN_VALUE);
+               break;
+        case Delete_kind:
+               VISIT_SEQ(c, expr, s->v.Delete.targets)
+               break;
+        case Assign_kind:
+               n = asdl_seq_LEN(s->v.Assign.targets);
+               VISIT(c, expr, s->v.Assign.value);
+               for (i = 0; i < n; i++) {
+                       if (i < n - 1)
+                               ADDOP(c, DUP_TOP);
+                       VISIT(c, expr,
+                             (expr_ty)asdl_seq_GET(s->v.Assign.targets, i));
+               }
+               break;
+        case AugAssign_kind:
+               return compiler_augassign(c, s);
+        case Print_kind:
+               return compiler_print(c, s);
+        case For_kind:
+               return compiler_for(c, s);
+        case While_kind:
+               return compiler_while(c, s);
+        case If_kind:
+               return compiler_if(c, s);
+        case Raise_kind:
+               n = 0;
+               if (s->v.Raise.type) {
+                       VISIT(c, expr, s->v.Raise.type);
+                       n++;
+                       if (s->v.Raise.inst) {
+                               VISIT(c, expr, s->v.Raise.inst);
+                               n++;
+                               if (s->v.Raise.tback) {
+                                       VISIT(c, expr, s->v.Raise.tback);
+                                       n++;
                                }
                        }
                }
-       }
-       if (list == NULL)
-               return 0;
-
-       /* There are cellvars that are also arguments.  Create a dict
-          to replace cellvars and put the args at the front.
-       */
-       d = PyDict_New();
-       if (d == NULL)
-               return -1;
-       for (i = PyList_GET_SIZE(list); --i >= 0; ) {
-               v = PyInt_FromLong(i);
-               if (v == NULL) 
-                       goto fail;
-               if (PyDict_SetItem(d, PyList_GET_ITEM(list, i), v) < 0)
-                       goto fail;
-               if (PyDict_DelItem(*cellvars, PyList_GET_ITEM(list, i)) < 0)
-                       goto fail;
-               Py_DECREF(v);
-       }
-       pos = 0;
-       i = PyList_GET_SIZE(list);
-       Py_DECREF(list);
-       while (PyDict_Next(*cellvars, &pos, &v, &w)) {
-               w = PyInt_FromLong(i++);  /* don't care about the old key */
-               if (w == NULL)
-                       goto fail;
-               if (PyDict_SetItem(d, v, w) < 0) {
-                       Py_DECREF(w);
-                       v = NULL;
-                       goto fail;
+               ADDOP_I(c, RAISE_VARARGS, n);
+               break;
+        case TryExcept_kind:
+               return compiler_try_except(c, s);
+        case TryFinally_kind:
+               return compiler_try_finally(c, s);
+        case Assert_kind:
+               return compiler_assert(c, s);
+        case Import_kind:
+               return compiler_import(c, s);
+        case ImportFrom_kind:
+               return compiler_from_import(c, s);
+        case Exec_kind:
+               VISIT(c, expr, s->v.Exec.body);
+               if (s->v.Exec.globals) {
+                       VISIT(c, expr, s->v.Exec.globals);
+                       if (s->v.Exec.locals) {
+                               VISIT(c, expr, s->v.Exec.locals);
+                       } else {
+                               ADDOP(c, DUP_TOP);
+                       }
+               } else {
+                       ADDOP_O(c, LOAD_CONST, Py_None, consts);
+                       ADDOP(c, DUP_TOP);
+               }
+               ADDOP(c, EXEC_STMT);
+               break;
+        case Global_kind:
+               break;
+        case Expr_kind:
+               VISIT(c, expr, s->v.Expr.value);
+               if (c->c_interactive && c->c_nestlevel <= 1) {
+                       ADDOP(c, PRINT_EXPR);
+               }
+               else {
+                       ADDOP(c, POP_TOP);
                }
-               Py_DECREF(w);
+               break;
+        case Pass_kind:
+               break;
+        case Break_kind:
+               if (!c->u->u_nfblocks)
+                       return compiler_error(c, "'break' outside loop");
+               ADDOP(c, BREAK_LOOP);
+               break;
+        case Continue_kind:
+               return compiler_continue(c);
        }
-       Py_DECREF(*cellvars);
-       *cellvars = d;
        return 1;
- fail:
-       Py_DECREF(d);
-       Py_XDECREF(v);
-       return -1;
 }
 
 static int
-symtable_freevar_offsets(PyObject *freevars, int offset)
-{
-       PyObject *name, *v;
-       int pos;
-
-       /* The cell vars are the first elements of the closure,
-          followed by the free vars.  Update the offsets in
-          c_freevars to account for number of cellvars. */  
-       pos = 0;
-       while (PyDict_Next(freevars, &pos, &name, &v)) {
-               int i = PyInt_AS_LONG(v) + offset;
-               PyObject *o = PyInt_FromLong(i);
-               if (o == NULL)
-                       return -1;
-               if (PyDict_SetItem(freevars, name, o) < 0) {
-                       Py_DECREF(o);
-                       return -1;
-               }
-               Py_DECREF(o);
+unaryop(unaryop_ty op)
+{
+       switch (op) {
+       case Invert:
+               return UNARY_INVERT;
+       case Not:
+               return UNARY_NOT;
+       case UAdd:
+               return UNARY_POSITIVE;
+       case USub:
+               return UNARY_NEGATIVE;
        }
        return 0;
 }
 
 static int
-symtable_check_unoptimized(struct compiling *c,
-                          PySymtableEntryObject *ste, 
-                          struct symbol_info *si)
-{
-       char buf[300];
-
-       if (!(si->si_ncells || si->si_nfrees || ste->ste_child_free
-             || (ste->ste_nested && si->si_nimplicit)))
-               return 0;
-
-#define ILLEGAL_CONTAINS "contains a nested function with free variables"
-
-#define ILLEGAL_IS "is a nested function"
-
-#define ILLEGAL_IMPORT_STAR \
-"import * is not allowed in function '%.100s' because it %s"
-
-#define ILLEGAL_BARE_EXEC \
-"unqualified exec is not allowed in function '%.100s' it %s"
-
-#define ILLEGAL_EXEC_AND_IMPORT_STAR \
-"function '%.100s' uses import * and bare exec, which are illegal " \
-"because it %s"
-
-       /* XXX perhaps the linenos for these opt-breaking statements
-          should be stored so the exception can point to them. */
-
-       if (ste->ste_child_free) {
-               if (ste->ste_optimized == OPT_IMPORT_STAR)
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     ILLEGAL_IMPORT_STAR, 
-                                     PyString_AS_STRING(ste->ste_name),
-                                     ILLEGAL_CONTAINS);
-               else if (ste->ste_optimized == (OPT_BARE_EXEC | OPT_EXEC))
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     ILLEGAL_BARE_EXEC,
-                                     PyString_AS_STRING(ste->ste_name),
-                                     ILLEGAL_CONTAINS);
-               else {
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     ILLEGAL_EXEC_AND_IMPORT_STAR,
-                                     PyString_AS_STRING(ste->ste_name),
-                                     ILLEGAL_CONTAINS);
-               }
-       } else {
-               if (ste->ste_optimized == OPT_IMPORT_STAR)
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     ILLEGAL_IMPORT_STAR, 
-                                     PyString_AS_STRING(ste->ste_name),
-                                     ILLEGAL_IS);
-               else if (ste->ste_optimized == (OPT_BARE_EXEC | OPT_EXEC))
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     ILLEGAL_BARE_EXEC,
-                                     PyString_AS_STRING(ste->ste_name),
-                                     ILLEGAL_IS);
-               else {
-                       PyOS_snprintf(buf, sizeof(buf),
-                                     ILLEGAL_EXEC_AND_IMPORT_STAR,
-                                     PyString_AS_STRING(ste->ste_name),
-                                     ILLEGAL_IS);
-               }
+binop(struct compiler *c, operator_ty op)
+{
+       switch (op) {
+       case Add:
+               return BINARY_ADD;
+       case Sub:
+               return BINARY_SUBTRACT;
+       case Mult:
+               return BINARY_MULTIPLY;
+       case Div:
+               if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION)
+                       return BINARY_TRUE_DIVIDE;
+               else
+                       return BINARY_DIVIDE;
+       case Mod:
+               return BINARY_MODULO;
+       case Pow:
+               return BINARY_POWER;
+       case LShift:
+               return BINARY_LSHIFT;
+       case RShift:
+               return BINARY_RSHIFT;
+       case BitOr:
+               return BINARY_OR;
+       case BitXor:
+               return BINARY_XOR;
+       case BitAnd:
+               return BINARY_AND;
+       case FloorDiv:
+               return BINARY_FLOOR_DIVIDE;
        }
-
-       PyErr_SetString(PyExc_SyntaxError, buf);
-       PyErr_SyntaxLocation(c->c_symtable->st_filename,
-                            ste->ste_opt_lineno);
-       return -1;
+       return 0;
 }
 
 static int
-symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
-                     struct symbol_info *si)
-{
-       if (c->c_future)
-               c->c_flags |= c->c_future->ff_features;
-       if (ste->ste_generator)
-               c->c_flags |= CO_GENERATOR;
-       if (ste->ste_type != TYPE_MODULE)
-               c->c_flags |= CO_NEWLOCALS;
-       if (ste->ste_type == TYPE_FUNCTION) {
-               c->c_nlocals = si->si_nlocals;
-               if (ste->ste_optimized == 0)
-                       c->c_flags |= CO_OPTIMIZED;
-               else if (ste->ste_optimized != OPT_EXEC) 
-                       return symtable_check_unoptimized(c, ste, si);
+cmpop(cmpop_ty op)
+{
+       switch (op) {
+       case Eq:
+               return PyCmp_EQ;
+       case NotEq:
+               return PyCmp_NE;
+       case Lt:
+               return PyCmp_LT;
+       case LtE:
+               return PyCmp_LE;
+       case Gt:
+               return PyCmp_GT;
+       case GtE:
+               return PyCmp_GE;
+       case Is:
+               return PyCmp_IS;
+       case IsNot:
+               return PyCmp_IS_NOT;
+       case In:
+               return PyCmp_IN;
+       case NotIn:
+               return PyCmp_NOT_IN;
        }
-       return 0;
+       return PyCmp_BAD;
 }
 
 static int
-symtable_error(struct symtable *st, int lineno)
-{
-       if (lineno == 0)
-               lineno = st->st_cur->ste_lineno;
-       PyErr_SyntaxLocation(st->st_filename, lineno);
-       st->st_errors++;
-       return -1;
+inplace_binop(struct compiler *c, operator_ty op)
+{
+       switch (op) {
+       case Add:
+               return INPLACE_ADD;
+       case Sub:
+               return INPLACE_SUBTRACT;
+       case Mult:
+               return INPLACE_MULTIPLY;
+       case Div:
+               if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION)
+                       return INPLACE_TRUE_DIVIDE;
+               else
+                       return INPLACE_DIVIDE;
+       case Mod:
+               return INPLACE_MODULO;
+       case Pow:
+               return INPLACE_POWER;
+       case LShift:
+               return INPLACE_LSHIFT;
+       case RShift:
+               return INPLACE_RSHIFT;
+       case BitOr:
+               return INPLACE_OR;
+       case BitXor:
+               return INPLACE_XOR;
+       case BitAnd:
+               return INPLACE_AND;
+       case FloorDiv:
+               return INPLACE_FLOOR_DIVIDE;
+       }
+       assert(0);
+       return 0;
 }
 
 static int
-symtable_load_symbols(struct compiling *c)
+compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx)
 {
-       struct symtable *st = c->c_symtable;
-       PySymtableEntryObject *ste = st->st_cur;
-       PyObject *name, *varnames, *v;
-       int i, flags, pos;
-       struct symbol_info si;
-
-       v = NULL;
-
-       if (symtable_init_compiling_symbols(c) < 0)
-               goto fail;
-       symtable_init_info(&si);
-       varnames = st->st_cur->ste_varnames;
-       si.si_nlocals = PyList_GET_SIZE(varnames);
-       c->c_argcount = si.si_nlocals;
-
-       for (i = 0; i < si.si_nlocals; ++i) {
-               v = PyInt_FromLong(i);
-               if (v == NULL)
-                       goto fail;
-               if (PyDict_SetItem(c->c_locals, 
-                                  PyList_GET_ITEM(varnames, i), v) < 0)
-                       goto fail;
-               Py_DECREF(v);
-       }
-
-       /* XXX The cases below define the rules for whether a name is
-          local or global.  The logic could probably be clearer. */
-       pos = 0;
-       while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
-               flags = PyInt_AS_LONG(v);
+       int op, scope;
+       enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype;
 
-               if (flags & DEF_FREE_GLOBAL)
-                       /* undo the original DEF_FREE */
-                       flags &= ~(DEF_FREE | DEF_FREE_CLASS);
+        PyObject *dict = c->u->u_names;
+       /* XXX AugStore isn't used anywhere! */
 
-               /* Deal with names that need two actions:
-                  1. Cell variables that are also locals.
-                  2. Free variables in methods that are also class
-                  variables or declared global.
-               */
-               if (flags & (DEF_FREE | DEF_FREE_CLASS))
-                       symtable_resolve_free(c, name, flags, &si);
-
-               if (flags & DEF_STAR) {
-                       c->c_argcount--;
-                       c->c_flags |= CO_VARARGS;
-               } else if (flags & DEF_DOUBLESTAR) {
-                       c->c_argcount--;
-                       c->c_flags |= CO_VARKEYWORDS;
-               } else if (flags & DEF_INTUPLE) 
-                       c->c_argcount--;
-               else if (flags & DEF_GLOBAL) {
-                       if (flags & DEF_PARAM) {
-                               PyErr_Format(PyExc_SyntaxError, PARAM_GLOBAL,
-                                            PyString_AS_STRING(name));
-                               symtable_error(st, 0);
-                               goto fail;
-                       }
-                       if (PyDict_SetItem(c->c_globals, name, Py_None) < 0)
-                               goto fail;
-               } else if (flags & DEF_FREE_GLOBAL) {
-                       si.si_nimplicit++;
-                       if (PyDict_SetItem(c->c_globals, name, Py_True) < 0)
-                               goto fail;
-               } else if ((flags & DEF_LOCAL) && !(flags & DEF_PARAM)) {
-                       v = PyInt_FromLong(si.si_nlocals++);
-                       if (v == NULL)
-                               goto fail;
-                       if (PyDict_SetItem(c->c_locals, name, v) < 0)
-                               goto fail;
-                       Py_DECREF(v);
-                       if (ste->ste_type != TYPE_CLASS) 
-                               if (PyList_Append(c->c_varnames, name) < 0)
-                                       goto fail;
-               } else if (is_free(flags)) {
-                       if (ste->ste_nested) {
-                               v = PyInt_FromLong(si.si_nfrees++);
-                               if (v == NULL)
-                                       goto fail;
-                               if (PyDict_SetItem(c->c_freevars, name, v) < 0)
-                                       goto fail;
-                               Py_DECREF(v);
-                       } else {
-                               si.si_nimplicit++;
-                               if (PyDict_SetItem(c->c_globals, name,
-                                                  Py_True) < 0)
-                                       goto fail;
-                               if (st->st_nscopes != 1) {
-                                       v = PyInt_FromLong(flags);
-                                       if (v == NULL)
-                                               goto fail;
-                                       if (PyDict_SetItem(st->st_global, 
-                                                          name, v)) 
-                                               goto fail;
-                                       Py_DECREF(v);
-                               }
-                       }
-               }
+       /* First check for assignment to __debug__. Param? */
+       if ((ctx == Store || ctx == AugStore || ctx == Del)
+           && !strcmp(PyString_AS_STRING(name), "__debug__")) {
+               return compiler_error(c, "can not assign to __debug__");
        }
-       assert(PyDict_Size(c->c_freevars) == si.si_nfrees);
 
-       if (si.si_ncells > 1) { /* one cell is always in order */
-               if (symtable_cellvar_offsets(&c->c_cellvars, c->c_argcount,
-                                            c->c_varnames, c->c_flags) < 0)
-                       return -1;
+       op = 0;
+       optype = OP_NAME;
+       scope = PyST_GetScope(c->u->u_ste, name);
+       switch (scope) {
+       case FREE:
+                dict = c->u->u_freevars;
+               optype = OP_DEREF;
+               break;
+       case CELL:
+                dict = c->u->u_cellvars;
+               optype = OP_DEREF;
+               break;
+       case LOCAL:
+               if (c->u->u_ste->ste_type == FunctionBlock)
+                       optype = OP_FAST;
+               break;
+       case GLOBAL_IMPLICIT:
+               if (!c->u->u_ste->ste_unoptimized)
+                       optype = OP_GLOBAL;
+               break;
+       case GLOBAL_EXPLICIT:
+               optype = OP_GLOBAL;
+               break;
        }
-       if (symtable_freevar_offsets(c->c_freevars, si.si_ncells) < 0)
-               return -1;
-       return symtable_update_flags(c, ste, &si);
- fail:
-       /* is this always the right thing to do? */
-       Py_XDECREF(v);
-       return -1;
-}
 
-static struct symtable *
-symtable_init()
-{
-       struct symtable *st;
+       /* XXX Leave assert here, but handle __doc__ and the like better */
+       assert(scope || PyString_AS_STRING(name)[0] == '_');
 
-       st = (struct symtable *)PyObject_MALLOC(sizeof(struct symtable));
-       if (st == NULL)
-               return NULL;
-       st->st_pass = 1;
-
-       st->st_filename = NULL;
-       st->st_symbols = NULL;
-       if ((st->st_stack = PyList_New(0)) == NULL)
-               goto fail;
-       if ((st->st_symbols = PyDict_New()) == NULL)
-               goto fail; 
-       st->st_cur = NULL;
-       st->st_nscopes = 0;
-       st->st_errors = 0;
-       st->st_private = NULL;
-       return st;
- fail:
-       PySymtable_Free(st);
-       return NULL;
-}
+       switch (optype) {
+       case OP_DEREF:
+               switch (ctx) {
+               case Load: op = LOAD_DEREF; break;
+               case Store: op = STORE_DEREF; break;
+               case AugLoad:
+               case AugStore:
+                       break;
+               case Del:
+                       PyErr_Format(PyExc_SyntaxError,
+                                    "can not delete variable '%s' referenced "
+                                    "in nested scope",
+                                    PyString_AS_STRING(name));
+                       return 0;
+                       break;
+               case Param:
+                       assert(0); /* impossible */
+               }
+               break;
+       case OP_FAST:
+               switch (ctx) {
+               case Load: op = LOAD_FAST; break;
+               case Store: op = STORE_FAST; break;
+               case Del: op = DELETE_FAST; break;
+               case AugLoad:
+               case AugStore:
+                       break;
+               case Param:
+                       assert(0); /* impossible */
+               }
+               ADDOP_O(c, op, name, varnames);
+               return 1;
+       case OP_GLOBAL:
+               switch (ctx) {
+               case Load: op = LOAD_GLOBAL; break;
+               case Store: op = STORE_GLOBAL; break;
+               case Del: op = DELETE_GLOBAL; break;
+               case AugLoad:
+               case AugStore:
+                       break;
+               case Param:
+                       assert(0); /* impossible */
+               }
+               break;
+       case OP_NAME:
+               switch (ctx) {
+               case Load: op = LOAD_NAME; break;
+               case Store: op = STORE_NAME; break;
+               case Del: op = DELETE_NAME; break;
+               case AugLoad:
+               case AugStore:
+                       break;
+               case Param:
+                       assert(0); /* impossible */
+               }
+               break;
+       }
 
-void
-PySymtable_Free(struct symtable *st)
-{
-       Py_XDECREF(st->st_symbols);
-       Py_XDECREF(st->st_stack);
-       Py_XDECREF(st->st_cur);
-       PyObject_FREE((void *)st);
+       assert(op);
+       return compiler_addop_name(c, op, dict, name);
 }
 
-/* When the compiler exits a scope, it must should update the scope's
-   free variable information with the list of free variables in its
-   children.
-
-   Variables that are free in children and defined in the current
-   scope are cellvars.
-
-   If the scope being exited is defined at the top-level (ste_nested is
-   false), free variables in children that are not defined here are
-   implicit globals.
-
-*/
-
 static int
-symtable_update_free_vars(struct symtable *st)
+compiler_boolop(struct compiler *c, expr_ty e)
 {
-       int i, j, def;
-       PyObject *o, *name, *list = NULL;
-       PySymtableEntryObject *child, *ste = st->st_cur;
+       basicblock *end;
+       int jumpi, i, n;
+       asdl_seq *s;
 
-       if (ste->ste_type == TYPE_CLASS)
-               def = DEF_FREE_CLASS;
+       assert(e->kind == BoolOp_kind);
+       if (e->v.BoolOp.op == And)
+               jumpi = JUMP_IF_FALSE;
        else
-               def = DEF_FREE;
-       for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
-               int pos = 0;
-
-               if (list && PyList_SetSlice(list, 0, 
-                                           PyList_GET_SIZE(list), 0) < 0)
-                               return -1;
-               child = (PySymtableEntryObject *)
-                       PyList_GET_ITEM(ste->ste_children, i);
-               while (PyDict_Next(child->ste_symbols, &pos, &name, &o)) {
-                       int flags = PyInt_AS_LONG(o);
-                       if (!(is_free(flags)))
-                               continue; /* avoids indentation */
-                       if (list == NULL) {
-                               list = PyList_New(0);
-                               if (list == NULL)
-                                       return -1;
-                       }
-                       ste->ste_child_free = 1;
-                       if (PyList_Append(list, name) < 0) {
-                               Py_DECREF(list);
-                               return -1;
-                       }
-               }
-               for (j = 0; list && j < PyList_GET_SIZE(list); j++) {
-                       PyObject *v;
-                       name = PyList_GET_ITEM(list, j);
-                       v = PyDict_GetItem(ste->ste_symbols, name);
-                       /* If a name N is declared global in scope A and
-                          referenced in scope B contained (perhaps
-                          indirectly) in A and there are no scopes
-                          with bindings for N between B and A, then N
-                          is global in B.  Unless A is a class scope,
-                          because class scopes are not considered for
-                          nested scopes.
-                       */
-                       if (v && (ste->ste_type != TYPE_CLASS)) {
-                               int flags = PyInt_AS_LONG(v); 
-                               if (flags & DEF_GLOBAL) {
-                                       symtable_undo_free(st, child->ste_id,
-                                                          name);
-                                       continue;
-                               }
-                       }
-                       if (ste->ste_nested) {
-                               if (symtable_add_def_o(st, ste->ste_symbols,
-                                                      name, def) < 0) {
-                                   Py_DECREF(list);
-                                   return -1;
-                               }
-                       } else {
-                               if (symtable_check_global(st, child->ste_id, 
-                                                         name) < 0) {
-                                   Py_DECREF(list);
-                                   return -1;
-                               }
-                       }
-               }
-       }
-
-       Py_XDECREF(list);
-       return 0;
+               jumpi = JUMP_IF_TRUE;
+       end = compiler_new_block(c);
+       if (end < 0)
+               return 0;
+       s = e->v.BoolOp.values;
+       n = asdl_seq_LEN(s) - 1;
+       for (i = 0; i < n; ++i) {
+               VISIT(c, expr, asdl_seq_GET(s, i));
+               ADDOP_JREL(c, jumpi, end);
+               ADDOP(c, POP_TOP)
+       }
+       VISIT(c, expr, asdl_seq_GET(s, n));
+       compiler_use_next_block(c, end);
+       return 1;
 }
 
-/* If the current scope is a non-nested class or if name is not
-   defined in the current, non-nested scope, then it is an implicit
-   global in all nested scopes.
-*/
-
 static int
-symtable_check_global(struct symtable *st, PyObject *child, PyObject *name)
+compiler_list(struct compiler *c, expr_ty e)
 {
-       PyObject *o;
-       int v;
-       PySymtableEntryObject *ste = st->st_cur;
-                       
-       if (ste->ste_type == TYPE_CLASS)
-               return symtable_undo_free(st, child, name);
-       o = PyDict_GetItem(ste->ste_symbols, name);
-       if (o == NULL)
-               return symtable_undo_free(st, child, name);
-       v = PyInt_AS_LONG(o);
-
-       if (is_free(v) || (v & DEF_GLOBAL)) 
-               return symtable_undo_free(st, child, name);
-       else
-               return symtable_add_def_o(st, ste->ste_symbols,
-                                         name, DEF_FREE);
+       int n = asdl_seq_LEN(e->v.List.elts);
+       if (e->v.List.ctx == Store) {
+               ADDOP_I(c, UNPACK_SEQUENCE, n);
+       }
+       VISIT_SEQ(c, expr, e->v.List.elts);
+       if (e->v.List.ctx == Load) {
+               ADDOP_I(c, BUILD_LIST, n);
+       }
+       return 1;
 }
 
 static int
-symtable_undo_free(struct symtable *st, PyObject *id, 
-                     PyObject *name)
+compiler_tuple(struct compiler *c, expr_ty e)
 {
-       int i, v, x;
-       PyObject *info;
-       PySymtableEntryObject *ste;
-
-       ste = (PySymtableEntryObject *)PyDict_GetItem(st->st_symbols, id);
-       if (ste == NULL)
-               return -1;
-
-       info = PyDict_GetItem(ste->ste_symbols, name);
-       if (info == NULL)
-               return 0;
-       v = PyInt_AS_LONG(info);
-       if (is_free(v)) {
-               if (symtable_add_def_o(st, ste->ste_symbols, name,
-                                      DEF_FREE_GLOBAL) < 0)
-                       return -1;
-       } else
-               /* If the name is defined here or declared global,
-                  then the recursion stops. */
-               return 0;
-       
-       for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
-               PySymtableEntryObject *child;
-               child = (PySymtableEntryObject *)
-                       PyList_GET_ITEM(ste->ste_children, i);
-               x = symtable_undo_free(st, child->ste_id, name);
-               if (x < 0)
-                       return x;
+       int n = asdl_seq_LEN(e->v.Tuple.elts);
+       if (e->v.Tuple.ctx == Store) {
+               ADDOP_I(c, UNPACK_SEQUENCE, n);
        }
-       return 0;
+       VISIT_SEQ(c, expr, e->v.Tuple.elts);
+       if (e->v.Tuple.ctx == Load) {
+               ADDOP_I(c, BUILD_TUPLE, n);
+       }
+       return 1;
 }
 
-/* symtable_enter_scope() gets a reference via PySymtableEntry_New().
-   This reference is released when the scope is exited, via the DECREF
-   in symtable_exit_scope().
-*/
-
 static int
-symtable_exit_scope(struct symtable *st)
-{
-       int end;
-
-       if (st->st_pass == 1)
-               symtable_update_free_vars(st);
-       Py_DECREF(st->st_cur);
-       end = PyList_GET_SIZE(st->st_stack) - 1;
-       st->st_cur = (PySymtableEntryObject *)PyList_GET_ITEM(st->st_stack, 
-                                                             end);
-       if (PySequence_DelItem(st->st_stack, end) < 0)
-               return -1;
-       return 0;
+compiler_compare(struct compiler *c, expr_ty e)
+{
+       int i, n;
+        basicblock *cleanup = NULL;
+
+       /* XXX the logic can be cleaned up for 1 or multiple comparisons */
+       VISIT(c, expr, e->v.Compare.left);
+       n = asdl_seq_LEN(e->v.Compare.ops);
+       assert(n > 0);
+       if (n > 1) {
+               cleanup = compiler_new_block(c);
+                if (cleanup == NULL)
+                    return 0;
+               VISIT(c, expr, asdl_seq_GET(e->v.Compare.comparators, 0));
+       }
+       for (i = 1; i < n; i++) {
+               ADDOP(c, DUP_TOP);
+               ADDOP(c, ROT_THREE);
+               /* XXX We're casting a void* to cmpop_ty in the next stmt. */
+               ADDOP_I(c, COMPARE_OP,
+                       cmpop((cmpop_ty)asdl_seq_GET(e->v.Compare.ops, i - 1)));
+               ADDOP_JREL(c, JUMP_IF_FALSE, cleanup);
+               NEXT_BLOCK(c);
+               ADDOP(c, POP_TOP);
+               if (i < (n - 1))
+                   VISIT(c, expr, asdl_seq_GET(e->v.Compare.comparators, i));
+       }
+       VISIT(c, expr, asdl_seq_GET(e->v.Compare.comparators, n - 1));
+       ADDOP_I(c, COMPARE_OP,
+               /* XXX We're casting a void* to cmpop_ty in the next stmt. */
+              cmpop((cmpop_ty)asdl_seq_GET(e->v.Compare.ops, n - 1)));
+       if (n > 1) {
+               basicblock *end = compiler_new_block(c);
+                if (end == NULL)
+                    return 0;
+               ADDOP_JREL(c, JUMP_FORWARD, end);
+               compiler_use_next_block(c, cleanup);
+               ADDOP(c, ROT_TWO);
+               ADDOP(c, POP_TOP);
+               compiler_use_next_block(c, end);
+       }
+       return 1;
 }
 
-static void
-symtable_enter_scope(struct symtable *st, char *name, int type,
-                    int lineno)
+static int
+compiler_call(struct compiler *c, expr_ty e)
 {
-       PySymtableEntryObject *prev = NULL;
+       int n, code = 0;
 
-       if (st->st_cur) {
-               prev = st->st_cur;
-               if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
-                       st->st_errors++;
-                       return;
-               }
+       VISIT(c, expr, e->v.Call.func);
+       n = asdl_seq_LEN(e->v.Call.args);
+       VISIT_SEQ(c, expr, e->v.Call.args);
+       if (e->v.Call.keywords) {
+               VISIT_SEQ(c, keyword, e->v.Call.keywords);
+               n |= asdl_seq_LEN(e->v.Call.keywords) << 8;
        }
-       st->st_cur = (PySymtableEntryObject *)
-               PySymtableEntry_New(st, name, type, lineno);
-       if (st->st_cur == NULL) {
-               st->st_errors++;
-               return;
+       if (e->v.Call.starargs) {
+               VISIT(c, expr, e->v.Call.starargs);
+               code |= 1;
        }
-       if (strcmp(name, TOP) == 0)
-               st->st_global = st->st_cur->ste_symbols;
-       if (prev && st->st_pass == 1) {
-               if (PyList_Append(prev->ste_children, 
-                                 (PyObject *)st->st_cur) < 0)
-                       st->st_errors++;
+       if (e->v.Call.kwargs) {
+               VISIT(c, expr, e->v.Call.kwargs);
+               code |= 2;
+       }
+       switch (code) {
+       case 0:
+               ADDOP_I(c, CALL_FUNCTION, n);
+               break;
+       case 1:
+               ADDOP_I(c, CALL_FUNCTION_VAR, n);
+               break;
+       case 2:
+               ADDOP_I(c, CALL_FUNCTION_KW, n);
+               break;
+       case 3:
+               ADDOP_I(c, CALL_FUNCTION_VAR_KW, n);
+               break;
        }
+       return 1;
 }
 
 static int
-symtable_lookup(struct symtable *st, char *name)
-{
-       char buffer[MANGLE_LEN];
-       PyObject *v;
-       int flags;
-
-       if (_Py_Mangle(st->st_private, name, buffer, sizeof(buffer)))
-               name = buffer;
-       v = PyDict_GetItemString(st->st_cur->ste_symbols, name);
-       if (v == NULL) {
-               if (PyErr_Occurred())
-                       return -1;
-               else
-                       return 0;
-       }
-
-       flags = PyInt_AS_LONG(v);
-       return flags;
+compiler_listcomp_generator(struct compiler *c, PyObject *tmpname,
+                            asdl_seq *generators, int gen_index, 
+                            expr_ty elt)
+{
+       /* generate code for the iterator, then each of the ifs,
+          and then write to the element */
+
+       comprehension_ty l;
+       basicblock *start, *anchor, *skip, *if_cleanup;
+        int i, n;
+
+       start = compiler_new_block(c);
+       skip = compiler_new_block(c);
+       if_cleanup = compiler_new_block(c);
+       anchor = compiler_new_block(c);
+
+        if (start == NULL || skip == NULL || if_cleanup == NULL ||
+                anchor == NULL)
+            return 0;
+
+       l = asdl_seq_GET(generators, gen_index);
+       VISIT(c, expr, l->iter);
+       ADDOP(c, GET_ITER);
+       compiler_use_next_block(c, start);
+       ADDOP_JREL(c, FOR_ITER, anchor);
+       NEXT_BLOCK(c);
+       VISIT(c, expr, l->target);
+
+        /* XXX this needs to be cleaned up...a lot! */
+       n = asdl_seq_LEN(l->ifs);
+       for (i = 0; i < n; i++) {
+               expr_ty e = asdl_seq_GET(l->ifs, i);
+               VISIT(c, expr, e);
+               ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup);
+               NEXT_BLOCK(c);
+               ADDOP(c, POP_TOP);
+       } 
+
+        if (++gen_index < asdl_seq_LEN(generators))
+            if (!compiler_listcomp_generator(c, tmpname, 
+                                             generators, gen_index, elt))
+                return 0;
+
+        /* only append after the last for generator */
+        if (gen_index >= asdl_seq_LEN(generators)) {
+            if (!compiler_nameop(c, tmpname, Load))
+               return 0;
+            VISIT(c, expr, elt);
+            ADDOP_I(c, CALL_FUNCTION, 1);
+            ADDOP(c, POP_TOP);
+
+            compiler_use_next_block(c, skip);
+        }
+       for (i = 0; i < n; i++) {
+               ADDOP_I(c, JUMP_FORWARD, 1);
+                if (i == 0)
+                    compiler_use_next_block(c, if_cleanup);
+               ADDOP(c, POP_TOP);
+       } 
+       ADDOP_JABS(c, JUMP_ABSOLUTE, start);
+       compiler_use_next_block(c, anchor);
+        /* delete the append method added to locals */
+       if (gen_index == 1)
+            if (!compiler_nameop(c, tmpname, Del))
+               return 0;
+       
+       return 1;
 }
 
 static int
-symtable_add_def(struct symtable *st, char *name, int flag)
-{
-       PyObject *s;
-       char buffer[MANGLE_LEN];
-       int ret;
-
-       /* Warn about None, except inside a tuple (where the assignment
-          code already issues a warning). */
-       if ((flag & DEF_PARAM) && !(flag & DEF_INTUPLE) &&
-           *name == 'N' && strcmp(name, "None") == 0)
-       {
-               PyErr_SetString(PyExc_SyntaxError, 
-                       "Invalid syntax.  Assignment to None.");
-               symtable_error(st, 0);
-               return  -1;
+compiler_listcomp(struct compiler *c, expr_ty e)
+{
+       char tmpname[256];
+       identifier tmp;
+        int rc = 0;
+       static identifier append;
+       asdl_seq *generators = e->v.ListComp.generators;
+
+       assert(e->kind == ListComp_kind);
+       if (!append) {
+               append = PyString_InternFromString("append");
+               if (!append)
+                       return 0;
        }
-       if (_Py_Mangle(st->st_private, name, buffer, sizeof(buffer)))
-               name = buffer;
-       if ((s = PyString_InternFromString(name)) == NULL)
-               return -1;
-       ret = symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag);
-       Py_DECREF(s);
-       return ret;
+       PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname);
+       tmp = PyString_FromString(tmpname);
+       if (!tmp)
+               return 0;
+       ADDOP_I(c, BUILD_LIST, 0);
+       ADDOP(c, DUP_TOP);
+       ADDOP_O(c, LOAD_ATTR, append, names);
+       if (compiler_nameop(c, tmp, Store))
+            rc = compiler_listcomp_generator(c, tmp, generators, 0, 
+                                             e->v.ListComp.elt);
+        Py_DECREF(tmp);
+       return rc;
 }
 
-/* Must only be called with mangled names */
-
 static int
-symtable_add_def_o(struct symtable *st, PyObject *dict, 
-                  PyObject *name, int flag) 
+compiler_genexp_generator(struct compiler *c,
+                          asdl_seq *generators, int gen_index, 
+                          expr_ty elt)
 {
-       PyObject *o;
-       int val;
-
-       if ((o = PyDict_GetItem(dict, name))) {
-           val = PyInt_AS_LONG(o);
-           if ((flag & DEF_PARAM) && (val & DEF_PARAM)) {
-                   PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
-                                PyString_AsString(name));
-                   return symtable_error(st, 0);
-           }
-           val |= flag;
-       } else
-           val = flag;
-       o = PyInt_FromLong(val);
-       if (o == NULL)
-               return -1;
-       if (PyDict_SetItem(dict, name, o) < 0) {
-               Py_DECREF(o);
-               return -1;
-       }
-       Py_DECREF(o);
+       /* generate code for the iterator, then each of the ifs,
+          and then write to the element */
 
-       if (flag & DEF_PARAM) {
-               if (PyList_Append(st->st_cur->ste_varnames, name) < 0) 
-                       return -1;
-       } else  if (flag & DEF_GLOBAL) {
-               /* XXX need to update DEF_GLOBAL for other flags too;
-                  perhaps only DEF_FREE_GLOBAL */
-               if ((o = PyDict_GetItem(st->st_global, name))) {
-                       val = PyInt_AS_LONG(o);
-                       val |= flag;
-               } else
-                       val = flag;
-               o = PyInt_FromLong(val);
-               if (o == NULL)
-                       return -1;
-               if (PyDict_SetItem(st->st_global, name, o) < 0) {
-                       Py_DECREF(o);
-                       return -1;
-               }
-               Py_DECREF(o);
+       comprehension_ty ge;
+       basicblock *start, *anchor, *skip, *if_cleanup, *end;
+        int i, n;
+
+       start = compiler_new_block(c);
+       skip = compiler_new_block(c);
+       if_cleanup = compiler_new_block(c);
+       anchor = compiler_new_block(c);
+       end = compiler_new_block(c);
+
+        if (start == NULL || skip == NULL || if_cleanup == NULL ||
+           anchor == NULL || end == NULL)
+               return 0;
+
+       ge = asdl_seq_GET(generators, gen_index);
+       ADDOP_JREL(c, SETUP_LOOP, end);
+       if (!compiler_push_fblock(c, LOOP, start))
+               return 0;
+
+       if (gen_index == 0) {
+               /* Receive outermost iter as an implicit argument */
+               c->u->u_argcount = 1;
+               ADDOP_I(c, LOAD_FAST, 0);
        }
-       return 0;
-}
+       else {
+               /* Sub-iter - calculate on the fly */
+               VISIT(c, expr, ge->iter);
+               ADDOP(c, GET_ITER);
+       }
+       compiler_use_next_block(c, start);
+       ADDOP_JREL(c, FOR_ITER, anchor);
+       NEXT_BLOCK(c);
+       VISIT(c, expr, ge->target);
+
+        /* XXX this needs to be cleaned up...a lot! */
+       n = asdl_seq_LEN(ge->ifs);
+       for (i = 0; i < n; i++) {
+               expr_ty e = asdl_seq_GET(ge->ifs, i);
+               VISIT(c, expr, e);
+               ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup);
+               NEXT_BLOCK(c);
+               ADDOP(c, POP_TOP);
+       } 
+
+        if (++gen_index < asdl_seq_LEN(generators))
+               if (!compiler_genexp_generator(c, generators, gen_index, elt))
+                       return 0;
 
-#define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE)
+        /* only append after the last 'for' generator */
+        if (gen_index >= asdl_seq_LEN(generators)) {
+               VISIT(c, expr, elt);
+               ADDOP(c, YIELD_VALUE);
+               ADDOP(c, POP_TOP);
+
+               compiler_use_next_block(c, skip);
+        }
+       for (i = 0; i < n; i++) {
+               ADDOP_I(c, JUMP_FORWARD, 1);
+                if (i == 0)
+                       compiler_use_next_block(c, if_cleanup);
+
+               ADDOP(c, POP_TOP);
+       } 
+       ADDOP_JABS(c, JUMP_ABSOLUTE, start);
+       compiler_use_next_block(c, anchor);
+       ADDOP(c, POP_BLOCK);
+       compiler_pop_fblock(c, LOOP, start);
+       compiler_use_next_block(c, end);
+
+       return 1;
+}
 
-/* Look for a yield stmt or expr under n.  Return 1 if found, else 0.
-   This hack is used to look inside "if 0:" blocks (which are normally
-   ignored) in case those are the only places a yield occurs (so that this
-   function is a generator). */
 static int
-look_for_yield(node *n)
+compiler_genexp(struct compiler *c, expr_ty e)
 {
-       int i;
-
-       for (i = 0; i < NCH(n); ++i) {
-               node *kid = CHILD(n, i);
+       PyObject *name;
+       PyCodeObject *co;
+       expr_ty outermost_iter = ((comprehension_ty)
+                                (asdl_seq_GET(e->v.GeneratorExp.generators,
+                                              0)))->iter;
 
-               switch (TYPE(kid)) {
+       name = PyString_FromString("<generator expression>");
+       if (!name)
+               return 0;
 
-               case classdef:
-               case funcdef:
-               case lambdef:
-                       /* Stuff in nested functions and classes can't make
-                          the parent a generator. */
-                       return 0;
+       if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
+               return 0;
+       compiler_genexp_generator(c, e->v.GeneratorExp.generators, 0,
+                                 e->v.GeneratorExp.elt);
+       co = assemble(c, 1);
+       if (co == NULL)
+               return 0;
+       compiler_exit_scope(c);
 
-               case yield_stmt:
-               case yield_expr:
-                       return GENERATOR;
+        compiler_make_closure(c, co, 0);
+       VISIT(c, expr, outermost_iter);
+       ADDOP(c, GET_ITER);
+       ADDOP_I(c, CALL_FUNCTION, 1);
+       Py_DECREF(name);
+       Py_DECREF(co);
 
-               default:
-                       if (look_for_yield(kid))
-                               return GENERATOR;
-               }
-       }
-       return 0;
-}                      
+       return 1;
+}
 
-static void
-symtable_node(struct symtable *st, node *n)
+static int
+compiler_visit_keyword(struct compiler *c, keyword_ty k)
 {
-       int i;
+       ADDOP_O(c, LOAD_CONST, k->arg, consts);
+       VISIT(c, expr, k->value);
+       return 1;
+}
 
- loop:
-       switch (TYPE(n)) {
-       case funcdef: {
-               char *func_name;
-               if (NCH(n) == 6)
-                       symtable_node(st, CHILD(n, 0));
-               func_name = STR(RCHILD(n, -4));
-               symtable_add_def(st, func_name, DEF_LOCAL);
-               symtable_default_args(st, RCHILD(n, -3));
-               symtable_enter_scope(st, func_name, TYPE(n), n->n_lineno);
-               symtable_funcdef(st, n);
-               symtable_exit_scope(st);
-               break;
-       }
-       case lambdef:
-               if (NCH(n) == 4)
-                       symtable_default_args(st, CHILD(n, 1));
-               symtable_enter_scope(st, "lambda", TYPE(n), n->n_lineno);
-               symtable_funcdef(st, n);
-               symtable_exit_scope(st);
-               break;
-       case classdef: {
-               char *tmp, *class_name = STR(CHILD(n, 1));
-               symtable_add_def(st, class_name, DEF_LOCAL);
-               if (TYPE(CHILD(n, 2)) == LPAR) {
-                       node *bases = CHILD(n, 3);
-                       int i;
-                       for (i = 0; i < NCH(bases); i += 2) {
-                               symtable_node(st, CHILD(bases, i));
-                       }
-               }
-               symtable_enter_scope(st, class_name, TYPE(n), n->n_lineno);
-               tmp = st->st_private;
-               st->st_private = class_name;
-               symtable_node(st, CHILD(n, NCH(n) - 1));
-               st->st_private = tmp;
-               symtable_exit_scope(st);
-               break;
-       }
-       case if_stmt:
-               for (i = 0; i + 3 < NCH(n); i += 4) {
-                       if (is_constant_false(NULL, (CHILD(n, i + 1)))) {
-                               if (st->st_cur->ste_generator == 0)
-                                       st->st_cur->ste_generator =
-                                               look_for_yield(CHILD(n, i+3));
-                               continue;
-                       }
-                       symtable_node(st, CHILD(n, i + 1));
-                       symtable_node(st, CHILD(n, i + 3));
-               }
-               if (i + 2 < NCH(n))
-                       symtable_node(st, CHILD(n, i + 2));
-               break;
-       case global_stmt:
-               symtable_global(st, n);
-               break;
-       case import_stmt:
-               symtable_import(st, n);
-               break;
-       case exec_stmt: {
-               st->st_cur->ste_optimized |= OPT_EXEC;
-               symtable_node(st, CHILD(n, 1));
-               if (NCH(n) > 2)
-                       symtable_node(st, CHILD(n, 3));
-               else {
-                       st->st_cur->ste_optimized |= OPT_BARE_EXEC;
-                       st->st_cur->ste_opt_lineno = n->n_lineno;
-               }
-               if (NCH(n) > 4)
-                       symtable_node(st, CHILD(n, 5));
-               break;
+/* Test whether expression is constant.  For constants, report
+   whether they are true or false.
+
+   Return values: 1 for true, 0 for false, -1 for non-constant.
+ */
 
+static int
+expr_constant(expr_ty e)
+{
+       switch (e->kind) {
+       case Num_kind:
+               return PyObject_IsTrue(e->v.Num.n);
+       case Str_kind:
+               return PyObject_IsTrue(e->v.Str.s);
+       default:
+               return -1;
        }
-       case assert_stmt: 
-               if (Py_OptimizeFlag)
-                       return;
-               if (NCH(n) == 2) {
-                       n = CHILD(n, 1);
-                       goto loop;
-               } else {
-                       symtable_node(st, CHILD(n, 1));
-                       n = CHILD(n, 3);
-                       goto loop;
-               }
-       case except_clause:
-               if (NCH(n) == 4)
-                       symtable_assign(st, CHILD(n, 3), 0);
-               if (NCH(n) > 1) {
-                       n = CHILD(n, 1);
-                       goto loop;
+}
+
+static int
+compiler_visit_expr(struct compiler *c, expr_ty e)
+{
+       int i, n;
+
+       if (e->lineno > c->u->u_lineno) {
+               c->u->u_lineno = e->lineno;
+               c->u->u_lineno_set = false;
+       }
+       switch (e->kind) {
+        case BoolOp_kind:
+               return compiler_boolop(c, e);
+        case BinOp_kind:
+               VISIT(c, expr, e->v.BinOp.left);
+               VISIT(c, expr, e->v.BinOp.right);
+               ADDOP(c, binop(c, e->v.BinOp.op));
+               break;
+        case UnaryOp_kind:
+               VISIT(c, expr, e->v.UnaryOp.operand);
+               ADDOP(c, unaryop(e->v.UnaryOp.op));
+               break;
+        case Lambda_kind:
+               return compiler_lambda(c, e);
+        case Dict_kind:
+               /* XXX get rid of arg? */
+               ADDOP_I(c, BUILD_MAP, 0);
+               n = asdl_seq_LEN(e->v.Dict.values);
+               /* We must arrange things just right for STORE_SUBSCR.
+                  It wants the stack to look like (value) (dict) (key) */
+               for (i = 0; i < n; i++) {
+                       ADDOP(c, DUP_TOP);
+                       VISIT(c, expr, asdl_seq_GET(e->v.Dict.values, i));
+                       ADDOP(c, ROT_TWO);
+                       VISIT(c, expr, asdl_seq_GET(e->v.Dict.keys, i));
+                       ADDOP(c, STORE_SUBSCR);
+               }
+               break;
+        case ListComp_kind:
+               return compiler_listcomp(c, e);
+        case GeneratorExp_kind:
+               return compiler_genexp(c, e);
+       case Yield_kind:
+               if (c->u->u_ste->ste_type != FunctionBlock)
+                        return compiler_error(c, "'yield' outside function");
+               /*
+               for (i = 0; i < c->u->u_nfblocks; i++) {
+                       if (c->u->u_fblock[i].fb_type == FINALLY_TRY)
+                               return compiler_error(
+                                       c, "'yield' not allowed in a 'try' "
+                                       "block with a 'finally' clause");
                }
-               break;
-       case del_stmt:
-               symtable_assign(st, CHILD(n, 1), 0);
-               break;
-       case yield_expr:
-               st->st_cur->ste_generator = 1;
-               if (NCH(n)==1) 
-                       break;
-               n = CHILD(n, 1);
-               goto loop;
-       case expr_stmt:
-               if (NCH(n) == 1)
-                       n = CHILD(n, 0);
-               else {
-                       if (TYPE(CHILD(n, 1)) == augassign) {
-                               symtable_assign(st, CHILD(n, 0), 0);
-                               symtable_node(st, CHILD(n, 2));
-                               break;
-                       } else {
-                               int i;
-                               for (i = 0; i < NCH(n) - 2; i += 2) 
-                                       symtable_assign(st, CHILD(n, i), 0);
-                               n = CHILD(n, NCH(n) - 1);
-                       }
+               */
+               if (e->v.Yield.value) {
+                       VISIT(c, expr, e->v.Yield.value);
                }
-               goto loop;
-       case list_iter:
-               /* only occurs when there are multiple for loops
-                  in a list comprehension */
-               n = CHILD(n, 0);
-               if (TYPE(n) == list_for)
-                       symtable_list_for(st, n);
                else {
-                       REQ(n, list_if);
-                       symtable_node(st, CHILD(n, 1));
-                       if (NCH(n) == 3) {
-                               n = CHILD(n, 2); 
-                               goto loop;
-                       }
+                       ADDOP_O(c, LOAD_CONST, Py_None, consts);
+               }
+               ADDOP(c, YIELD_VALUE);
+               break;
+        case Compare_kind:
+               return compiler_compare(c, e);
+        case Call_kind:
+               return compiler_call(c, e);
+        case Repr_kind:
+               VISIT(c, expr, e->v.Repr.value);
+               ADDOP(c, UNARY_CONVERT);
+               break;
+        case Num_kind:
+               ADDOP_O(c, LOAD_CONST, e->v.Num.n, consts);
+               break;
+        case Str_kind:
+               ADDOP_O(c, LOAD_CONST, e->v.Str.s, consts);
+               break;
+       /* The following exprs can be assignment targets. */
+        case Attribute_kind:
+               if (e->v.Attribute.ctx != AugStore)
+                       VISIT(c, expr, e->v.Attribute.value);
+               switch (e->v.Attribute.ctx) {
+               case AugLoad:
+                       ADDOP(c, DUP_TOP);
+                       /* Fall through to load */
+               case Load:
+                       ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names);
+                       break;
+               case AugStore:
+                       ADDOP(c, ROT_TWO);
+                       /* Fall through to save */
+               case Store:
+                       ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names);
+                       break;
+               case Del:
+                       ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names);
+                       break;
+               case Param:
+                       assert(0);
+                       break;
                }
                break;
-       case for_stmt:
-               symtable_assign(st, CHILD(n, 1), 0);
-               for (i = 3; i < NCH(n); ++i)
-                       if (TYPE(CHILD(n, i)) >= single_input)
-                               symtable_node(st, CHILD(n, i));
-               break;
-       case arglist:
-               if (NCH(n) > 1)
-                       for (i = 0; i < NCH(n); ++i) {
-                               node *ch = CHILD(n, i);
-                               if (TYPE(ch) == argument && NCH(ch) == 2 &&
-                                   TYPE(CHILD(ch, 1)) == gen_for) {
-                                       PyErr_SetString(PyExc_SyntaxError,
-                                                       "invalid syntax");
-                                       symtable_error(st, n->n_lineno);
-                                       return;
-                               }
-                       }
-       /* The remaining cases fall through to default except in
-          special circumstances.  This requires the individual cases
-          to be coded with great care, even though they look like
-          rather innocuous.  Each case must double-check TYPE(n).
-       */
-       case decorator:
-               if (TYPE(n) == decorator) {
-                       /* decorator: '@' dotted_name [ '(' [arglist] ')' ] */
-                       node *name, *varname;
-                       name = CHILD(n, 1);
-                       REQ(name, dotted_name);
-                       varname = CHILD(name, 0);
-                       REQ(varname, NAME);
-                       symtable_add_use(st, STR(varname));
-               }
-               /* fall through */
-       case argument:
-               if (TYPE(n) == argument && NCH(n) == 3) {
-                       n = CHILD(n, 2);
-                       goto loop;
-               }
-               else if (TYPE(n) == argument && NCH(n) == 2 &&
-                       TYPE(CHILD(n, 1)) == gen_for) {
-                       symtable_generator_expression(st, n);
+        case Subscript_kind:
+               switch (e->v.Subscript.ctx) {
+               case AugLoad:
+                       VISIT(c, expr, e->v.Subscript.value);
+                       VISIT_SLICE(c, e->v.Subscript.slice, AugLoad);
                        break;
-               }
-               /* fall through */
-       case listmaker:
-               if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) {
-                       symtable_list_comprehension(st, n);
+               case Load:
+                       VISIT(c, expr, e->v.Subscript.value);
+                       VISIT_SLICE(c, e->v.Subscript.slice, Load);
                        break;
-               }
-               /* fall through */
-       case testlist_gexp:
-               if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) {
-                       symtable_generator_expression(st, n); 
+               case AugStore:
+                       VISIT_SLICE(c, e->v.Subscript.slice, AugStore);
+                       break;
+               case Store:
+                       VISIT(c, expr, e->v.Subscript.value);
+                       VISIT_SLICE(c, e->v.Subscript.slice, Store);
+                       break;
+               case Del:
+                       VISIT(c, expr, e->v.Subscript.value);
+                       VISIT_SLICE(c, e->v.Subscript.slice, Del);
+                       break;
+               case Param:
+                       assert(0);
                        break;
                }
-               /* fall through */
-
-       case atom:
-               if (TYPE(n) == atom) {
-                       if (TYPE(CHILD(n, 0)) == NAME) {
-                               symtable_add_use(st, STR(CHILD(n, 0)));
-                               break;
-                       }
-                       else if (TYPE(CHILD(n,0)) == LPAR) {
-                               n = CHILD(n,1);
-                               goto loop;
-                       }
-               }
-               /* fall through */
+               break;
+        case Name_kind:
+               return compiler_nameop(c, e->v.Name.id, e->v.Name.ctx);
+       /* child nodes of List and Tuple will have expr_context set */
+        case List_kind:
+               return compiler_list(c, e);
+        case Tuple_kind:
+               return compiler_tuple(c, e);
+       }
+       return 1;
+}
+
+static int
+compiler_augassign(struct compiler *c, stmt_ty s)
+{
+       expr_ty e = s->v.AugAssign.target;
+       expr_ty auge;
+
+       assert(s->kind == AugAssign_kind);
+
+       switch (e->kind) {
+                case Attribute_kind:
+               auge = Attribute(e->v.Attribute.value, e->v.Attribute.attr,
+                                AugLoad, e->lineno);
+                if (auge == NULL)
+                    return 0;
+               VISIT(c, expr, auge);
+               VISIT(c, expr, s->v.AugAssign.value);
+               ADDOP(c, inplace_binop(c, s->v.AugAssign.op));
+               auge->v.Attribute.ctx = AugStore;
+               VISIT(c, expr, auge);
+               free(auge);
+               break;
+       case Subscript_kind:
+               auge = Subscript(e->v.Subscript.value, e->v.Subscript.slice,
+                                AugLoad, e->lineno);
+                if (auge == NULL)
+                    return 0;
+               VISIT(c, expr, auge);
+               VISIT(c, expr, s->v.AugAssign.value);
+               ADDOP(c, inplace_binop(c, s->v.AugAssign.op));
+                auge->v.Subscript.ctx = AugStore;
+               VISIT(c, expr, auge);
+               free(auge);
+                break;
+       case Name_kind:
+               VISIT(c, expr, s->v.AugAssign.target);
+               VISIT(c, expr, s->v.AugAssign.value);
+               ADDOP(c, inplace_binop(c, s->v.AugAssign.op));
+               return compiler_nameop(c, e->v.Name.id, Store);
        default:
-               /* Walk over every non-token child with a special case
-                  for one child.
-               */
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               }
-               for (i = 0; i < NCH(n); ++i)
-                       if (TYPE(CHILD(n, i)) >= single_input)
-                               symtable_node(st, CHILD(n, i));
+                fprintf(stderr, 
+                        "invalid node type for augmented assignment\n");
+                return 0;
        }
+       return 1;
 }
 
-static void
-symtable_funcdef(struct symtable *st, node *n)
+static int
+compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
 {
-       node *body;
-
-       if (TYPE(n) == lambdef) {
-               if (NCH(n) == 4)
-                       symtable_params(st, CHILD(n, 1));
-       } else
-               symtable_params(st, RCHILD(n, -3));
-       body = CHILD(n, NCH(n) - 1);
-       symtable_node(st, body);
+       struct fblockinfo *f;
+       if (c->u->u_nfblocks >= CO_MAXBLOCKS)
+               return 0;
+       f = &c->u->u_fblock[c->u->u_nfblocks++];
+       f->fb_type = t;
+       f->fb_block = b;
+       return 1;
 }
 
-/* The next two functions parse the argument tuple.
-   symtable_default_args() checks for names in the default arguments,
-   which are references in the defining scope.  symtable_params()
-   parses the parameter names, which are defined in the function's
-   body. 
+static void
+compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
+{
+       struct compiler_unit *u = c->u;
+       assert(u->u_nfblocks > 0);
+       u->u_nfblocks--;
+       assert(u->u_fblock[u->u_nfblocks].fb_type == t);
+       assert(u->u_fblock[u->u_nfblocks].fb_block == b);
+}
 
-   varargslist: 
-       (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) 
-       | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+/* Raises a SyntaxError and returns 0.
+   If something goes wrong, a different exception may be raised.
 */
 
-static void
-symtable_default_args(struct symtable *st, node *n)
+static int
+compiler_error(struct compiler *c, const char *errstr)
 {
-       node *c;
-       int i;
+       PyObject *loc;
+       PyObject *u = NULL, *v = NULL;
 
-       if (TYPE(n) == parameters) {
-               n = CHILD(n, 1);
-               if (TYPE(n) == RPAR)
-                       return;
-       }
-       REQ(n, varargslist);
-       for (i = 0; i < NCH(n); i += 2) {
-               c = CHILD(n, i);
-               if (TYPE(c) == STAR || TYPE(c) == DOUBLESTAR) {
-                       break;
-               }
-               if (i > 0 && (TYPE(CHILD(n, i - 1)) == EQUAL))
-                       symtable_node(st, CHILD(n, i));
+       loc = PyErr_ProgramText(c->c_filename, c->u->u_lineno);
+       if (!loc) {
+               Py_INCREF(Py_None);
+               loc = Py_None;
        }
+       u = Py_BuildValue("(ziOO)", c->c_filename, c->u->u_lineno,
+                         Py_None, loc);
+       if (!u)
+               goto exit;
+       v = Py_BuildValue("(zO)", errstr, u);
+       if (!v)
+               goto exit;
+       PyErr_SetObject(PyExc_SyntaxError, v);
+ exit:
+       Py_DECREF(loc);
+       Py_XDECREF(u);
+       Py_XDECREF(v);
+       return 0;
 }
 
-static void
-symtable_params(struct symtable *st, node *n)
+static int
+compiler_handle_subscr(struct compiler *c, const char *kind, 
+                       expr_context_ty ctx) 
+{
+        int op = 0;
+
+        /* XXX this code is duplicated */
+        switch (ctx) {
+                case AugLoad: /* fall through to Load */
+                case Load:    op = BINARY_SUBSCR; break;
+                case AugStore:/* fall through to Store */
+                case Store:   op = STORE_SUBSCR; break;
+                case Del:     op = DELETE_SUBSCR; break;
+                case Param:
+                        fprintf(stderr, 
+                                "invalid %s kind %d in subscript\n", 
+                                kind, ctx);
+                        return 0;
+        }
+        if (ctx == AugLoad) {
+                ADDOP_I(c, DUP_TOPX, 2);
+        }
+        else if (ctx == AugStore) {
+                ADDOP(c, ROT_THREE);
+        }
+        ADDOP(c, op);
+        return 1;
+}
+
+static int
+compiler_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
 {
-       int i, complex = -1, ext = 0;
-       node *c = NULL;
+       int n = 2;
+       assert(s->kind == Slice_kind);
 
-       if (TYPE(n) == parameters) {
-               n = CHILD(n, 1);
-               if (TYPE(n) == RPAR)
-                       return;
+       /* only handles the cases where BUILD_SLICE is emitted */
+       if (s->v.Slice.lower) {
+                VISIT(c, expr, s->v.Slice.lower);
        }
-       REQ(n, varargslist);
-       for (i = 0; i < NCH(n); i += 2) {
-               c = CHILD(n, i);
-               if (TYPE(c) == STAR || TYPE(c) == DOUBLESTAR) {
-                       ext = 1;
-                       break;
-               }
-               if (TYPE(c) == test) {
-                       continue;
-               }
-               if (TYPE(CHILD(c, 0)) == NAME)
-                       symtable_add_def(st, STR(CHILD(c, 0)), DEF_PARAM);
-               else {
-                       char nbuf[30];
-                       PyOS_snprintf(nbuf, sizeof(nbuf), ".%d", i);
-                       symtable_add_def(st, nbuf, DEF_PARAM);
-                       complex = i;
-               }
+       else {
+                ADDOP_O(c, LOAD_CONST, Py_None, consts);
        }
-       if (ext) {
-               c = CHILD(n, i);
-               if (TYPE(c) == STAR) {
-                       i++;
-                       symtable_add_def(st, STR(CHILD(n, i)), 
-                                        DEF_PARAM | DEF_STAR);
-                       i += 2;
-                       if (i >= NCH(n))
-                               c = NULL;
-                       else
-                               c = CHILD(n, i);
+                
+       if (s->v.Slice.upper) {
+                VISIT(c, expr, s->v.Slice.upper);
+       }
+       else {
+                ADDOP_O(c, LOAD_CONST, Py_None, consts);
+       }
+
+       if (s->v.Slice.step) {
+               n++;
+               VISIT(c, expr, s->v.Slice.step);
+       }
+       ADDOP_I(c, BUILD_SLICE, n);
+       return 1;
+}
+
+static int
+compiler_simple_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
+{
+       int op = 0, slice_offset = 0, stack_count = 0;
+
+       assert(s->v.Slice.step == NULL);
+       if (s->v.Slice.lower) {
+               slice_offset++;
+               stack_count++;
+               if (ctx != AugStore) 
+                       VISIT(c, expr, s->v.Slice.lower);
+       }
+       if (s->v.Slice.upper) {
+               slice_offset += 2;
+               stack_count++;
+               if (ctx != AugStore) 
+                       VISIT(c, expr, s->v.Slice.upper);
+       }
+
+       if (ctx == AugLoad) {
+               switch (stack_count) {
+               case 0: ADDOP(c, DUP_TOP); break;
+               case 1: ADDOP_I(c, DUP_TOPX, 2); break;
+               case 2: ADDOP_I(c, DUP_TOPX, 3); break;
+               }
+       }
+       else if (ctx == AugStore) {
+               switch (stack_count) {
+               case 0: ADDOP(c, ROT_TWO); break;
+               case 1: ADDOP(c, ROT_THREE); break;
+               case 2: ADDOP(c, ROT_FOUR); break;
+               }
+       }
+
+       switch (ctx) {
+       case AugLoad: /* fall through to Load */
+       case Load: op = SLICE; break;
+       case AugStore:/* fall through to Store */
+       case Store: op = STORE_SLICE; break;
+       case Del: op = DELETE_SLICE; break;
+       case Param:  /* XXX impossible? */
+               fprintf(stderr, "param invalid\n");
+               assert(0);
+       }
+
+       ADDOP(c, op + slice_offset);
+       return 1;
+}
+
+static int
+compiler_visit_nested_slice(struct compiler *c, slice_ty s, 
+                           expr_context_ty ctx)
+{
+       switch (s->kind) {
+       case Ellipsis_kind:
+               ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts);
+               break;
+       case Slice_kind:
+               return compiler_slice(c, s, ctx);
+               break;
+       case Index_kind:
+               VISIT(c, expr, s->v.Index.value);
+               break;
+       case ExtSlice_kind:
+               assert(0);
+               break;
+       }
+       return 1;
+}
+
+
+static int
+compiler_visit_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
+{
+       switch (s->kind) {
+       case Ellipsis_kind:
+               ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts);
+               break;
+       case Slice_kind:
+               if (!s->v.Slice.step) 
+                       return compiler_simple_slice(c, s, ctx);
+                if (!compiler_slice(c, s, ctx))
+                       return 0;
+               if (ctx == AugLoad) {
+                       ADDOP_I(c, DUP_TOPX, 2);
                }
-               if (c && TYPE(c) == DOUBLESTAR) {
-                       i++;
-                       symtable_add_def(st, STR(CHILD(n, i)), 
-                                        DEF_PARAM | DEF_DOUBLESTAR);
+               else if (ctx == AugStore) {
+                       ADDOP(c, ROT_THREE);
+               }
+               return compiler_handle_subscr(c, "slice", ctx);
+               break;
+       case ExtSlice_kind: {
+               int i, n = asdl_seq_LEN(s->v.ExtSlice.dims);
+               for (i = 0; i < n; i++) {
+                       slice_ty sub = asdl_seq_GET(s->v.ExtSlice.dims, i);
+                       if (!compiler_visit_nested_slice(c, sub, ctx))
+                               return 0;
                }
+               ADDOP_I(c, BUILD_TUPLE, n);
+                return compiler_handle_subscr(c, "extended slice", ctx);
+               break;
        }
-       if (complex >= 0) {
-               int j;
-               for (j = 0; j <= complex; j++) {
-                       c = CHILD(n, j);
-                       if (TYPE(c) == COMMA)
-                               c = CHILD(n, ++j);
-                       else if (TYPE(c) == EQUAL)
-                               c = CHILD(n, j += 3);
-                       if (TYPE(CHILD(c, 0)) == LPAR)
-                               symtable_params_fplist(st, CHILD(c, 1));
-               } 
+       case Index_kind:
+                if (ctx != AugStore)
+                       VISIT(c, expr, s->v.Index.value);
+                return compiler_handle_subscr(c, "index", ctx);
        }
+       return 1;
 }
 
+/* do depth-first search of basic block graph, starting with block.
+   post records the block indices in post-order.
+
+   XXX must handle implicit jumps from one block to next
+*/
+
 static void
-symtable_params_fplist(struct symtable *st, node *n)
+dfs(struct compiler *c, basicblock *b, struct assembler *a)
 {
        int i;
-       node *c;
-
-       REQ(n, fplist);
-       for (i = 0; i < NCH(n); i += 2) {
-               c = CHILD(n, i);
-               REQ(c, fpdef);
-               if (NCH(c) == 1)
-                       symtable_add_def(st, STR(CHILD(c, 0)), 
-                                        DEF_PARAM | DEF_INTUPLE);
-               else
-                       symtable_params_fplist(st, CHILD(c, 1));
+       struct instr *instr = NULL;
+
+       if (b->b_seen)
+               return;
+       b->b_seen = 1;
+       if (b->b_next != NULL)
+               dfs(c, b->b_next, a);
+       for (i = 0; i < b->b_iused; i++) {
+               instr = &b->b_instr[i];
+               if (instr->i_jrel || instr->i_jabs)
+                       dfs(c, instr->i_target, a);
        }
-       
+       a->a_postorder[a->a_nblocks++] = b;
 }
 
-static void
-symtable_global(struct symtable *st, node *n)
+int
+stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth)
 {
        int i;
-
-       /* XXX It might be helpful to warn about module-level global
-          statements, but it's hard to tell the difference between
-          module-level and a string passed to exec.
-       */
-
-       for (i = 1; i < NCH(n); i += 2) {
-               char *name = STR(CHILD(n, i));
-               int flags;
-
-               flags = symtable_lookup(st, name);
-               if (flags < 0)
-                       continue;
-               if (flags && flags != DEF_GLOBAL) {
-                       char buf[500];
-                       if (flags & DEF_PARAM) {
-                               PyErr_Format(PyExc_SyntaxError, PARAM_GLOBAL,
-                                            name);
-                               symtable_error(st, 0);
-                               return;
-                       }
-                       else {
-                               if (flags & DEF_LOCAL)
-                                       PyOS_snprintf(buf, sizeof(buf),
-                                                     GLOBAL_AFTER_ASSIGN,
-                                                     name);
-                               else
-                                       PyOS_snprintf(buf, sizeof(buf),
-                                                     GLOBAL_AFTER_USE, name);
-                               symtable_warn(st, buf);
+       struct instr *instr;
+       if (b->b_seen || b->b_startdepth >= depth)
+               return maxdepth;
+       b->b_seen = 1;
+       b->b_startdepth = depth;
+       for (i = 0; i < b->b_iused; i++) {
+               instr = &b->b_instr[i];
+               depth += opcode_stack_effect(instr->i_opcode, instr->i_oparg);
+               if (depth > maxdepth)
+                       maxdepth = depth;
+               assert(depth >= 0); /* invalid code or bug in stackdepth() */
+               if (instr->i_jrel || instr->i_jabs) {
+                       maxdepth = stackdepth_walk(c, instr->i_target,
+                                                  depth, maxdepth);
+                       if (instr->i_opcode == JUMP_ABSOLUTE ||
+                           instr->i_opcode == JUMP_FORWARD) {
+                               goto out; /* remaining code is dead */
                        }
                }
-               symtable_add_def(st, name, DEF_GLOBAL);
        }
+       if (b->b_next)
+               maxdepth = stackdepth_walk(c, b->b_next, depth, maxdepth);
+out:
+       b->b_seen = 0;
+       return maxdepth;
 }
 
-static void
-symtable_list_comprehension(struct symtable *st, node *n)
+/* Find the flow path that needs the largest stack.  We assume that
+ * cycles in the flow graph have no net effect on the stack depth.
+ */
+static int
+stackdepth(struct compiler *c)
 {
-       /* listmaker: test list_for */
-       char tmpname[30];
-
-       REQ(n, listmaker);
-       PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", 
-                     ++st->st_cur->ste_tmpname);
-       symtable_add_def(st, tmpname, DEF_LOCAL);
-       symtable_list_for(st, CHILD(n, 1));
-       symtable_node(st, CHILD(n, 0));
-       --st->st_cur->ste_tmpname;
+       basicblock *b, *entryblock;
+       entryblock = NULL;
+       for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+               b->b_seen = 0;
+               b->b_startdepth = INT_MIN;
+               entryblock = b;
+       }
+       return stackdepth_walk(c, entryblock, 0, 0);
 }
 
-static void
-symtable_generator_expression(struct symtable *st, node *n)
+static int
+assemble_init(struct assembler *a, int nblocks, int firstlineno)
 {
-       /* testlist_gexp: test gen_for */
-       REQ(CHILD(n, 0), test);
-       REQ(CHILD(n, 1), gen_for);
+       memset(a, 0, sizeof(struct assembler));
+       a->a_lineno = firstlineno;
+       a->a_bytecode = PyString_FromStringAndSize(NULL, DEFAULT_CODE_SIZE);
+       if (!a->a_bytecode)
+               return 0;
+       a->a_lnotab = PyString_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE);
+       if (!a->a_lnotab)
+               return 0;
+       a->a_postorder = (basicblock **)PyObject_Malloc(
+                                            sizeof(basicblock *) * nblocks);
+       if (!a->a_postorder)
+               return 0;
+       return 1;
+}
 
-       symtable_enter_scope(st, "<genexpr>", TYPE(n), n->n_lineno);
-       st->st_cur->ste_generator = GENERATOR_EXPRESSION;
+static void
+assemble_free(struct assembler *a)
+{
+       Py_XDECREF(a->a_bytecode);
+       Py_XDECREF(a->a_lnotab);
+       if (a->a_postorder)
+               PyObject_Free(a->a_postorder);
+}
 
-       symtable_add_def(st, "[outmost-iterable]", DEF_PARAM);
-       
-       symtable_gen_for(st, CHILD(n, 1), 1);
-       symtable_node(st, CHILD(n, 0));
-       symtable_exit_scope(st);
+/* Return the size of a basic block in bytes. */
 
-       /* for outmost iterable precomputation */
-       symtable_node(st, CHILD(CHILD(n, 1), 3)); 
+static int
+instrsize(struct instr *instr)
+{
+       int size = 1;
+       if (instr->i_hasarg) {
+               size += 2;
+               if (instr->i_oparg >> 16)
+                       size += 2;
+       }
+       return size;
 }
 
-static void
-symtable_list_for(struct symtable *st, node *n)
+static int
+blocksize(basicblock *b)
 {
-       REQ(n, list_for);
-       /* list_for: for v in expr [list_iter] */
-       symtable_assign(st, CHILD(n, 1), 0);
-       symtable_node(st, CHILD(n, 3));
-       if (NCH(n) == 5)
-               symtable_node(st, CHILD(n, 4));
+       int i;
+       int size = 0;
+
+       for (i = 0; i < b->b_iused; i++)
+               size += instrsize(&b->b_instr[i]);
+       return size;
 }
 
-static void
-symtable_gen_for(struct symtable *st, node *n, int is_outmost)
+/* All about a_lnotab.
+
+c_lnotab is an array of unsigned bytes disguised as a Python string.
+It is used to map bytecode offsets to source code line #s (when needed
+for tracebacks).
+
+The array is conceptually a list of
+    (bytecode offset increment, line number increment)
+pairs.  The details are important and delicate, best illustrated by example:
+
+    byte code offset    source code line number
+        0                  1
+        6                  2
+       50                  7
+      350                 307
+      361                 308
+
+The first trick is that these numbers aren't stored, only the increments
+from one row to the next (this doesn't really work, but it's a start):
+
+    0, 1,  6, 1,  44, 5,  300, 300,  11, 1
+
+The second trick is that an unsigned byte can't hold negative values, or
+values larger than 255, so (a) there's a deep assumption that byte code
+offsets and their corresponding line #s both increase monotonically, and (b)
+if at least one column jumps by more than 255 from one row to the next, more
+than one pair is written to the table. In case #b, there's no way to know
+from looking at the table later how many were written.  That's the delicate
+part.  A user of c_lnotab desiring to find the source line number
+corresponding to a bytecode address A should do something like this
+
+    lineno = addr = 0
+    for addr_incr, line_incr in c_lnotab:
+        addr += addr_incr
+        if addr > A:
+            return lineno
+        lineno += line_incr
+
+In order for this to work, when the addr field increments by more than 255,
+the line # increment in each pair generated must be 0 until the remaining addr
+increment is < 256.  So, in the example above, com_set_lineno should not (as
+was actually done until 2.2) expand 300, 300 to 255, 255,  45, 45, but to
+255, 0,  45, 255,  0, 45.
+*/
+
+static int
+assemble_lnotab(struct assembler *a, struct instr *i)
 {
-       REQ(n, gen_for);
+       int d_bytecode, d_lineno;
+       int len;
+       char *lnotab;
 
-       /* gen_for: for v in test [gen_iter] */
-       symtable_assign(st, CHILD(n, 1), 0);
-       if (is_outmost)
-               symtable_add_use(st, "[outmost-iterable]");
-       else
-               symtable_node(st, CHILD(n, 3));
+       d_bytecode = a->a_offset - a->a_lineno_off;
+       d_lineno = i->i_lineno - a->a_lineno;
+
+       assert(d_bytecode >= 0);
+       assert(d_lineno >= 0);
+
+       if (d_lineno == 0)
+               return 1;
+
+       if (d_bytecode > 255) {
+               int i, nbytes, ncodes = d_bytecode / 255;
+               nbytes = a->a_lnotab_off + 2 * ncodes;
+               len = PyString_GET_SIZE(a->a_lnotab);
+               if (nbytes >= len) {
+                       if (len * 2 < nbytes)
+                               len = nbytes;
+                       else
+                               len *= 2;
+                       if (_PyString_Resize(&a->a_lnotab, len) < 0)
+                               return 0;
+               }
+               lnotab = PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off;
+               for (i = 0; i < ncodes; i++) {
+                       *lnotab++ = 255;
+                       *lnotab++ = 0;
+               }
+               d_bytecode -= ncodes * 255;
+               a->a_lnotab_off += ncodes * 2;
+       }
+       assert(d_bytecode <= 255);
+       if (d_lineno > 255) {
+               int i, nbytes, ncodes = d_lineno / 255;
+               nbytes = a->a_lnotab_off + 2 * ncodes;
+               len = PyString_GET_SIZE(a->a_lnotab);
+               if (nbytes >= len) {
+                       if (len * 2 < nbytes)
+                               len = nbytes;
+                       else
+                               len *= 2;
+                       if (_PyString_Resize(&a->a_lnotab, len) < 0)
+                               return 0;
+               }
+               lnotab = PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off;
+               *lnotab++ = 255;
+               *lnotab++ = d_bytecode;
+               d_bytecode = 0;
+               for (i = 1; i < ncodes; i++) {
+                       *lnotab++ = 255;
+                       *lnotab++ = 0;
+               }
+               d_lineno -= ncodes * 255;
+               a->a_lnotab_off += ncodes * 2;
+       }
 
-       if (NCH(n) == 5)
-               symtable_gen_iter(st, CHILD(n, 4));
+       len = PyString_GET_SIZE(a->a_lnotab);
+       if (a->a_lnotab_off + 2 >= len) {
+               if (_PyString_Resize(&a->a_lnotab, len * 2) < 0)
+                       return 0;
+       }
+       lnotab = PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off;
+
+       a->a_lnotab_off += 2;
+       if (d_bytecode) {
+               *lnotab++ = d_bytecode;
+               *lnotab++ = d_lineno;
+       }
+       else {  /* First line of a block; def stmt, etc. */
+               *lnotab++ = 0;
+               *lnotab++ = d_lineno;
+       }
+       a->a_lineno = i->i_lineno;
+       a->a_lineno_off = a->a_offset;
+       return 1;
 }
 
-static void
-symtable_gen_iter(struct symtable *st, node *n)
+/* assemble_emit()
+   Extend the bytecode with a new instruction.
+   Update lnotab if necessary.
+*/
+
+static int
+assemble_emit(struct assembler *a, struct instr *i)
 {
-       REQ(n, gen_iter);
+       int arg = 0, size = 0, ext = i->i_oparg >> 16;
+       int len = PyString_GET_SIZE(a->a_bytecode);
+       char *code;
 
-       n = CHILD(n, 0);
-       if (TYPE(n) == gen_for)
-               symtable_gen_for(st, n, 0);
+       if (!i->i_hasarg)
+               size = 1;
        else {
-               REQ(n, gen_if);
-               symtable_node(st, CHILD(n, 1));
-
-               if (NCH(n) == 3)
-                       symtable_gen_iter(st, CHILD(n, 2));
+               if (ext)
+                       size = 6;
+               else
+                       size = 3;
+               arg = i->i_oparg;
        }
+       if (i->i_lineno && !assemble_lnotab(a, i))
+                       return 0;
+       if (a->a_offset + size >= len) {
+               if (_PyString_Resize(&a->a_bytecode, len * 2) < 0)
+                   return 0;
+       }
+       code = PyString_AS_STRING(a->a_bytecode) + a->a_offset;
+       a->a_offset += size;
+       if (ext > 0) {
+           *code++ = (char)EXTENDED_ARG;
+           *code++ = ext & 0xff;
+           *code++ = ext >> 8;
+           arg &= 0xffff;
+       }
+       *code++ = i->i_opcode;
+       if (size == 1)
+               return 1;
+       *code++ = arg & 0xff;
+       *code++ = arg >> 8;
+       return 1;
 }
 
-static void
-symtable_import(struct symtable *st, node *n)
+static int
+assemble_jump_offsets(struct assembler *a, struct compiler *c)
 {
-       node *nn;
+       basicblock *b;
+       int bsize, totsize = 0;
        int i;
-       /* import_stmt: import_name | import_from */
-       n = CHILD(n, 0);
-       if (TYPE(n) == import_from) {
-               /* import_from: 'from' dotted_name 'import' ('*' |
-                    | '(' import_as_names ')' | import_as_names) */
-               node *dotname = CHILD(n, 1);
-               REQ(dotname, dotted_name);
-               if (strcmp(STR(CHILD(dotname, 0)), "__future__") == 0) {
-                       /* check for bogus imports */
-                       if (n->n_lineno >= st->st_future->ff_last_lineno) {
-                               PyErr_SetString(PyExc_SyntaxError,
-                                               LATE_FUTURE);
-                               symtable_error(st, n->n_lineno);
-                               return;
-                       }
-               }
-               nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR));
-               if (TYPE(nn) == STAR) {
-                       if (st->st_cur->ste_type != TYPE_MODULE) {
-                               if (symtable_warn(st,
-                                 "import * only allowed at module level") < 0)
-                                       return;
-                       }
-                       st->st_cur->ste_optimized |= OPT_IMPORT_STAR;
-                       st->st_cur->ste_opt_lineno = n->n_lineno;
-               } else {
-                       REQ(nn, import_as_names);
-                       for (i = 0; i < NCH(nn); i += 2) {
-                               node *c = CHILD(nn, i);
-                               if (NCH(c) > 1) /* import as */
-                                       symtable_assign(st, CHILD(c, 2),
-                                                       DEF_IMPORT);
-                               else
-                                       symtable_assign(st, CHILD(c, 0),
-                                                       DEF_IMPORT);
+
+       /* Compute the size of each block and fixup jump args.
+          Replace block pointer with position in bytecode. */
+       for (i = a->a_nblocks - 1; i >= 0; i--) {
+               basicblock *b = a->a_postorder[i];
+               bsize = blocksize(b);
+               b->b_offset = totsize;
+               totsize += bsize;
+       }
+       for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+               bsize = b->b_offset;
+               for (i = 0; i < b->b_iused; i++) {
+                       struct instr *instr = &b->b_instr[i];
+                       /* Relative jumps are computed relative to
+                          the instruction pointer after fetching
+                          the jump instruction.
+                       */
+                       bsize += instrsize(instr);
+                       if (instr->i_jabs)
+                               instr->i_oparg = instr->i_target->b_offset;
+                       else if (instr->i_jrel) {
+                               int delta = instr->i_target->b_offset - bsize;
+                               instr->i_oparg = delta;
                        }
                }
-       } else {
-               /* 'import' dotted_as_names */
-               nn = CHILD(n, 1);
-               REQ(nn, dotted_as_names);
-               for (i = 0; i < NCH(nn); i += 2)
-                       symtable_assign(st, CHILD(nn, i), DEF_IMPORT);
        }
+       return 1;
 }
 
-/* The third argument to symatble_assign() is a flag to be passed to
-   symtable_add_def() if it is eventually called.  The flag is useful
-   to specify the particular type of assignment that should be
-   recorded, e.g. an assignment caused by import.
- */
+static PyObject *
+dict_keys_inorder(PyObject *dict, int offset)
+{
+       PyObject *tuple, *k, *v;
+       int i, pos = 0, size = PyDict_Size(dict);
+
+       tuple = PyTuple_New(size);
+       if (tuple == NULL)
+               return NULL;
+       while (PyDict_Next(dict, &pos, &k, &v)) {
+               i = PyInt_AS_LONG(v);
+                k = PyTuple_GET_ITEM(k, 0);
+               Py_INCREF(k);
+               assert((i - offset) < size);
+                assert((i - offset) >= 0);
+               PyTuple_SET_ITEM(tuple, i - offset, k);
+       }
+       return tuple;
+}
+
+static int
+compute_code_flags(struct compiler *c)
+{
+       PySTEntryObject *ste = c->u->u_ste;
+       int flags = 0, n;
+       if (ste->ste_type != ModuleBlock)
+               flags |= CO_NEWLOCALS;
+       if (ste->ste_type == FunctionBlock) {
+               if (!ste->ste_unoptimized)
+                       flags |= CO_OPTIMIZED;
+               if (ste->ste_nested)
+                       flags |= CO_NESTED;
+               if (ste->ste_generator)
+                       flags |= CO_GENERATOR;
+       }
+       if (ste->ste_varargs)
+               flags |= CO_VARARGS;
+       if (ste->ste_varkeywords)
+               flags |= CO_VARKEYWORDS;
+       if (ste->ste_generator)
+               flags |= CO_GENERATOR;
+        if (c->c_flags->cf_flags & CO_FUTURE_DIVISION)
+                flags |= CO_FUTURE_DIVISION;
+       n = PyDict_Size(c->u->u_freevars);
+       if (n < 0)
+           return -1;
+       if (n == 0) {
+           n = PyDict_Size(c->u->u_cellvars);
+           if (n < 0)
+               return -1;
+           if (n == 0) {
+               flags |= CO_NOFREE;
+           }
+       }
+
+       return flags;
+}
+
+static PyCodeObject *
+makecode(struct compiler *c, struct assembler *a)
+{
+       PyObject *tmp;
+       PyCodeObject *co = NULL;
+       PyObject *consts = NULL;
+       PyObject *names = NULL;
+       PyObject *varnames = NULL;
+       PyObject *filename = NULL;
+       PyObject *name = NULL;
+       PyObject *freevars = NULL;
+       PyObject *cellvars = NULL;
+        PyObject *bytecode = NULL;
+       int nlocals, flags;
+
+       tmp = dict_keys_inorder(c->u->u_consts, 0);
+       if (!tmp)
+               goto error;
+       consts = PySequence_List(tmp); /* optimize_code requires a list */
+       Py_DECREF(tmp);
+
+       names = dict_keys_inorder(c->u->u_names, 0);
+       varnames = dict_keys_inorder(c->u->u_varnames, 0);
+       if (!consts || !names || !varnames)
+               goto error;
+      
+        cellvars = dict_keys_inorder(c->u->u_cellvars, 0);
+        if (!cellvars)
+            goto error;
+        freevars = dict_keys_inorder(c->u->u_freevars, PyTuple_Size(cellvars));
+        if (!freevars)
+            goto error;
+       filename = PyString_FromString(c->c_filename);
+       if (!filename)
+               goto error;
+
+        nlocals = PyDict_Size(c->u->u_varnames);
+       flags = compute_code_flags(c);
+       if (flags < 0)
+               goto error;
+
+       bytecode = optimize_code(a->a_bytecode, consts, names, a->a_lnotab);
+       if (!bytecode)
+               goto error;
+
+       tmp = PyList_AsTuple(consts); /* PyCode_New requires a tuple */
+       if (!tmp)
+               goto error;
+       Py_DECREF(consts);
+       consts = tmp;
+
+       co = PyCode_New(c->u->u_argcount, nlocals, stackdepth(c), flags,
+                       bytecode, consts, names, varnames,
+                       freevars, cellvars,
+                       filename, c->u->u_name,
+                       c->u->u_firstlineno,
+                       a->a_lnotab);
+ error:
+       Py_XDECREF(consts);
+       Py_XDECREF(names);
+       Py_XDECREF(varnames);
+       Py_XDECREF(filename);
+       Py_XDECREF(name);
+       Py_XDECREF(freevars);
+       Py_XDECREF(cellvars);
+       Py_XDECREF(bytecode);
+       return co;
+}
 
-static void 
-symtable_assign(struct symtable *st, node *n, int def_flag)
+static PyCodeObject *
+assemble(struct compiler *c, int addNone)
 {
-       node *tmp;
-       int i;
+       basicblock *b, *entryblock;
+       struct assembler a;
+       int i, j, nblocks;
+       PyCodeObject *co = NULL;
 
- loop:
-       switch (TYPE(n)) {
-       case lambdef:
-               /* invalid assignment, e.g. lambda x:x=2.  The next
-                  pass will catch this error. */
-               return;
-       case power:
-               if (NCH(n) > 2) {
-                       for (i = 2; i < NCH(n); ++i)
-                               if (TYPE(CHILD(n, i)) != DOUBLESTAR)
-                                       symtable_node(st, CHILD(n, i));
-               }
-               if (NCH(n) > 1) { 
-                       symtable_node(st, CHILD(n, 0));
-                       symtable_node(st, CHILD(n, 1));
-               } else {
-                       n = CHILD(n, 0);
-                       goto loop;
-               }
-               return;
-       case listmaker:
-               if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) {
-                       /* XXX This is an error, but the next pass
-                          will catch it. */ 
-                       return;
-               } else {
-                       for (i = 0; i < NCH(n); i += 2)
-                               symtable_assign(st, CHILD(n, i), def_flag);
-               }
-               return;
-       case testlist_gexp:
-               if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) {
-                       /* XXX This is an error, but the next pass
-                          will catch it. */ 
-                       return;
-               } else {
-                       for (i = 0; i < NCH(n); i += 2)
-                               symtable_assign(st, CHILD(n, i), def_flag);
-               }
-               return;
+       /* Make sure every block that falls off the end returns None.
+          XXX NEXT_BLOCK() isn't quite right, because if the last
+          block ends with a jump or return b_next shouldn't set.
+        */
+       if (!c->u->u_curblock->b_return) {
+               NEXT_BLOCK(c);
+               if (addNone)
+                       ADDOP_O(c, LOAD_CONST, Py_None, consts);
+               ADDOP(c, RETURN_VALUE);
+       }
 
-       case exprlist:
-       case testlist:
-       case testlist1:
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               }
-               else {
-                       int i;
-                       for (i = 0; i < NCH(n); i += 2)
-                               symtable_assign(st, CHILD(n, i), def_flag);
-                       return;
-               }
-       case atom:
-               tmp = CHILD(n, 0);
-               if (TYPE(tmp) == LPAR || TYPE(tmp) == LSQB) {
-                       n = CHILD(n, 1);
-                       goto loop;
-               } else if (TYPE(tmp) == NAME) {
-                       if (strcmp(STR(tmp), "__debug__") == 0) {
-                               PyErr_SetString(PyExc_SyntaxError, 
-                                               ASSIGN_DEBUG);
-                               symtable_error(st, n->n_lineno);
-                               return;
-                       }
-                       symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag);
-               }
-               return;
+       nblocks = 0;
+       entryblock = NULL;
+       for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+               nblocks++;
+               entryblock = b; 
+       }
 
-       case yield_expr:
-               st->st_cur->ste_generator = 1;
-               if (NCH(n)==2) {
-                       n = CHILD(n, 1);
-                       goto loop;
-               }
-               return;
+       if (!assemble_init(&a, nblocks, c->u->u_firstlineno))
+               goto error;
+       dfs(c, entryblock, &a);
 
-       case dotted_as_name:
-               if (NCH(n) == 3)
-                       symtable_add_def(st, STR(CHILD(n, 2)),
-                                        DEF_LOCAL | def_flag);
-               else
-                       symtable_add_def(st,
-                                        STR(CHILD(CHILD(n,
-                                                        0), 0)),
-                                        DEF_LOCAL | def_flag);
-               return;
-       case dotted_name:
-               symtable_add_def(st, STR(CHILD(n, 0)), DEF_LOCAL | def_flag);
-               return;
-       case NAME:
-               symtable_add_def(st, STR(n), DEF_LOCAL | def_flag);
-               return;
-       default:
-               if (NCH(n) == 0)
-                       return;
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               }
-               /* Should only occur for errors like x + 1 = 1,
-                  which will be caught in the next pass. */
-               for (i = 0; i < NCH(n); ++i)
-                       if (TYPE(CHILD(n, i)) >= single_input)
-                               symtable_assign(st, CHILD(n, i), def_flag);
+       /* Can't modify the bytecode after computing jump offsets. */
+       if (!assemble_jump_offsets(&a, c))
+               goto error;
+
+       /* Emit code in reverse postorder from dfs. */
+       for (i = a.a_nblocks - 1; i >= 0; i--) {
+               basicblock *b = a.a_postorder[i];
+               for (j = 0; j < b->b_iused; j++)
+                       if (!assemble_emit(&a, &b->b_instr[j]))
+                               goto error;
        }
+
+       if (_PyString_Resize(&a.a_lnotab, a.a_lnotab_off) < 0)
+               goto error;
+       if (_PyString_Resize(&a.a_bytecode, a.a_offset) < 0)
+               goto error;
+
+       co = makecode(c, &a);
+ error:
+       assemble_free(&a);
+       return co;
 }
index 95d6a5c9a3224b539cbc976fcaf1f05d95fd1f42..a0cfeac63ae748dffdaed78efa87a0ee2f6c778e 100644 (file)
@@ -1,37 +1,30 @@
 #include "Python.h"
+#include "Python-ast.h"
 #include "node.h"
 #include "token.h"
 #include "graminit.h"
+#include "code.h"
 #include "compile.h"
 #include "symtable.h"
 
 #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
 #define FUTURE_IMPORT_STAR "future statement does not support import *"
 
-/* FUTURE_POSSIBLE() is provided to accomodate doc strings, which is
-   the only statement that can occur before a future statement.
-*/
-#define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
-
 static int
-future_check_features(PyFutureFeatures *ff, node *n, const char *filename)
+future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
 {
        int i;
-       char *feature;
-       node *ch, *nn;
+       const char *feature;
+       asdl_seq *names;
 
-       REQ(n, import_from);
-       nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR));
-       if (TYPE(nn) == STAR) {
-               PyErr_SetString(PyExc_SyntaxError, FUTURE_IMPORT_STAR);
-               PyErr_SyntaxLocation(filename, nn->n_lineno);
-               return -1;
-       }
-       REQ(nn, import_as_names);
-       for (i = 0; i < NCH(nn); i += 2) {
-               ch = CHILD(nn, i);
-               REQ(ch, import_as_name);
-               feature = STR(CHILD(ch, 0));
+       assert(s->kind == ImportFrom_kind);
+
+       names = s->v.ImportFrom.names;
+       for (i = 0; i < asdl_seq_LEN(names); i++) {
+                alias_ty name = asdl_seq_GET(names, i);
+               feature = PyString_AsString(name->name);
+               if (!feature)
+                       return 0;
                if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
                        continue;
                } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
@@ -41,218 +34,97 @@ future_check_features(PyFutureFeatures *ff, node *n, const char *filename)
                } else if (strcmp(feature, "braces") == 0) {
                        PyErr_SetString(PyExc_SyntaxError,
                                        "not a chance");
-                       PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
-                       return -1;
+                       PyErr_SyntaxLocation(filename, s->lineno);
+                       return 0;
                } else {
                        PyErr_Format(PyExc_SyntaxError,
                                     UNDEFINED_FUTURE_FEATURE, feature);
-                       PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
-                       return -1;
+                       PyErr_SyntaxLocation(filename, s->lineno);
+                       return 0;
                }
        }
-       return 0;
+       return 1;
 }
 
-static void
-future_error(node *n, const char *filename)
+int
+future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
 {
-       PyErr_SetString(PyExc_SyntaxError,
-                       "from __future__ imports must occur at the "
-                       "beginning of the file");
-       PyErr_SyntaxLocation(filename, n->n_lineno);
-}
-
-/* Relevant portions of the grammar:
-
-single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
-file_input: (NEWLINE | stmt)* ENDMARKER
-stmt: simple_stmt | compound_stmt
-simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
-small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt 
-    | import_stmt | global_stmt | exec_stmt | assert_stmt
-import_stmt: 'import' dotted_as_name (',' dotted_as_name)* 
-    | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
-import_as_name: NAME [NAME NAME]
-dotted_as_name: dotted_name [NAME NAME]
-dotted_name: NAME ('.' NAME)*
-*/
-
-/* future_parse() finds future statements at the beginnning of a
-   module.  The function calls itself recursively, rather than
-   factoring out logic for different kinds of statements into
-   different routines.
-
-   Return values:
-   -1 indicates an error occurred, e.g. unknown feature name
-   0 indicates no feature was found
-   1 indicates a feature was found
-*/
+       int i, found_docstring = 0, done = 0, prev_line = 0;
 
-static int
-future_parse(PyFutureFeatures *ff, node *n, const char *filename)
-{
-       int i, r;
- loop:
-       switch (TYPE(n)) {
+       static PyObject *future;
+       if (!future) {
+               future = PyString_InternFromString("__future__");
+               if (!future)
+                       return 0;
+       }
 
-       case single_input:
-               if (TYPE(CHILD(n, 0)) == simple_stmt) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               }
-               return 0;
+       if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
+               return 1;
 
-       case file_input:
-               /* Check each statement in the file, starting with the
-                  first, and continuing until the first statement
-                  that isn't a future statement.
+       /* A subsequent pass will detect future imports that don't
+          appear at the beginning of the file.  There's one case,
+          however, that is easier to handl here: A series of imports
+          joined by semi-colons, where the first import is a future
+          statement but some subsequent import has the future form
+          but is preceded by a regular import.
+       */
+          
+
+       for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) {
+               stmt_ty s = asdl_seq_GET(mod->v.Module.body, i);
+
+               if (done && s->lineno > prev_line)
+                       return 1;
+               prev_line = s->lineno;
+
+               /* The tests below will return from this function unless it is
+                  still possible to find a future statement.  The only things
+                  that can precede a future statement are another future
+                  statement and a doc string.
                */
-               for (i = 0; i < NCH(n); i++) {
-                       node *ch = CHILD(n, i);
-                       if (TYPE(ch) == stmt) {
-                               r = future_parse(ff, ch, filename);
-                               /* Need to check both conditions below
-                                  to accomodate doc strings, which
-                                  causes r < 0.
-                               */
-                               if (r < 1 && !FUTURE_POSSIBLE(ff))
-                                       return r;
-                       }
-               }
-               return 0;
-
-       case simple_stmt:
-               if (NCH(n) == 2) {
-                       REQ(CHILD(n, 0), small_stmt);
-                       n = CHILD(n, 0);
-                       goto loop;
-               } else {
-                       /* Deal with the special case of a series of
-                          small statements on a single line.  If a
-                          future statement follows some other
-                          statement, the SyntaxError is raised here.
-                          In all other cases, the symtable pass
-                          raises the exception.
-                       */
-                       int found = 0, end_of_future = 0;
 
-                       for (i = 0; i < NCH(n); i += 2) {
-                               if (TYPE(CHILD(n, i)) == small_stmt) {
-                                       r = future_parse(ff, CHILD(n, i), 
-                                                        filename);
-                                       if (r < 1)
-                                               end_of_future = 1;
-                                       else {
-                                               found = 1;
-                                               if (end_of_future) {
-                                                       future_error(n, 
-                                                                    filename);
-                                                       return -1;
-                                               }
-                                       }
+               if (s->kind == ImportFrom_kind) {
+                       if (s->v.ImportFrom.module == future) {
+                               if (done) {
+                                       PyErr_SetString(PyExc_SyntaxError,
+                                                       ERR_LATE_FUTURE);
+                                       PyErr_SyntaxLocation(filename, 
+                                                            s->lineno);
+                                       return 0;
                                }
+                               if (!future_check_features(ff, s, filename))
+                                       return 0;
+                               ff->ff_lineno = s->lineno;
                        }
-
-                       /* If we found one and only one, then the
-                          current lineno is legal. 
-                       */
-                       if (found)
-                               ff->ff_last_lineno = n->n_lineno + 1;
                        else
-                               ff->ff_last_lineno = n->n_lineno;
-
-                       if (end_of_future && found)
-                               return 1;
-                       else 
-                               return 0;
-               }
-       
-       case stmt:
-               if (TYPE(CHILD(n, 0)) == simple_stmt) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               } else if (TYPE(CHILD(n, 0)) == expr_stmt) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               } else {
-                       REQ(CHILD(n, 0), compound_stmt);
-                       ff->ff_last_lineno = n->n_lineno;
-                       return 0;
-               }
-
-       case small_stmt:
-               n = CHILD(n, 0);
-               goto loop;
-
-       case import_stmt: {
-               node *name;
-
-               n = CHILD(n, 0);
-               if (TYPE(n) != import_from) {
-                       ff->ff_last_lineno = n->n_lineno;
-                       return 0;
+                               done = 1;
                }
-               name = CHILD(n, 1);
-               if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
-                       return 0;
-               if (future_check_features(ff, n, filename) < 0)
-                       return -1;
-               ff->ff_last_lineno = n->n_lineno + 1;
-               return 1;
-       }
-
-       /* The cases below -- all of them! -- are necessary to find
-          and skip doc strings. */
-       case expr_stmt:
-       case testlist:
-       case test:
-       case and_test:
-       case not_test:
-       case comparison:
-       case expr:
-       case xor_expr:
-       case and_expr:
-       case shift_expr:
-       case arith_expr:
-       case term:
-       case factor:
-       case power:
-               if (NCH(n) == 1) {
-                       n = CHILD(n, 0);
-                       goto loop;
-               }
-                ff->ff_last_lineno = n->n_lineno;
-               break;
-
-       case atom:
-               if (TYPE(CHILD(n, 0)) == STRING 
-                   && ff->ff_found_docstring == 0) {
-                       ff->ff_found_docstring = 1;
-                       return 0;
+               else if (s->kind == Expr_kind && !found_docstring) {
+                       expr_ty e = s->v.Expr.value;
+                       if (e->kind != Str_kind)
+                               done = 1;
+                       else
+                               found_docstring = 1;
                }
-               ff->ff_last_lineno = n->n_lineno;
-               return 0;
-
-       default:
-               ff->ff_last_lineno = n->n_lineno;
-               return 0;
+               else
+                       done = 1;
        }
-       return 0;
+       return 1;
 }
 
+
 PyFutureFeatures *
-PyNode_Future(node *n, const char *filename)
+PyFuture_FromAST(mod_ty mod, const char *filename)
 {
        PyFutureFeatures *ff;
 
        ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
        if (ff == NULL)
                return NULL;
-       ff->ff_found_docstring = 0;
-       ff->ff_last_lineno = -1;
        ff->ff_features = 0;
+       ff->ff_lineno = -1;
 
-       if (future_parse(ff, n, filename) < 0) {
+       if (!future_parse(ff, mod, filename)) {
                PyMem_Free((void *)ff);
                return NULL;
        }
index 35de13e5f9b8bb605b986155f0db36aee49157c7..dcbca38e974cb1e166483e4198b7c66794f2bd3f 100644 (file)
@@ -3,10 +3,11 @@
 
 #include "Python.h"
 
-#include "node.h"
-#include "token.h"
+#include "Python-ast.h"
+#include "pythonrun.h"
 #include "errcode.h"
 #include "marshal.h"
+#include "code.h"
 #include "compile.h"
 #include "eval.h"
 #include "osdefs.h"
@@ -766,17 +767,17 @@ load_compiled_module(char *name, char *cpathname, FILE *fp)
 /* Parse a source file and return the corresponding code object */
 
 static PyCodeObject *
-parse_source_module(char *pathname, FILE *fp)
+parse_source_module(const char *pathname, FILE *fp)
 {
-       PyCodeObject *co;
-       node *n;
-
-       n = PyParser_SimpleParseFile(fp, pathname, Py_file_input);
-       if (n == NULL)
-               return NULL;
-       co = PyNode_Compile(n, pathname);
-       PyNode_Free(n);
+       PyCodeObject *co = NULL;
+       mod_ty mod;
 
+       mod = PyParser_ASTFromFile(fp, pathname, Py_file_input, 0, 0, 0, 
+                                  NULL);
+       if (mod) {
+               co = PyAST_Compile(mod, pathname, NULL);
+               free_mod(mod);
+       }
        return co;
 }
 
index 20d637d2b2c1392ade775d9d478bc5434ab173b2..4114c8edc3fb289cebeb04645c2f34d78f063451 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "Python.h"
 #include "longintrepr.h"
+#include "code.h"
 #include "compile.h"
 #include "marshal.h"
 
index e007f98a9bfb3954553f2f08b1775fa95e576312..ad837d28f628f940efcdadb34dc0def26abad2fa 100644 (file)
@@ -3,13 +3,16 @@
 
 #include "Python.h"
 
+#include "Python-ast.h"
 #include "grammar.h"
 #include "node.h"
 #include "token.h"
 #include "parsetok.h"
 #include "errcode.h"
+#include "code.h"
 #include "compile.h"
 #include "symtable.h"
+#include "ast.h"
 #include "eval.h"
 #include "marshal.h"
 
@@ -32,9 +35,9 @@ extern grammar _PyParser_Grammar; /* From graminit.c */
 /* Forward */
 static void initmain(void);
 static void initsite(void);
-static PyObject *run_err_node(node *, const char *, PyObject *, PyObject *,
+static PyObject *run_err_mod(mod_ty, const char *, PyObject *, PyObject *,
                              PyCompilerFlags *);
-static PyObject *run_node(node *, const char *, PyObject *, PyObject *,
+static PyObject *run_mod(mod_ty, const char *, PyObject *, PyObject *,
                          PyCompilerFlags *);
 static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *,
                              PyCompilerFlags *);
@@ -634,25 +637,7 @@ initsite(void)
 /* Parse input from a file and execute it */
 
 int
-PyRun_AnyFile(FILE *fp, const char *filename)
-{
-       return PyRun_AnyFileExFlags(fp, filename, 0, NULL);
-}
-
-int
-PyRun_AnyFileFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
-{
-       return PyRun_AnyFileExFlags(fp, filename, 0, flags);
-}
-
-int
-PyRun_AnyFileEx(FILE *fp, const char *filename, int closeit)
-{
-       return PyRun_AnyFileExFlags(fp, filename, closeit, NULL);
-}
-
-int
-PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
+PyRun_AnyFileExFlags(FILE *fp, char *filename, int closeit, 
                     PyCompilerFlags *flags)
 {
        if (filename == NULL)
@@ -667,12 +652,6 @@ PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
                return PyRun_SimpleFileExFlags(fp, filename, closeit, flags);
 }
 
-int
-PyRun_InteractiveLoop(FILE *fp, const char *filename)
-{
-       return PyRun_InteractiveLoopFlags(fp, filename, NULL);
-}
-
 int
 PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
 {
@@ -708,12 +687,6 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag
        }
 }
 
-int
-PyRun_InteractiveOne(FILE *fp, const char *filename)
-{
-       return PyRun_InteractiveOneFlags(fp, filename, NULL);
-}
-
 /* compute parser flags based on compiler flags */
 #define PARSER_FLAGS(flags) \
        (((flags) && (flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \
@@ -723,9 +696,9 @@ int
 PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
 {
        PyObject *m, *d, *v, *w;
-       node *n;
-       perrdetail err;
+       mod_ty mod;
        char *ps1 = "", *ps2 = "";
+       int errcode = 0;
 
        v = PySys_GetObject("ps1");
        if (v != NULL) {
@@ -743,26 +716,25 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags
                else if (PyString_Check(w))
                        ps2 = PyString_AsString(w);
        }
-       n = PyParser_ParseFileFlags(fp, filename, &_PyParser_Grammar,
-                                   Py_single_input, ps1, ps2, &err,
-                                   PARSER_FLAGS(flags));
+       mod = PyParser_ASTFromFile(fp, filename, 
+                                  Py_single_input, ps1, ps2,
+                                  flags, &errcode);
        Py_XDECREF(v);
        Py_XDECREF(w);
-       if (n == NULL) {
-               if (err.error == E_EOF) {
-                       if (err.text)
-                               PyMem_DEL(err.text);
+       if (mod == NULL) {
+               if (errcode == E_EOF) {
+                       PyErr_Clear();
                        return E_EOF;
                }
-               err_input(&err);
                PyErr_Print();
-               return err.error;
+               return -1;
        }
        m = PyImport_AddModule("__main__");
        if (m == NULL)
                return -1;
        d = PyModule_GetDict(m);
-       v = run_node(n, filename, d, d, flags);
+       v = run_mod(mod, filename, d, d, flags);
+       free_mod(mod);
        if (v == NULL) {
                PyErr_Print();
                return -1;
@@ -773,12 +745,6 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags
        return 0;
 }
 
-int
-PyRun_SimpleFile(FILE *fp, const char *filename)
-{
-       return PyRun_SimpleFileEx(fp, filename, 0);
-}
-
 /* Check whether a file maybe a pyc file: Look at the extension,
    the file type, and, if we may close it, at the first few bytes. */
 
@@ -819,12 +785,6 @@ maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit)
        return 0;
 }
 
-int
-PyRun_SimpleFileEx(FILE *fp, const char *filename, int closeit)
-{
-       return PyRun_SimpleFileExFlags(fp, filename, closeit, NULL);
-}
-
 int
 PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
                        PyCompilerFlags *flags)
@@ -873,12 +833,6 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
        return 0;
 }
 
-int
-PyRun_SimpleString(const char *command)
-{
-       return PyRun_SimpleStringFlags(command, NULL);
-}
-
 int
 PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
 {
@@ -1054,6 +1008,8 @@ PyErr_PrintEx(int set_sys_last_vars)
                handle_system_exit();
        }
        PyErr_Fetch(&exception, &v, &tb);
+       if (exception == NULL)
+               return;
        PyErr_NormalizeException(&exception, &v, &tb);
        if (exception == NULL)
                return;
@@ -1195,74 +1151,48 @@ void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
 }
 
 PyObject *
-PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
-{
-       return run_err_node(PyParser_SimpleParseString(str, start),
-                           "<string>", globals, locals, NULL);
-}
-
-PyObject *
-PyRun_File(FILE *fp, const char *filename, int start, PyObject *globals,
-          PyObject *locals)
+PyRun_StringFlags(const char *str, int start, PyObject *globals, 
+                 PyObject *locals, PyCompilerFlags *flags)
 {
-       return PyRun_FileEx(fp, filename, start, globals, locals, 0);
-}
-
-PyObject *
-PyRun_FileEx(FILE *fp, const char *filename, int start, PyObject *globals,
-            PyObject *locals, int closeit)
-{
-       node *n = PyParser_SimpleParseFile(fp, filename, start);
-       if (closeit)
-               fclose(fp);
-       return run_err_node(n, filename, globals, locals, NULL);
-}
-
-PyObject *
-PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals,
-                 PyCompilerFlags *flags)
-{
-       return run_err_node(PyParser_SimpleParseStringFlags(
-                                   str, start, PARSER_FLAGS(flags)),
-                           "<string>", globals, locals, flags);
-}
-
-PyObject *
-PyRun_FileFlags(FILE *fp, const char *filename, int start, PyObject *globals,
-               PyObject *locals, PyCompilerFlags *flags)
-{
-       return PyRun_FileExFlags(fp, filename, start, globals, locals, 0,
-                                flags);
+       PyObject *ret;
+       mod_ty mod = PyParser_ASTFromString(str, "<string>", start, flags);
+       ret = run_err_mod(mod, "<string>", globals, locals, flags);
+       free_mod(mod);
+       return ret;
 }
 
 PyObject *
 PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals,
                  PyObject *locals, int closeit, PyCompilerFlags *flags)
 {
-       node *n = PyParser_SimpleParseFileFlags(fp, filename, start,
-                                               PARSER_FLAGS(flags));
+       PyObject *ret;
+       mod_ty mod = PyParser_ASTFromFile(fp, filename, start, 0, 0,
+                                         flags, NULL);
+       if (mod == NULL)
+               return NULL;
        if (closeit)
                fclose(fp);
-       return run_err_node(n, filename, globals, locals, flags);
+       ret = run_err_mod(mod, filename, globals, locals, flags);
+       free_mod(mod);
+       return ret;
 }
 
 static PyObject *
-run_err_node(node *n, const char *filename, PyObject *globals, PyObject *locals,
-            PyCompilerFlags *flags)
+run_err_mod(mod_ty mod, const char *filename, PyObject *globals, 
+           PyObject *locals, PyCompilerFlags *flags)
 {
-       if (n == NULL)
+       if (mod == NULL)
                return  NULL;
-       return run_node(n, filename, globals, locals, flags);
+       return run_mod(mod, filename, globals, locals, flags);
 }
 
 static PyObject *
-run_node(node *n, const char *filename, PyObject *globals, PyObject *locals,
+run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals,
         PyCompilerFlags *flags)
 {
        PyCodeObject *co;
        PyObject *v;
-       co = PyNode_CompileFlags(n, filename, flags);
-       PyNode_Free(n);
+       co = PyAST_Compile(mod, filename, flags);
        if (co == NULL)
                return NULL;
        v = PyEval_EvalCode(co, globals, locals);
@@ -1271,8 +1201,8 @@ run_node(node *n, const char *filename, PyObject *globals, PyObject *locals,
 }
 
 static PyObject *
-run_pyc_file(FILE *fp, const char *filename, PyObject *globals, PyObject *locals,
-            PyCompilerFlags *flags)
+run_pyc_file(FILE *fp, const char *filename, PyObject *globals, 
+            PyObject *locals, PyCompilerFlags *flags)
 {
        PyCodeObject *co;
        PyObject *v;
@@ -1302,42 +1232,78 @@ run_pyc_file(FILE *fp, const char *filename, PyObject *globals, PyObject *locals
        return v;
 }
 
-PyObject *
-Py_CompileString(const char *str, const char *filename, int start)
-{
-       return Py_CompileStringFlags(str, filename, start, NULL);
-}
-
 PyObject *
 Py_CompileStringFlags(const char *str, const char *filename, int start,
                      PyCompilerFlags *flags)
 {
-       node *n;
+       mod_ty mod;
        PyCodeObject *co;
-
-       n = PyParser_SimpleParseStringFlagsFilename(str, filename, start,
-                                                   PARSER_FLAGS(flags));
-       if (n == NULL)
+       mod = PyParser_ASTFromString(str, filename, start, flags);
+       if (mod == NULL)
                return NULL;
-       co = PyNode_CompileFlags(n, filename, flags);
-       PyNode_Free(n);
+       co = PyAST_Compile(mod, filename, flags);
+       free_mod(mod);
        return (PyObject *)co;
 }
 
 struct symtable *
 Py_SymtableString(const char *str, const char *filename, int start)
 {
-       node *n;
+       mod_ty mod;
        struct symtable *st;
-       n = PyParser_SimpleParseStringFlagsFilename(str, filename,
-                                                   start, 0);
-       if (n == NULL)
+
+       mod = PyParser_ASTFromString(str, filename, start, NULL);
+       if (mod == NULL)
                return NULL;
-       st = PyNode_CompileSymtable(n, filename);
-       PyNode_Free(n);
+       st = PySymtable_Build(mod, filename, 0);
+       free_mod(mod);
        return st;
 }
 
+/* Preferred access to parser is through AST. */
+mod_ty
+PyParser_ASTFromString(const char *s, const char *filename, int start, 
+                      PyCompilerFlags *flags)
+{
+       node *n;
+       mod_ty mod;
+       perrdetail err;
+       n = PyParser_ParseStringFlagsFilename(s, filename, &_PyParser_Grammar,
+                                             start, &err, 
+                                             PARSER_FLAGS(flags));
+       if (n) {
+               mod = PyAST_FromNode(n, flags, filename);
+               PyNode_Free(n);
+               return mod;
+       }
+       else {
+               err_input(&err);
+               return NULL;
+       }
+}
+
+mod_ty
+PyParser_ASTFromFile(FILE *fp, const char *filename, int start, char *ps1, 
+                    char *ps2, PyCompilerFlags *flags, int *errcode)
+{
+       node *n;
+       mod_ty mod;
+       perrdetail err;
+       n = PyParser_ParseFileFlags(fp, filename, &_PyParser_Grammar, start, 
+                                   ps1, ps2, &err, PARSER_FLAGS(flags));
+       if (n) {
+               mod = PyAST_FromNode(n, flags, filename);
+               PyNode_Free(n);
+               return mod;
+       }
+       else {
+               err_input(&err);
+               if (errcode)
+                       *errcode = err.error;
+               return NULL;
+       }
+}
+
 /* Simplified interface to parsefile -- return node or set exception */
 
 node *
@@ -1349,15 +1315,10 @@ PyParser_SimpleParseFileFlags(FILE *fp, const char *filename, int start, int fla
                                        (char *)0, (char *)0, &err, flags);
        if (n == NULL)
                err_input(&err);
+               
        return n;
 }
 
-node *
-PyParser_SimpleParseFile(FILE *fp, const char *filename, int start)
-{
-       return PyParser_SimpleParseFileFlags(fp, filename, start, 0);
-}
-
 /* Simplified interface to parsestring -- return node or set exception */
 
 node *
@@ -1372,12 +1333,6 @@ PyParser_SimpleParseStringFlags(const char *str, int start, int flags)
        return n;
 }
 
-node *
-PyParser_SimpleParseString(const char *str, int start)
-{
-       return PyParser_SimpleParseStringFlags(str, start, 0);
-}
-
 node *
 PyParser_SimpleParseStringFlagsFilename(const char *str, const char *filename,
                                        int start, int flags)
@@ -1418,12 +1373,6 @@ err_input(perrdetail *err)
        PyObject* u = NULL;
        char *msg = NULL;
        errtype = PyExc_SyntaxError;
-       v = Py_BuildValue("(ziiz)", err->filename,
-                           err->lineno, err->offset, err->text);
-       if (err->text != NULL) {
-               PyMem_DEL(err->text);
-               err->text = NULL;
-       }
        switch (err->error) {
        case E_SYNTAX:
                errtype = PyExc_IndentationError;
@@ -1450,11 +1399,9 @@ err_input(perrdetail *err)
        case E_INTR:
                if (!PyErr_Occurred())
                        PyErr_SetNone(PyExc_KeyboardInterrupt);
-               Py_XDECREF(v);
                return;
        case E_NOMEM:
                PyErr_NoMemory();
-               Py_XDECREF(v);
                return;
        case E_EOF:
                msg = "unexpected EOF while parsing";
@@ -1498,7 +1445,15 @@ err_input(perrdetail *err)
                msg = "unknown parsing error";
                break;
        }
-       w = Py_BuildValue("(sO)", msg, v);
+       v = Py_BuildValue("(ziiz)", err->filename,
+                         err->lineno, err->offset, err->text);
+       if (err->text != NULL) {
+               PyMem_DEL(err->text);
+               err->text = NULL;
+       }
+       w = NULL;
+       if (v != NULL)
+               w = Py_BuildValue("(sO)", msg, v);
        Py_XDECREF(u);
        Py_XDECREF(v);
        PyErr_SetObject(errtype, w);
@@ -1687,3 +1642,20 @@ PyOS_setsig(int sig, PyOS_sighandler_t handler)
        return oldhandler;
 #endif
 }
+
+/* Deprecated C API functions still provided for binary compatiblity */
+
+#undef PyParser_SimpleParseFile
+#undef PyParser_SimpleParseString
+
+node *
+PyParser_SimpleParseFile(FILE *fp, const char *filename, int start)
+{
+       return PyParser_SimpleParseFileFlags(fp, filename, start, 0);
+}
+
+node *
+PyParser_SimpleParseString(const char *str, int start)
+{
+       return PyParser_SimpleParseStringFlags(str, start, 0);
+}
index 5ca204164a2225a7d8d63c22f5de4311ce654b28..bd4120231a2fc794955d267f6b5db2bf4d3e0224 100644 (file)
@@ -1,48 +1,35 @@
 #include "Python.h"
+#include "Python-ast.h"
+#include "code.h"
 #include "compile.h"
 #include "symtable.h"
-#include "graminit.h"
 #include "structmember.h"
 
-/* The compiler uses this function to load a PySymtableEntry object
-   for a code block.  Each block is loaded twice, once during the
-   symbol table pass and once during the code gen pass.  Entries
-   created during the first pass are cached for the second pass, using
-   the st_symbols dictionary.  
-
-   The cache is keyed by st_nscopes.  Each code block node in a
-   module's parse tree can be assigned a unique id based on the order
-   in which the nodes are visited by the compiler.  This strategy
-   works so long as the symbol table and codegen passes visit the same
-   nodes in the same order.
-*/
+/* two error strings used for warnings */
+#define GLOBAL_AFTER_ASSIGN \
+"name '%.400s' is assigned to before global declaration"
 
+#define GLOBAL_AFTER_USE \
+"name '%.400s' is used prior to global declaration"
 
-PyObject *
-PySymtableEntry_New(struct symtable *st, char *name, int type, int lineno)
+PySTEntryObject *
+PySTEntry_New(struct symtable *st, identifier name, block_ty block,
+             void *key, int lineno)
 {
-       PySymtableEntryObject *ste = NULL;
+       PySTEntryObject *ste = NULL;
        PyObject *k, *v;
 
-       k = PyInt_FromLong(st->st_nscopes++);
+       k = PyLong_FromVoidPtr(key);
        if (k == NULL)
                goto fail;
-       v = PyDict_GetItem(st->st_symbols, k);
-       if (v) {
-               Py_DECREF(k);
-               Py_INCREF(v);
-               return v;
-       }
-       
-       ste = (PySymtableEntryObject *)PyObject_New(PySymtableEntryObject,
-                                                   &PySymtableEntry_Type);
+       ste = (PySTEntryObject *)PyObject_New(PySTEntryObject,
+                                             &PySTEntry_Type);
        ste->ste_table = st;
        ste->ste_id = k;
+       ste->ste_tmpname = 0;
 
-       v = PyString_FromString(name);
-       if (v == NULL)
-               goto fail;
-       ste->ste_name = v;
+       ste->ste_name = name;
+       Py_INCREF(name);
        
        v = PyDict_New();
        if (v == NULL)
@@ -59,61 +46,46 @@ PySymtableEntry_New(struct symtable *st, char *name, int type, int lineno)
            goto fail;
        ste->ste_children = v;
 
-       ste->ste_optimized = 0;
+       ste->ste_type = block;
+       ste->ste_unoptimized = 0;
+       ste->ste_nested = 0;
+       ste->ste_free = 0;
+       ste->ste_varargs = 0;
+       ste->ste_varkeywords = 0;
        ste->ste_opt_lineno = 0;
        ste->ste_tmpname = 0;
        ste->ste_lineno = lineno;
-       switch (type) {
-       case funcdef:
-       case lambdef:
-       case testlist_gexp: /* generator expression */
-       case argument:      /* generator expression */
-               ste->ste_type = TYPE_FUNCTION;
-               break;
-       case classdef:
-               ste->ste_type = TYPE_CLASS;
-               break;
-       case single_input:
-       case eval_input:
-       case file_input:
-               ste->ste_type = TYPE_MODULE;
-               break;
-       }
 
-       if (st->st_cur == NULL)
-               ste->ste_nested = 0;
-       else if (st->st_cur->ste_nested 
-                || st->st_cur->ste_type == TYPE_FUNCTION)
+       if (st->st_cur != NULL &&
+           (st->st_cur->ste_nested ||
+            st->st_cur->ste_type == FunctionBlock))
                ste->ste_nested = 1;
-       else
-               ste->ste_nested = 0;
        ste->ste_child_free = 0;
        ste->ste_generator = 0;
 
        if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0)
            goto fail;
        
-       return (PyObject *)ste;
+       return ste;
  fail:
        Py_XDECREF(ste);
        return NULL;
 }
 
 static PyObject *
-ste_repr(PySymtableEntryObject *ste)
+ste_repr(PySTEntryObject *ste)
 {
        char buf[256];
 
        PyOS_snprintf(buf, sizeof(buf),
                      "<symtable entry %.100s(%ld), line %d>",
                      PyString_AS_STRING(ste->ste_name),
-                     PyInt_AS_LONG(ste->ste_id),
-                     ste->ste_lineno);
+                     PyInt_AS_LONG(ste->ste_id), ste->ste_lineno);
        return PyString_FromString(buf);
 }
 
 static void
-ste_dealloc(PySymtableEntryObject *ste)
+ste_dealloc(PySTEntryObject *ste)
 {
        ste->ste_table = NULL;
        Py_XDECREF(ste->ste_id);
@@ -124,7 +96,7 @@ ste_dealloc(PySymtableEntryObject *ste)
        PyObject_Del(ste);
 }
 
-#define OFF(x) offsetof(PySymtableEntryObject, x)
+#define OFF(x) offsetof(PySTEntryObject, x)
 
 static PyMemberDef ste_memberlist[] = {
        {"id",       T_OBJECT, OFF(ste_id), READONLY},
@@ -134,16 +106,14 @@ static PyMemberDef ste_memberlist[] = {
        {"children", T_OBJECT, OFF(ste_children), READONLY},
        {"type",     T_INT,    OFF(ste_type), READONLY},
        {"lineno",   T_INT,    OFF(ste_lineno), READONLY},
-       {"optimized",T_INT,    OFF(ste_optimized), READONLY},
-       {"nested",   T_INT,    OFF(ste_nested), READONLY},
        {NULL}
 };
 
-PyTypeObject PySymtableEntry_Type = {
+PyTypeObject PySTEntry_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
        "symtable entry",
-       sizeof(PySymtableEntryObject),
+       sizeof(PySTEntryObject),
        0,
        (destructor)ste_dealloc,                /* tp_dealloc */
        0,                                      /* tp_print */
@@ -180,3 +150,1148 @@ PyTypeObject PySymtableEntry_Type = {
        0,                                      /* tp_alloc */
        0,                                      /* tp_new */
 };
+
+static int symtable_analyze(struct symtable *st);
+static int symtable_warn(struct symtable *st, char *msg);
+static int symtable_enter_block(struct symtable *st, identifier name, 
+                               block_ty block, void *ast, int lineno);
+static int symtable_exit_block(struct symtable *st, void *ast);
+static int symtable_visit_stmt(struct symtable *st, stmt_ty s);
+static int symtable_visit_expr(struct symtable *st, expr_ty s);
+static int symtable_visit_genexp(struct symtable *st, expr_ty s);
+static int symtable_visit_arguments(struct symtable *st, arguments_ty);
+static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty);
+static int symtable_visit_alias(struct symtable *st, alias_ty);
+static int symtable_visit_comprehension(struct symtable *st, comprehension_ty);
+static int symtable_visit_keyword(struct symtable *st, keyword_ty);
+static int symtable_visit_slice(struct symtable *st, slice_ty);
+static int symtable_visit_params(struct symtable *st, asdl_seq *args, int top);
+static int symtable_visit_params_nested(struct symtable *st, asdl_seq *args);
+static int symtable_implicit_arg(struct symtable *st, int pos);
+
+
+static identifier top = NULL, lambda = NULL;
+
+#define GET_IDENTIFIER(VAR) \
+       ((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR)))
+
+#define DUPLICATE_ARGUMENT \
+"duplicate argument '%s' in function definition"
+
+static struct symtable *
+symtable_new(void)
+{
+       struct symtable *st;
+
+       st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable));
+       if (st == NULL)
+               return NULL;
+
+       st->st_filename = NULL;
+       if ((st->st_stack = PyList_New(0)) == NULL)
+               goto fail;
+       if ((st->st_symbols = PyDict_New()) == NULL)
+               goto fail; 
+       st->st_cur = NULL;
+       st->st_tmpname = 0;
+       st->st_private = NULL;
+       return st;
+ fail:
+       PySymtable_Free(st);
+       return NULL;
+}
+
+struct symtable *
+PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future)
+{
+       struct symtable *st = symtable_new();
+       asdl_seq *seq;
+       int i;
+
+       if (st == NULL)
+               return st;
+       st->st_filename = filename;
+       st->st_future = future;
+       symtable_enter_block(st, GET_IDENTIFIER(top), ModuleBlock, 
+                            (void *)mod, 0);
+       st->st_top = st->st_cur;
+       st->st_cur->ste_unoptimized = OPT_TOPLEVEL;
+       /* Any other top-level initialization? */
+       switch (mod->kind) {
+       case Module_kind:
+               seq = mod->v.Module.body;
+               for (i = 0; i < asdl_seq_LEN(seq); i++)
+                       if (!symtable_visit_stmt(st, asdl_seq_GET(seq, i)))
+                               goto error;
+               break;
+       case Expression_kind:
+               if (!symtable_visit_expr(st, mod->v.Expression.body))
+                       goto error;
+               break;
+       case Interactive_kind:
+               seq = mod->v.Interactive.body;
+               for (i = 0; i < asdl_seq_LEN(seq); i++)
+                       if (!symtable_visit_stmt(st, asdl_seq_GET(seq, i)))
+                               goto error;
+               break;
+       case Suite_kind:
+               PyErr_SetString(PyExc_RuntimeError,
+                               "this compiler does not handle Suites");
+               return NULL;
+       }
+       if (!symtable_exit_block(st, (void *)mod))
+               return NULL;
+       if (symtable_analyze(st))
+               return st;
+ error:
+       PySymtable_Free(st);
+       return NULL;
+}
+
+void
+PySymtable_Free(struct symtable *st)
+{
+       Py_XDECREF(st->st_symbols);
+       Py_XDECREF(st->st_stack);
+       PyMem_Free((void *)st);
+}
+
+PySTEntryObject *
+PySymtable_Lookup(struct symtable *st, void *key)
+{
+       PyObject *k, *v;
+
+       k = PyLong_FromVoidPtr(key);
+       if (k == NULL)
+               return NULL;
+       v = PyDict_GetItem(st->st_symbols, k);
+       if (v) {
+               assert(PySTEntry_Check(v));
+               Py_DECREF(k);
+               Py_INCREF(v);
+               return (PySTEntryObject *)v;
+       }
+       else {
+               PyErr_SetString(PyExc_KeyError,
+                               "unknown symbol table entry");
+               return NULL;
+       }
+}
+
+int 
+PyST_GetScope(PySTEntryObject *ste, PyObject *name)
+{
+       PyObject *v = PyDict_GetItem(ste->ste_symbols, name);
+       if (!v)
+               return 0;
+       assert(PyInt_Check(v));
+       return (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK;
+}
+
+
+/* Analyze raw symbol information to determine scope of each name.
+
+   The next several functions are helpers for PySymtable_Analyze(),
+   which determines whether a name is local, global, or free.  In addition, 
+   it determines which local variables are cell variables; they provide
+   bindings that are used for free variables in enclosed blocks.  
+
+   There are also two kinds of free variables, implicit and explicit.  An 
+   explicit global is declared with the global statement.  An implicit
+   global is a free variable for which the compiler has found no binding
+   in an enclosing function scope.  The implicit global is either a global
+   or a builtin.  Python's module and class blocks use the xxx_NAME opcodes
+   to handle these names to implement slightly odd semantics.  In such a
+   block, the name is treated as global until it is assigned to; then it
+   is treated as a local.
+
+   The symbol table requires two passes to determine the scope of each name.
+   The first pass collects raw facts from the AST: the name is a parameter 
+   here, the name is used by not defined here, etc.  The second pass analyzes
+   these facts during a pass over the PySTEntryObjects created during pass 1.
+
+   When a function is entered during the second pass, the parent passes
+   the set of all name bindings visible to its children.  These bindings 
+   are used to determine if the variable is free or an implicit global.
+   After doing the local analysis, it analyzes each of its child blocks
+   using an updated set of name bindings.  
+
+   The children update the free variable set.  If a local variable is free 
+   in a child, the variable is marked as a cell.  The current function must 
+   provide runtime storage for the variable that may outlive the function's 
+   frame.  Cell variables are removed from the free set before the analyze
+   function returns to its parent.
+   
+   The sets of bound and free variables are implemented as dictionaries
+   mapping strings to None.
+*/
+
+#define SET_SCOPE(DICT, NAME, I) { \
+       PyObject *o = PyInt_FromLong(I); \
+       if (!o) \
+               return 0; \
+       if (PyDict_SetItem((DICT), (NAME), o) < 0) \
+               return 0; \
+}
+
+/* Decide on scope of name, given flags.
+
+   The dicts passed in as arguments are modified as necessary.
+   ste is passed so that flags can be updated.
+*/
+
+static int 
+analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, int flags,
+            PyObject *bound, PyObject *local, PyObject *free, 
+            PyObject *global)
+{
+       if (flags & DEF_GLOBAL) {
+               if (flags & DEF_PARAM) {
+                       PyErr_Format(PyExc_SyntaxError,
+                                    "name '%s' is local and global",
+                                    PyString_AS_STRING(name));
+                       return 0;
+               }
+               SET_SCOPE(dict, name, GLOBAL_EXPLICIT);
+               if (PyDict_SetItem(global, name, Py_None) < 0)
+                       return 0;
+               if (bound && PyDict_GetItem(bound, name)) {
+                       if (PyDict_DelItem(bound, name) < 0)
+                               return 0;
+               }
+               return 1;
+       }
+       if (flags & DEF_BOUND) {
+               SET_SCOPE(dict, name, LOCAL);
+               if (PyDict_SetItem(local, name, Py_None) < 0)
+                       return 0;
+               if (PyDict_GetItem(global, name)) {
+                       if (PyDict_DelItem(global, name) < 0)
+                               return 0;
+               }
+               return 1;
+       }
+       /* If an enclosing block has a binding for this name, it
+          is a free variable rather than a global variable.
+          Note that having a non-NULL bound implies that the block
+          is nested.
+       */
+       if (bound && PyDict_GetItem(bound, name)) {
+               SET_SCOPE(dict, name, FREE);
+               ste->ste_free = 1;
+               if (PyDict_SetItem(free, name, Py_None) < 0)
+                       return 0;
+               return 1;
+       }
+       /* If a parent has a global statement, then call it global
+          explicit?  It could also be global implicit.
+        */
+       else if (global && PyDict_GetItem(global, name)) {
+               SET_SCOPE(dict, name, GLOBAL_EXPLICIT);
+               return 1;
+       }
+       else {
+               if (ste->ste_nested)
+                       ste->ste_free = 1;
+               SET_SCOPE(dict, name, GLOBAL_IMPLICIT);
+               return 1;
+       }
+       return 0; /* Can't get here */
+}
+
+#undef SET_SCOPE
+
+/* If a name is defined in free and also in locals, then this block
+   provides the binding for the free variable.  The name should be
+   marked CELL in this block and removed from the free list.
+
+   Note that the current block's free variables are included in free.
+   That's safe because no name can be free and local in the same scope.
+*/
+
+static int
+analyze_cells(PyObject *scope, PyObject *free)
+{
+        PyObject *name, *v, *w;
+       int flags, pos = 0, success = 0;
+
+       w = PyInt_FromLong(CELL);
+       if (!w)
+               return 0;
+       while (PyDict_Next(scope, &pos, &name, &v)) {
+               assert(PyInt_Check(v));
+               flags = PyInt_AS_LONG(v);
+               if (flags != LOCAL)
+                       continue;
+               if (!PyDict_GetItem(free, name))
+                       continue;
+               /* Replace LOCAL with CELL for this name, and remove
+                  from free. It is safe to replace the value of name 
+                  in the dict, because it will not cause a resize.
+                */
+               if (PyDict_SetItem(scope, name, w) < 0)
+                       goto error;
+               if (!PyDict_DelItem(free, name) < 0)
+                       goto error;
+       }
+       success = 1;
+ error:
+       Py_DECREF(w);
+       return success;
+}
+
+/* Check for illegal statements in unoptimized namespaces */
+static int
+check_unoptimized(const PySTEntryObject* ste) {
+       char buf[300];
+
+       if (ste->ste_type == ModuleBlock || !ste->ste_unoptimized
+           || !(ste->ste_free || ste->ste_child_free))
+               return 1;
+
+       const char* trailer = (ste->ste_child_free ? 
+                      "contains a nested function with free variables" :
+                              "is a nested function");
+
+       switch (ste->ste_unoptimized) {
+       case OPT_TOPLEVEL: /* exec / import * at top-level is fine */
+       case OPT_EXEC: /* qualified exec is fine */
+               return 1;
+       case OPT_IMPORT_STAR:
+               PyOS_snprintf(buf, sizeof(buf), 
+                             "import * is not allowed in function '%.100s' "
+                             "because it is %s",
+                             PyString_AS_STRING(ste->ste_name), trailer);
+               break;
+       case OPT_BARE_EXEC:
+               PyOS_snprintf(buf, sizeof(buf),
+                             "unqualified exec is not allowed in function "
+                             "'%.100s' it %s",
+                             PyString_AS_STRING(ste->ste_name), trailer);
+               break;
+       default:
+               PyOS_snprintf(buf, sizeof(buf), 
+                             "function '%.100s' uses import * and bare exec, "
+                             "which are illegal because it %s",
+                             PyString_AS_STRING(ste->ste_name), trailer);
+               break;
+       }
+
+       PyErr_SetString(PyExc_SyntaxError, buf);
+       PyErr_SyntaxLocation(ste->ste_table->st_filename, 
+                            ste->ste_opt_lineno);
+       return 0;
+}
+
+/* Enter the final scope information into the st_symbols dict. 
+ * 
+ * All arguments are dicts.  Modifies symbols, others are read-only.
+*/
+static int
+update_symbols(PyObject *symbols, PyObject *scope, 
+               PyObject *bound, PyObject *free, int class)
+{
+       PyObject *name, *v, *u, *w, *free_value = NULL;
+       int i, flags, pos = 0;
+
+       while (PyDict_Next(symbols, &pos, &name, &v)) {
+               assert(PyInt_Check(v));
+               flags = PyInt_AS_LONG(v);
+               w = PyDict_GetItem(scope, name);
+               assert(w && PyInt_Check(w));
+               i = PyInt_AS_LONG(w);
+               flags |= (i << SCOPE_OFF);
+               u = PyInt_FromLong(flags);
+               if (PyDict_SetItem(symbols, name, u) < 0) {
+                       Py_DECREF(u);
+                       return 0;
+               }
+               Py_DECREF(u);
+       }
+
+        free_value = PyInt_FromLong(FREE << SCOPE_OFF);
+        if (!free_value)
+               return 0;
+
+        /* add a free variable when it's only use is for creating a closure */
+        pos = 0;
+       while (PyDict_Next(free, &pos, &name, &v)) {
+               PyObject *o = PyDict_GetItem(symbols, name);
+
+               if (o) {
+                       /* It could be a free variable in a method of
+                          the class that has the same name as a local
+                          or global in the class scope.
+                       */
+                       if  (class && 
+                            PyInt_AS_LONG(o) & (DEF_BOUND | DEF_GLOBAL)) {
+                               int i = PyInt_AS_LONG(o) | DEF_FREE_CLASS;
+                               o = PyInt_FromLong(i);
+                               if (!o) {
+                                       Py_DECREF(free_value);
+                                       return 0;
+                               }
+                               if (PyDict_SetItem(symbols, name, o) < 0) {
+                                       Py_DECREF(o);
+                                       Py_DECREF(free_value);
+                                       return 0;
+                               }
+                       }
+                       /* else it's not free, probably a cell */
+                       continue;
+               }
+               if (!PyDict_GetItem(bound, name))
+                       continue;       /* it's a global */
+
+               if (PyDict_SetItem(symbols, name, free_value) < 0) {
+                       Py_DECREF(free_value);
+                       return 0;
+               }
+        }
+        Py_DECREF(free_value);
+       return 1;
+}   
+
+/* Make final symbol table decisions for block of ste.
+   Arguments:
+   ste -- current symtable entry (input/output)
+   bound -- set of variables bound in enclosing scopes (input)
+   free -- set of free variables in enclosed scopes (output)
+   globals -- set of declared global variables in enclosing scopes (input)
+*/
+
+static int
+analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, 
+             PyObject *global)
+{
+       PyObject *name, *v, *local = NULL, *scope = NULL, *newbound = NULL;
+       PyObject *newglobal = NULL, *newfree = NULL;
+       int i, flags, pos = 0, success = 0;
+
+       local = PyDict_New();
+       if (!local)
+               goto error;
+       scope = PyDict_New();
+       if (!scope)
+               goto error;
+       newglobal = PyDict_New();
+       if (!newglobal)
+               goto error;
+       newfree = PyDict_New();
+       if (!newfree)
+               goto error;
+       newbound = PyDict_New();
+       if (!newbound)
+               goto error;
+
+       if (ste->ste_type == ClassBlock) {
+               /* make a copy of globals before calling analyze_name(),
+                  because global statements in the class have no effect
+                  on nested functions.
+               */
+               if (PyDict_Update(newglobal, global) < 0)
+                       goto error;
+               if (bound)
+                       if (PyDict_Update(newbound, bound) < 0)
+                               goto error;
+       }
+
+       assert(PySTEntry_Check(ste));
+       assert(PyDict_Check(ste->ste_symbols));
+       while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
+               flags = PyInt_AS_LONG(v);
+               if (!analyze_name(ste, scope, name, flags, bound, local, free,
+                                 global))
+                       goto error;
+       }
+
+       if (ste->ste_type != ClassBlock) {
+               if (ste->ste_type == FunctionBlock) {
+                       if (PyDict_Update(newbound, local) < 0)
+                               goto error;
+               }
+               if (bound) {
+                       if (PyDict_Update(newbound, bound) < 0)
+                               goto error;
+               }
+               if (PyDict_Update(newglobal, global) < 0)
+                       goto error;
+       }
+
+       /* Recursively call analyze_block() on each child block */
+       for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
+               PyObject *c = PyList_GET_ITEM(ste->ste_children, i);
+               assert(c && PySTEntry_Check(c));
+               PySTEntryObject* entry = (PySTEntryObject*)c;
+               if (!analyze_block(entry, newbound, newfree, newglobal))
+                       goto error;
+               if (entry->ste_free || entry->ste_child_free)
+                       ste->ste_child_free = 1;
+       }
+
+       if (ste->ste_type == FunctionBlock && !analyze_cells(scope, newfree))
+               goto error;
+       if (!update_symbols(ste->ste_symbols, scope, bound, newfree,
+                           ste->ste_type == ClassBlock))
+               goto error;
+       if (!check_unoptimized(ste))
+               goto error;
+
+       if (PyDict_Update(free, newfree) < 0)
+               goto error;
+       success = 1;
+ error:
+       Py_XDECREF(local);
+       Py_XDECREF(scope);
+       Py_XDECREF(newbound);
+       Py_XDECREF(newglobal);
+       Py_XDECREF(newfree);
+       if (!success)
+               assert(PyErr_Occurred());
+       return success;
+}
+
+static int
+symtable_analyze(struct symtable *st)
+{
+       PyObject *free, *global;
+       int r;
+
+       free = PyDict_New();
+       if (!free)
+           return 0;
+       global = PyDict_New();
+       if (!global) {
+           Py_DECREF(global);
+           return 0;
+       }
+       r = analyze_block(st->st_top, NULL, free, global);
+       Py_DECREF(free);
+       Py_DECREF(global);
+       return r;
+}
+
+
+static int
+symtable_warn(struct symtable *st, char *msg)
+{
+       if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, st->st_filename,
+                              st->st_cur->ste_lineno, NULL, NULL) < 0) {
+               if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
+                       PyErr_SetString(PyExc_SyntaxError, msg);
+                       PyErr_SyntaxLocation(st->st_filename, 
+                                            st->st_cur->ste_lineno);
+               }
+               return 0;
+       }
+       return 1;
+}
+
+/* symtable_enter_block() gets a reference via PySTEntry_New().
+   This reference is released when the block is exited, via the DECREF
+   in symtable_exit_block().
+*/
+
+static int
+symtable_exit_block(struct symtable *st, void *ast)
+{
+       int end;
+
+       Py_DECREF(st->st_cur);
+       end = PyList_GET_SIZE(st->st_stack) - 1;
+       if (end >= 0) {
+               st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, 
+                                                               end);
+               Py_INCREF(st->st_cur);
+               if (PySequence_DelItem(st->st_stack, end) < 0)
+                       return 0;
+       }
+       return 1;
+}
+
+static int
+symtable_enter_block(struct symtable *st, identifier name, block_ty block, 
+                    void *ast, int lineno)
+{
+       PySTEntryObject *prev = NULL;
+
+       if (st->st_cur) {
+               prev = st->st_cur;
+               if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
+                       Py_DECREF(st->st_cur);
+                       return 0;
+               }
+               Py_DECREF(st->st_cur);
+       }
+       st->st_cur = PySTEntry_New(st, name, block, ast, lineno);
+       if (name == GET_IDENTIFIER(top))
+               st->st_global = st->st_cur->ste_symbols;
+       if (prev) {
+               if (PyList_Append(prev->ste_children, 
+                                 (PyObject *)st->st_cur) < 0) {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static int
+symtable_lookup(struct symtable *st, PyObject *name)
+{
+       PyObject *o;
+
+       o = PyDict_GetItem(st->st_cur->ste_symbols, name);
+       if (!o)
+               return 0;
+       return PyInt_AsLong(o);
+}
+
+static int
+symtable_add_def(struct symtable *st, PyObject *name, int flag) 
+{
+       PyObject *o;
+       PyObject *dict;
+       int val;
+
+       dict = st->st_cur->ste_symbols;
+       if ((o = PyDict_GetItem(dict, name))) {
+           val = PyInt_AS_LONG(o);
+           if ((flag & DEF_PARAM) && (val & DEF_PARAM)) {
+                   PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
+                                PyString_AsString(name));
+                   PyErr_SyntaxLocation(st->st_filename,
+                                      st->st_cur->ste_lineno);
+                   return 0;
+           }
+           val |= flag;
+       } else
+           val = flag;
+       o = PyInt_FromLong(val);
+        if (o == NULL)
+            return 0;
+       if (PyDict_SetItem(dict, name, o) < 0) {
+               Py_DECREF(o);
+               return 0;
+       }
+       Py_DECREF(o);
+
+       if (flag & DEF_PARAM) {
+               if (PyList_Append(st->st_cur->ste_varnames, name) < 0) 
+                       return 0;
+       } else  if (flag & DEF_GLOBAL) {
+               /* XXX need to update DEF_GLOBAL for other flags too;
+                  perhaps only DEF_FREE_GLOBAL */
+               val = flag;
+               if ((o = PyDict_GetItem(st->st_global, name))) {
+                       val |= PyInt_AS_LONG(o);
+               }
+               o = PyInt_FromLong(val);
+               if (o == NULL)
+                       return 0;
+               if (PyDict_SetItem(st->st_global, name, o) < 0) {
+                       Py_DECREF(o);
+                       return 0;
+               }
+               Py_DECREF(o);
+       }
+       return 1;
+}
+
+/* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument.
+   They use the ASDL name to synthesize the name of the C type and the visit
+   function. 
+   
+   VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is
+   useful if the first node in the sequence requires special treatment.
+*/
+
+#define VISIT(ST, TYPE, V) \
+       if (!symtable_visit_ ## TYPE((ST), (V))) \
+               return 0; 
+                                                   
+#define VISIT_SEQ(ST, TYPE, SEQ) { \
+       int i; \
+       asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+       for (i = 0; i < asdl_seq_LEN(seq); i++) { \
+               TYPE ## _ty elt = asdl_seq_GET(seq, i); \
+               if (!symtable_visit_ ## TYPE((ST), elt)) \
+                       return 0; \
+       } \
+}
+                                                   
+#define VISIT_SEQ_TAIL(ST, TYPE, SEQ, START) { \
+       int i; \
+       asdl_seq *seq = (SEQ); /* avoid variable capture */ \
+       for (i = (START); i < asdl_seq_LEN(seq); i++) { \
+               TYPE ## _ty elt = asdl_seq_GET(seq, i); \
+               if (!symtable_visit_ ## TYPE((ST), elt)) \
+                       return 0; \
+       } \
+}
+                                                   
+static int
+symtable_visit_stmt(struct symtable *st, stmt_ty s)
+{
+       switch (s->kind) {
+        case FunctionDef_kind:
+               if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL))
+                       return 0;
+               if (s->v.FunctionDef.args->defaults)
+                       VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults);
+               if (s->v.FunctionDef.decorators)
+                       VISIT_SEQ(st, expr, s->v.FunctionDef.decorators);
+               if (!symtable_enter_block(st, s->v.FunctionDef.name, 
+                                         FunctionBlock, (void *)s, s->lineno))
+                       return 0;
+               VISIT(st, arguments, s->v.FunctionDef.args);
+               VISIT_SEQ(st, stmt, s->v.FunctionDef.body);
+               if (!symtable_exit_block(st, s))
+                       return 0;
+               break;
+        case ClassDef_kind:
+               if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL))
+                       return 0;
+               VISIT_SEQ(st, expr, s->v.ClassDef.bases);
+               if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, 
+                                         (void *)s, s->lineno))
+                       return 0;
+               VISIT_SEQ(st, stmt, s->v.ClassDef.body);
+               if (!symtable_exit_block(st, s))
+                       return 0;
+               break;
+        case Return_kind:
+               if (s->v.Return.value)
+                       VISIT(st, expr, s->v.Return.value);
+               break;
+        case Delete_kind:
+               VISIT_SEQ(st, expr, s->v.Delete.targets);
+               break;
+        case Assign_kind:
+               VISIT_SEQ(st, expr, s->v.Assign.targets);
+               VISIT(st, expr, s->v.Assign.value);
+               break;
+        case AugAssign_kind:
+               VISIT(st, expr, s->v.AugAssign.target);
+               VISIT(st, expr, s->v.AugAssign.value);
+               break;
+        case Print_kind:
+               if (s->v.Print.dest)
+                       VISIT(st, expr, s->v.Print.dest);
+               VISIT_SEQ(st, expr, s->v.Print.values);
+               break;
+        case For_kind:
+               VISIT(st, expr, s->v.For.target);
+               VISIT(st, expr, s->v.For.iter);
+               VISIT_SEQ(st, stmt, s->v.For.body);
+               if (s->v.For.orelse)
+                       VISIT_SEQ(st, stmt, s->v.For.orelse);
+               break;
+        case While_kind:
+               VISIT(st, expr, s->v.While.test);
+               VISIT_SEQ(st, stmt, s->v.While.body);
+               if (s->v.While.orelse)
+                       VISIT_SEQ(st, stmt, s->v.While.orelse);
+               break;
+        case If_kind:
+               /* XXX if 0: and lookup_yield() hacks */
+               VISIT(st, expr, s->v.If.test);
+               VISIT_SEQ(st, stmt, s->v.If.body);
+               if (s->v.If.orelse)
+                       VISIT_SEQ(st, stmt, s->v.If.orelse);
+               break;
+        case Raise_kind:
+               if (s->v.Raise.type) {
+                       VISIT(st, expr, s->v.Raise.type);
+                       if (s->v.Raise.inst) {
+                               VISIT(st, expr, s->v.Raise.inst);
+                               if (s->v.Raise.tback)
+                                       VISIT(st, expr, s->v.Raise.tback);
+                       }
+               }
+               break;
+        case TryExcept_kind:
+               VISIT_SEQ(st, stmt, s->v.TryExcept.body);
+               VISIT_SEQ(st, stmt, s->v.TryExcept.orelse);
+               VISIT_SEQ(st, excepthandler, s->v.TryExcept.handlers);
+               break;
+        case TryFinally_kind:
+               VISIT_SEQ(st, stmt, s->v.TryFinally.body);
+               VISIT_SEQ(st, stmt, s->v.TryFinally.finalbody);
+               break;
+        case Assert_kind:
+               VISIT(st, expr, s->v.Assert.test);
+               if (s->v.Assert.msg)
+                       VISIT(st, expr, s->v.Assert.msg);
+               break;
+        case Import_kind:
+               VISIT_SEQ(st, alias, s->v.Import.names);
+               /* XXX Don't have the lineno available inside
+                  visit_alias */
+               if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno)
+                       st->st_cur->ste_opt_lineno = s->lineno;
+               break;
+        case ImportFrom_kind:
+               VISIT_SEQ(st, alias, s->v.ImportFrom.names);
+               /* XXX Don't have the lineno available inside
+                  visit_alias */
+               if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno)
+                       st->st_cur->ste_opt_lineno = s->lineno;
+               break;
+        case Exec_kind:
+               VISIT(st, expr, s->v.Exec.body);
+               if (!st->st_cur->ste_opt_lineno)
+                       st->st_cur->ste_opt_lineno = s->lineno;
+               if (s->v.Exec.globals) {
+                       st->st_cur->ste_unoptimized |= OPT_EXEC;
+                       VISIT(st, expr, s->v.Exec.globals);
+                       if (s->v.Exec.locals) 
+                               VISIT(st, expr, s->v.Exec.locals);
+               } else {
+                       st->st_cur->ste_unoptimized |= OPT_BARE_EXEC;
+               }
+               break;
+        case Global_kind: {
+               int i;
+               asdl_seq *seq = s->v.Global.names;
+               for (i = 0; i < asdl_seq_LEN(seq); i++) {
+                       identifier name = asdl_seq_GET(seq, i);
+                       char *c_name = PyString_AS_STRING(name);
+                       int cur = symtable_lookup(st, name);
+                       if (cur < 0)
+                               return 0;
+                       if (cur & (DEF_LOCAL | USE)) {
+                               char buf[1000];
+                               if (cur & DEF_LOCAL) 
+                                       PyOS_snprintf(buf, sizeof(buf),
+                                                     GLOBAL_AFTER_ASSIGN,
+                                                     c_name);
+                               else
+                                       PyOS_snprintf(buf, sizeof(buf),
+                                                     GLOBAL_AFTER_USE,
+                                                     c_name);
+                               if (!symtable_warn(st, buf))
+                                    return 0;
+                       }
+                       if (!symtable_add_def(st, name, DEF_GLOBAL))
+                               return 0;
+                       
+               }
+               
+               break;
+       }
+        case Expr_kind:
+               VISIT(st, expr, s->v.Expr.value);
+               break;
+        case Pass_kind:
+        case Break_kind:
+        case Continue_kind:
+               /* nothing to do here */
+               break;
+       }
+       return 1;
+}
+
+static int 
+symtable_visit_expr(struct symtable *st, expr_ty e)
+{
+       switch (e->kind) {
+        case BoolOp_kind:
+               VISIT_SEQ(st, expr, e->v.BoolOp.values);
+               break;
+        case BinOp_kind:
+               VISIT(st, expr, e->v.BinOp.left);
+               VISIT(st, expr, e->v.BinOp.right);
+               break;
+        case UnaryOp_kind:
+               VISIT(st, expr, e->v.UnaryOp.operand);
+               break;
+        case Lambda_kind: {
+               if (!symtable_add_def(st, GET_IDENTIFIER(lambda), DEF_LOCAL))
+                       return 0;
+               if (e->v.Lambda.args->defaults)
+                       VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
+               /* XXX how to get line numbers for expressions */
+               if (!symtable_enter_block(st, GET_IDENTIFIER(lambda),
+                                          FunctionBlock, (void *)e, 0))
+                       return 0;
+               VISIT(st, arguments, e->v.Lambda.args);
+               VISIT(st, expr, e->v.Lambda.body);
+               if (!symtable_exit_block(st, (void *)e))
+                       return 0;
+               break;
+       }
+        case Dict_kind:
+               VISIT_SEQ(st, expr, e->v.Dict.keys);
+               VISIT_SEQ(st, expr, e->v.Dict.values);
+               break;
+        case ListComp_kind: {
+               char tmpname[256];
+               identifier tmp;
+
+               PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]",
+                             ++st->st_cur->ste_tmpname);
+               tmp = PyString_FromString(tmpname);
+               if (!symtable_add_def(st, tmp, DEF_LOCAL))
+                       return 0;
+               VISIT(st, expr, e->v.ListComp.elt);
+               VISIT_SEQ(st, comprehension, e->v.ListComp.generators);
+               break;
+       }
+        case GeneratorExp_kind: {
+               if (!symtable_visit_genexp(st, e)) {
+                       return 0;
+               }
+               break;
+       }
+        case Yield_kind:
+               if (e->v.Yield.value)
+                       VISIT(st, expr, e->v.Yield.value);
+                st->st_cur->ste_generator = 1;
+               break;
+        case Compare_kind:
+               VISIT(st, expr, e->v.Compare.left);
+               VISIT_SEQ(st, expr, e->v.Compare.comparators);
+               break;
+        case Call_kind:
+               VISIT(st, expr, e->v.Call.func);
+               VISIT_SEQ(st, expr, e->v.Call.args);
+               VISIT_SEQ(st, keyword, e->v.Call.keywords);
+               if (e->v.Call.starargs)
+                       VISIT(st, expr, e->v.Call.starargs);
+               if (e->v.Call.kwargs)
+                       VISIT(st, expr, e->v.Call.kwargs);
+               break;
+        case Repr_kind:
+               VISIT(st, expr, e->v.Repr.value);
+               break;
+        case Num_kind:
+        case Str_kind:
+               /* Nothing to do here. */
+               break;
+       /* The following exprs can be assignment targets. */
+        case Attribute_kind:
+               VISIT(st, expr, e->v.Attribute.value);
+               break;
+        case Subscript_kind:
+               VISIT(st, expr, e->v.Subscript.value);
+               VISIT(st, slice, e->v.Subscript.slice);
+               break;
+        case Name_kind:
+               if (!symtable_add_def(st, e->v.Name.id, 
+                                     e->v.Name.ctx == Load ? USE : DEF_LOCAL))
+                       return 0;
+               break;
+       /* child nodes of List and Tuple will have expr_context set */
+        case List_kind:
+               VISIT_SEQ(st, expr, e->v.List.elts);
+               break;
+        case Tuple_kind:
+               VISIT_SEQ(st, expr, e->v.Tuple.elts);
+               break;
+       }
+       return 1;
+}
+
+static int
+symtable_implicit_arg(struct symtable *st, int pos)
+{
+       PyObject *id = PyString_FromFormat(".%d", pos);
+       if (id == NULL)
+               return 0;
+       if (!symtable_add_def(st, id, DEF_PARAM)) {
+               Py_DECREF(id);
+               return 0;
+       }
+       Py_DECREF(id);
+       return 1;
+}
+
+static int 
+symtable_visit_params(struct symtable *st, asdl_seq *args, int toplevel)
+{
+       int i, complex = 0;
+       
+        /* go through all the toplevel arguments first */
+       for (i = 0; i < asdl_seq_LEN(args); i++) {
+               expr_ty arg = asdl_seq_GET(args, i);
+               if (arg->kind == Name_kind) {
+                       assert(arg->v.Name.ctx == Param ||
+                               (arg->v.Name.ctx == Store && !toplevel));
+                       if (!symtable_add_def(st, arg->v.Name.id, DEF_PARAM))
+                               return 0;
+               }
+               else if (arg->kind == Tuple_kind) {
+                       assert(arg->v.Tuple.ctx == Store);
+                        complex = 1;
+                       if (toplevel) {
+                               if (!symtable_implicit_arg(st, i))
+                                       return 0;
+                       }
+               }
+               else {
+                       /* syntax error */
+                       fprintf(stderr, "unexpected expr in parameter list\n");
+                       return 0;
+               }
+       }
+
+       if (!toplevel) {
+               if (!symtable_visit_params_nested(st, args))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int
+symtable_visit_params_nested(struct symtable *st, asdl_seq *args)
+{
+       int i;
+       for (i = 0; i < asdl_seq_LEN(args); i++) {
+               expr_ty arg = asdl_seq_GET(args, i);
+               if (arg->kind == Tuple_kind &&
+                   !symtable_visit_params(st, arg->v.Tuple.elts, 0))
+                       return 0;
+       }
+       
+       return 1;
+}
+
+static int 
+symtable_visit_arguments(struct symtable *st, arguments_ty a)
+{
+       /* skip default arguments inside function block
+          XXX should ast be different?
+       */
+       if (a->args && !symtable_visit_params(st, a->args, 1))
+               return 0;
+       if (a->vararg) {
+               if (!symtable_add_def(st, a->vararg, DEF_PARAM))
+                       return 0;
+               st->st_cur->ste_varargs = 1;
+       }
+       if (a->kwarg) {
+               if (!symtable_add_def(st, a->kwarg, DEF_PARAM))
+                       return 0;
+               st->st_cur->ste_varkeywords = 1;
+       }
+       if (a->args && !symtable_visit_params_nested(st, a->args))
+               return 0;
+       return 1;
+}
+
+
+static int 
+symtable_visit_excepthandler(struct symtable *st, excepthandler_ty eh)
+{
+       if (eh->type)
+               VISIT(st, expr, eh->type);
+       if (eh->name)
+               VISIT(st, expr, eh->name);
+       VISIT_SEQ(st, stmt, eh->body);
+       return 1;
+}
+
+
+static int 
+symtable_visit_alias(struct symtable *st, alias_ty a)
+{
+       /* Compute store_name, the name actually bound by the import
+          operation.  It is diferent than a->name when a->name is a
+          dotted package name (e.g. spam.eggs) 
+       */
+       PyObject *store_name;
+       PyObject *name = (a->asname == NULL) ? a->name : a->asname;
+       const char *base = PyString_AS_STRING(name);
+       char *dot = strchr(base, '.');
+       if (dot)
+               store_name = PyString_FromStringAndSize(base, dot - base);
+       else {
+               store_name = name;
+               Py_INCREF(store_name);
+       }
+       if (strcmp(PyString_AS_STRING(name), "*")) {
+               int r = symtable_add_def(st, store_name, DEF_IMPORT); 
+               Py_DECREF(store_name);
+               return r;
+       }
+       else {
+            if (st->st_cur->ste_type != ModuleBlock) {
+                if (!symtable_warn(st,
+                                   "import * only allowed at module level"))
+                    return 0;
+            }
+           st->st_cur->ste_unoptimized |= OPT_IMPORT_STAR;
+           return 1;
+       }
+}
+
+
+static int 
+symtable_visit_comprehension(struct symtable *st, comprehension_ty lc)
+{
+       VISIT(st, expr, lc->target);
+       VISIT(st, expr, lc->iter);
+       VISIT_SEQ(st, expr, lc->ifs);
+       return 1;
+}
+
+
+static int 
+symtable_visit_keyword(struct symtable *st, keyword_ty k)
+{
+       VISIT(st, expr, k->value);
+       return 1;
+}
+
+
+static int 
+symtable_visit_slice(struct symtable *st, slice_ty s)
+{
+       switch (s->kind) {
+       case Slice_kind:
+               if (s->v.Slice.lower)
+                       VISIT(st, expr, s->v.Slice.lower)
+               if (s->v.Slice.upper)
+                       VISIT(st, expr, s->v.Slice.upper)
+               if (s->v.Slice.step)
+                       VISIT(st, expr, s->v.Slice.step)
+               break;
+       case ExtSlice_kind:
+               VISIT_SEQ(st, slice, s->v.ExtSlice.dims)
+               break;
+       case Index_kind:
+               VISIT(st, expr, s->v.Index.value)
+               break;
+       case Ellipsis_kind:
+               break;
+       }
+       return 1;
+}
+
+static int 
+symtable_visit_genexp(struct symtable *st, expr_ty e)
+{
+       identifier tmp;
+       comprehension_ty outermost = ((comprehension_ty)
+                        (asdl_seq_GET(e->v.GeneratorExp.generators, 0)));
+       /* Outermost iterator is evaluated in current scope */
+       VISIT(st, expr, outermost->iter);
+       /* Create generator scope for the rest */
+       tmp = PyString_FromString("<genexpr>");
+       if (!symtable_enter_block(st, tmp, FunctionBlock, (void *)e, 0)) {
+               return 0;
+       }
+       st->st_cur->ste_generator = 1;
+       /* Outermost iter is received as an argument */
+       if (!symtable_implicit_arg(st, 0)) {
+               return 0;
+       }
+       VISIT(st, expr, outermost->target);
+       VISIT_SEQ(st, expr, outermost->ifs);
+       VISIT_SEQ_TAIL(st, comprehension, e->v.GeneratorExp.generators, 1);
+       VISIT(st, expr, e->v.GeneratorExp.elt);
+       if (!symtable_exit_block(st, (void *)e))
+               return 0;
+       return 1;
+}
index 0775bb83c614987f7247884393cba3cf0e5e6fbe..d9f133705705d68ef8db9506a0ceab7596ab9bb1 100644 (file)
@@ -15,7 +15,7 @@ Data members:
 */
 
 #include "Python.h"
-#include "compile.h"
+#include "code.h"
 #include "frameobject.h"
 #include "eval.h"
 
index f40cfb4a2365abbcb8dc1b71b981b50d03c6461c..b58e8adceb42c8f9934469f65a79558ce52de072 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "Python.h"
 
-#include "compile.h"
+#include "code.h"
 #include "frameobject.h"
 #include "structmember.h"
 #include "osdefs.h"
index dd460c9911856d9a765ca8049d5b83d02aee15d8..8cfe3b1336b754cb9efbe5132559619262b16972 100755 (executable)
@@ -28,7 +28,7 @@ def walk(co, match=None):
         if type(obj) == types.CodeType:
             walk(obj, match)
 
-def main(filename, codename=None):
+def load(filename, codename=None):
     co = loadCode(filename)
     walk(co, codename)
 
@@ -39,6 +39,9 @@ if __name__ == "__main__":
     else:
         filename = sys.argv[1]
         codename = None
-    if filename.endswith('.py') and os.path.exists(filename+"c"):
-        filename += "c"
-    main(filename, codename)
+    if filename.endswith('.py'):
+        buf = open(filename).read()
+        co = compile(buf, filename, "exec")
+        walk(co)
+    else:   
+        load(filename, codename)