1 /*
2 $Header: d:/cvsroot/tads/TADS2/RUN.H,v 1.2 1999/05/17 02:52:13 MJRoberts Exp $
3 */
4 
5 /*
6  *   Copyright (c) 1991, 2002 Michael J. Roberts.  All Rights Reserved.
7  *
8  *   Please see the accompanying license file, LICENSE.TXT, for information
9  *   on using and copying this software.
10  */
11 /*
12 Name
13   run.h - definitions for code execution
14 Function
15   Definitions for code execution
16 Notes
17   The preprocessor symbol RUNFAST can be defined if run-time checking
18   of stack overflow, stack underflow, and other unusual but potentially
19   dangerous conditions is to be turned off.  This will result in
20   somewhat faster run-time performance, but run-time errors could be
21   disastrous.
22 Modified
23   10/20/91 MJRoberts     - creation
24 */
25 
26 #ifndef RUN_INCLUDED
27 #define RUN_INCLUDED
28 
29 #include "os.h"
30 #ifndef STD_INCLUDED
31 # include "std.h"
32 #endif
33 #ifndef OBJ_INCLUDED
34 # include "obj.h"
35 #endif
36 #ifndef PRP_INCLUDED
37 # include "prp.h"
38 #endif
39 #ifndef OPC_INCLUDED
40 # include "opc.h"
41 #endif
42 #ifndef TIO_INCLUDED
43 # include "tio.h"
44 #endif
45 #ifndef DBG_INCLUDED
46 # include "dbg.h"
47 #endif
48 #ifndef TOK_INCLUDED
49 # include "tok.h"
50 #endif
51 
52 #ifdef __cplusplus
53 extern "C" {
54 #endif
55 
56 /* forward declarations */
57 struct bifcxdef;
58 
59 /* stack element - the stack is an array of these structures */
60 struct runsdef
61 {
62     uchar  runstyp;                                      /* type of element */
63     union
64     {
65         long    runsvnum;                                  /* numeric value */
66         objnum  runsvobj;                                   /* object value */
67         prpnum  runsvprp;                          /* property number value */
68         uchar  *runsvstr;                              /* string/list value */
69     }      runsv;
70 };
71 typedef struct runsdef runsdef;
72 
73 /* external function control structure */
74 struct runxdef
75 {
76     char    runxnam[TOKNAMMAX + 1];            /* name of external function */
77     int   (*runxptr)(void *);          /* pointer to memory containing code */
78 };
79 typedef struct runxdef runxdef;
80 
81 /* external function context structure - passed to user exits */
82 struct runuxdef
83 {
84     struct runcxdef osfar_t *runuxctx;                  /* run-time context */
85     struct runufdef osfar_t *runuxvec;               /* vector of functions */
86     int                      runuxargc;   /* count of arguments to function */
87 };
88 typedef struct runuxdef runuxdef;
89 
90 /* external function callback vector */
91 struct runufdef
92 {
93     int    (osfar_t *runuftyp)(runuxdef *);         /* type of top of stack */
94     long   (osfar_t *runufnpo)(runuxdef *);                 /* pop a number */
95     uchar *(osfar_t *runufspo)(runuxdef *);                 /* pop a string */
96     void   (osfar_t *runufdsc)(runuxdef *); /* discard item at top of stack */
97     void   (osfar_t *runufnpu)(runuxdef *, long);          /* push a number */
98     void   (osfar_t *runufspu)(runuxdef *, uchar *); /* push alloc'd string */
99     void   (osfar_t *runufcspu)(runuxdef *, char *);     /* push a C-string */
100     uchar *(osfar_t *runufsal)(runuxdef *, int);   /* allocate a new string */
101     void   (osfar_t *runuflpu)(runuxdef *, int);/* push DAT_TRUE or DAT_NIL */
102 };
103 typedef struct runufdef runufdef;
104 
105 /* execution context */
106 struct runcxdef
107 {
108     errcxdef   *runcxerr;                       /* error management context */
109     mcmcxdef   *runcxmem;    /* cache manager context for object references */
110     runsdef    *runcxstk;                      /* base of interpreter stack */
111     runsdef    *runcxstop;                                  /* top of stack */
112     runsdef    *runcxsp;     /* current stack pointer (stack grows upwards) */
113     runsdef    *runcxbp;                                    /* base pointer */
114     uchar      *runcxheap;          /* run-time variable-length object heap */
115     uchar      *runcxhp;                            /* current heap pointer */
116     uchar      *runcxhtop;                                   /* top of heap */
117     objucxdef  *runcxundo;                                  /* undo context */
118     tiocxdef   *runcxtio;                               /* text I/O context */
119     void       *runcxbcx;        /* context for built-in callback functions */
120     void     (**runcxbi)(struct bifcxdef *ctx, int argc);
121                                                       /* built-in functions */
122     struct dbgcxdef *runcxdbg;                          /* debugger context */
123     struct voccxdef *runcxvoc;             /* player command parser context */
124     void      (*runcxdmd)(void *ctx, objnum obj, prpnum prp);
125                                          /* demand-loader callback function */
126     void       *runcxdmc;                 /* demand-loader callback context */
127     runxdef    *runcxext;                        /* external function array */
128     int         runcxexc;                    /* count of external functions */
129     uint        runcxlofs;        /* offset of last line record encountered */
130     char       *runcxgamename;                     /* name of the .GAM file */
131 };
132 typedef struct runcxdef runcxdef;
133 
134 /* execute a function, given the function object number */
135 void runfn(runcxdef *ctx, noreg objnum objn, int argc);
136 
137 /*
138  *   Execute p-code given a pointer to the code.  p is the actual pointer
139  *   to the first byte of code to be executed. self is the object to be
140  *   used for the special 'self' pseudo-object, and target is the object
141  *   whose data are actually being executed.  targprop is the property being
142  *   executed; 0 is used for functions.
143  */
144 void runexe(runcxdef *ctx, uchar *p, objnum self, objnum target,
145             prpnum targprop, int argc);
146 
147 /* push a value onto the stack */
148 void runpush(runcxdef *ctx, dattyp typ, runsdef *val);
149 
150 /* push a value onto the stack that's already in the heap */
151 void runrepush(runcxdef *ctx, runsdef *val);
152 
153 /* push a number onto the stack */
154 void runpnum(runcxdef *ctx, long val);
155 
156 /* push an object onto the stack */
157 void runpobj(runcxdef *ctx, objnum obj);
158 
159 /* push nil */
160 void runpnil(runcxdef *ctx);
161 
162 /* push a value onto the stack from a buffer (propdef, list) */
163 void runpbuf(runcxdef *ctx, int typ, void *val);
164 
165 /* push a counted-length string onto the stack */
166 void runpstr(runcxdef *ctx, char *str, int len, int sav);
167 
168 /*
169  *   Push a C-style string onto the stack, converting escape codes.  If
170  *   the character contains backslashes, newline, or tab characters, we'll
171  *   convert these characters to their escaped equivalent.
172  */
173 void runpushcstr(runcxdef *ctx, char *str, size_t len, int sav);
174 
175 /*
176  *   Push a property onto the stack.  codepp is a pointer to the caller's
177  *   code pointer, which will be updated if necessary; callobj and
178  *   callofsp are the object and starting offset within the object of the
179  *   code being executed by the caller, which are needed to update
180  *   *codepp.  Property 0 is used if a function is being executed.  obj
181  *   and prop are the object and property number whose value is to be
182  *   pushed.  If 'inh' is TRUE, it means that only a property inherited
183  *   by 'obj' is to be considered; this is used for "pass"/"inherited"
184  *   operations, with the current target object given as 'obj'.
185  */
186 void runpprop(runcxdef *ctx, uchar *noreg *codepp, objnum callobj,
187               prpnum callprop, noreg objnum obj, prpnum prop, int inh,
188               int argc, objnum self);
189 
190 /* top level runpprop, when caller is not executing in an object */
191 /* void runppr(runcxdef *ctx, objnum obj, prpnum prp, int argc); */
192 #define runppr(ctx, obj, prp, argc) \
193  runpprop(ctx, (uchar **)0, (objnum)0, (prpnum)0, obj, prp, FALSE, argc, obj)
194 
195 /* discard top element on stack */
196 /* void rundisc(runcxdef *ctx); */
197 #define rundisc(ctx) (runstkund(ctx), (--((ctx)->runcxsp)))
198 
199 /* pop the top element on the stack */
200 /* void runpop(runcxdef *ctx, runsdef *val); */
201 #define runpop(ctx, v) \
202  (runstkund(ctx), memcpy(v, (--((ctx)->runcxsp)), (size_t)sizeof(runsdef)))
203 
204 /* pop a numeric value, signalling an error if not a number */
205 /* long runpopnum(runcxdef *ctx); */
206 #define runpopnum(ctx) \
207  (runstkund(ctx), ((--((ctx)->runcxsp))->runstyp!=DAT_NUMBER ? \
208   (runsig(ctx,ERR_REQNUM), (long)0) : \
209   ((ctx)->runcxsp->runsv.runsvnum)))
210 
211 /* pop an object, signalling an error if not an object */
212 /* objnum runpopobj(runcxdef *ctx); */
213 #define runpopobj(ctx) \
214  (runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_OBJECT ? \
215   (runsig(ctx,ERR_REQVOB), (objnum)0) : \
216   ((ctx)->runcxsp->runsv.runsvobj))
217 
218 /* pop an object or nil - returns MCMONINV if the value is nil */
219 #define runpopobjnil(ctx) \
220   (runstkund(ctx), ((--(ctx)->runcxsp))->runstyp==DAT_OBJECT ? \
221    ((ctx)->runcxsp->runsv.runsvobj) : \
222    ((ctx)->runcxsp->runstyp==DAT_NIL ? MCMONINV : \
223     (runsig(ctx,ERR_REQVOB), (objnum)0)))
224 
225 /* pop a list, signalling an error if not a list */
226 /* uchar *runpoplst(runcxdef *ctx); */
227 #define runpoplst(ctx) \
228  (runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_LIST ? \
229   (runsig(ctx,ERR_REQVLS), (uchar *)0) : \
230   (uchar *)((ctx)->runcxsp->runsv.runsvstr))
231 
232 /* pop a property number, signalling an error if not a property number */
233 /* prpnum runpopprp(runcxdef *ctx); */
234 #define runpopprp(ctx) \
235  (runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_PROPNUM ? \
236   (runsig(ctx,ERR_REQVPR), (prpnum)0) : \
237   ((ctx)->runcxsp->runsv.runsvprp))
238 
239 
240 /* pop function pointer */
241 /* objnum runpopfn(runcxdef *ctx); */
242 #define runpopfn(ctx) \
243   ((objnum)(runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_FNADDR ? \
244                       (runsig(ctx,ERR_REQVFN), (objnum)0) : \
245                       ((ctx)->runcxsp->runsv.runsvobj)))
246 
247 /* pop a string value */
248 /* char *runpopstr(runcxdef *ctx); */
249 #define runpopstr(ctx) \
250  (runstkund(ctx), ((--((ctx)->runcxsp))->runstyp!=DAT_SSTRING ? \
251   (runsig(ctx,ERR_REQSTR), (uchar *)0) : \
252   ((ctx)->runcxsp->runsv.runsvstr)))
253 
254 
255 /* pop a logical value - TRUE for DAT_TRUE, FALSE for DAT_NIL */
256 /* int runpoplog(runcxdef *ctx); */
257 #define runpoplog(ctx) \
258  ((--((ctx)->runcxsp))->runstyp==DAT_TRUE ? TRUE : \
259   (ctx)->runcxsp->runstyp==DAT_NIL ? FALSE : \
260   (runsig(ctx, ERR_REQLOG), 0))
261 
262 /* get type of top of stack */
263 /* int runtostyp(runcxdef *ctx); */
264 #define runtostyp(ctx) (((ctx)->runcxsp - 1)->runstyp)
265 
266 /* determine if top of stack is logical value (returns TRUE if so) */
267 /* int runtoslog(runcxdef *ctx); */
268 #define runtoslog(ctx) \
269  (runtostyp(ctx) == DAT_TRUE || runtostyp(ctx) == DAT_NIL)
270 
271 /* convert C logical to TADS logical (TRUE->DAT_TRUE, FALSE->DAT_NIL) */
272 /* int runclog(int log); */
273 #define runclog(l) ((l) ? DAT_TRUE : DAT_NIL)
274 
275 /* compare magnitudes of numbers/strings on top of stack; strcmp-like value */
276 int runmcmp(runcxdef *ctx);
277 
278 /* TRUE if items at top of stack are equal, FALSE otherwise */
279 int runeq(runcxdef *ctx);
280 
281 /* check for stack underflow */
282 /* void runstkund(runcxdef *ctx); */
283 
284 /* check for stack overflow */
285 /* void runstkovf(runcxdef *ctx); */
286 
287 /*
288  *   Check to ensure we have enough arguments to pass to a function or method
289  *   call - this simply ensures we have enough data in the current frame.
290  *   This is important because the called function will be able to write to
291  *   our frame.  If we don't have enough arguments, we'll push enough 'nil'
292  *   values to meet the need.
293  */
294 #define runcheckargc(ctx, nargc) \
295     while ((ctx)->runcxsp - (ctx)->runcxbp < *(nargc)) \
296         runpnil(ctx)
297 
298 #ifdef RUNFAST
299 # define runstkovf(ctx) (DISCARD 0)
300 # define runstkund(ctx) (DISCARD 0)
301 #else /* RUNFAST */
302 # define runstkovf(ctx) \
303  ((ctx)->runcxsp >= (ctx)->runcxstop ? (runsig(ctx, ERR_STKOVF), \
304  DISCARD 0) : DISCARD 0)
305 # define runstkund(ctx) \
306  ((ctx)->runcxsp == (ctx)->runcxstk ? runsig(ctx, ERR_STKUND), \
307  DISCARD 0 : DISCARD 0)
308 #endif /* RUNFAST */
309 
310 /* reserve space in heap, collecting garbage if necessary */
311 /* void runhres(runcxdef *ctx, uint siz, uint below); */
312 #define runhres(ctx, siz, below) \
313  ((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
314  (runhcmp(ctx, siz, below, (runsdef *)0, (runsdef *)0, (runsdef *)0),\
315   DISCARD 0))
316 
317 /* reserve space, with various amounts of saving */
318 #define runhres1(ctx, siz, below, val1) \
319   ((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
320   (runhcmp(ctx, siz, below, val1, (runsdef *)0, (runsdef *)0), DISCARD 0))
321 
322 #define runhres2(ctx, siz, below, val1, val2) \
323  ((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
324  (runhcmp(ctx, siz, below, val1, val2, (runsdef *)0), DISCARD 0))
325 
326 #define runhres3(ctx, siz, below, val1, val2, val3) \
327  ((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
328  (runhcmp(ctx, siz, below, val1, val2, val3), DISCARD 0))
329 
330 /* garbage collect heap, making sure 'siz' bytes are available afterwards */
331 void runhcmp(runcxdef *ctx, uint siz, uint below,
332              runsdef *val1, runsdef *val2, runsdef *val3);
333 
334 /* determine size of a data item */
335 int runsiz(runsdef *item);
336 
337 /* find a sublist within a list, returning pointer to sublist or NULL */
338 uchar *runfind(uchar *list, runsdef *item);
339 
340 /* add two runsdef values, returning result in *val */
341 void runadd(runcxdef *ctx, runsdef *val, runsdef *val2, uint below);
342 
343 /*
344  *   subtract val2 from val, returning result in *val; return TRUE if
345  *   value changed, FALSE otherwise (this is returned when subtracting
346  *   something from a list that isn't in the list)
347  */
348 int runsub(runcxdef *ctx, runsdef *val, runsdef *val2, uint below);
349 
350 /* restore code pointer from object.property + offset */
351 uchar *runcprst(runcxdef *ctx, uint ofs, objnum obj, prpnum prop);
352 
353 /* leave a stack frame, removing arguments */
354 /* void runleave(runcxdef *ctx, uint parms); */
355 #define runleave(ctx, parms) \
356  (((ctx)->runcxsp = (ctx)->runcxbp), \
357   ((ctx)->runcxbp = (runsdef *)((--((ctx)->runcxsp))->runsv.runsvstr)), \
358   ((ctx)->runcxsp -= (parms)))
359 
360 /* reset run-time: throw away entire stack and heap */
361 /* void runrst(runcxdef *ctx); */
362 #define runrst(ctx) (((ctx)->runcxsp = (ctx)->runcxstk), \
363                      ((ctx)->runcxhp = (ctx)->runcxheap), \
364                      dbgrst(ctx->runcxdbg))
365 
366 /* set up runtime status line display */
367 void runistat(struct voccxdef *vctx, struct runcxdef *rctx,
368                   struct tiocxdef *tctx);
369 
370 /* signal a run-time error - allows debugger trapping */
371 void runsign(runcxdef *ctx, int err);
372 
373 /* sign a run-time error with zero arguments */
374 #define runsig(ctx, err) (errargc((ctx)->runcxerr,0),runsign(ctx,err))
375 
376 /* signal a run-time error with one argument */
377 #define runsig1(ctx, err, typ, arg) \
378   (errargv((ctx)->runcxerr,0,typ,arg),errargc((ctx)->runcxerr,1),\
379    runsign(ctx,err))
380 
381 /* draw status line */
382 void runstat(void);
383 
384 /* initialize output status */
385 void runistat(struct voccxdef *vctx, struct runcxdef *rctx,
386               struct tiocxdef *tctx);
387 
388 #ifdef __cplusplus
389 }
390 #endif
391 
392 #endif /* RUN_INCLUDED */
393