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