9fe65bc913a4491d1d316b27fb6fb3fd6e98f3e0
[inform.git] / src / verbs.c
1 /* ------------------------------------------------------------------------- */
2 /*   "verbs" :  Manages actions and grammar tables; parses the directives    */
3 /*              Verb and Extend.                                             */
4 /*                                                                           */
5 /*   Part of Inform 6.41                                                     */
6 /*   copyright (c) Graham Nelson 1993 - 2022                                 */
7 /*                                                                           */
8 /* Inform is free software: you can redistribute it and/or modify            */
9 /* it under the terms of the GNU General Public License as published by      */
10 /* the Free Software Foundation, either version 3 of the License, or         */
11 /* (at your option) any later version.                                       */
12 /*                                                                           */
13 /* Inform is distributed in the hope that it will be useful,                 */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
16 /* GNU General Public License for more details.                              */
17 /*                                                                           */
18 /* You should have received a copy of the GNU General Public License         */
19 /* along with Inform. If not, see https://gnu.org/licenses/                  */
20 /*                                                                           */
21 /* ------------------------------------------------------------------------- */
22
23 #include "header.h"
24
25 int grammar_version_number;            /* 1 for pre-Inform 6.06 table format */
26 int32 grammar_version_symbol;          /* Index of "Grammar__Version"
27                                           within symbols table               */
28
29 /* ------------------------------------------------------------------------- */
30 /*   Actions.                                                                */
31 /* ------------------------------------------------------------------------- */
32 /*   Array defined below:                                                    */
33 /*                                                                           */
34 /*    actioninfo actions[n]               Symbol table index and byte offset */
35 /*                                        of the ...Sub routine              */
36 /* ------------------------------------------------------------------------- */
37
38 int no_actions,                        /* Number of actions made so far      */
39     no_fake_actions;                   /* Number of fake actions made so far */
40
41 /* ------------------------------------------------------------------------- */
42 /*   Adjectives.  (The term "adjective" is traditional; they are mainly      */
43 /*                prepositions, such as "onto".)                             */
44 /* ------------------------------------------------------------------------- */
45 /*   Arrays defined below:                                                   */
46 /*                                                                           */
47 /*    int32 adjectives[n]                 Byte address of dictionary entry   */
48 /*                                        for the nth adjective              */
49 /*    dict_word adjective_sort_code[n]    Dictionary sort code of nth adj    */
50 /* ------------------------------------------------------------------------- */
51
52 int no_adjectives;                     /* Number of adjectives made so far   */
53
54 /* ------------------------------------------------------------------------- */
55 /*   Verbs.  Note that Inform-verbs are not quite the same as English verbs: */
56 /*           for example the English verbs "take" and "drop" both normally   */
57 /*           correspond in a game's dictionary to the same Inform verb.  An  */
58 /*           Inform verb is essentially a list of grammar lines.             */
59 /*           (Calling them "English verbs" is of course out of date. Read    */
60 /*           this as jargon for "dict words which are verbs".                */
61 /* ------------------------------------------------------------------------- */
62 /*   Arrays defined below:                                                   */
63 /*                                                                           */
64 /*    verbt Inform_verbs[n]               The n-th grammar line sequence:    */
65 /*                                        see "header.h" for the definition  */
66 /*                                        of the typedef struct verbt        */
67 /*    int32 grammar_token_routine[n]      The byte offset from start of code */
68 /*                                        area of the n-th one               */
69 /* ------------------------------------------------------------------------- */
70
71 int no_Inform_verbs,                   /* Number of Inform-verbs made so far */
72     no_grammar_token_routines;         /* Number of routines given in tokens */
73
74 /* ------------------------------------------------------------------------- */
75 /*   We keep a list of English verb-words known (e.g. "take" or "eat") and   */
76 /*   which Inform-verbs they correspond to.  (This list is needed for some   */
77 /*   of the grammar extension operations.)                                   */
78 /*   The format of this list is a sequence of variable-length records:       */
79 /*                                                                           */
80 /*     Byte offset to start of next record  (1 byte)                         */
81 /*     Inform verb number this word corresponds to  (2 bytes)                */
82 /*     The English verb-word (reduced to lower case), null-terminated        */
83 /* ------------------------------------------------------------------------- */
84
85 static char *English_verb_list;       /* Allocated to English_verb_list_size */
86 static memory_list English_verb_list_memlist;
87
88 static int English_verb_list_size;     /* Size of the list in bytes          */
89
90 static char *English_verbs_given;      /* Allocated to verbs_given_pos
91                                           (Used only within make_verb())     */
92 static memory_list English_verbs_given_memlist;
93
94 /* ------------------------------------------------------------------------- */
95 /*   Arrays used by this file                                                */
96 /* ------------------------------------------------------------------------- */
97
98   verbt   *Inform_verbs;  /* Allocated up to no_Inform_verbs */
99   static memory_list Inform_verbs_memlist;
100   uchar   *grammar_lines; /* Allocated to grammar_lines_top */
101   static memory_list grammar_lines_memlist;
102   int32    grammar_lines_top;
103   int      no_grammar_lines, no_grammar_tokens;
104
105   actioninfo *actions; /* Allocated to no_actions */
106   memory_list actions_memlist;
107   int32   *grammar_token_routine; /* Allocated to no_grammar_token_routines */
108   static memory_list grammar_token_routine_memlist;
109
110   int32   *adjectives; /* Allocated to no_adjectives */
111   static memory_list adjectives_memlist;
112
113   static uchar *adjective_sort_code; /* Allocated to no_adjectives*DICT_WORD_BYTES */
114   static memory_list adjective_sort_code_memlist;
115
116 /* ------------------------------------------------------------------------- */
117 /*   Tracing for compiler maintenance                                        */
118 /* ------------------------------------------------------------------------- */
119
120 static char *find_verb_by_number(int num);
121
122 static void list_grammar_line_v1(int mark)
123 {
124     int action, actsym;
125     int ix, len;
126     char *str;
127
128     /* There is no GV1 for Glulx. */
129     if (glulx_mode)
130         return;
131     
132     action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
133     mark += 2;
134     
135     printf("  *");
136     while (grammar_lines[mark] != 15) {
137         uchar tok = grammar_lines[mark];
138         mark += 3;
139         
140         switch (tok) {
141         case 0:
142             printf(" noun");
143             break;
144         case 1:
145             printf(" held");
146             break;
147         case 2:
148             printf(" multi");
149             break;
150         case 3:
151             printf(" multiheld");
152             break;
153         case 4:
154             printf(" multiexcept");
155             break;
156         case 5:
157             printf(" multiinside");
158             break;
159         case 6:
160             printf(" creature");
161             break;
162         case 7:
163             printf(" special");
164             break;
165         case 8:
166             printf(" number");
167             break;
168         default:
169             if (tok >= 16 && tok < 48) {
170                 printf(" noun=%d", tok-16);
171             }
172             else if (tok >= 48 && tok < 80) {
173                 printf(" routine=%d", tok-48);
174             }
175             else if (tok >= 80 && tok < 128) {
176                 printf(" scope=%d", tok-80);
177             }
178             else if (tok >= 128 && tok < 160) {
179                 printf(" attr=%d", tok-128);
180             }
181             else if (tok >= 160) {
182                 printf(" prep=%d", tok);
183             }
184             else {
185                 printf(" ???");
186             }
187         }
188     }
189
190     printf(" -> ");
191     actsym = actions[action].symbol;
192     str = (symbols[actsym].name);
193     len = strlen(str) - 3;   /* remove "__A" */
194     for (ix=0; ix<len; ix++) putchar(str[ix]);
195     printf("\n");
196 }
197
198 static void list_grammar_line_v2(int mark)
199 {
200     int action, flags, actsym;
201     int ix, len;
202     char *str;
203     
204     if (!glulx_mode) {
205         action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
206         flags = (action & 0x400);
207         action &= 0x3FF;
208         mark += 2;
209     }
210     else {
211         action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
212         mark += 2;
213         flags = grammar_lines[mark++];
214     }
215     
216     printf("  *");
217     while (grammar_lines[mark] != 15) {
218         int toktype, tokdat, tokalt;
219         if (!glulx_mode) {
220             toktype = grammar_lines[mark] & 0x0F;
221             tokalt = (grammar_lines[mark] >> 4) & 0x03;
222             mark += 1;
223             tokdat = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
224             mark += 2;
225         }
226         else {
227             toktype = grammar_lines[mark] & 0x0F;
228             tokalt = (grammar_lines[mark] >> 4) & 0x03;
229             mark += 1;
230             tokdat = (grammar_lines[mark] << 24) | (grammar_lines[mark+1] << 16) | (grammar_lines[mark+2] << 8) | (grammar_lines[mark+3]);
231             mark += 4;
232         }
233
234         if (tokalt == 3 || tokalt == 1)
235             printf(" /");
236                 
237         switch (toktype) {
238         case 1:
239             switch (tokdat) {
240             case 0: printf(" noun"); break;
241             case 1: printf(" held"); break;
242             case 2: printf(" multi"); break;
243             case 3: printf(" multiheld"); break;
244             case 4: printf(" multiexcept"); break;
245             case 5: printf(" multiinside"); break;
246             case 6: printf(" creature"); break;
247             case 7: printf(" special"); break;
248             case 8: printf(" number"); break;
249             case 9: printf(" topic"); break;
250             default: printf(" ???"); break;
251             }
252             break;
253         case 2:
254             printf(" '");
255             print_dict_word(tokdat);
256             printf("'");
257             break;
258         case 3:
259             printf(" noun=%d", tokdat);
260             break;
261         case 4:
262             printf(" attr=%d", tokdat);
263             break;
264         case 5:
265             printf(" scope=%d", tokdat);
266             break;
267         case 6:
268             printf(" routine=%d", tokdat);
269             break;
270         default:
271             printf(" ???%d:%d", toktype, tokdat);
272             break;
273         }
274     }
275     printf(" -> ");
276     actsym = actions[action].symbol;
277     str = (symbols[actsym].name);
278     len = strlen(str) - 3;   /* remove "__A" */
279     for (ix=0; ix<len; ix++) putchar(str[ix]);
280     if (flags) printf(" (reversed)");
281     printf("\n");
282 }
283
284 extern void list_verb_table(void)
285 {
286     int verb, lx;
287     printf("Grammar table: %d verbs\n", no_Inform_verbs);
288     for (verb=0; verb<no_Inform_verbs; verb++) {
289         char *verbword = find_verb_by_number(verb);
290         printf("Verb '%s'\n", verbword);
291         for (lx=0; lx<Inform_verbs[verb].lines; lx++) {
292             int mark = Inform_verbs[verb].l[lx];
293             switch (grammar_version_number) {
294             case 1:
295                 list_grammar_line_v1(mark);
296                 break;
297             case 2:
298                 list_grammar_line_v2(mark);
299                 break;
300             }
301         }
302     }
303 }
304
305 /* ------------------------------------------------------------------------- */
306 /*   Actions.                                                                */
307 /* ------------------------------------------------------------------------- */
308
309 static void new_action(char *b, int c)
310 {
311     /*  Called whenever a new action (or fake action) is created (either
312         by using make_action above, or the Fake_Action directive).
313         At present just a hook for some tracing code.                        */
314
315     if (printactions_switch)
316         printf("Action '%s' is numbered %d\n",b,c);
317 }
318
319 /* Note that fake actions are numbered from a high base point upwards;
320    real actions are numbered from 0 upward in GV2.                           */
321
322 extern void make_fake_action(void)
323 {   int i;
324     char action_sub[MAX_IDENTIFIER_LENGTH+4];
325     debug_location_beginning beginning_debug_location =
326         get_token_location_beginning();
327
328     get_next_token();
329     if (token_type != SYMBOL_TT)
330     {   discard_token_location(beginning_debug_location);
331         ebf_error("new fake action name", token_text);
332         panic_mode_error_recovery(); return;
333     }
334     /* Action symbols (including fake_actions) may collide with other kinds of symbols. So we don't check that. */
335
336     snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", token_text);
337     i = symbol_index(action_sub, -1);
338
339     if (!(symbols[i].flags & UNKNOWN_SFLAG))
340     {   discard_token_location(beginning_debug_location);
341         /* The user didn't know they were defining FOO__A, but they were and it's a problem. */
342         ebf_symbol_error("new fake action name", action_sub, typename(symbols[i].type), symbols[i].line);
343         panic_mode_error_recovery(); return;
344     }
345
346     assign_symbol(i, ((grammar_version_number==1)?256:4096)+no_fake_actions++,
347         FAKE_ACTION_T);
348
349     new_action(token_text, i);
350
351     if (debugfile_switch)
352     {   debug_file_printf("<fake-action>");
353         debug_file_printf("<identifier>##%s</identifier>", token_text);
354         debug_file_printf("<value>%d</value>", symbols[i].value);
355         get_next_token();
356         write_debug_locations
357             (get_token_location_end(beginning_debug_location));
358         put_token_back();
359         debug_file_printf("</fake-action>");
360     }
361
362     return;
363 }
364
365 extern assembly_operand action_of_name(char *name)
366 {
367     /*  Returns the action number of the given name, creating it as a new
368         action name if it isn't already known as such.                       */
369
370     char action_sub[MAX_IDENTIFIER_LENGTH+4];
371     int j;
372     assembly_operand AO;
373
374     snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", name);
375     j = symbol_index(action_sub, -1);
376
377     if (symbols[j].type == FAKE_ACTION_T)
378     {   INITAO(&AO);
379         AO.value = symbols[j].value;
380         if (!glulx_mode)
381           AO.type = LONG_CONSTANT_OT;
382         else
383           set_constant_ot(&AO);
384         symbols[j].flags |= USED_SFLAG;
385         return AO;
386     }
387
388     if (symbols[j].flags & UNKNOWN_SFLAG)
389     {
390         ensure_memory_list_available(&actions_memlist, no_actions+1);
391         new_action(name, no_actions);
392         actions[no_actions].symbol = j;
393         actions[no_actions].byte_offset = 0; /* fill in later */
394         assign_symbol(j, no_actions++, CONSTANT_T);
395         symbols[j].flags |= ACTION_SFLAG;
396     }
397     symbols[j].flags |= USED_SFLAG;
398
399     INITAO(&AO);
400     AO.value = symbols[j].value;
401     AO.marker = ACTION_MV;
402     if (!glulx_mode) {
403       AO.type = SHORT_CONSTANT_OT;
404       if (symbols[j].value >= 256) AO.type = LONG_CONSTANT_OT;
405     }
406     else {
407       AO.type = CONSTANT_OT;
408     }
409     return AO;
410 }
411
412 extern void find_the_actions(void)
413 {   int i; int32 j;
414     char action_name[MAX_IDENTIFIER_LENGTH+4];
415     char action_sub[MAX_IDENTIFIER_LENGTH+4];
416
417     for (i=0; i<no_actions; i++)
418     {   strcpy(action_name, symbols[actions[i].symbol].name);
419         action_name[strlen(action_name) - 3] = '\0'; /* remove "__A" */
420         strcpy(action_sub, action_name);
421         strcat(action_sub, "Sub");
422         j = symbol_index(action_sub, -1);
423         if (symbols[j].flags & UNKNOWN_SFLAG)
424         {
425             error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
426         }
427         else
428         if (symbols[j].type != ROUTINE_T)
429         {
430             error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
431             error_named_at("-- ...Sub symbol found, but not a routine:", action_sub, symbols[j].line);
432         }
433         else
434         {   actions[i].byte_offset = symbols[j].value;
435             symbols[j].flags |= USED_SFLAG;
436         }
437     }
438 }
439
440 /* ------------------------------------------------------------------------- */
441 /*   Adjectives.                                                             */
442 /* ------------------------------------------------------------------------- */
443
444 static int make_adjective(char *English_word)
445 {
446     /*  Returns adjective number of the English word supplied, creating
447         a new adjective number if need be.
448
449         Note that (partly for historical reasons) adjectives are numbered
450         from 0xff downwards.  (And partly to make them stand out as tokens.)
451
452         This routine is used only in grammar version 1: the corresponding
453         table is left empty in GV2.                                          */
454
455     int i; 
456     uchar new_sort_code[MAX_DICT_WORD_BYTES];
457
458     if (no_adjectives >= 255) {
459         error("Grammar version 1 cannot support more than 255 prepositions");
460         return 0;
461     }
462     if (ZCODE_LESS_DICT_DATA && !glulx_mode) {
463         /* We need to use #dict_par3 for the preposition number. */
464         error("Grammar version 1 cannot be used with ZCODE_LESS_DICT_DATA");
465         return 0;
466     }
467     ensure_memory_list_available(&adjectives_memlist, no_adjectives+1);
468     ensure_memory_list_available(&adjective_sort_code_memlist, (no_adjectives+1) * DICT_WORD_BYTES);
469
470     dictionary_prepare(English_word, new_sort_code);
471     for (i=0; i<no_adjectives; i++)
472         if (compare_sorts(new_sort_code,
473           adjective_sort_code+i*DICT_WORD_BYTES) == 0)
474             return(0xff-i);
475     adjectives[no_adjectives]
476         = dictionary_add(English_word,8,0,0xff-no_adjectives);
477     copy_sorts(adjective_sort_code+no_adjectives*DICT_WORD_BYTES,
478         new_sort_code);
479     return(0xff-no_adjectives++);
480 }
481
482 /* ------------------------------------------------------------------------- */
483 /*   Parsing routines.                                                       */
484 /* ------------------------------------------------------------------------- */
485
486 static int make_parsing_routine(int32 routine_address)
487 {
488     /*  This routine is used only in grammar version 1: the corresponding
489         table is left empty in GV2.                                          */
490
491     int l;
492     for (l=0; l<no_grammar_token_routines; l++)
493         if (grammar_token_routine[l] == routine_address)
494             return l;
495
496     ensure_memory_list_available(&grammar_token_routine_memlist, no_grammar_token_routines+1);
497     
498     grammar_token_routine[no_grammar_token_routines] = routine_address;
499     return(no_grammar_token_routines++);
500 }
501
502 /* ------------------------------------------------------------------------- */
503 /*   The English-verb list.                                                  */
504 /* ------------------------------------------------------------------------- */
505
506 static int find_or_renumber_verb(char *English_verb, int *new_number)
507 {
508     /*  If new_number is null, returns the Inform-verb number which the
509      *  given English verb causes, or -1 if the given verb is not in the
510      *  dictionary                     */
511
512     /*  If new_number is non-null, renumbers the Inform-verb number which
513      *  English_verb matches in English_verb_list to account for the case
514      *  when we are extending a verb.  Returns 0 if successful, or -1 if
515      *  the given verb is not in the dictionary (which shouldn't happen as
516      *  get_verb has already run) */
517
518     char *p;
519     p=English_verb_list;
520     while (p < English_verb_list+English_verb_list_size)
521     {   if (strcmp(English_verb, p+3) == 0)
522         {   if (new_number)
523             {   p[1] = (*new_number)/256;
524                 p[2] = (*new_number)%256;
525                 return 0;
526             }
527             return(256*((uchar)p[1]))+((uchar)p[2]);
528         }
529         p=p+(uchar)p[0];
530     }
531     return(-1);
532 }
533
534 static char *find_verb_by_number(int num)
535 {
536     /*  Find the English verb string with the given verb number. */
537     char *p;
538     p=English_verb_list;
539     while (p < English_verb_list+English_verb_list_size)
540     {
541         int val = (p[1] << 8) | p[2];
542         if (val == num) {
543             return p+3;
544         }
545         p=p+(uchar)p[0];
546     }
547     return "???";
548 }
549
550 static void register_verb(char *English_verb, int number)
551 {
552     /*  Registers a new English verb as referring to the given Inform-verb
553         number.  (See comments above for format of the list.)                */
554     char *top;
555     int entrysize;
556
557     if (find_or_renumber_verb(English_verb, NULL) != -1)
558     {   error_named("Two different verb definitions refer to", English_verb);
559         return;
560     }
561
562     /* We set a hard limit of MAX_VERB_WORD_SIZE=120 because the
563        English_verb_list table stores length in a leading byte. (We could
564        raise that to 250, really, but there's little point when
565        MAX_DICT_WORD_SIZE is 40.) */
566     entrysize = strlen(English_verb)+4;
567     if (entrysize > MAX_VERB_WORD_SIZE+4)
568         error_numbered("Verb word is too long -- max length is", MAX_VERB_WORD_SIZE);
569     ensure_memory_list_available(&English_verb_list_memlist, English_verb_list_size + entrysize);
570     top = English_verb_list + English_verb_list_size;
571     English_verb_list_size += entrysize;
572
573     top[0] = entrysize;
574     top[1] = number/256;
575     top[2] = number%256;
576     strcpy(top+3, English_verb);
577 }
578
579 static int get_verb(void)
580 {
581     /*  Look at the last-read token: if it's the name of an English verb
582         understood by Inform, in double-quotes, then return the Inform-verb
583         that word refers to: otherwise give an error and return -1.          */
584
585     int j;
586
587     if ((token_type == DQ_TT) || (token_type == SQ_TT))
588     {   j = find_or_renumber_verb(token_text, NULL);
589         if (j==-1)
590             error_named("There is no previous grammar for the verb",
591                 token_text);
592         return j;
593     }
594
595     ebf_error("an English verb in quotes", token_text);
596
597     return -1;
598 }
599
600 /* ------------------------------------------------------------------------- */
601 /*   Grammar lines for Verb/Extend directives.                               */
602 /* ------------------------------------------------------------------------- */
603
604 static void ensure_grammar_lines_available(int verbnum, int num)
605 {
606     /* Note that the size field always starts positive. */
607     if (num > Inform_verbs[verbnum].size) {
608         int newsize = 2*num+4;
609         my_realloc(&Inform_verbs[verbnum].l, sizeof(int) * Inform_verbs[verbnum].size, sizeof(int) * newsize, "grammar lines for one verb");
610         Inform_verbs[verbnum].size = newsize;
611     }
612 }
613
614 static int grammar_line(int verbnum, int line)
615 {
616     /*  Parse a grammar line, to be written into grammar_lines[] starting
617         at grammar_lines_top. grammar_lines_top is left at the end
618         of the new line.
619
620         This stores the line position in Inform_verbs[verbnum].l[line].
621         (It does not increment Inform_verbs[verbnum].lines; the caller
622         must do that.)
623
624         Syntax: * <token1> ... <token-n> -> <action>
625
626         is compiled to a table in the form:
627
628                 <action number : word>
629                 <token 1> ... <token n> <ENDIT>
630
631         where <ENDIT> is the byte 15, and each <token> is 3 bytes long.
632
633         If grammar_version_number is 1, the token holds
634
635                 <bytecode> 00 00
636
637         and otherwise a GV2 token.
638
639         Return TRUE if grammar continues after the line, FALSE if the
640         directive comes to an end.                                           */
641
642     int j, bytecode, mark; int32 wordcode;
643     int grammar_token, slash_mode, last_was_slash;
644     int reverse_action, TOKEN_SIZE;
645     debug_location_beginning beginning_debug_location =
646         get_token_location_beginning();
647
648     get_next_token();
649     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
650     {   discard_token_location(beginning_debug_location);
651         return FALSE;
652     }
653     if (!((token_type == SEP_TT) && (token_value == TIMES_SEP)))
654     {   discard_token_location(beginning_debug_location);
655         ebf_error("'*' divider", token_text);
656         panic_mode_error_recovery();
657         return FALSE;
658     }
659
660     mark = grammar_lines_top;
661
662     ensure_grammar_lines_available(verbnum, line+1);
663     Inform_verbs[verbnum].l[line] = mark;
664
665     if (!glulx_mode) {
666         mark = mark + 2;
667         TOKEN_SIZE = 3;
668     }
669     else {
670         mark = mark + 3;
671         TOKEN_SIZE = 5;
672     }
673     ensure_memory_list_available(&grammar_lines_memlist, mark);
674
675     grammar_token = 0; last_was_slash = TRUE; slash_mode = FALSE;
676     no_grammar_lines++;
677
678     do
679     {   get_next_token();
680         bytecode = 0; wordcode = 0;
681         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
682         {   discard_token_location(beginning_debug_location);
683             ebf_error("'->' clause", token_text);
684             return FALSE;
685         }
686         if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
687         {   if (last_was_slash && (grammar_token>0))
688                 ebf_error("grammar token", token_text);
689             break;
690         }
691
692         if (!last_was_slash) slash_mode = FALSE;
693         if ((token_type == SEP_TT) && (token_value == DIVIDE_SEP))
694         {   if (grammar_version_number == 1)
695                 error("'/' can only be used with Library 6/3 or later");
696             if (last_was_slash)
697                 ebf_error("grammar token or '->'", token_text);
698             else
699             {   last_was_slash = TRUE;
700                 slash_mode = TRUE;
701                 if (((grammar_lines[mark-TOKEN_SIZE]) & 0x0f) != 2)
702                     error("'/' can only be applied to prepositions");
703                 grammar_lines[mark-TOKEN_SIZE] |= 0x20;
704                 continue;
705             }
706         }
707         else last_was_slash = FALSE;
708
709         if ((token_type == DQ_TT) || (token_type == SQ_TT))
710         {    if (grammar_version_number == 1)
711                  bytecode = make_adjective(token_text);
712              else
713              {   bytecode = 0x42;
714                  wordcode = dictionary_add(token_text, 8, 0, 0);
715              }
716         }
717         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NOUN_DK))
718              {   get_next_token();
719                  if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
720                  {
721                      /*  noun = <routine>                                    */
722
723                      get_next_token();
724                      if ((token_type != SYMBOL_TT)
725                          || (symbols[token_value].type != ROUTINE_T))
726                      {   discard_token_location(beginning_debug_location);
727                          ebf_error("routine name after 'noun='", token_text);
728                          panic_mode_error_recovery();
729                          return FALSE;
730                      }
731                      if (grammar_version_number == 1)
732                          bytecode
733                              = 16 + make_parsing_routine(symbols[token_value].value);
734                      else
735                      {   bytecode = 0x83;
736                          wordcode = symbols[token_value].value;
737                      }
738                      symbols[token_value].flags |= USED_SFLAG;
739                  }
740                  else
741                  {   put_token_back();
742                      if (grammar_version_number == 1) bytecode=0;
743                      else { bytecode = 1; wordcode = 0; }
744                  }
745              }
746         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==HELD_DK))
747              {   if (grammar_version_number==1) bytecode=1;
748                  else { bytecode=1; wordcode=1; } }
749         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTI_DK))
750              {   if (grammar_version_number==1) bytecode=2;
751                  else { bytecode=1; wordcode=2; } }
752         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIHELD_DK))
753              {   if (grammar_version_number==1) bytecode=3;
754                  else { bytecode=1; wordcode=3; } }
755         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIEXCEPT_DK))
756              {   if (grammar_version_number==1) bytecode=4;
757                  else { bytecode=1; wordcode=4; } }
758         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIINSIDE_DK))
759              {   if (grammar_version_number==1) bytecode=5;
760                  else { bytecode=1; wordcode=5; } }
761         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==CREATURE_DK))
762              {   if (grammar_version_number==1) bytecode=6;
763                  else { bytecode=1; wordcode=6; } }
764         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==SPECIAL_DK))
765              {   if (grammar_version_number==1) bytecode=7;
766                  else { bytecode=1; wordcode=7; } }
767         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NUMBER_DK))
768              {   if (grammar_version_number==1) bytecode=8;
769                  else { bytecode=1; wordcode=8; } }
770         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TOPIC_DK))
771              {   if (grammar_version_number==1)
772                      error("The 'topic' token is only available if you \
773 are using Library 6/3 or later");
774                  else { bytecode=1; wordcode=9; } }
775         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==SCOPE_DK))
776              {
777                  /*  scope = <routine> */
778
779                  get_next_token();
780                  if (!((token_type==SEP_TT)&&(token_value==SETEQUALS_SEP)))
781                  {   discard_token_location(beginning_debug_location);
782                      ebf_error("'=' after 'scope'", token_text);
783                      panic_mode_error_recovery();
784                      return FALSE;
785                  }
786
787                  get_next_token();
788                  if ((token_type != SYMBOL_TT)
789                      || (symbols[token_value].type != ROUTINE_T))
790                  {   discard_token_location(beginning_debug_location);
791                      ebf_error("routine name after 'scope='", token_text);
792                      panic_mode_error_recovery();
793                      return FALSE;
794                  }
795
796                  if (grammar_version_number == 1)
797                      bytecode = 80 +
798                          make_parsing_routine(symbols[token_value].value);
799                  else { bytecode = 0x85; wordcode = symbols[token_value].value; }
800                  symbols[token_value].flags |= USED_SFLAG;
801              }
802         else if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
803              {   discard_token_location(beginning_debug_location);
804                  error("'=' is only legal here as 'noun=Routine'");
805                  panic_mode_error_recovery();
806                  return FALSE;
807              }
808         else {   /*  <attribute>  or  <general-parsing-routine>  tokens      */
809
810                  if ((token_type != SYMBOL_TT)
811                      || ((symbols[token_value].type != ATTRIBUTE_T)
812                          && (symbols[token_value].type != ROUTINE_T)))
813                  {   discard_token_location(beginning_debug_location);
814                      error_named("No such grammar token as", token_text);
815                      panic_mode_error_recovery();
816                      return FALSE;
817                  }
818                  if (symbols[token_value].type==ATTRIBUTE_T)
819                  {   if (grammar_version_number == 1)
820                          bytecode = 128 + symbols[token_value].value;
821                      else { bytecode = 4; wordcode = symbols[token_value].value; }
822                  }
823                  else
824                  {   if (grammar_version_number == 1)
825                          bytecode = 48 +
826                              make_parsing_routine(symbols[token_value].value);
827                      else { bytecode = 0x86; wordcode = symbols[token_value].value; }
828                  }
829                  symbols[token_value].flags |= USED_SFLAG;
830              }
831
832         grammar_token++; no_grammar_tokens++;
833         if ((grammar_version_number == 1) && (grammar_token > 6))
834         {   if (grammar_token == 7)
835                 warning("Grammar line cut short: you can only have up to 6 \
836 tokens in any line (unless you're compiling with library 6/3 or later)");
837         }
838         else
839         {   if (slash_mode)
840             {   if (bytecode != 0x42)
841                     error("'/' can only be applied to prepositions");
842                 bytecode |= 0x10;
843             }
844             ensure_memory_list_available(&grammar_lines_memlist, mark+5);
845             grammar_lines[mark++] = bytecode;
846             if (!glulx_mode) {
847                 grammar_lines[mark++] = wordcode/256;
848                 grammar_lines[mark++] = wordcode%256;
849             }
850             else {
851                 grammar_lines[mark++] = ((wordcode >> 24) & 0xFF);
852                 grammar_lines[mark++] = ((wordcode >> 16) & 0xFF);
853                 grammar_lines[mark++] = ((wordcode >> 8) & 0xFF);
854                 grammar_lines[mark++] = ((wordcode) & 0xFF);
855             }
856         }
857
858     } while (TRUE);
859
860     ensure_memory_list_available(&grammar_lines_memlist, mark+1);
861     grammar_lines[mark++] = 15;
862     grammar_lines_top = mark;
863
864     dont_enter_into_symbol_table = TRUE;
865     get_next_token();
866     dont_enter_into_symbol_table = FALSE;
867
868     if (token_type != DQ_TT)
869     {   discard_token_location(beginning_debug_location);
870         ebf_error("name of new or existing action", token_text);
871         panic_mode_error_recovery();
872         return FALSE;
873     }
874
875     {   assembly_operand AO = action_of_name(token_text);
876         j = AO.value;
877         if (j >= ((grammar_version_number==1)?256:4096))
878             error_named("This is a fake action, not a real one:", token_text);
879     }
880
881     reverse_action = FALSE;
882     get_next_token();
883     if ((token_type == DIR_KEYWORD_TT) && (token_value == REVERSE_DK))
884     {   if (grammar_version_number == 1)
885             error("'reverse' actions can only be used with \
886 Library 6/3 or later");
887         reverse_action = TRUE;
888     }
889     else put_token_back();
890
891     mark = Inform_verbs[verbnum].l[line];
892
893     if (debugfile_switch)
894     {   debug_file_printf("<table-entry>");
895         debug_file_printf("<type>grammar line</type>");
896         debug_file_printf("<address>");
897         write_debug_grammar_backpatch(mark);
898         debug_file_printf("</address>");
899         debug_file_printf("<end-address>");
900         write_debug_grammar_backpatch(grammar_lines_top);
901         debug_file_printf("</end-address>");
902         write_debug_locations
903             (get_token_location_end(beginning_debug_location));
904         debug_file_printf("</table-entry>");
905     }
906
907     ensure_memory_list_available(&grammar_lines_memlist, mark+3);
908     if (!glulx_mode) {
909         if (reverse_action)
910             j = j + 0x400;
911         grammar_lines[mark++] = j/256;
912         grammar_lines[mark++] = j%256;
913     }
914     else {
915         grammar_lines[mark++] = ((j >> 8) & 0xFF);
916         grammar_lines[mark++] = ((j) & 0xFF);
917         grammar_lines[mark++] = (reverse_action ? 1 : 0);
918     }
919
920     return TRUE;
921 }
922
923 /* ------------------------------------------------------------------------- */
924 /*   The Verb directive:                                                     */
925 /*                                                                           */
926 /*       Verb [meta] "word-1" ... "word-n" | = "existing-English-verb"       */
927 /*                                         | <grammar-line-1> ... <g-line-n> */
928 /*                                                                           */
929 /* ------------------------------------------------------------------------- */
930
931 extern void make_verb(void)
932 {
933     /*  Parse an entire Verb ... directive.                                  */
934
935     int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
936
937     int no_given = 0, verbs_given_pos = 0;
938     int i, pos;
939
940     directive_keywords.enabled = TRUE;
941
942     get_next_token();
943
944     if ((token_type == DIR_KEYWORD_TT) && (token_value == META_DK))
945     {   meta_verb_flag = TRUE;
946         get_next_token();
947     }
948
949     while ((token_type == DQ_TT) || (token_type == SQ_TT))
950     {
951         int len = strlen(token_text) + 1;
952         ensure_memory_list_available(&English_verbs_given_memlist, verbs_given_pos + len);
953         strcpy(English_verbs_given+verbs_given_pos, token_text);
954         verbs_given_pos += len;
955         no_given++;
956         get_next_token();
957     }
958
959     if (no_given == 0)
960     {   ebf_error("English verb in quotes", token_text);
961         panic_mode_error_recovery(); return;
962     }
963
964     if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
965     {   verb_equals_form = TRUE;
966         get_next_token();
967         Inform_verb = get_verb();
968         if (Inform_verb == -1) return;
969         get_next_token();
970         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
971             ebf_error("';' after English verb", token_text);
972     }
973     else
974     {   verb_equals_form = FALSE;
975         if (!glulx_mode && no_Inform_verbs >= 255) {
976             error("Z-code is limited to 255 verbs.");
977             panic_mode_error_recovery(); return;
978         }
979         ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1);
980         Inform_verb = no_Inform_verbs;
981         Inform_verbs[no_Inform_verbs].lines = 0;
982         Inform_verbs[no_Inform_verbs].size = 4;
983         Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb");
984     }
985
986     for (i=0, pos=0; i<no_given; i++) {
987         char *wd = English_verbs_given+pos;
988         dictionary_add(wd,
989             0x41 + ((meta_verb_flag)?0x02:0x00),
990             (glulx_mode)?(0xffff-Inform_verb):(0xff-Inform_verb), 0);
991         register_verb(wd, Inform_verb);
992         pos += (strlen(wd) + 1);
993     }
994
995     if (!verb_equals_form)
996     {   int lines = 0;
997         put_token_back();
998         while (grammar_line(no_Inform_verbs, lines++)) ;
999         Inform_verbs[no_Inform_verbs++].lines = --lines;
1000     }
1001
1002     directive_keywords.enabled = FALSE;
1003 }
1004
1005 /* ------------------------------------------------------------------------- */
1006 /*   The Extend directive:                                                   */
1007 /*                                                                           */
1008 /*      Extend | only "verb-1" ... "verb-n"  |             <grammar-lines>   */
1009 /*             | "verb"                      | "replace"                     */
1010 /*                                           | "first"                       */
1011 /*                                           | "last"                        */
1012 /*                                                                           */
1013 /* ------------------------------------------------------------------------- */
1014
1015 #define EXTEND_REPLACE 1
1016 #define EXTEND_FIRST   2
1017 #define EXTEND_LAST    3
1018
1019 extern void extend_verb(void)
1020 {
1021     /*  Parse an entire Extend ... directive.                                */
1022
1023     int Inform_verb = -1, k, l, lines, extend_mode;
1024
1025     directive_keywords.enabled = TRUE;
1026     directives.enabled = FALSE;
1027
1028     get_next_token();
1029     if ((token_type == DIR_KEYWORD_TT) && (token_value == ONLY_DK))
1030     {
1031         if (!glulx_mode && no_Inform_verbs >= 255) {
1032             error("Z-code is limited to 255 verbs.");
1033             panic_mode_error_recovery(); return;
1034         }
1035         ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1);
1036         l = -1;
1037         while (get_next_token(),
1038                ((token_type == DQ_TT) || (token_type == SQ_TT)))
1039         {   Inform_verb = get_verb();
1040             if (Inform_verb == -1) return;
1041             if ((l!=-1) && (Inform_verb!=l))
1042               warning_named("Verb disagrees with previous verbs:", token_text);
1043             l = Inform_verb;
1044             dictionary_set_verb_number(token_text,
1045               (glulx_mode)?(0xffff-no_Inform_verbs):(0xff-no_Inform_verbs));
1046             /* make call to renumber verb in English_verb_list too */
1047             if (find_or_renumber_verb(token_text, &no_Inform_verbs) == -1)
1048               warning_named("Verb to extend not found in English_verb_list:",
1049                  token_text);
1050         }
1051
1052         /*  Copy the old Inform-verb into a new one which the list of
1053             English-verbs given have had their dictionary entries modified
1054             to point to                                                      */
1055         /*  (We are copying entry Inform_verb to no_Inform_verbs here.) */
1056
1057         l = Inform_verbs[Inform_verb].lines; /* number of lines to copy */
1058         
1059         Inform_verbs[no_Inform_verbs].lines = l;
1060         Inform_verbs[no_Inform_verbs].size = l+4;
1061         Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb");
1062         for (k=0; k<l; k++)
1063             Inform_verbs[no_Inform_verbs].l[k] = Inform_verbs[Inform_verb].l[k];
1064         Inform_verb = no_Inform_verbs++;
1065     }
1066     else
1067     {   Inform_verb = get_verb();
1068         if (Inform_verb == -1) return;
1069         get_next_token();
1070     }
1071
1072     /*  Inform_verb now contains the number of the Inform-verb to extend...  */
1073
1074     extend_mode = EXTEND_LAST;
1075     if ((token_type == SEP_TT) && (token_value == TIMES_SEP))
1076         put_token_back();
1077     else
1078     {   extend_mode = 0;
1079         if ((token_type == DIR_KEYWORD_TT) && (token_value == REPLACE_DK))
1080             extend_mode = EXTEND_REPLACE;
1081         if ((token_type == DIR_KEYWORD_TT) && (token_value == FIRST_DK))
1082             extend_mode = EXTEND_FIRST;
1083         if ((token_type == DIR_KEYWORD_TT) && (token_value == LAST_DK))
1084             extend_mode = EXTEND_LAST;
1085
1086         if (extend_mode==0)
1087         {   ebf_error("'replace', 'last', 'first' or '*'", token_text);
1088             extend_mode = EXTEND_LAST;
1089         }
1090     }
1091
1092     l = Inform_verbs[Inform_verb].lines;
1093     lines = 0;
1094     if (extend_mode == EXTEND_LAST) lines=l;
1095     do
1096     {
1097         if (extend_mode == EXTEND_FIRST) {
1098             ensure_grammar_lines_available(Inform_verb, l+lines+1);
1099             for (k=l; k>0; k--)
1100                  Inform_verbs[Inform_verb].l[k+lines]
1101                      = Inform_verbs[Inform_verb].l[k-1+lines];
1102         }
1103     } while (grammar_line(Inform_verb, lines++));
1104
1105     if (extend_mode == EXTEND_FIRST)
1106     {
1107         ensure_grammar_lines_available(Inform_verb, l+lines+1);
1108         Inform_verbs[Inform_verb].lines = l+lines-1;
1109         for (k=0; k<l; k++) {
1110             Inform_verbs[Inform_verb].l[k+lines-1]
1111                 = Inform_verbs[Inform_verb].l[k+lines];
1112         }
1113     }
1114     else Inform_verbs[Inform_verb].lines = --lines;
1115
1116     directive_keywords.enabled = FALSE;
1117     directives.enabled = TRUE;
1118 }
1119
1120 /* ========================================================================= */
1121 /*   Data structure management routines                                      */
1122 /* ------------------------------------------------------------------------- */
1123
1124 extern void init_verbs_vars(void)
1125 {
1126     no_fake_actions = 0;
1127     no_actions = 0;
1128     no_grammar_lines = 0;
1129     no_grammar_tokens = 0;
1130     English_verb_list_size = 0;
1131
1132     Inform_verbs = NULL;
1133     actions = NULL;
1134     grammar_lines = NULL;
1135     grammar_token_routine = NULL;
1136     adjectives = NULL;
1137     adjective_sort_code = NULL;
1138     English_verb_list = NULL;
1139     English_verbs_given = NULL;
1140
1141     if (!glulx_mode)
1142         grammar_version_number = 1;
1143     else
1144         grammar_version_number = 2;
1145 }
1146
1147 extern void verbs_begin_pass(void)
1148 {
1149     no_Inform_verbs=0; no_adjectives=0;
1150     no_grammar_token_routines=0;
1151     no_actions=0;
1152
1153     no_fake_actions=0;
1154     grammar_lines_top = 0;
1155 }
1156
1157 extern void verbs_allocate_arrays(void)
1158 {
1159     initialise_memory_list(&Inform_verbs_memlist,
1160         sizeof(verbt), 128, (void**)&Inform_verbs,
1161         "verbs");
1162     
1163     initialise_memory_list(&grammar_lines_memlist,
1164         sizeof(uchar), 4000, (void**)&grammar_lines,
1165         "grammar lines");
1166     
1167     initialise_memory_list(&actions_memlist,
1168         sizeof(actioninfo), 128, (void**)&actions,
1169         "actions");
1170     
1171     initialise_memory_list(&grammar_token_routine_memlist,
1172         sizeof(int32), 50, (void**)&grammar_token_routine,
1173         "grammar token routines");
1174
1175     initialise_memory_list(&adjectives_memlist,
1176         sizeof(int32), 50, (void**)&adjectives,
1177         "adjectives");
1178     initialise_memory_list(&adjective_sort_code_memlist,
1179         sizeof(uchar), 50*DICT_WORD_BYTES, (void**)&adjective_sort_code,
1180         "adjective sort codes");
1181
1182     initialise_memory_list(&English_verb_list_memlist,
1183         sizeof(char), 2048, (void**)&English_verb_list,
1184         "register of verbs");
1185
1186     initialise_memory_list(&English_verbs_given_memlist,
1187         sizeof(char), 80, (void**)&English_verbs_given,
1188         "verb words within a single definition");
1189 }
1190
1191 extern void verbs_free_arrays(void)
1192 {
1193     int ix;
1194     for (ix=0; ix<no_Inform_verbs; ix++)
1195     {
1196         my_free(&Inform_verbs[ix].l, "grammar lines for one verb");
1197     }
1198     deallocate_memory_list(&Inform_verbs_memlist);
1199     deallocate_memory_list(&grammar_lines_memlist);
1200     deallocate_memory_list(&actions_memlist);
1201     deallocate_memory_list(&grammar_token_routine_memlist);
1202     deallocate_memory_list(&adjectives_memlist);
1203     deallocate_memory_list(&adjective_sort_code_memlist);
1204     deallocate_memory_list(&English_verb_list_memlist);
1205     deallocate_memory_list(&English_verbs_given_memlist);
1206 }
1207
1208 /* ========================================================================= */