cfad47cfa3/tads2/run.h

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
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 */