[Python-checkins] python/dist/src/Python newcompile.c,1.1.2.1,1.1.2.2
jhylton@users.sourceforge.net
jhylton@users.sourceforge.net
Fri, 02 Aug 2002 10:53:01 -0700
Update of /cvsroot/python/python/dist/src/Python
In directory usw-pr-cvs1:/tmp/cvs-serv26163/Python
Modified Files:
Tag: ast-branch
newcompile.c
Log Message:
Extend compiler to handle for and while loops and if statements,
including break and continue.
Add fblock support -- a block on the frame for loops and try/excepts
as opposed to a basic block in the compiler.
Add compiler_error() helper to raise SyntaxError.
Fix many small bugs and typos to allow compilation without (much)
warning.
Index: newcompile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/Attic/newcompile.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -C2 -d -r1.1.2.1 -r1.1.2.2
*** newcompile.c 9 Jul 2002 13:24:45 -0000 1.1.2.1
--- newcompile.c 2 Aug 2002 17:52:59 -0000 1.1.2.2
***************
*** 7,10 ****
--- 7,24 ----
#include "opcode.h"
+ /* 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.
+ */
+
+ enum fblocktype { LOOP, EXCEPT, FINALLY_TRY, FINALLY_END };
+
+ struct fblockinfo {
+ enum fblocktype fb_type;
+ int fb_block;
+ };
+
struct compiler {
const char *c_filename;
***************
*** 22,42 ****
struct basicblock c_exit;
struct basicblock **c_blocks;
};
! static void
! compiler_free(struct compiler *c)
! {
! int i;
! if (c->c_st)
! PySymtable_Free(c->c_st);
! if (c->c_future)
! PyMem_Free((void *)c->c_future);
! for (i = 0; i < c->c_nblocks; i++)
! free((void *)c->c_blocks[i]);
! if (c->c_blocks)
! free((void *)c->c_blocks);
! }
PyCodeObject *
--- 36,67 ----
struct basicblock c_exit;
struct basicblock **c_blocks;
+
+ int c_nfblocks;
+ struct fblockinfo c_fblock[CO_MAXBLOCKS];
+
+ int c_lineno;
};
! static int compiler_enter_scope(struct compiler *, identifier, void *);
! static int compiler_exit_scope(struct compiler *, identifier, void *);
! static void compiler_free(struct compiler *);
! static PyCodeObject *compiler_get_code(struct compiler *);
! static int compiler_new_block(struct compiler *);
! static int compiler_next_instr(struct compiler *, int);
! static int compiler_addop(struct compiler *, int);
! static int compiler_addop_o(struct compiler *, int, PyObject *);
! static int compiler_addop_i(struct compiler *, int, int);
! static void compiler_use_block(struct compiler *, int);
! static int compiler_use_new_block(struct compiler *);
! static int compiler_error(struct compiler *, const char *);
! static int compiler_mod(struct compiler *, mod_ty);
! static int compiler_visit_stmt(struct compiler *, stmt_ty);
! static int compiler_visit_expr(struct compiler *, expr_ty);
! static int compiler_visit_arguments(struct compiler *, arguments_ty);
! static int compiler_visit_slice(struct compiler *, slice_ty);
+ static int compiler_push_fblock(struct compiler *, enum fblocktype, int);
+ static void compiler_pop_fblock(struct compiler *, enum fblocktype, int);
PyCodeObject *
***************
*** 44,48 ****
{
struct compiler c;
- PyCodeObject *co;
c.c_filename = filename;
--- 69,72 ----
***************
*** 56,60 ****
}
! c.c_st = PySymtable_Build(mod, filename, flags);
if (c.c_st == NULL)
goto error;
--- 80,84 ----
}
! c.c_st = PySymtable_Build(mod, filename, c.c_future);
if (c.c_st == NULL)
goto error;
***************
*** 68,71 ****
--- 92,111 ----
}
+ static void
+ compiler_free(struct compiler *c)
+ {
+ int i;
+
+ if (c->c_st)
+ PySymtable_Free(c->c_st);
+ if (c->c_future)
+ PyMem_Free((void *)c->c_future);
+ for (i = 0; i < c->c_nblocks; i++)
+ free((void *)c->c_blocks[i]);
+ if (c->c_blocks)
+ free((void *)c->c_blocks);
+ }
+
+
static int
compiler_enter_scope(struct compiler *c, identifier name, void *key)
***************
*** 84,88 ****
}
assert(PySymtableEntry_Check(v));
! c->c_symbols = v;
c->c_nblocks = 0;
--- 124,128 ----
}
assert(PySymtableEntry_Check(v));
! c->c_symbols = (PySymtableEntryObject *)v;
c->c_nblocks = 0;
***************
*** 111,114 ****
--- 151,158 ----
}
+ /* Allocate a new block and return its index in c_blocks.
+ Returns 0 on error.
+ */
+
static int
compiler_new_block(struct compiler *c)
***************
*** 135,139 ****
}
! /* Note: returns -1 on failure */
static int
compiler_next_instr(struct compiler *c, int block)
--- 179,204 ----
}
! static void
! compiler_use_block(struct compiler *c, int block)
! {
! assert(block < c->c_nblocks);
! c->c_curblock = block;
! }
!
! static int
! compiler_use_new_block(struct compiler *c)
! {
! int block = compiler_new_block(c);
! if (!block)
! return 0;
! c->c_curblock = block;
! return block;
! }
!
! /* 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 int
compiler_next_instr(struct compiler *c, int block)
***************
*** 142,146 ****
assert(block < c->c_nblocks);
b = c->c_blocks[block];
! if (b->b_ioffset == b->b_ialloc) {
void *ptr;
int newsize;
--- 207,211 ----
assert(block < c->c_nblocks);
b = c->c_blocks[block];
! if (b->b_iused == b->b_ialloc) {
void *ptr;
int newsize;
***************
*** 153,159 ****
c->c_blocks[block] = (struct basicblock *)ptr;
}
! return b->b_ioffset++;
}
static int
compiler_addop(struct compiler *c, int opcode)
--- 218,228 ----
c->c_blocks[block] = (struct basicblock *)ptr;
}
! return b->b_iused++;
}
+ /* Add an opcode with no argument.
+ Returns 0 on failure, 1 on success.
+ */
+
static int
compiler_addop(struct compiler *c, int opcode)
***************
*** 167,170 ****
--- 236,243 ----
}
+ /* Add an opcode with a PyObject * argument.
+ Returns 0 on failure, 1 on success.
+ */
+
static int
compiler_addop_o(struct compiler *c, int opcode, PyObject *o)
***************
*** 175,179 ****
if (off < 0)
return 0;
! i = c->c_blocks[c->c_curblock];
i->i_opcode = i->i_opcode;
i->i_arg = o;
--- 248,252 ----
if (off < 0)
return 0;
! i = &c->c_blocks[c->c_curblock]->b_instr[off];
i->i_opcode = i->i_opcode;
i->i_arg = o;
***************
*** 181,184 ****
--- 254,261 ----
}
+ /* Add an opcode with an integer argument.
+ Returns 0 on failure, 1 on success.
+ */
+
static int
compiler_addop_i(struct compiler *c, int opcode, int oparg)
***************
*** 189,193 ****
if (off < 0)
return 0;
! i = c->c_blocks[c->c_curblock];
i->i_opcode = i->i_opcode;
i->i_oparg = oparg;
--- 266,270 ----
if (off < 0)
return 0;
! i = &c->c_blocks[c->c_curblock]->b_instr[off];
i->i_opcode = i->i_opcode;
i->i_oparg = oparg;
***************
*** 195,201 ****
}
! /* 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.
! */
#define ADDOP(C, OP) { \
--- 272,279 ----
}
! #define NEW_BLOCK(C) { \
! if (!compiler_use_new_block((C))) \
! return 0; \
! }
#define ADDOP(C, OP) { \
***************
*** 214,217 ****
--- 292,299 ----
}
+ /* 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.
+ */
+
#define VISIT(C, TYPE, V) {\
if (!compiler_visit_ ## TYPE((C), (V))) \
***************
*** 249,253 ****
{
PyCodeObject *co;
! assert(s->kind == Function_kind);
if (s->v.FunctionDef.args->defaults)
--- 331,335 ----
{
PyCodeObject *co;
! assert(s->kind == FunctionDef_kind);
if (s->v.FunctionDef.args->defaults)
***************
*** 274,278 ****
dest = false;
if (s->v.Print.dest) {
! VISIT(C, EXPR, s->v.Print.dest);
dest = true;
}
--- 356,360 ----
dest = false;
if (s->v.Print.dest) {
! VISIT(c, expr, s->v.Print.dest);
dest = true;
}
***************
*** 280,289 ****
if (dest) {
ADDOP(c, DUP_TOP);
! VISIT(c, expr, asdl_get_seq(s->v.Print.values, i));
ADDOP(c, ROT_TWO);
ADDOP(c, PRINT_ITEM_TO);
}
else {
! VISIT(c, expr, asdl_get_seq(s->v.Print.values, i));
ADDOP(c, PRINT_ITEM);
}
--- 362,373 ----
if (dest) {
ADDOP(c, DUP_TOP);
! VISIT(c, expr,
! (expr_ty)asdl_seq_get(s->v.Print.values, i));
ADDOP(c, ROT_TWO);
ADDOP(c, PRINT_ITEM_TO);
}
else {
! VISIT(c, expr,
! (expr_ty)asdl_seq_get(s->v.Print.values, i));
ADDOP(c, PRINT_ITEM);
}
***************
*** 291,297 ****
if (s->v.Print.nl) {
if (dest)
! ADDOP(c, PRINT_NEWLINE_TO);
else
! ADDOP(c, PRINT_NEWLINE);
}
else if (dest)
--- 375,381 ----
if (s->v.Print.nl) {
if (dest)
! ADDOP(c, PRINT_NEWLINE_TO)
else
! ADDOP(c, PRINT_NEWLINE)
}
else if (dest)
***************
*** 301,317 ****
static int
! compiler_function(struct compiler *c, stmt_ty s)
{
! int i, n;
assert(s->kind == If_kind);
}
static int
! compiler_stmt(struct compiler *c, stmt_ty s)
{
int i, n;
!
switch (s->kind) {
case FunctionDef_kind:
--- 385,532 ----
static int
! compiler_if(struct compiler *c, stmt_ty s)
{
! int end, next, elif = 1;
assert(s->kind == If_kind);
+ end = compiler_new_block(c);
+ if (!end)
+ return 0;
+ while (elif) {
+ next = compiler_new_block(c);
+ if (!next)
+ return 0;
+ VISIT(c, expr, s->v.If.test);
+ ADDOP_I(c, JUMP_IF_FALSE, next);
+ NEW_BLOCK(c);
+ ADDOP(c, POP_TOP);
+ VISIT_SEQ(c, stmt, s->v.If.body);
+ ADDOP_I(c, JUMP_FORWARD, end);
+ compiler_use_block(c, next);
+ ADDOP(c, POP_TOP);
+ if (s->v.If.orelse) {
+ stmt_ty t = asdl_seq_get(s->v.If.orelse, 0);
+ if (t->kind == If_kind) {
+ elif = 1;
+ s = t;
+ c->c_lineno = t->lineno;
+ }
+ }
+ if (!elif)
+ VISIT_SEQ(c, stmt, s->v.If.orelse);
+ }
+ compiler_use_block(c, end);
+ return 1;
+ }
+
+ static int
+ compiler_for(struct compiler *c, stmt_ty s)
+ {
+ int start, cleanup, end;
+
+ start = compiler_new_block(c);
+ cleanup = compiler_new_block(c);
+ end = compiler_new_block(c);
+ if (!(start && end && cleanup))
+ return 0;
+ ADDOP_I(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_block(c, start);
+ ADDOP_I(c, FOR_ITER, cleanup);
+ VISIT(c, expr, s->v.For.target);
+ VISIT_SEQ(c, stmt, s->v.For.body);
+ ADDOP_I(c, JUMP_ABSOLUTE, start);
+ compiler_use_block(c, cleanup);
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, LOOP, start);
+ VISIT_SEQ(c, stmt, s->v.For.orelse);
+ compiler_use_block(c, end);
+ return 1;
+ }
+
+ static int
+ compiler_while(struct compiler *c, stmt_ty s)
+ {
+ int loop, orelse, end;
+ loop = compiler_new_block(c);
+ end = compiler_new_block(c);
+ if (!(loop && end))
+ return 0;
+ if (s->v.While.orelse) {
+ orelse = compiler_new_block(c);
+ if (!orelse)
+ return 0;
+ }
+ else
+ orelse = -1;
+
+ ADDOP_I(c, SETUP_LOOP, end);
+ compiler_use_block(c, loop);
+ if (!compiler_push_fblock(c, LOOP, loop))
+ return 0;
+ VISIT(c, expr, s->v.While.test);
+ ADDOP_I(c, JUMP_IF_FALSE, orelse == -1 ? end : orelse);
+ NEW_BLOCK(c);
+ ADDOP(c, POP_TOP);
+ VISIT_SEQ(c, stmt, s->v.While.body);
+ ADDOP_I(c, JUMP_ABSOLUTE, loop);
+
+ /* XXX should the two POP instructions be in a separate block
+ if there is no else clause ?
+ */
+ if (orelse == -1)
+ compiler_use_block(c, end);
+ else
+ compiler_use_block(c, orelse);
+ ADDOP(c, POP_TOP);
+ ADDOP(c, POP_BLOCK);
+ compiler_pop_fblock(c, LOOP, loop);
+ if (orelse != -1)
+ VISIT_SEQ(c, stmt, s->v.While.orelse);
+ compiler_use_block(c, end);
+
+ return 1;
+ }
+
+ static int
+ compiler_continue(struct compiler *c)
+ {
+ int i;
+ if (!c->c_nfblocks)
+ return compiler_error(c, "'continue' outside loop");
+ i = c->c_nfblocks - 1;
+ switch (c->c_fblock[i].fb_type) {
+ case LOOP:
+ ADDOP_I(c, JUMP_ABSOLUTE, c->c_fblock[i].fb_block);
+ NEW_BLOCK(c);
+ break;
+ case EXCEPT:
+ case FINALLY_TRY:
+ while (--i > 0 && c->c_fblock[i].fb_type != LOOP)
+ ;
+ if (i == -1)
+ return compiler_error(c, "'continue' outside loop");
+ ADDOP_I(c, CONTINUE_LOOP, c->c_fblock[i].fb_block);
+ NEW_BLOCK(c);
+ break;
+ case FINALLY_END:
+ return compiler_error(c,
+ "'continue' not allowed in 'finally' block");
+ break;
+ }
+
+ return 1;
}
static int
! compiler_visit_stmt(struct compiler *c, stmt_ty s)
{
int i, n;
!
! c->c_lineno = s->lineno; /* XXX this isn't right */
switch (s->kind) {
case FunctionDef_kind:
***************
*** 338,344 ****
VISIT(c, expr, s->v.Assign.value);
for (i = 0; i < n; i++) {
! if (i < n - 1)
ADDOP(c, DUP_TOP);
! VISIT(c, expr, asdl_get_seq(s->v.Assign.targets, i));
}
break;
--- 553,560 ----
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;
***************
*** 349,354 ****
--- 565,572 ----
break;
case For_kind:
+ return compiler_for(c, s);
break;
case While_kind:
+ return compiler_if(c, s);
break;
case If_kind:
***************
*** 357,367 ****
case Raise_kind:
if (s->v.Raise.type) {
! VISIT(st, expr, s->v.Raise.type);
n++;
if (s->v.Raise.inst) {
! VISIT(st, expr, s->v.Raise.inst);
n++;
if (s->v.Raise.tback) {
! VISIT(st, expr, s->v.Raise.tback);
n++;
}
--- 575,585 ----
case Raise_kind:
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++;
}
***************
*** 381,391 ****
break;
case Exec_kind:
! VISIT(st, expr, s->v.Exec.body);
if (s->v.Exec.globals) {
! VISIT(st, expr, s->v.Exec.globals);
! if (s->v.Exec.locals)
! VISIT(st, expr, s->v.Exec.locals);
! else
ADDOP(c, DUP_TOP);
} else {
ADDOP_O(c, LOAD_CONST, Py_None);
--- 599,610 ----
break;
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);
***************
*** 398,411 ****
case Expr_kind:
VISIT(c, expr, s->v.Expr.value);
! if (c->c_interactive)
ADDOP(c, PRINT_EXPR);
! else
ADDOP(c, DUP_TOP);
break;
case Pass_kind:
break;
case Break_kind:
break;
case Continue_kind:
break;
}
--- 617,636 ----
case Expr_kind:
VISIT(c, expr, s->v.Expr.value);
! if (c->c_interactive) {
ADDOP(c, PRINT_EXPR);
! }
! else {
ADDOP(c, DUP_TOP);
+ }
break;
case Pass_kind:
break;
case Break_kind:
+ if (!c->c_nfblocks)
+ return compiler_error(c, "'break' outside loop");
+ ADDOP(c, BREAK_LOOP);
break;
case Continue_kind:
+ compiler_continue(c);
break;
}
***************
*** 426,433 ****
return UNARY_NEGATIVE;
}
}
static int
! binop(operator_ty op)
{
switch (op) {
--- 651,659 ----
return UNARY_NEGATIVE;
}
+ return 0;
}
static int
! binop(struct compiler *c, operator_ty op)
{
switch (op) {
***************
*** 439,443 ****
return BINARY_MULTIPLY;
case Div:
! if (c->c_flags & CO_FUTURE_DIVISION)
return BINARY_TRUE_DIVIDE;
else
--- 665,669 ----
return BINARY_MULTIPLY;
case Div:
! if (c->c_flags->cf_flags & CO_FUTURE_DIVISION)
return BINARY_TRUE_DIVIDE;
else
***************
*** 460,463 ****
--- 686,690 ----
return BINARY_FLOOR_DIVIDE;
}
+ return 0;
}
***************
*** 473,477 ****
VISIT(c, expr, e->v.BinOp.left);
VISIT(c, expr, e->v.BinOp.right);
! ADDOP(c, binop(e->v.BinOp.op));
break;
case UnaryOp_kind:
--- 700,704 ----
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:
***************
*** 532,537 ****
break;
case Name_kind:
- compiler_add_def(c, e->v.Name.id,
- e->v.Name.ctx == Load ? USE : DEF_LOCAL);
break;
/* child nodes of List and Tuple will have expr_context set */
--- 759,762 ----
***************
*** 546,547 ****
--- 771,821 ----
}
+ static int
+ compiler_push_fblock(struct compiler *c, enum fblocktype t, int b)
+ {
+ struct fblockinfo *f;
+ if (c->c_nfblocks >= CO_MAXBLOCKS)
+ return 0;
+ f = &c->c_fblock[c->c_nfblocks++];
+ f->fb_type = t;
+ f->fb_block = b;
+ return 1;
+ }
+
+ static void
+ compiler_pop_fblock(struct compiler *c, enum fblocktype t, int b)
+ {
+ assert(c->c_nfblocks > 0);
+ c->c_nfblocks--;
+ assert(c->c_fblock[c->c_nfblocks].fb_type == t);
+ assert(c->c_fblock[c->c_nfblocks].fb_block == b);
+ }
+
+ /* Raises a SyntaxError and returns 0.
+ If something goes wrong, a different exception may be raised.
+ */
+
+ static int
+ compiler_error(struct compiler *c, const char *errstr)
+ {
+ PyObject *loc;
+ PyObject *u, *v;
+
+ loc = PyErr_ProgramText(c->c_filename, c->c_lineno);
+ if (!loc) {
+ Py_INCREF(Py_None);
+ loc = Py_None;
+ }
+ u = Py_BuildValue("(ziOO)", c->c_filename, c->c_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;
+ }