1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
*/
#include <string.h>
#define import_spp
#define import_libc
#define import_stdio
#include <iraf.h>
#include "config.h"
#include "mem.h"
#include "operand.h"
#include "param.h"
#include "task.h"
#include "errs.h"
#include "mem.h"
#include "proto.h"
/*
* STACK -- "stack" is actually two stacks:
* starting at the top and growing downwards is the "control stack",
* used for stacking compiler intermediates at compile time and the
* running and any pending task structs at runtime.
* the other, called the "operand stack", starts at the bottom and grows up.
* compiled code is put at its base and basos and topos are set when
* compilation completes to just above the last instruction. at run-time,
* starting at basos and growing upwards, it contains struct operands,
* possibly a string if o_type == OT_STRING, and the index of the last
* operand in a linked-list fashion; see pushop(). when runtime completes,
* its entire contents are disgarded by setting pc = bascode and starting new
* code compilation.
*
* in both cases, the respective "top" values are the indices into "stack" that
* were most recently last assigned. They are not related to the size of the
* object on the stack but always refer simply to the last integer index.
* valid topcs and topos always satisfy: 0 <= topos < topcs < STACKSIZ.
*/
memel stack[STACKSIZ]; /* control and operand stack combined */
XINT topcs = STACKSIZ; /* index of last cstack; grows downward */
XINT topos = -1; /* index of last ostack; grows upward */
XINT basos = -1; /* lowest legal index of operand stack */
/* Push a memel value onto the control stack. Return ERR if it would cause
* overflow, else OK. The control stack is used by the parser during
* compilation. If an error occurs during compilation, taskunwind() will
* call poptask() to pop tasks off the control stack. We must be careful
* to avoid having the compiler temporaries interfere with task frames.
*/
void
pushmem (memel v)
{
if (topcs - 1 > topos)
stack[--topcs] = v;
else
eprintf ("control stack overflow; topcs/topos = %d/%d\n",
topcs, topos);
}
/* Pop top memory value off control stack and return it.
* ==> no real err return, although it is checked.
*/
memel
popmem (void)
{
if (topcs < STACKSIZ)
return (stack[topcs++]);
else {
eprintf ("control stack underflow\n");
return ((memel) ERR);
}
}
/* PPush pushes an element onto the stack, but leaves the top
* of the stack untouched.
*/
void
ppushmem (memel p)
{
register memel q;
q = popmem();
pushmem(p);
pushmem(q);
}
/* push operand *op, string storage if o_type == OT_STRING, and last topos
* onto operand stack.
* return copy of new operand so that its o.o_val.v_s will point to the
* stack-stored string; if not string, it will be same as the passed *op.
* call error() if overflow and DO NOT RETURN.
*
* N.B. opcast() uses this layout intimately.
*
* --------------
* (new) topos -> | last topos |
* |--------------|
* | possible |
* | string |
* | storage |<-
* |--------------| |
* |struct operand| |
* | (o.o_val.v_s)|--
* |--------------|
* (last topos ->) | last topos |
* |--------------|
* ...
*/
struct operand
pushop (struct operand *op)
{
struct operand junk;
if (topos + OPSIZ+1 < topcs) {
int lasttopos = topos;
struct operand *dest;
dest = (struct operand *) &stack[topos+1];
*dest = *op;
if (op->o_type == OT_STRING) {
int len = btoi (strlen (op->o_val.v_s) + 1);
if (topos + OPSIZ+1 + len >= topcs)
goto overflow;
dest->o_val.v_s = (char *) &stack[topos+OPSIZ+1];
strcpy (dest->o_val.v_s, op->o_val.v_s);
topos += len;
}
topos += OPSIZ+1;
stack[topos] = lasttopos;
return (*dest);
}
overflow:
cl_error (E_IERR, e_soverflow, topcs, topos);
/* NOTREACHED */
return (junk);
}
/* pop top operand from stack and return copy of it. If type is string,
* be sure to use it before the next pushop() or the string will get clobbered.
* set topos to top of stack; see diagram with pushop().
* call error() and do not return if underflow.
*/
struct operand
popop (void)
{
struct operand junk;
if (topos > basos) {
struct operand *op;
topos = stack[topos];
op = (struct operand *) &stack[topos+1];
return (*op);
}
cl_error (E_UERR, e_sunderflow);
/* NOTREACHED */
return (junk);
}
/* Create a new, uninitialized, task on the control stack. Call error()
* and don't return if overflow, else return pointer to new entry. Save
* index of new task frame so that we don't get confused by temporaries
* left on the stack by the parser if error occurs during parsing.
*/
int last_task_frame; /* for error recovery */
struct task *
pushtask (void)
{
if (topcs - TASKSIZ > topos) {
topcs -= TASKSIZ;
last_task_frame = topcs;
return ((struct task *) &stack[topcs]);
}
cl_error (E_UERR, "task stack overflow"); /* does not return */
/* NOTREACHED */
return ((struct task *) NULL);
}
/* Increment topcs and return pointer to next task struct on control stack.
* (Top entry may be inspected with pushtask (poptask()) or with currentask.)
* Call error() and do not return on underflow.
*/
struct task *
poptask (void)
{
if (topcs <= STACKSIZ - TASKSIZ) {
if (topcs < last_task_frame) {
/* If we get here, something has been pushed on the control
* stack by pop() since the last task frame, which did not
* get cleared off. This may happen if error() is called
* during compilation.
*/
topcs = last_task_frame;
}
topcs += TASKSIZ;
last_task_frame = topcs;
return ((struct task *) &stack[topcs]);
}
cl_error (E_IERR, "Control stack underflow: topcs = %d", topcs);
/* NOTREACHED */
return ((struct task *) NULL);
}
|