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