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