1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /*
24  * Defines TADS vocabulary (player command parser) functionality
25  */
26 
27 #ifndef GLK_TADS_TADS2_VOCABULARY
28 #define GLK_TADS_TADS2_VOCABULARY
29 
30 #include "common/util.h"
31 #include "glk/tads/tads2/lib.h"
32 #include "glk/tads/tads2/object.h"
33 #include "glk/tads/tads2/property.h"
34 #include "glk/tads/tads2/run.h"
35 
36 namespace Glk {
37 namespace TADS {
38 namespace TADS2 {
39 
40 /*
41  *   Cover macro for parser errors.  Any parser error should be covered
42  *   with this macro for documentation and search purposes.  (The macro
43  *   doesn't do anything - this is just something to search for when we're
44  *   trying to enumerate parser error codes.)
45  */
46 #define VOCERR(errcode) errcode
47 
48 /* maximum number of objects matching an ambiguous word */
49 #define VOCMAXAMBIG 200
50 
51 /* size of input buffer */
52 #define VOCBUFSIZ 128
53 
54 /*
55  *   Vocabulary relation structure - this structure relates a vocabulary
56  *   word to an object and part of speech.  A list of these structures is
57  *   attached to each vocabulary word structure to provide the word's
58  *   meanings.
59  */
60 struct vocwdef {
61 	uint   vocwnxt;      /* index of next vocwdef attached to the same word */
62 	objnum vocwobj;                      /* object associated with the word */
63 	uchar  vocwtyp;   /* property associated with the word (part of speech) */
64 	uchar  vocwflg;                                   /* flags for the word */
65 #define VOCFCLASS  1                          /* word is for a class object */
66 #define VOCFINH    2                 /* word is inherited from a superclass */
67 #define VOCFNEW    4                          /* word was added at run-time */
68 #define VOCFDEL    8                               /* word has been deleted */
69 };
70 
71 /* vocabulary word structure */
72 struct vocdef {
73 	vocdef *vocnxt;                         /* next word at same hash value */
74 	uchar   voclen;                                   /* length of the word */
75 	uchar   vocln2;          /* length of second word (0 if no second word) */
76 	uint    vocwlst;      /* head of list of vocwdef's attached to the word */
77 	uchar   voctxt[1];                                  /* text of the word */
78 };
79 
80 /* vocabulary inheritance cell */
81 struct vocidef {
82 	uchar            vocinsc;   /* # of superclasses (gives size of record) */
83 	union {
84 		struct {
85 			uchar    vociusflg;                          /* flags for entry */
86 #define VOCIFCLASS  1  /* entry refers to a class object (loc records only) */
87 #define VOCIFVOC    2                 /* entry has vocabulary words defined */
88 #define VOCIFXLAT   4  /* superclasses must be translated from portable fmt */
89 #define VOCIFLOCNIL 8                  /* location is explicitly set to nil */
90 #define VOCIFNEW    16       /* object was allocated at run-time with "new" */
91 			objnum   vociusloc;                   /* location of the object */
92 			objnum   vociusilc;                       /* inherited location */
93 			objnum   vociussc[1];                  /* array of superclasses */
94 		} vocius;
95 		vocidef     *vociunxt;
96 	} vociu;
97 #define   vociflg vociu.vocius.vociusflg
98 #define   vociloc vociu.vocius.vociusloc
99 #define   vociilc vociu.vocius.vociusilc
100 #define   vocisc  vociu.vocius.vociussc
101 #define   vocinxt vociu.vociunxt
102 };
103 
104 /* size of a page in a vocabulary pool */
105 #define VOCPGSIZ  8192
106 
107 /* number of bytes in an inheritance cell page */
108 #define VOCISIZ 8192
109 
110 /* maximum number of inheritance pages */
111 #define VOCIPGMAX 32
112 
113 /* maximum number of inheritance pages (256 objects per page) */
114 #define VOCINHMAX 128
115 
116 /* size of vocabulary hash table */
117 #define VOCHASHSIZ  256
118 
119 /* size of a template structure */
120 #define VOCTPLSIZ 10
121 
122 /* new-style template structure */
123 #define VOCTPL2SIZ  16
124 
125 
126 /*
127  *   vocwdef's are fixed in size.  They're allocated in a set of arrays
128  *   (the voccxwp member of the voc context has the list of arrays).  Each
129  *   array is of a fixed number of vocwdef entries; a maximum number of
130  *   vocwdef arrays is possible.
131  */
132 #define VOCWPGSIZ   2000                   /* number of vocwdef's per array */
133 #define VOCWPGMAX   16                  /* maximum number of vocwdef arrays */
134 
135 /*
136  *   To find a vocwdef entry given its index, divide the index by the
137  *   number of entries per array to find the array number, and use the
138  *   remainder to find the index within that array.
139  */
140 /*#define VOCW_IN_CACHE*/
141 #ifdef VOCW_IN_CACHE
142 vocwdef *vocwget(struct voccxdef *ctx, uint idx);
143 #else
144 #define vocwget(ctx, idx) \
145 	((idx) == VOCCXW_NONE ? (vocwdef *)0 : \
146 	  ((ctx)->voccxwp[(idx)/VOCWPGSIZ] + ((idx) % VOCWPGSIZ)))
147 #endif
148 
149 /*
150  *   Special values for vocdtim - these values indicate that the daemon
151  *   does not have a normal turn-based expiration time.
152  */
153 #define VOCDTIM_EACH_TURN  0xffff            /* the daemon fires every turn */
154 
155 /* daemon/fuse/alarm slot */
156 struct vocddef {
157 	objnum   vocdfn;             /* object number of function to be invoked */
158 	runsdef  vocdarg;                  /* argument for daemon/fuse function */
159 	prpnum   vocdprp;             /* property number (used only for alarms) */
160 	uint     vocdtim;  /* time for fuses/alarms (0xffff -> each-turn alarm) */
161 };
162 
163 /* vocabulary object list entry */
164 struct vocoldef {
165 	objnum  vocolobj;                           /* object matching the word */
166 	const char *vocolfst;     /* first word in cmd[] that identified object */
167 	const char *vocollst;      /* last word in cmd[] that identified object */
168 	char   *vocolhlst;      /* hypothetical last word, if we trimmed a prep */
169 	int     vocolflg;                           /* special flags (ALL, etc) */
170 };
171 
172 /* vocabulary context */
173 struct voccxdef {
174 	errcxdef  *voccxerr;                          /* error handling context */
175 	tiocxdef  *voccxtio;                                /* text i/o context */
176 	runcxdef  *voccxrun;                               /* execution context */
177 	mcmcxdef  *voccxmem;                          /* memory manager context */
178 	objucxdef *voccxundo;                                   /* undo context */
179 	uchar     *voccxpool;                  /* next free byte in vocdef pool */
180 	vocdef    *voccxfre;                        /* head of vocdef free list */
181 	char      *voccxcpp;                   /* pointer to compound word area */
182 	int        voccxcpl;                    /* length of compound word area */
183 	char      *voccxspp;                    /* pointer to special word area */
184 	int        voccxspl;                     /* length of special word area */
185 	uint       voccxrem;        /* number of bytes remaining in vocdef pool */
186 	vocidef  **voccxinh[VOCINHMAX];     /* vocidef page table: 256 per page */
187 	uchar     *voccxip[VOCIPGMAX];                 /* inheritance cell pool */
188 	vocidef   *voccxifr;              /* head of inheritance cell free list */
189 	uint       voccxiplst;          /* last inheritance cell page allocated */
190 	uint       voccxilst;      /* next unused byte in last inheritance page */
191 	int        voccxredo;                   /* flag: redo command in buffer */
192 
193 	/*
194 	 *   redo buffer - if voccxredo is set, and this buffer is not empty,
195 	 *   we'll redo the command in this buffer rather than the one in our
196 	 *   internal stack buffer
197 	 */
198 	char       voccxredobuf[VOCBUFSIZ];
199 
200 	/*
201 	 *   "again" buffer - when we save the last command for repeating via
202 	 *   the "again" command, we'll save the direct and indirect object
203 	 *   words here, so that they can be recovered if "again" is used
204 	 */
205 	char       voccxagainbuf[VOCBUFSIZ];
206 
207 	vocdef    *voccxhsh[VOCHASHSIZ];                          /* hash table */
208 
209 #ifdef VOCW_IN_CACHE
210 	mcmon      voccxwp[VOCWPGMAX];        /* list of pages of vocab records */
211 	mcmon      voccxwplck;                  /* locked page of vocab records */
212 	vocwdef   *voccxwpgptr;             /* pointer to currently locked page */
213 #else
214 	vocwdef   *voccxwp[VOCWPGMAX];                  /* vocabulary word pool */
215 #endif
216 
217 	uint       voccxwalocnt;             /* number of vocwdef's used so far */
218 	uint       voccxwfre;            /* index of first vocwdef in free list */
219 #define VOCCXW_NONE  ((uint)(-1))     /* index value indicating end of list */
220 
221 	vocddef   *voccxdmn;                           /* array of daemon slots */
222 	uint       voccxdmc;                 /* number of slots in daemon array */
223 	vocddef   *voccxfus;                             /* array of fuse slots */
224 	uint       voccxfuc;                   /* number of slots in fuse array */
225 	vocddef   *voccxalm;                            /* array of alarm slots */
226 	uint       voccxalc;                  /* number of slots in alarm array */
227 	char       voccxtim[26];            /* game's timestamp (asctime value) */
228 
229 	objnum     voccxvtk;                /* object number of "take" deepverb */
230 	objnum     voccxme;                      /* object number of "Me" actor */
231 	objnum     voccxme_init;                     /* initial setting of "Me" */
232 	objnum     voccxstr;                       /* object number of "strObj" */
233 	objnum     voccxnum;                       /* object number of "numObj" */
234 	objnum     voccxit;                                  /* last "it" value */
235 	objnum     voccxhim;                                /* last "him" value */
236 	objnum     voccxher;                                /* last "her" value */
237 	objnum     voccxthc;                   /* count of items in "them" list */
238 	objnum     voccxthm[VOCMAXAMBIG];            /* list of items in "them" */
239 	objnum     voccxprd;                 /* "pardon" function object number */
240 	objnum     voccxpre;               /* "preparse" function object number */
241 	objnum     voccxppc;            /* "preparseCmd" function object number */
242 	objnum     voccxpre2;           /* "preparseExt" function object number */
243 	objnum     voccxvag;                             /* "again" verb object */
244 	objnum     voccxini;                                 /* "init" function */
245 	objnum     voccxper;             /* "parseError" function object number */
246 	objnum     voccxprom;             /* "cmdPrompt" function object number */
247 	objnum     voccxpostprom;     /* "cmdPostPrompt" function object number */
248 	objnum     voccxpdis;                         /* parseDisambig function */
249 	objnum     voccxper2;                           /* parseError2 function */
250 	objnum     voccxperp;                       /* parseErrorParam function */
251 	objnum     voccxpdef;                          /* parseDefault function */
252 	objnum     voccxpdef2;                      /* parseDefaultExt function */
253 	objnum     voccxpask;                           /* parseAskobj function */
254 	objnum     voccxpask2;                     /* parseAskobjActor function */
255 	objnum     voccxpask3;                  /* parseAskobjIndirect function */
256 	objnum     voccxinitrestore;    /* "initRestore" function object number */
257 	objnum     voccxpuv;         /* parseUnknownVerb function object number */
258 	objnum     voccxpnp;          /* parseNounPhrase function object number */
259 	objnum     voccxpostact;           /* postAction function object number */
260 	objnum     voccxprecmd;            /* preCommand function object number */
261 	objnum     voccxendcmd;            /* endCommand function object number */
262 
263 	/* current command word list values */
264 	vocoldef  *voccxdobj;                /* current direct object word list */
265 	vocoldef  *voccxiobj;              /* current indirect object word list */
266 
267 	/* current command objects */
268 	objnum     voccxactor;                                 /* current actor */
269 	objnum     voccxverb;                       /* current command deepverb */
270 	objnum     voccxprep;                    /* current command preposition */
271 
272 	/* previous command values - used by "again" */
273 	objnum     voccxlsa;                                  /* previous actor */
274 	objnum     voccxlsv;                                   /* previous verb */
275 	vocoldef   voccxlsd;                          /* previous direct object */
276 	vocoldef   voccxlsi;                        /* previous indirect object */
277 	objnum     voccxlsp;                                     /* preposition */
278 	int        voccxlssty;              /* style (new/old) of last template */
279 	uchar      voccxlst[VOCTPL2SIZ];                            /* template */
280 
281 	objnum     voccxpreinit;                            /* preinit function */
282 
283 	/* special flags */
284 	uchar      voccxflg;
285 #define VOCCXFCLEAR    1      /* ignore remainder of command line (restore) */
286 #define VOCCXFVWARN    2                /* generate redundant verb warnings */
287 #define VOCCXFDBG      4           /* debug mode:  show parsing information */
288 #define VOCCXAGAINDEL  8             /* "again" lost due to object deletion */
289 
290 	/* number of remaining unresolved unknown words in the command */
291 	int        voccxunknown;
292 
293 	/* total number of unresolved words in the last command */
294 	int        voccxlastunk;
295 
296 	/* parser stack area */
297 	uchar *voc_stk_ptr;
298 	uchar *voc_stk_cur;
299 	uchar *voc_stk_end;
300 };
301 
302 /* allocate and push a list, returning a pointer to the list's memory */
303 uchar *voc_push_list_siz(voccxdef *ctx, uint lstsiz);
304 
305 /* push a list of objects from a vocoldef array */
306 void voc_push_vocoldef_list(voccxdef *ctx, vocoldef *objlist, int cnt);
307 
308 /* push a list of objects from an objnum array */
309 void voc_push_objlist(voccxdef *ctx, objnum objlist[], int cnt);
310 
311 /* change the player character ("Me") object */
312 void voc_set_me(voccxdef *ctx, objnum new_me);
313 
314 /* add a vocabulary word */
315 void vocadd(voccxdef *ctx, prpnum p, objnum objn,
316 			int classflag, char *wrdval);
317 
318 /* internal addword - must already be split into two words and lengths */
319 void vocadd2(voccxdef *ctx, prpnum p, objnum objn, int classflg,
320 			 uchar *wrd1, int len1, uchar *wrd2, int len2);
321 
322 /* delete vocabulary for a given object */
323 void vocdel(voccxdef *ctx, objnum objn);
324 
325 /* lower-level vocabulary deletion routine */
326 void vocdel1(voccxdef *ctx, objnum objn, char *wrd, prpnum prp,
327 			 int really_delete, int revert, int keep_undo);
328 
329 /* delete all inherited vocabulary */
330 void vocdelinh(voccxdef *ctx);
331 
332 /* allocate space for an inheritance record if needed */
333 void vocialo(voccxdef *ctx, objnum obj);
334 
335 /* add an inheritance/location record */
336 void vociadd(voccxdef *ctx, objnum obj, objnum loc,
337 			 int numsc, objnum *sc, int flags);
338 
339 /* delete inheritance records for an object */
340 void vocidel(voccxdef *ctx, objnum chi);
341 
342 /* renumber an object's inheritance records - used for 'modify' */
343 void vociren(voccxdef *ctx, objnum oldnum, objnum newnum);
344 
345 /* caller-provided context structure for vocffw/vocfnw searches */
346 struct vocseadef {
347 	vocdef  *v;
348 	vocwdef *vw;
349 	const uchar *wrd1;
350 	int      len1;
351 	const uchar *wrd2;
352 	int      len2;
353 };
354 
355 /* find first word matching a given word */
356 vocwdef *vocffw(voccxdef *ctx, const char *wrd, int len, const char *wrd2, int len2,
357 				int p, vocseadef *search_ctx);
358 
359 /* find next word */
360 vocwdef *vocfnw(voccxdef *voccx, vocseadef *search_ctx);
361 
362 /* read a line of input text */
363 int vocread(voccxdef *ctx, objnum actor, objnum verb,
364 			char *buf, int bufl, int type);
365 #define VOCREAD_OK    0
366 #define VOCREAD_REDO  1
367 
368 /* compute size of a vocoldef list */
369 int voclistlen(vocoldef *lst);
370 
371 /* tokenize an input buffer */
372 int voctok(voccxdef *ctx, char *cmd, char *outbuf,
373 		   char **wrd, int lower, int cvt_ones, int show_errors);
374 
375 /* get types for a word list */
376 int vocgtyp(voccxdef *ctx, char **cmd, int *types, char *orgbuf);
377 
378 /* execute a player command */
379 int voccmd(voccxdef *ctx, char *cmd, uint cmdlen);
380 
381 /* disambiguator */
382 int vocdisambig(voccxdef *ctx, vocoldef *outlist, vocoldef *inlist,
383 				prpnum defprop, prpnum accprop, prpnum verprop,
384 				char *cmd[], objnum otherobj, objnum cmdActor,
385 				objnum cmdVerb, objnum cmdPrep, char *cmdbuf,
386 				int silent);
387 
388 /* display a multiple-object prefix */
389 void voc_multi_prefix(voccxdef *ctx, objnum objn,
390 					  int show_prefix, int multi_flags,
391 					  int cur_index, int count);
392 
393 /* low-level executor */
394 int execmd(voccxdef *ctx, objnum actor, objnum prep,
395 		   char *vverb, char *vprep, vocoldef *dolist, vocoldef *iolist,
396 		   char **cmd, int *typelist,
397 		   char *cmdbuf, int wrdcnt, uchar **preparse_list, int *next_start);
398 
399 /* recursive command execution */
400 int execmd_recurs(voccxdef *ctx, objnum actor, objnum verb,
401 				  objnum dobj, objnum prep, objnum iobj,
402 				  int validate_dobj, int validate_iobj);
403 
404 /* try running preparseCmd user function */
405 int try_preparse_cmd(voccxdef *ctx, char **cmd, int wrdcnt,
406 					 uchar **preparse_list);
407 
408 /*
409  *   Handle an unknown verb or sentence structure.  We'll call this when
410  *   we encounter a sentence where we don't know the verb word, or we
411  *   don't know the combination of verb and verb preposition, or we don't
412  *   recognize the sentence structure (for example, an indirect object is
413  *   present, but we don't have a template defined using an indirect
414  *   object for the verb).
415  *
416  *   'wrdcnt' is the number of words in the cmd[] array.  If wrdcnt is
417  *   zero, we'll automatically count the array entries, with the end of
418  *   the array indicated by a null pointer entry.
419  *
420  *   If do_fuses is true, we'll execute the fuses and daemons if the
421  *   function exists and doesn't throw an ABORT error, or any other
422  *   run-time error other than EXIT.
423  *
424  *   This function calls the game-defined function parseUnknownVerb, if it
425  *   exists.  If the function doesn't exist, we'll simply display the
426  *   given error message, using the normal parseError mechanism.  The
427  *   function should use "abort" or "exit" if it wants to cancel further
428  *   processing of the command.
429  *
430  *   We'll return true if the function exists and executes successfully,
431  *   in which case normal processing should continue with any remaining
432  *   command on the command line.  We'll return false if the function
433  *   doesn't exist or throws an error other than EXIT, in which case the
434  *   remainder of the command should be aborted.
435  */
436 int try_unknown_verb(voccxdef *ctx, objnum actor,
437 					 char **cmd, int *typelist, int wrdcnt, int *next_start,
438 					 int do_fuses, int err, const char *msg, ...);
439 
440 /* find a template */
441 int voctplfnd(voccxdef *ctx, objnum verb_in, objnum prep,
442 			  uchar *tplout, int *newstyle);
443 
444 /* build a printable name for an object from the words in a command list */
445 void voc_make_obj_name(voccxdef *ctx, char *namebuf, char *cmd[],
446 					   int firstwrd, int lastwrd);
447 void voc_make_obj_name_from_list(voccxdef *ctx, char *namebuf,
448 								 char *cmd[], const char *firstwrd, const char *lastwrd);
449 
450 /*
451  *   check noun - determines whether the next set of words is a valid noun
452  *   phrase.  No complaint is issued if not; this check is generally made
453  *   to figure out what type of sentence we're dealing with.  This is
454  *   simple; we just call vocgobj() with the complaint flag turned off.
455  */
456 /* int vocchknoun(voccxdef *ctx, char **cmd, int *typelist, int cur,
457 				  int *next, vocoldef *nounlist, int chkact); */
458 #define vocchknoun(ctx, cmd, typelist, cur, next, nounlist, chkact) \
459  vocgobj(ctx, cmd, typelist, cur, next, FALSE, nounlist, TRUE, chkact, 0)
460 #define vocchknoun2(ctx, cmd, typlst, cur, next, nounlist, chkact, nomatch) \
461  vocgobj(ctx, cmd, typlst, cur, next, FALSE, nounlist, TRUE, chkact, nomatch)
462 
463 /*
464  *   get noun - reads an object list.  We simply call vocgobj() with the
465  *   complaint and multiple-noun flags turned on.
466  */
467 /* int vocgetnoun(voccxdef *ctx, char **cmd, int *typelist, int cur,
468 				  int *next, vocoldef *nounlist); */
469 #define vocgetnoun(ctx, cmd, typelist, cur, next, nounlist) \
470  vocgobj(ctx, cmd, typelist, cur, next, TRUE, nounlist, TRUE, FALSE, 0)
471 
472 /* get object */
473 int vocgobj(voccxdef *ctx, char **cmd, int *typelist, int cur,
474 			int *next, int complain, vocoldef *nounlist,
475 			int multi, int chkact, int *nomatch);
476 
477 /* tokenize a string - TADS program code interface */
478 void voc_parse_tok(voccxdef *ctx);
479 
480 /* get token types - TADS program code interface */
481 void voc_parse_types(voccxdef *ctx);
482 
483 /* get objects matching all of the given words - TADS program code interface */
484 void voc_parse_dict_lookup(voccxdef *ctx);
485 
486 /* parse a noun list - TADS program code interface */
487 void voc_parse_np(voccxdef *ctx);
488 
489 /* disambiguate a noun list - TADS program code interface */
490 void voc_parse_disambig(voccxdef *ctx);
491 
492 /* replace the current command - TADS program code interface */
493 void voc_parse_replace_cmd(voccxdef *ctx);
494 
495 /* check access to an object */
496 int vocchkaccess(voccxdef *ctx, objnum obj, prpnum verprop,
497 				 int seqno, objnum actor, objnum verb);
498 
499 /* check to see if an object is visible */
500 int vocchkvis(voccxdef *ctx, objnum obj, objnum cmdActor);
501 
502 /* display an appropriate message for an unreachable object */
503 void vocnoreach(voccxdef *ctx, objnum *list1, int cnt,
504 				objnum actor, objnum verb, objnum prep, prpnum defprop,
505 				int show_multi_prefix, int multi_flags,
506 				int multi_base_index, int multi_total_count);
507 
508 /* set {numObj | strObj}.value, as appropriate */
509 void vocsetobj(voccxdef *ctx, objnum obj, dattyp typ, const void *val,
510 			   vocoldef *inobj, vocoldef *outobj);
511 
512 /* macros to read values out of templates */
513 #define voctplpr(tpl) ((objnum)osrp2(((uchar *)tpl)))        /* preposition */
514 #define voctplvi(tpl) ((prpnum)osrp2(((uchar *)tpl) + 2))      /* verIoVerb */
515 #define voctplio(tpl) ((prpnum)osrp2(((uchar *)tpl) + 4))         /* ioVerb */
516 #define voctplvd(tpl) ((prpnum)osrp2(((uchar *)tpl) + 6))      /* verDoVerb */
517 #define voctpldo(tpl) ((prpnum)osrp2(((uchar *)tpl) + 8))         /* doVerb */
518 #define voctplflg(tpl) (*(((uchar *)tpl) + 10))                    /* flags */
519 
520 /* flag values for the voctplflg */
521 #define VOCTPLFLG_DOBJ_FIRST   0x01     /* disambiguate direct object first */
522 
523 
524 /* word type flags */
525 #define VOCT_ARTICLE  1
526 #define VOCT_ADJ      2
527 #define VOCT_NOUN     4
528 #define VOCT_PREP     8
529 #define VOCT_VERB     16
530 #define VOCT_SPEC     32            /* special words - "of", ",", ".", etc. */
531 #define VOCT_PLURAL   64
532 #define VOCT_UNKNOWN  128                                /* word is unknown */
533 
534 /* special type flags */
535 #define VOCS_ALL     1                                             /* "all" */
536 #define VOCS_EXCEPT  2                                          /* "except" */
537 #define VOCS_IT      4                                              /* "it" */
538 #define VOCS_THEM    8                                            /* "them" */
539 #define VOCS_NUM     16                                         /* a number */
540 #define VOCS_COUNT   32                   /* a number being used as a count */
541 #define VOCS_PLURAL  64                                           /* plural */
542 #define VOCS_ANY     128                                           /* "any" */
543 #define VOCS_HIM     256                                           /* "him" */
544 #define VOCS_HER     512                                           /* "her" */
545 #define VOCS_STR     1024                                /* a quoted string */
546 #define VOCS_UNKNOWN 2048           /* noun phrase contains an unknown word */
547 #define VOCS_ENDADJ  4096        /* word matched adjective at end of phrase */
548 #define VOCS_TRUNC   8192    /* truncated match - word is leading substring */
549 #define VOCS_TRIMPREP 16384 /* trimmed prep phrase: assumed it was for verb */
550 
551 /* special internally-defined one-character word flags */
552 #define VOCW_AND     ','
553 #define VOCW_THEN    '.'
554 #define VOCW_OF      'O'
555 #define VOCW_ALL     'A'
556 #define VOCW_BOTH    'B'
557 #define VOCW_IT      'I'
558 #define VOCW_HIM     'M'
559 #define VOCW_ONE     'N'
560 #define VOCW_ONES    'P'
561 #define VOCW_HER     'R'
562 #define VOCW_THEM    'T'
563 #define VOCW_BUT     'X'
564 #define VOCW_ANY     'Y'
565 
566 /* structure for special internal word table */
567 struct vocspdef {
568 	const char *vocspin;
569 	char  vocspout;
570 };
571 
572 /* check if a word is a special word - true if word is given special word */
573 /* int vocspec(char *wordptr, int speccode); */
574 #define vocspec(w, s) (*(w) == (s))
575 
576 /*
577  *   Set a fuse/daemon/notifier.
578  */
579 void vocsetfd(voccxdef *ctx, vocddef *what, objnum func, prpnum prop,
580 			  uint tm, runsdef *val, int err);
581 
582 /* remove a fuse/daemon/notifier */
583 void vocremfd(voccxdef *ctx, vocddef *what, objnum func, prpnum prop,
584 			  runsdef *val, int err);
585 
586 /* count a turn (down all fuse/notifier timers) */
587 void vocturn(voccxdef *ctx, int turncnt, int do_fuses);
588 
589 /* initialize voc context */
590 void vocini(voccxdef *vocctx, errcxdef *errctx, mcmcxdef *memctx,
591 			runcxdef *runctx, objucxdef *undoctx, int fuses,
592 			int daemons, int notifiers);
593 
594 /* clean up the voc context - frees memory allocated by vocini() */
595 void vocterm(voccxdef *vocctx);
596 
597 /* allocate/free fuse/daemon/notifier array for voc ctx initialization */
598 void vocinialo(voccxdef *ctx, vocddef **what, int cnt);
599 void voctermfree(vocddef *what);
600 
601 /* get a vocidef given an object number */
602 /* vocidef *vocinh(voccxdef *ctx, objnum obj); */
603 #define vocinh(ctx, obj) ((ctx)->voccxinh[(obj) >> 8][(obj) & 255])
604 
605 /* revert all objects back to original state, using inheritance records */
606 void vocrevert(voccxdef *ctx);
607 
608 /* clear all fuses/daemons/notifiers (useful for restarting) */
609 void vocdmnclr(voccxdef *ctx);
610 
611 /* display a parser error message */
612 void vocerr(voccxdef *ctx, int err, const char *f, ...);
613 
614 /*
615  *   display a parser informational error message - this will display the
616  *   message whether or not we're suppressing messages due to unknown
617  *   words, and should be used when providing information, such as objects
618  *   we're assuming by default
619  */
620 void vocerr_info(voccxdef *ctx, int err, const char *f, ...);
621 
622 /* client undo callback - undoes a daemon/fuse/notifier */
623 void vocdundo(void *ctx, uchar *data);
624 
625 /* client undo size figuring callback - return size of client undo record */
626 ushort OS_LOADDS vocdusz(void *ctx, uchar *data);
627 
628 /* save undo for object creation */
629 void vocdusave_newobj(voccxdef *ctx, objnum objn);
630 
631 /* save undo for adding a word */
632 void vocdusave_addwrd(voccxdef *ctx, objnum objn, prpnum typ, int flags,
633 					  char *wrd);
634 
635 /* save undo for deleting a word */
636 void vocdusave_delwrd(voccxdef *ctx, objnum objn, prpnum typ, int flags,
637 					  char *wrd);
638 
639 /* save undo for object deletion */
640 void vocdusave_delobj(voccxdef *ctx, objnum objn);
641 
642 /* save undo for changing the "Me" object */
643 void vocdusave_me(voccxdef *ctx, objnum old_me);
644 
645 /* compute vocabulary word hash value */
646 uint vochsh(const uchar *t, int len);
647 
648 /* TADS versions of isalpha, isspace, isdigit, etc */
649 #define vocisupper(c) ((uchar)(c) <= 127 && Common::isUpper((uchar)(c)))
650 #define vocislower(c) ((uchar)(c) <= 127 && Common::isLower((uchar)(c)))
651 #define vocisalpha(c) ((uchar)(c) > 127 || Common::isAlpha((uchar)(c)))
652 #define vocisspace(c) ((uchar)(c) <= 127 && Common::isSpace((uchar)(c)))
653 #define vocisdigit(c) ((uchar)(c) <= 127 && Common::isDigit((uchar)(c)))
654 
655 
656 /*
657  *   Undo types for voc subsystem
658  */
659 #define VOC_UNDO_DAEMON   1                    /* fuse/daemon status change */
660 #define VOC_UNDO_NEWOBJ   2                              /* object creation */
661 #define VOC_UNDO_DELOBJ   3                              /* object deletion */
662 #define VOC_UNDO_ADDVOC   4                  /* add vocabulary to an object */
663 #define VOC_UNDO_DELVOC   5             /* delete vocabulary from an object */
664 #define VOC_UNDO_SETME    6                          /* set the "Me" object */
665 
666 
667 /*
668  *   Our own stack.  We need to allocate some fairly large structures
669  *   (for the disambiguation lists, mostly) in a stack-like fashion, and
670  *   we don't want to consume vast quantities of the real stack, because
671  *   some machines have relatively restrictive limitations on stack usage.
672  *   To provide some elbow room, we'll use a stack-like structure of our
673  *   own: we'll allocate out of this structure as needed, and whenever we
674  *   leave a C stack frame, we'll also leave our own stack frame.
675  */
676 
677 /* re-initialize the stack, allocating space for it if needed */
678 void  voc_stk_ini(voccxdef *ctx, uint siz);
679 
680 /* enter a stack frame, marking our current position */
681 #define voc_enter(ctx, marker)  (*(marker) = (ctx)->voc_stk_cur)
682 
683 /* leave a stack frame, restoring the entry position */
684 #define voc_leave(ctx, marker)  ((ctx)->voc_stk_cur = marker)
685 
686 /* return a value */
687 #define VOC_RETVAL(ctx, marker, retval) \
688 	   voc_leave(ctx, marker); return retval
689 
690 /* allocate space from the stack */
691 void *voc_stk_alo(voccxdef *ctx, uint siz);
692 
693 /* allocation cover macros */
694 #define VOC_STK_ARRAY(ctx, typ, var, cnt) \
695 	(var = (typ *)voc_stk_alo(ctx, (uint)((cnt) * sizeof(typ))))
696 
697 #define VOC_MAX_ARRAY(ctx, typ, var) \
698 	VOC_STK_ARRAY(ctx, typ, var, VOCMAXAMBIG)
699 
700 /*
701  *   Stack size for the vocab stack.  We'll scale our stack needs based
702  *   on the size of the vocoldef structure, since this is the most common
703  *   item to be allocated on the vocab stack.  We'll also scale based on
704  *   the defined VOCMAXAMBIG parameter, since it is the number of elements
705  *   usually allocated.  The actual amount of space needed depends on how
706  *   the functions in vocab.c and execmd.c work, so this parameter may
707  *   need to be adjusted for changes to the player command parser.
708  */
709 #define VOC_STACK_SIZE  (16 * VOCMAXAMBIG * sizeof(vocoldef))
710 
711 /*
712  *   Execute all fuses and daemons, then execute the endCommand user
713  *   function.  Returns zero on success, or ERR_ABORT if 'abort' was
714  *   thrown during execution.  This is a convenient cover single function
715  *   to do all end-of-turn processing; this calls exefuse() and exedaem()
716  *   as needed, trapping any 'abort' or 'exit' errors that occur.
717  *
718  *   If 'do_fuses' is true, we'll run fuses and daemons.  Otherwise,
719  */
720 int exe_fuses_and_daemons(voccxdef *ctx, int err, int do_fuses,
721 						  objnum actor, objnum verb,
722 						  vocoldef *dobj_list, int do_cnt,
723 						  objnum prep, objnum iobj);
724 
725 /*
726  *   Execute any pending fuses.  Return TRUE if any fuses were executed,
727  *   FALSE otherwise.
728  */
729 int exefuse(voccxdef *ctx, int do_run);
730 
731 /*
732  *   Execute daemons
733  */
734 void exedaem(voccxdef *ctx);
735 
736 /*
737  *   Get the number and size of words defined for an object.  The size
738  *   returns the total byte count from all the words involved.  Do not
739  *   include deleted words in the count.
740  */
741 void voc_count(voccxdef *ctx, objnum objn, prpnum prp, int *cnt, int *siz);
742 
743 /*
744  *   Iterate through all words for a particular object, calling a
745  *   function with each vocwdef found.  If objn == MCMONINV, we'll call
746  *   the callback for every word.
747  */
748 void voc_iterate(voccxdef *ctx, objnum objn,
749 				 void (*fn)(void *, vocdef *, vocwdef *), void *fnctx);
750 
751 /* ------------------------------------------------------------------------ */
752 /*
753  *   disambiguation status codes - used for disambigDobj and disambigIobj
754  *   methods in the deepverb
755  */
756 
757 /* continue with disambiguation process (using possibly updated list) */
758 #define VOC_DISAMBIG_CONT     1
759 
760 /* done - the list is fully resolved; return with (possibly updated) list */
761 #define VOC_DISAMBIG_DONE     2
762 
763 /* error - abort the command */
764 #define VOC_DISAMBIG_ERROR    3
765 
766 /* parse string returned in second element of list as interactive response */
767 #define VOC_DISAMBIG_PARSE_RESP  4
768 
769 /* already asked for an interactive response, but didn't read it yet */
770 #define VOC_DISAMBIG_PROMPTED 5
771 
772 
773 /* ------------------------------------------------------------------------ */
774 /*
775  *   parseNounPhrase status codes
776  */
777 
778 /* parse error occurred */
779 #define VOC_PNP_ERROR    1
780 
781 /* use built-in default parser */
782 #define VOC_PNP_DEFAULT  2
783 
784 /* successful parse */
785 #define VOC_PNP_SUCCESS  3
786 
787 
788 /* ------------------------------------------------------------------------ */
789 /*
790  *   parserResolveObjects usage codes
791  */
792 #define VOC_PRO_RESOLVE_DOBJ  1                            /* direct object */
793 #define VOC_PRO_RESOLVE_IOBJ  2                          /* indirect object */
794 #define VOC_PRO_RESOLVE_ACTOR 3                                    /* actor */
795 
796 } // End of namespace TADS2
797 } // End of namespace TADS
798 } // End of namespace Glk
799 
800 #endif
801