[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;
+ }