/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: estack.h,v 1.2.6.1.2.1 2003/01/17 00:49:00 giles Exp $ */ /* Definitions for the execution stack */ #ifndef estack_INCLUDED # define estack_INCLUDED #include "iestack.h" #include "icstate.h" /* for access to exec_stack */ /* There's only one exec stack right now.... */ #define esfile (iexec_stack.current_file) #define esfile_clear_cache() estack_clear_cache(&iexec_stack) #define esfile_set_cache(pref) estack_set_cache(&iexec_stack, pref) #define esfile_check_cache() estack_check_cache(&iexec_stack) /* Define the execution stack pointers for operators. */ #define iexec_stack (i_ctx_p->exec_stack) #define e_stack (iexec_stack.stack) #define esbot (e_stack.bot) #define esp (e_stack.p) #define estop (e_stack.top) /* * The execution stack is used for three purposes: * * - Procedures being executed are held here. They always have * type = t_array, t_mixedarray, or t_shortarray, with a_executable set. * More specifically, the e-stack holds the as yet unexecuted tail of the * procedure. * * - if, ifelse, etc. push arguments to be executed here. * They may be any kind of object whatever. * * - Control operators (filenameforall, for, repeat, loop, forall, * pathforall, run, stopped, ...) mark the stack by pushing whatever state * they need to save or keep track of and then an object with type = t_null, * attrs = a_executable, size = es_xxx (see below), and value.opproc = a * cleanup procedure that will get called whenever the execution stack is * about to get cut back beyond this point because of an error, stop, exit, * or quit. (Executable null objects can't ever appear on the e-stack * otherwise: if a control operator pushes one, it gets popped immediately.) * The cleanup procedure is called with esp pointing just BELOW the mark, * i.e., the mark has already been popped. * * The loop operators also push whatever state they need, * followed by an operator object that handles continuing the loop. * * Note that there are many internal operators that need to be handled like * looping operators -- for example, all the 'show' operators, since they * may call out to BuildChar procedures. */ /* Macro for marking the execution stack */ #define make_mark_estack(ep, es_idx, proc)\ make_tasv(ep, t_null, a_executable, es_idx, opproc, proc) #define push_mark_estack(es_idx, proc)\ (++esp, make_mark_estack(esp, es_idx, proc)) #define r_is_estack_mark(ep)\ r_has_type_attrs(ep, t_null, a_executable) #define estack_mark_index(ep) r_size(ep) #define set_estack_mark_index(ep, es_idx) r_set_size(ep, es_idx) /* Macro for pushing an operator on the execution stack */ /* to represent a continuation procedure */ #define make_op_estack(ep, proc)\ make_oper(ep, 0, proc) #define push_op_estack(proc)\ (++esp, make_op_estack(esp, proc)) /* Macro to ensure enough room on the execution stack */ #define check_estack(n)\ if ( esp > estop - (n) )\ { int es_code_ = ref_stack_extend(&e_stack, n);\ if ( es_code_ < 0 ) return es_code_;\ } /* Macro to ensure enough entries on the execution stack */ #define check_esp(n)\ if ( esp < esbot + ((n) - 1) )\ { e_stack.requested = (n); return_error(e_ExecStackUnderflow); } /* Define the various kinds of execution stack marks. */ #define es_other 0 /* internal use */ #define es_show 1 /* show operators */ #define es_for 2 /* iteration operators */ #define es_stopped 3 /* stopped operator */ /* * Pop a given number of elements off the execution stack, * executing cleanup procedures as necessary. */ void pop_estack(P2(i_ctx_t *, uint)); /* * The execution stack is implemented as a linked list of blocks; * operators that can push or pop an unbounded number of values, or that * access the entire e-stack, must take this into account. These are: * exit .stop .instopped countexecstack execstack currentfile * .execn * pop_estack(exit, stop, error recovery) * gs_show_find(all the show operators) * In addition, for e-stack entries created by control operators, we must * ensure that the mark and its data are never separated. We do this * by ensuring that when splitting the top block, at least N items * are kept in the new top block above the bottommost retained mark, * where N is the largest number of data items associated with a mark. * Finally, in order to avoid specific checks for underflowing a block, * we put a guard entry at the bottom of each block except the top one * that contains a procedure that returns an internal "exec stack block * underflow" error. */ #endif /* estack_INCLUDED */