31b42bb2ee999a5c92087c6c2c840f7e5ea9aa64
[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.40                                                     */
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, or by
313         the linker).  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 = (module_switch)?LONG_CONSTANT_OT: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     if (module_switch)
418         for (i=0; i<no_actions; i++) actions[i].byte_offset = 0;
419     else
420     for (i=0; i<no_actions; i++)
421     {   strcpy(action_name, symbols[actions[i].symbol].name);
422         action_name[strlen(action_name) - 3] = '\0'; /* remove "__A" */
423         strcpy(action_sub, action_name);
424         strcat(action_sub, "Sub");
425         j = symbol_index(action_sub, -1);
426         if (symbols[j].flags & UNKNOWN_SFLAG)
427         {
428             error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
429         }
430         else
431         if (symbols[j].type != ROUTINE_T)
432         {
433             error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
434             error_named_at("-- ...Sub symbol found, but not a routine:", action_sub, symbols[j].line);
435         }
436         else
437         {   actions[i].byte_offset = symbols[j].value;
438             symbols[j].flags |= USED_SFLAG;
439         }
440     }
441 }
442
443 /* ------------------------------------------------------------------------- */
444 /*   Adjectives.                                                             */
445 /* ------------------------------------------------------------------------- */
446
447 static int make_adjective(char *English_word)
448 {
449     /*  Returns adjective number of the English word supplied, creating
450         a new adjective number if need be.
451
452         Note that (partly for historical reasons) adjectives are numbered
453         from 0xff downwards.  (And partly to make them stand out as tokens.)
454
455         This routine is used only in grammar version 1: the corresponding
456         table is left empty in GV2.                                          */
457
458     int i; 
459     uchar new_sort_code[MAX_DICT_WORD_BYTES];
460
461     if (no_adjectives >= 255) {
462         error("Grammar version 1 cannot support more than 255 prepositions");
463         return 0;
464     }
465     if (ZCODE_LESS_DICT_DATA && !glulx_mode) {
466         /* We need to use #dict_par3 for the preposition number. */
467         error("Grammar version 1 cannot be used with ZCODE_LESS_DICT_DATA");
468         return 0;
469     }
470     ensure_memory_list_available(&adjectives_memlist, no_adjectives+1);
471     ensure_memory_list_available(&adjective_sort_code_memlist, (no_adjectives+1) * DICT_WORD_BYTES);
472
473     dictionary_prepare(English_word, new_sort_code);
474     for (i=0; i<no_adjectives; i++)
475         if (compare_sorts(new_sort_code,
476           adjective_sort_code+i*DICT_WORD_BYTES) == 0)
477             return(0xff-i);
478     adjectives[no_adjectives]
479         = dictionary_add(English_word,8,0,0xff-no_adjectives);
480     copy_sorts(adjective_sort_code+no_adjectives*DICT_WORD_BYTES,
481         new_sort_code);
482     return(0xff-no_adjectives++);
483 }
484
485 /* ------------------------------------------------------------------------- */
486 /*   Parsing routines.                                                       */
487 /* ------------------------------------------------------------------------- */
488
489 static int make_parsing_routine(int32 routine_address)
490 {
491     /*  This routine is used only in grammar version 1: the corresponding
492         table is left empty in GV2.                                          */
493
494     int l;
495     for (l=0; l<no_grammar_token_routines; l++)
496         if (grammar_token_routine[l] == routine_address)
497             return l;
498
499     ensure_memory_list_available(&grammar_token_routine_memlist, no_grammar_token_routines+1);
500     
501     grammar_token_routine[no_grammar_token_routines] = routine_address;
502     return(no_grammar_token_routines++);
503 }
504
505 /* ------------------------------------------------------------------------- */
506 /*   The English-verb list.                                                  */
507 /* ------------------------------------------------------------------------- */
508
509 static int find_or_renumber_verb(char *English_verb, int *new_number)
510 {
511     /*  If new_number is null, returns the Inform-verb number which the
512      *  given English verb causes, or -1 if the given verb is not in the
513      *  dictionary                     */
514
515     /*  If new_number is non-null, renumbers the Inform-verb number which
516      *  English_verb matches in English_verb_list to account for the case
517      *  when we are extending a verb.  Returns 0 if successful, or -1 if
518      *  the given verb is not in the dictionary (which shouldn't happen as
519      *  get_verb has already run) */
520
521     char *p;
522     p=English_verb_list;
523     while (p < English_verb_list+English_verb_list_size)
524     {   if (strcmp(English_verb, p+3) == 0)
525         {   if (new_number)
526             {   p[1] = (*new_number)/256;
527                 p[2] = (*new_number)%256;
528                 return 0;
529             }
530             return(256*((uchar)p[1]))+((uchar)p[2]);
531         }
532         p=p+(uchar)p[0];
533     }
534     return(-1);
535 }
536
537 static char *find_verb_by_number(int num)
538 {
539     /*  Find the English verb string with the given verb number. */
540     char *p;
541     p=English_verb_list;
542     while (p < English_verb_list+English_verb_list_size)
543     {
544         int val = (p[1] << 8) | p[2];
545         if (val == num) {
546             return p+3;
547         }
548         p=p+(uchar)p[0];
549     }
550     return "???";
551 }
552
553 static void register_verb(char *English_verb, int number)
554 {
555     /*  Registers a new English verb as referring to the given Inform-verb
556         number.  (See comments above for format of the list.)                */
557     char *top;
558     int entrysize;
559
560     if (find_or_renumber_verb(English_verb, NULL) != -1)
561     {   error_named("Two different verb definitions refer to", English_verb);
562         return;
563     }
564
565     /* We set a hard limit of MAX_VERB_WORD_SIZE=120 because the
566        English_verb_list table stores length in a leading byte. (We could
567        raise that to 250, really, but there's little point when
568        MAX_DICT_WORD_SIZE is 40.) */
569     entrysize = strlen(English_verb)+4;
570     if (entrysize > MAX_VERB_WORD_SIZE+4)
571         error_numbered("Verb word is too long -- max length is", MAX_VERB_WORD_SIZE);
572     ensure_memory_list_available(&English_verb_list_memlist, English_verb_list_size + entrysize);
573     top = English_verb_list + English_verb_list_size;
574     English_verb_list_size += entrysize;
575
576     top[0] = entrysize;
577     top[1] = number/256;
578     top[2] = number%256;
579     strcpy(top+3, English_verb);
580 }
581
582 static int get_verb(void)
583 {
584     /*  Look at the last-read token: if it's the name of an English verb
585         understood by Inform, in double-quotes, then return the Inform-verb
586         that word refers to: otherwise give an error and return -1.          */
587
588     int j;
589
590     if ((token_type == DQ_TT) || (token_type == SQ_TT))
591     {   j = find_or_renumber_verb(token_text, NULL);
592         if (j==-1)
593             error_named("There is no previous grammar for the verb",
594                 token_text);
595         return j;
596     }
597
598     ebf_error("an English verb in quotes", token_text);
599
600     return -1;
601 }
602
603 /* ------------------------------------------------------------------------- */
604 /*   Grammar lines for Verb/Extend directives.                               */
605 /* ------------------------------------------------------------------------- */
606
607 static void ensure_grammar_lines_available(int verbnum, int num)
608 {
609     /* Note that the size field always starts positive. */
610     if (num > Inform_verbs[verbnum].size) {
611         int newsize = 2*num+4;
612         my_realloc(&Inform_verbs[verbnum].l, sizeof(int) * Inform_verbs[verbnum].size, sizeof(int) * newsize, "grammar lines for one verb");
613         Inform_verbs[verbnum].size = newsize;
614     }
615 }
616
617 static int grammar_line(int verbnum, int line)
618 {
619     /*  Parse a grammar line, to be written into grammar_lines[] starting
620         at grammar_lines_top. grammar_lines_top is left at the end
621         of the new line.
622
623         This stores the line position in Inform_verbs[verbnum].l[line].
624         (It does not increment Inform_verbs[verbnum].lines; the caller
625         must do that.)
626
627         Syntax: * <token1> ... <token-n> -> <action>
628
629         is compiled to a table in the form:
630
631                 <action number : word>
632                 <token 1> ... <token n> <ENDIT>
633
634         where <ENDIT> is the byte 15, and each <token> is 3 bytes long.
635
636         If grammar_version_number is 1, the token holds
637
638                 <bytecode> 00 00
639
640         and otherwise a GV2 token.
641
642         Return TRUE if grammar continues after the line, FALSE if the
643         directive comes to an end.                                           */
644
645     int j, bytecode, mark; int32 wordcode;
646     int grammar_token, slash_mode, last_was_slash;
647     int reverse_action, TOKEN_SIZE;
648     debug_location_beginning beginning_debug_location =
649         get_token_location_beginning();
650
651     get_next_token();
652     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
653     {   discard_token_location(beginning_debug_location);
654         return FALSE;
655     }
656     if (!((token_type == SEP_TT) && (token_value == TIMES_SEP)))
657     {   discard_token_location(beginning_debug_location);
658         ebf_error("'*' divider", token_text);
659         panic_mode_error_recovery();
660         return FALSE;
661     }
662
663     mark = grammar_lines_top;
664
665     ensure_grammar_lines_available(verbnum, line+1);
666     Inform_verbs[verbnum].l[line] = mark;
667
668     if (!glulx_mode) {
669         mark = mark + 2;
670         TOKEN_SIZE = 3;
671     }
672     else {
673         mark = mark + 3;
674         TOKEN_SIZE = 5;
675     }
676     ensure_memory_list_available(&grammar_lines_memlist, mark);
677
678     grammar_token = 0; last_was_slash = TRUE; slash_mode = FALSE;
679     no_grammar_lines++;
680
681     do
682     {   get_next_token();
683         bytecode = 0; wordcode = 0;
684         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
685         {   discard_token_location(beginning_debug_location);
686             ebf_error("'->' clause", token_text);
687             return FALSE;
688         }
689         if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
690         {   if (last_was_slash && (grammar_token>0))
691                 ebf_error("grammar token", token_text);
692             break;
693         }
694
695         if (!last_was_slash) slash_mode = FALSE;
696         if ((token_type == SEP_TT) && (token_value == DIVIDE_SEP))
697         {   if (grammar_version_number == 1)
698                 error("'/' can only be used with Library 6/3 or later");
699             if (last_was_slash)
700                 ebf_error("grammar token or '->'", token_text);
701             else
702             {   last_was_slash = TRUE;
703                 slash_mode = TRUE;
704                 if (((grammar_lines[mark-TOKEN_SIZE]) & 0x0f) != 2)
705                     error("'/' can only be applied to prepositions");
706                 grammar_lines[mark-TOKEN_SIZE] |= 0x20;
707                 continue;
708             }
709         }
710         else last_was_slash = FALSE;
711
712         if ((token_type == DQ_TT) || (token_type == SQ_TT))
713         {    if (grammar_version_number == 1)
714                  bytecode = make_adjective(token_text);
715              else
716              {   bytecode = 0x42;
717                  wordcode = dictionary_add(token_text, 8, 0, 0);
718              }
719         }
720         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NOUN_DK))
721              {   get_next_token();
722                  if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
723                  {
724                      /*  noun = <routine>                                    */
725
726                      get_next_token();
727                      if ((token_type != SYMBOL_TT)
728                          || (symbols[token_value].type != ROUTINE_T))
729                      {   discard_token_location(beginning_debug_location);
730                          ebf_error("routine name after 'noun='", token_text);
731                          panic_mode_error_recovery();
732                          return FALSE;
733                      }
734                      if (grammar_version_number == 1)
735                          bytecode
736                              = 16 + make_parsing_routine(symbols[token_value].value);
737                      else
738                      {   bytecode = 0x83;
739                          wordcode = symbols[token_value].value;
740                      }
741                      symbols[token_value].flags |= USED_SFLAG;
742                  }
743                  else
744                  {   put_token_back();
745                      if (grammar_version_number == 1) bytecode=0;
746                      else { bytecode = 1; wordcode = 0; }
747                  }
748              }
749         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==HELD_DK))
750              {   if (grammar_version_number==1) bytecode=1;
751                  else { bytecode=1; wordcode=1; } }
752         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTI_DK))
753              {   if (grammar_version_number==1) bytecode=2;
754                  else { bytecode=1; wordcode=2; } }
755         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIHELD_DK))
756              {   if (grammar_version_number==1) bytecode=3;
757                  else { bytecode=1; wordcode=3; } }
758         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIEXCEPT_DK))
759              {   if (grammar_version_number==1) bytecode=4;
760                  else { bytecode=1; wordcode=4; } }
761         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIINSIDE_DK))
762              {   if (grammar_version_number==1) bytecode=5;
763                  else { bytecode=1; wordcode=5; } }
764         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==CREATURE_DK))
765              {   if (grammar_version_number==1) bytecode=6;
766                  else { bytecode=1; wordcode=6; } }
767         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==SPECIAL_DK))
768              {   if (grammar_version_number==1) bytecode=7;
769                  else { bytecode=1; wordcode=7; } }
770         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NUMBER_DK))
771              {   if (grammar_version_number==1) bytecode=8;
772                  else { bytecode=1; wordcode=8; } }
773         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TOPIC_DK))
774              {   if (grammar_version_number==1)
775                      error("The 'topic' token is only available if you \
776 are using Library 6/3 or later");
777                  else { bytecode=1; wordcode=9; } }
778         else if ((token_type==DIR_KEYWORD_TT)&&(token_value==SCOPE_DK))
779              {
780                  /*  scope = <routine> */
781
782                  get_next_token();
783                  if (!((token_type==SEP_TT)&&(token_value==SETEQUALS_SEP)))
784                  {   discard_token_location(beginning_debug_location);
785                      ebf_error("'=' after 'scope'", token_text);
786                      panic_mode_error_recovery();
787                      return FALSE;
788                  }
789
790                  get_next_token();
791                  if ((token_type != SYMBOL_TT)
792                      || (symbols[token_value].type != ROUTINE_T))
793                  {   discard_token_location(beginning_debug_location);
794                      ebf_error("routine name after 'scope='", token_text);
795                      panic_mode_error_recovery();
796                      return FALSE;
797                  }
798
799                  if (grammar_version_number == 1)
800                      bytecode = 80 +
801                          make_parsing_routine(symbols[token_value].value);
802                  else { bytecode = 0x85; wordcode = symbols[token_value].value; }
803                  symbols[token_value].flags |= USED_SFLAG;
804              }
805         else if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
806              {   discard_token_location(beginning_debug_location);
807                  error("'=' is only legal here as 'noun=Routine'");
808                  panic_mode_error_recovery();
809                  return FALSE;
810              }
811         else {   /*  <attribute>  or  <general-parsing-routine>  tokens      */
812
813                  if ((token_type != SYMBOL_TT)
814                      || ((symbols[token_value].type != ATTRIBUTE_T)
815                          && (symbols[token_value].type != ROUTINE_T)))
816                  {   discard_token_location(beginning_debug_location);
817                      error_named("No such grammar token as", token_text);
818                      panic_mode_error_recovery();
819                      return FALSE;
820                  }
821                  if (symbols[token_value].type==ATTRIBUTE_T)
822                  {   if (grammar_version_number == 1)
823                          bytecode = 128 + symbols[token_value].value;
824                      else { bytecode = 4; wordcode = symbols[token_value].value; }
825                  }
826                  else
827                  {   if (grammar_version_number == 1)
828                          bytecode = 48 +
829                              make_parsing_routine(symbols[token_value].value);
830                      else { bytecode = 0x86; wordcode = symbols[token_value].value; }
831                  }
832                  symbols[token_value].flags |= USED_SFLAG;
833              }
834
835         grammar_token++; no_grammar_tokens++;
836         if ((grammar_version_number == 1) && (grammar_token > 6))
837         {   if (grammar_token == 7)
838                 warning("Grammar line cut short: you can only have up to 6 \
839 tokens in any line (unless you're compiling with library 6/3 or later)");
840         }
841         else
842         {   if (slash_mode)
843             {   if (bytecode != 0x42)
844                     error("'/' can only be applied to prepositions");
845                 bytecode |= 0x10;
846             }
847             ensure_memory_list_available(&grammar_lines_memlist, mark+5);
848             grammar_lines[mark++] = bytecode;
849             if (!glulx_mode) {
850                 grammar_lines[mark++] = wordcode/256;
851                 grammar_lines[mark++] = wordcode%256;
852             }
853             else {
854                 grammar_lines[mark++] = ((wordcode >> 24) & 0xFF);
855                 grammar_lines[mark++] = ((wordcode >> 16) & 0xFF);
856                 grammar_lines[mark++] = ((wordcode >> 8) & 0xFF);
857                 grammar_lines[mark++] = ((wordcode) & 0xFF);
858             }
859         }
860
861     } while (TRUE);
862
863     ensure_memory_list_available(&grammar_lines_memlist, mark+1);
864     grammar_lines[mark++] = 15;
865     grammar_lines_top = mark;
866
867     dont_enter_into_symbol_table = TRUE;
868     get_next_token();
869     dont_enter_into_symbol_table = FALSE;
870
871     if (token_type != DQ_TT)
872     {   discard_token_location(beginning_debug_location);
873         ebf_error("name of new or existing action", token_text);
874         panic_mode_error_recovery();
875         return FALSE;
876     }
877
878     {   assembly_operand AO = action_of_name(token_text);
879         j = AO.value;
880         if (j >= ((grammar_version_number==1)?256:4096))
881             error_named("This is a fake action, not a real one:", token_text);
882     }
883
884     reverse_action = FALSE;
885     get_next_token();
886     if ((token_type == DIR_KEYWORD_TT) && (token_value == REVERSE_DK))
887     {   if (grammar_version_number == 1)
888             error("'reverse' actions can only be used with \
889 Library 6/3 or later");
890         reverse_action = TRUE;
891     }
892     else put_token_back();
893
894     mark = Inform_verbs[verbnum].l[line];
895
896     if (debugfile_switch)
897     {   debug_file_printf("<table-entry>");
898         debug_file_printf("<type>grammar line</type>");
899         debug_file_printf("<address>");
900         write_debug_grammar_backpatch(mark);
901         debug_file_printf("</address>");
902         debug_file_printf("<end-address>");
903         write_debug_grammar_backpatch(grammar_lines_top);
904         debug_file_printf("</end-address>");
905         write_debug_locations
906             (get_token_location_end(beginning_debug_location));
907         debug_file_printf("</table-entry>");
908     }
909
910     ensure_memory_list_available(&grammar_lines_memlist, mark+3);
911     if (!glulx_mode) {
912         if (reverse_action)
913             j = j + 0x400;
914         grammar_lines[mark++] = j/256;
915         grammar_lines[mark++] = j%256;
916     }
917     else {
918         grammar_lines[mark++] = ((j >> 8) & 0xFF);
919         grammar_lines[mark++] = ((j) & 0xFF);
920         grammar_lines[mark++] = (reverse_action ? 1 : 0);
921     }
922
923     return TRUE;
924 }
925
926 /* ------------------------------------------------------------------------- */
927 /*   The Verb directive:                                                     */
928 /*                                                                           */
929 /*       Verb [meta] "word-1" ... "word-n" | = "existing-English-verb"       */
930 /*                                         | <grammar-line-1> ... <g-line-n> */
931 /*                                                                           */
932 /* ------------------------------------------------------------------------- */
933
934 extern void make_verb(void)
935 {
936     /*  Parse an entire Verb ... directive.                                  */
937
938     int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
939
940     int no_given = 0, verbs_given_pos = 0;
941     int i, pos;
942
943     directive_keywords.enabled = TRUE;
944
945     get_next_token();
946
947     if ((token_type == DIR_KEYWORD_TT) && (token_value == META_DK))
948     {   meta_verb_flag = TRUE;
949         get_next_token();
950     }
951
952     while ((token_type == DQ_TT) || (token_type == SQ_TT))
953     {
954         int len = strlen(token_text) + 1;
955         ensure_memory_list_available(&English_verbs_given_memlist, verbs_given_pos + len);
956         strcpy(English_verbs_given+verbs_given_pos, token_text);
957         verbs_given_pos += len;
958         no_given++;
959         get_next_token();
960     }
961
962     if (no_given == 0)
963     {   ebf_error("English verb in quotes", token_text);
964         panic_mode_error_recovery(); return;
965     }
966
967     if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
968     {   verb_equals_form = TRUE;
969         get_next_token();
970         Inform_verb = get_verb();
971         if (Inform_verb == -1) return;
972         get_next_token();
973         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
974             ebf_error("';' after English verb", token_text);
975     }
976     else
977     {   verb_equals_form = FALSE;
978         if (!glulx_mode && no_Inform_verbs >= 255) {
979             error("Z-code is limited to 255 verbs.");
980             panic_mode_error_recovery(); return;
981         }
982         ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1);
983         Inform_verb = no_Inform_verbs;
984         Inform_verbs[no_Inform_verbs].lines = 0;
985         Inform_verbs[no_Inform_verbs].size = 4;
986         Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb");
987     }
988
989     for (i=0, pos=0; i<no_given; i++) {
990         char *wd = English_verbs_given+pos;
991         dictionary_add(wd,
992             0x41 + ((meta_verb_flag)?0x02:0x00),
993             (glulx_mode)?(0xffff-Inform_verb):(0xff-Inform_verb), 0);
994         register_verb(wd, Inform_verb);
995         pos += (strlen(wd) + 1);
996     }
997
998     if (!verb_equals_form)
999     {   int lines = 0;
1000         put_token_back();
1001         while (grammar_line(no_Inform_verbs, lines++)) ;
1002         Inform_verbs[no_Inform_verbs++].lines = --lines;
1003     }
1004
1005     directive_keywords.enabled = FALSE;
1006 }
1007
1008 /* ------------------------------------------------------------------------- */
1009 /*   The Extend directive:                                                   */
1010 /*                                                                           */
1011 /*      Extend | only "verb-1" ... "verb-n"  |             <grammar-lines>   */
1012 /*             | "verb"                      | "replace"                     */
1013 /*                                           | "first"                       */
1014 /*                                           | "last"                        */
1015 /*                                                                           */
1016 /* ------------------------------------------------------------------------- */
1017
1018 #define EXTEND_REPLACE 1
1019 #define EXTEND_FIRST   2
1020 #define EXTEND_LAST    3
1021
1022 extern void extend_verb(void)
1023 {
1024     /*  Parse an entire Extend ... directive.                                */
1025
1026     int Inform_verb = -1, k, l, lines, extend_mode;
1027
1028     directive_keywords.enabled = TRUE;
1029     directives.enabled = FALSE;
1030
1031     get_next_token();
1032     if ((token_type == DIR_KEYWORD_TT) && (token_value == ONLY_DK))
1033     {
1034         if (!glulx_mode && no_Inform_verbs >= 255) {
1035             error("Z-code is limited to 255 verbs.");
1036             panic_mode_error_recovery(); return;
1037         }
1038         ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1);
1039         l = -1;
1040         while (get_next_token(),
1041                ((token_type == DQ_TT) || (token_type == SQ_TT)))
1042         {   Inform_verb = get_verb();
1043             if (Inform_verb == -1) return;
1044             if ((l!=-1) && (Inform_verb!=l))
1045               warning_named("Verb disagrees with previous verbs:", token_text);
1046             l = Inform_verb;
1047             dictionary_set_verb_number(token_text,
1048               (glulx_mode)?(0xffff-no_Inform_verbs):(0xff-no_Inform_verbs));
1049             /* make call to renumber verb in English_verb_list too */
1050             if (find_or_renumber_verb(token_text, &no_Inform_verbs) == -1)
1051               warning_named("Verb to extend not found in English_verb_list:",
1052                  token_text);
1053         }
1054
1055         /*  Copy the old Inform-verb into a new one which the list of
1056             English-verbs given have had their dictionary entries modified
1057             to point to                                                      */
1058         /*  (We are copying entry Inform_verb to no_Inform_verbs here.) */
1059
1060         l = Inform_verbs[Inform_verb].lines; /* number of lines to copy */
1061         
1062         Inform_verbs[no_Inform_verbs].lines = l;
1063         Inform_verbs[no_Inform_verbs].size = l+4;
1064         Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb");
1065         for (k=0; k<l; k++)
1066             Inform_verbs[no_Inform_verbs].l[k] = Inform_verbs[Inform_verb].l[k];
1067         Inform_verb = no_Inform_verbs++;
1068     }
1069     else
1070     {   Inform_verb = get_verb();
1071         if (Inform_verb == -1) return;
1072         get_next_token();
1073     }
1074
1075     /*  Inform_verb now contains the number of the Inform-verb to extend...  */
1076
1077     extend_mode = EXTEND_LAST;
1078     if ((token_type == SEP_TT) && (token_value == TIMES_SEP))
1079         put_token_back();
1080     else
1081     {   extend_mode = 0;
1082         if ((token_type == DIR_KEYWORD_TT) && (token_value == REPLACE_DK))
1083             extend_mode = EXTEND_REPLACE;
1084         if ((token_type == DIR_KEYWORD_TT) && (token_value == FIRST_DK))
1085             extend_mode = EXTEND_FIRST;
1086         if ((token_type == DIR_KEYWORD_TT) && (token_value == LAST_DK))
1087             extend_mode = EXTEND_LAST;
1088
1089         if (extend_mode==0)
1090         {   ebf_error("'replace', 'last', 'first' or '*'", token_text);
1091             extend_mode = EXTEND_LAST;
1092         }
1093     }
1094
1095     l = Inform_verbs[Inform_verb].lines;
1096     lines = 0;
1097     if (extend_mode == EXTEND_LAST) lines=l;
1098     do
1099     {
1100         if (extend_mode == EXTEND_FIRST) {
1101             ensure_grammar_lines_available(Inform_verb, l+lines+1);
1102             for (k=l; k>0; k--)
1103                  Inform_verbs[Inform_verb].l[k+lines]
1104                      = Inform_verbs[Inform_verb].l[k-1+lines];
1105         }
1106     } while (grammar_line(Inform_verb, lines++));
1107
1108     if (extend_mode == EXTEND_FIRST)
1109     {
1110         ensure_grammar_lines_available(Inform_verb, l+lines+1);
1111         Inform_verbs[Inform_verb].lines = l+lines-1;
1112         for (k=0; k<l; k++) {
1113             Inform_verbs[Inform_verb].l[k+lines-1]
1114                 = Inform_verbs[Inform_verb].l[k+lines];
1115         }
1116     }
1117     else Inform_verbs[Inform_verb].lines = --lines;
1118
1119     directive_keywords.enabled = FALSE;
1120     directives.enabled = TRUE;
1121 }
1122
1123 /* ========================================================================= */
1124 /*   Data structure management routines                                      */
1125 /* ------------------------------------------------------------------------- */
1126
1127 extern void init_verbs_vars(void)
1128 {
1129     no_fake_actions = 0;
1130     no_actions = 0;
1131     no_grammar_lines = 0;
1132     no_grammar_tokens = 0;
1133     English_verb_list_size = 0;
1134
1135     Inform_verbs = NULL;
1136     actions = NULL;
1137     grammar_lines = NULL;
1138     grammar_token_routine = NULL;
1139     adjectives = NULL;
1140     adjective_sort_code = NULL;
1141     English_verb_list = NULL;
1142     English_verbs_given = NULL;
1143
1144     if (!glulx_mode)
1145         grammar_version_number = 1;
1146     else
1147         grammar_version_number = 2;
1148 }
1149
1150 extern void verbs_begin_pass(void)
1151 {
1152     no_Inform_verbs=0; no_adjectives=0;
1153     no_grammar_token_routines=0;
1154     no_actions=0;
1155
1156     no_fake_actions=0;
1157     grammar_lines_top = 0;
1158 }
1159
1160 extern void verbs_allocate_arrays(void)
1161 {
1162     initialise_memory_list(&Inform_verbs_memlist,
1163         sizeof(verbt), 128, (void**)&Inform_verbs,
1164         "verbs");
1165     
1166     initialise_memory_list(&grammar_lines_memlist,
1167         sizeof(uchar), 4000, (void**)&grammar_lines,
1168         "grammar lines");
1169     
1170     initialise_memory_list(&actions_memlist,
1171         sizeof(actioninfo), 128, (void**)&actions,
1172         "actions");
1173     
1174     initialise_memory_list(&grammar_token_routine_memlist,
1175         sizeof(int32), 50, (void**)&grammar_token_routine,
1176         "grammar token routines");
1177
1178     initialise_memory_list(&adjectives_memlist,
1179         sizeof(int32), 50, (void**)&adjectives,
1180         "adjectives");
1181     initialise_memory_list(&adjective_sort_code_memlist,
1182         sizeof(uchar), 50*DICT_WORD_BYTES, (void**)&adjective_sort_code,
1183         "adjective sort codes");
1184
1185     initialise_memory_list(&English_verb_list_memlist,
1186         sizeof(char), 2048, (void**)&English_verb_list,
1187         "register of verbs");
1188
1189     initialise_memory_list(&English_verbs_given_memlist,
1190         sizeof(char), 80, (void**)&English_verbs_given,
1191         "verb words within a single definition");
1192 }
1193
1194 extern void verbs_free_arrays(void)
1195 {
1196     int ix;
1197     for (ix=0; ix<no_Inform_verbs; ix++)
1198     {
1199         my_free(&Inform_verbs[ix].l, "grammar lines for one verb");
1200     }
1201     deallocate_memory_list(&Inform_verbs_memlist);
1202     deallocate_memory_list(&grammar_lines_memlist);
1203     deallocate_memory_list(&actions_memlist);
1204     deallocate_memory_list(&grammar_token_routine_memlist);
1205     deallocate_memory_list(&adjectives_memlist);
1206     deallocate_memory_list(&adjective_sort_code_memlist);
1207     deallocate_memory_list(&English_verb_list_memlist);
1208     deallocate_memory_list(&English_verbs_given_memlist);
1209 }
1210
1211 /* ========================================================================= */