Initial commit
This commit is contained in:
374
engines/glk/tads/tads2/run.h
Normal file
374
engines/glk/tads/tads2/run.h
Normal file
@@ -0,0 +1,374 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Definitions for code execution
|
||||
*
|
||||
* The preprocessor symbol RUNFAST can be defined if run - time checking
|
||||
* of stack overflow, stack underflow, and other unusual but potentially
|
||||
* dangerous conditions is to be turned off.This will result in somewhat
|
||||
* faster run-time performance, but run - time errors could be disastrous.
|
||||
*/
|
||||
|
||||
#ifndef GLK_TADS_TADS2_RUN
|
||||
#define GLK_TADS_TADS2_RUN
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "glk/tads/tads2/lib.h"
|
||||
#include "glk/tads/tads2/debug.h"
|
||||
#include "glk/tads/tads2/object.h"
|
||||
#include "glk/tads/tads2/memory_cache.h"
|
||||
#include "glk/tads/tads2/memory_cache_swap.h"
|
||||
#include "glk/tads/tads2/opcode.h"
|
||||
#include "glk/tads/tads2/property.h"
|
||||
#include "glk/tads/tads2/text_io.h"
|
||||
#include "glk/tads/tads2/tokenizer.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace TADS {
|
||||
namespace TADS2 {
|
||||
|
||||
/* forward declarations */
|
||||
struct bifcxdef;
|
||||
|
||||
/* stack element - the stack is an array of these structures */
|
||||
struct runsdef {
|
||||
uchar runstyp; /* type of element */
|
||||
union {
|
||||
long runsvnum; /* numeric value */
|
||||
objnum runsvobj; /* object value */
|
||||
prpnum runsvprp; /* property number value */
|
||||
uchar *runsvstr; /* string/list value */
|
||||
} runsv;
|
||||
|
||||
runsdef() : runstyp(0) {
|
||||
runsv.runsvnum = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/* external function control structure */
|
||||
struct runxdef {
|
||||
char runxnam[TOKNAMMAX + 1]; /* name of external function */
|
||||
int (*runxptr)(void *); /* pointer to memory containing code */
|
||||
};
|
||||
|
||||
/* external function context structure - passed to user exits */
|
||||
struct runuxdef {
|
||||
struct runcxdef osfar_t *runuxctx; /* run-time context */
|
||||
struct runufdef osfar_t *runuxvec; /* vector of functions */
|
||||
int runuxargc; /* count of arguments to function */
|
||||
};
|
||||
|
||||
/* external function callback vector */
|
||||
struct runufdef {
|
||||
int (osfar_t *runuftyp)(runuxdef *); /* type of top of stack */
|
||||
long (osfar_t *runufnpo)(runuxdef *); /* pop a number */
|
||||
uchar *(osfar_t *runufspo)(runuxdef *); /* pop a string */
|
||||
void (osfar_t *runufdsc)(runuxdef *); /* discard item at top of stack */
|
||||
void (osfar_t *runufnpu)(runuxdef *, long); /* push a number */
|
||||
void (osfar_t *runufspu)(runuxdef *, uchar *); /* push alloc'd string */
|
||||
void (osfar_t *runufcspu)(runuxdef *, char *); /* push a C-string */
|
||||
uchar *(osfar_t *runufsal)(runuxdef *, int); /* allocate a new string */
|
||||
void (osfar_t *runuflpu)(runuxdef *, int);/* push DAT_TRUE or DAT_NIL */
|
||||
};
|
||||
|
||||
/* execution context */
|
||||
struct runcxdef {
|
||||
errcxdef *runcxerr; /* error management context */
|
||||
mcmcxdef *runcxmem; /* cache manager context for object references */
|
||||
runsdef *runcxstk; /* base of interpreter stack */
|
||||
runsdef *runcxstop; /* top of stack */
|
||||
runsdef *runcxsp; /* current stack pointer (stack grows upwards) */
|
||||
runsdef *runcxbp; /* base pointer */
|
||||
uchar *runcxheap; /* run-time variable-length object heap */
|
||||
uchar *runcxhp; /* current heap pointer */
|
||||
uchar *runcxhtop; /* top of heap */
|
||||
objucxdef *runcxundo; /* undo context */
|
||||
tiocxdef *runcxtio; /* text I/O context */
|
||||
void *runcxbcx; /* context for built-in callback functions */
|
||||
void (**runcxbi)(struct bifcxdef *ctx, int argc);
|
||||
/* built-in functions */
|
||||
struct dbgcxdef *runcxdbg; /* debugger context */
|
||||
struct voccxdef *runcxvoc; /* player command parser context */
|
||||
void (*runcxdmd)(void *ctx, objnum obj, prpnum prp);
|
||||
/* demand-loader callback function */
|
||||
void *runcxdmc; /* demand-loader callback context */
|
||||
runxdef *runcxext; /* external function array */
|
||||
int runcxexc; /* count of external functions */
|
||||
uint runcxlofs; /* offset of last line record encountered */
|
||||
char *runcxgamename; /* name of the .GAM file */
|
||||
char *runcxgamepath; /* absolute directory path of .GAM file */
|
||||
};
|
||||
|
||||
/* execute a function, given the function object number */
|
||||
void runfn(runcxdef *ctx, noreg objnum objn, int argc);
|
||||
|
||||
/*
|
||||
* Execute p-code given a pointer to the code. p is the actual pointer
|
||||
* to the first byte of code to be executed. self is the object to be
|
||||
* used for the special 'self' pseudo-object, and target is the object
|
||||
* whose data are actually being executed. targprop is the property being
|
||||
* executed; 0 is used for functions.
|
||||
*/
|
||||
void runexe(runcxdef *ctx, uchar *p, objnum self, objnum target,
|
||||
prpnum targprop, int argc);
|
||||
|
||||
/* push a value onto the stack */
|
||||
void runpush(runcxdef *ctx, dattyp typ, runsdef *val);
|
||||
|
||||
/* push a value onto the stack that's already in the heap */
|
||||
void runrepush(runcxdef *ctx, runsdef *val);
|
||||
|
||||
/* push a number onto the stack */
|
||||
void runpnum(runcxdef *ctx, long val);
|
||||
|
||||
/* push an object onto the stack */
|
||||
void runpobj(runcxdef *ctx, objnum obj);
|
||||
|
||||
/* push nil */
|
||||
void runpnil(runcxdef *ctx);
|
||||
|
||||
/* push a value onto the stack from a buffer (propdef, list) */
|
||||
void runpbuf(runcxdef *ctx, int typ, void *val);
|
||||
|
||||
/* push a counted-length string onto the stack */
|
||||
void runpstr(runcxdef *ctx, const char *str, int len, int sav);
|
||||
|
||||
/*
|
||||
* Push a C-style string onto the stack, converting escape codes. If
|
||||
* the character contains backslashes, newline, or tab characters, we'll
|
||||
* convert these characters to their escaped equivalent.
|
||||
*/
|
||||
void runpushcstr(runcxdef *ctx, const char *str, size_t len, int sav);
|
||||
|
||||
/*
|
||||
* Push a property onto the stack. codepp is a pointer to the caller's
|
||||
* code pointer, which will be updated if necessary; callobj and
|
||||
* callofsp are the object and starting offset within the object of the
|
||||
* code being executed by the caller, which are needed to update
|
||||
* *codepp. Property 0 is used if a function is being executed. obj
|
||||
* and prop are the object and property number whose value is to be
|
||||
* pushed. If 'inh' is TRUE, it means that only a property inherited
|
||||
* by 'obj' is to be considered; this is used for "pass"/"inherited"
|
||||
* operations, with the current target object given as 'obj'.
|
||||
*/
|
||||
void runpprop(runcxdef *ctx, uchar *noreg *codepp, objnum callobj,
|
||||
prpnum callprop, noreg objnum obj, prpnum prop, int inh,
|
||||
int argc, objnum self);
|
||||
|
||||
/* top level runpprop, when caller is not executing in an object */
|
||||
/* void runppr(runcxdef *ctx, objnum obj, prpnum prp, int argc); */
|
||||
#define runppr(ctx, obj, prp, argc) \
|
||||
runpprop(ctx, (uchar **)0, (objnum)0, (prpnum)0, obj, prp, FALSE, argc, obj)
|
||||
|
||||
/* discard top element on stack */
|
||||
/* void rundisc(runcxdef *ctx); */
|
||||
#define rundisc(ctx) (runstkund(ctx), (--((ctx)->runcxsp)))
|
||||
|
||||
/* pop the top element on the stack */
|
||||
/* void runpop(runcxdef *ctx, runsdef *val); */
|
||||
#define runpop(ctx, v) \
|
||||
(runstkund(ctx), memcpy(v, (--((ctx)->runcxsp)), (size_t)sizeof(runsdef)))
|
||||
|
||||
/* pop a numeric value, signalling an error if not a number */
|
||||
/* long runpopnum(runcxdef *ctx); */
|
||||
#define runpopnum(ctx) \
|
||||
(runstkund(ctx), ((--((ctx)->runcxsp))->runstyp!=DAT_NUMBER ? \
|
||||
(runsig(ctx,ERR_REQNUM), (long)0) : \
|
||||
((ctx)->runcxsp->runsv.runsvnum)))
|
||||
|
||||
/* pop an object, signalling an error if not an object */
|
||||
/* objnum runpopobj(runcxdef *ctx); */
|
||||
#define runpopobj(ctx) \
|
||||
(runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_OBJECT ? \
|
||||
(runsig(ctx,ERR_REQVOB), (objnum)0) : \
|
||||
((ctx)->runcxsp->runsv.runsvobj))
|
||||
|
||||
/* pop an object or nil - returns MCMONINV if the value is nil */
|
||||
#define runpopobjnil(ctx) \
|
||||
(runstkund(ctx), ((--(ctx)->runcxsp))->runstyp==DAT_OBJECT ? \
|
||||
((ctx)->runcxsp->runsv.runsvobj) : \
|
||||
((ctx)->runcxsp->runstyp==DAT_NIL ? MCMONINV : \
|
||||
(runsig(ctx,ERR_REQVOB), (objnum)0)))
|
||||
|
||||
/* pop a list, signalling an error if not a list */
|
||||
/* uchar *runpoplst(runcxdef *ctx); */
|
||||
#define runpoplst(ctx) \
|
||||
(runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_LIST ? \
|
||||
(runsig(ctx,ERR_REQVLS), (uchar *)0) : \
|
||||
(uchar *)((ctx)->runcxsp->runsv.runsvstr))
|
||||
|
||||
/* pop a property number, signalling an error if not a property number */
|
||||
/* prpnum runpopprp(runcxdef *ctx); */
|
||||
#define runpopprp(ctx) \
|
||||
(runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_PROPNUM ? \
|
||||
(runsig(ctx,ERR_REQVPR), (prpnum)0) : \
|
||||
((ctx)->runcxsp->runsv.runsvprp))
|
||||
|
||||
|
||||
/* pop function pointer */
|
||||
/* objnum runpopfn(runcxdef *ctx); */
|
||||
#define runpopfn(ctx) \
|
||||
((objnum)(runstkund(ctx), ((--(ctx)->runcxsp))->runstyp!=DAT_FNADDR ? \
|
||||
(runsig(ctx,ERR_REQVFN), (objnum)0) : \
|
||||
((ctx)->runcxsp->runsv.runsvobj)))
|
||||
|
||||
/* pop a string value */
|
||||
/* char *runpopstr(runcxdef *ctx); */
|
||||
#define runpopstr(ctx) \
|
||||
(runstkund(ctx), ((--((ctx)->runcxsp))->runstyp!=DAT_SSTRING ? \
|
||||
(runsig(ctx,ERR_REQSTR), (uchar *)0) : \
|
||||
((ctx)->runcxsp->runsv.runsvstr)))
|
||||
|
||||
|
||||
/* pop a logical value - TRUE for DAT_TRUE, FALSE for DAT_NIL */
|
||||
/* int runpoplog(runcxdef *ctx); */
|
||||
#define runpoplog(ctx) \
|
||||
((--((ctx)->runcxsp))->runstyp==DAT_TRUE ? TRUE : \
|
||||
(ctx)->runcxsp->runstyp==DAT_NIL ? FALSE : \
|
||||
(runsig(ctx, ERR_REQLOG), 0))
|
||||
|
||||
/* get type of top of stack */
|
||||
/* int runtostyp(runcxdef *ctx); */
|
||||
#define runtostyp(ctx) (((ctx)->runcxsp - 1)->runstyp)
|
||||
|
||||
/* determine if top of stack is logical value (returns TRUE if so) */
|
||||
/* int runtoslog(runcxdef *ctx); */
|
||||
#define runtoslog(ctx) \
|
||||
(runtostyp(ctx) == DAT_TRUE || runtostyp(ctx) == DAT_NIL)
|
||||
|
||||
/* convert C logical to TADS logical (TRUE->DAT_TRUE, FALSE->DAT_NIL) */
|
||||
/* int runclog(int log); */
|
||||
#define runclog(l) ((l) ? DAT_TRUE : DAT_NIL)
|
||||
|
||||
/* compare magnitudes of numbers/strings on top of stack; strcmp-like value */
|
||||
int runmcmp(runcxdef *ctx);
|
||||
|
||||
/* TRUE if items at top of stack are equal, FALSE otherwise */
|
||||
int runeq(runcxdef *ctx);
|
||||
|
||||
/* check for stack underflow */
|
||||
/* void runstkund(runcxdef *ctx); */
|
||||
|
||||
/* check for stack overflow */
|
||||
/* void runstkovf(runcxdef *ctx); */
|
||||
|
||||
/*
|
||||
* Check to ensure we have enough arguments to pass to a function or method
|
||||
* call - this simply ensures we have enough data in the current frame.
|
||||
* This is important because the called function will be able to write to
|
||||
* our frame. If we don't have enough arguments, we'll push enough 'nil'
|
||||
* values to meet the need.
|
||||
*/
|
||||
#define runcheckargc(ctx, nargc) \
|
||||
while ((ctx)->runcxsp - (ctx)->runcxbp < *(nargc)) \
|
||||
runpnil(ctx)
|
||||
|
||||
#ifdef RUNFAST
|
||||
# define runstkovf(ctx) (DISCARD 0)
|
||||
# define runstkund(ctx) (DISCARD 0)
|
||||
#else /* RUNFAST */
|
||||
# define runstkovf(ctx) \
|
||||
((ctx)->runcxsp >= (ctx)->runcxstop ? (runsig(ctx, ERR_STKOVF), \
|
||||
DISCARD 0) : DISCARD 0)
|
||||
# define runstkund(ctx) \
|
||||
((ctx)->runcxsp == (ctx)->runcxstk ? runsig(ctx, ERR_STKUND), \
|
||||
DISCARD 0 : DISCARD 0)
|
||||
#endif /* RUNFAST */
|
||||
|
||||
/* reserve space in heap, collecting garbage if necessary */
|
||||
/* void runhres(runcxdef *ctx, uint siz, uint below); */
|
||||
#define runhres(ctx, siz, below) \
|
||||
((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
|
||||
(runhcmp(ctx, siz, below, (runsdef *)0, (runsdef *)0, (runsdef *)0),\
|
||||
DISCARD 0))
|
||||
|
||||
/* reserve space, with various amounts of saving */
|
||||
#define runhres1(ctx, siz, below, val1) \
|
||||
((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
|
||||
(runhcmp(ctx, siz, below, val1, (runsdef *)0, (runsdef *)0), DISCARD 0))
|
||||
|
||||
#define runhres2(ctx, siz, below, val1, val2) \
|
||||
((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
|
||||
(runhcmp(ctx, siz, below, val1, val2, (runsdef *)0), DISCARD 0))
|
||||
|
||||
#define runhres3(ctx, siz, below, val1, val2, val3) \
|
||||
((uint)((ctx)->runcxhtop - (ctx)->runcxhp) > (uint)(siz) ? DISCARD 0 : \
|
||||
(runhcmp(ctx, siz, below, val1, val2, val3), DISCARD 0))
|
||||
|
||||
/* garbage collect heap, making sure 'siz' bytes are available afterwards */
|
||||
void runhcmp(runcxdef *ctx, uint siz, uint below,
|
||||
runsdef *val1, runsdef *val2, runsdef *val3);
|
||||
|
||||
/* determine size of a data item */
|
||||
int runsiz(runsdef *item);
|
||||
|
||||
/* find a sublist within a list, returning pointer to sublist or NULL */
|
||||
uchar *runfind(uchar *list, runsdef *item);
|
||||
|
||||
/* add two runsdef values, returning result in *val */
|
||||
void runadd(runcxdef *ctx, runsdef *val, runsdef *val2, uint below);
|
||||
|
||||
/*
|
||||
* subtract val2 from val, returning result in *val; return TRUE if
|
||||
* value changed, FALSE otherwise (this is returned when subtracting
|
||||
* something from a list that isn't in the list)
|
||||
*/
|
||||
int runsub(runcxdef *ctx, runsdef *val, runsdef *val2, uint below);
|
||||
|
||||
/* restore code pointer from object.property + offset */
|
||||
uchar *runcprst(runcxdef *ctx, uint ofs, objnum obj, prpnum prop);
|
||||
|
||||
/* leave a stack frame, removing arguments */
|
||||
/* void runleave(runcxdef *ctx, uint parms); */
|
||||
#define runleave(ctx, parms) \
|
||||
(((ctx)->runcxsp = (ctx)->runcxbp), \
|
||||
((ctx)->runcxbp = (runsdef *)((--((ctx)->runcxsp))->runsv.runsvstr)), \
|
||||
((ctx)->runcxsp -= (parms)))
|
||||
|
||||
/* reset run-time: throw away entire stack and heap */
|
||||
/* void runrst(runcxdef *ctx); */
|
||||
#define runrst(ctx) (((ctx)->runcxsp = (ctx)->runcxstk), \
|
||||
((ctx)->runcxhp = (ctx)->runcxheap), \
|
||||
dbgrst(ctx->runcxdbg))
|
||||
|
||||
/* set up runtime status line display */
|
||||
void runistat(struct voccxdef *vctx, struct runcxdef *rctx,
|
||||
struct tiocxdef *tctx);
|
||||
|
||||
/* signal a run-time error - allows debugger trapping */
|
||||
void runsign(runcxdef *ctx, int err);
|
||||
|
||||
/* sign a run-time error with zero arguments */
|
||||
#define runsig(ctx, err) (errargc((ctx)->runcxerr,0),runsign(ctx,err))
|
||||
|
||||
/* signal a run-time error with one argument */
|
||||
#define runsig1(ctx, err, typ, arg) \
|
||||
(errargv((ctx)->runcxerr,0,typ,arg),errargc((ctx)->runcxerr,1),\
|
||||
runsign(ctx,err))
|
||||
|
||||
/* draw status line */
|
||||
void runstat();
|
||||
|
||||
} // End of namespace TADS2
|
||||
} // End of namespace TADS
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user