1 /* ------------------------------------------------------------------------- */
2 /* "verbs" : Manages actions and grammar tables; parses the directives */
5 /* Part of Inform 6.42 */
6 /* copyright (c) Graham Nelson 1993 - 2024 */
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. */
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. */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with Inform. If not, see https://gnu.org/licenses/ */
21 /* ------------------------------------------------------------------------- */
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 */
29 /* ------------------------------------------------------------------------- */
31 /* ------------------------------------------------------------------------- */
32 /* Array defined below: */
34 /* actioninfo actions[n] Symbol table index and byte offset */
35 /* of the ...Sub routine */
36 /* ------------------------------------------------------------------------- */
38 int no_actions, /* Number of actions made so far */
39 no_fake_actions; /* Number of fake actions made so far */
41 /* ------------------------------------------------------------------------- */
42 /* Adjectives. (The term "adjective" is traditional; they are mainly */
43 /* prepositions, such as "onto".) */
44 /* ------------------------------------------------------------------------- */
45 /* Arrays defined below: */
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 /* ------------------------------------------------------------------------- */
52 int no_adjectives; /* Number of adjectives made so far */
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: */
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 /* ------------------------------------------------------------------------- */
71 int no_Inform_verbs, /* Number of Inform-verbs made so far */
72 no_grammar_token_routines; /* Number of routines given in tokens */
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: */
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 /* ------------------------------------------------------------------------- */
85 static char *English_verb_list; /* Allocated to English_verb_list_size */
86 static memory_list English_verb_list_memlist;
88 static int English_verb_list_size; /* Size of the list in bytes */
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;
94 /* ------------------------------------------------------------------------- */
95 /* Arrays used by this file */
96 /* ------------------------------------------------------------------------- */
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;
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;
110 int32 *adjectives; /* Allocated to no_adjectives */
111 static memory_list adjectives_memlist;
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;
116 static memory_list action_symname_memlist; /* Used for temporary symbols */
118 /* ------------------------------------------------------------------------- */
119 /* Tracing for compiler maintenance */
120 /* ------------------------------------------------------------------------- */
122 static char *find_verb_by_number(int num);
124 static void list_grammar_line_v1(int mark)
130 /* There is no GV1 for Glulx. */
134 action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
138 while (grammar_lines[mark] != 15) {
139 uchar tok = grammar_lines[mark];
153 printf(" multiheld");
156 printf(" multiexcept");
159 printf(" multiinside");
171 if (tok >= 16 && tok < 48) {
172 printf(" noun=%d", tok-16);
174 else if (tok >= 48 && tok < 80) {
175 printf(" routine=%d", tok-48);
177 else if (tok >= 80 && tok < 128) {
178 printf(" scope=%d", tok-80);
180 else if (tok >= 128 && tok < 160) {
181 printf(" attr=%d", tok-128);
183 else if (tok >= 160) {
184 printf(" prep=%d", tok);
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]);
200 static void list_grammar_line_v2(int mark)
202 int action, flags, actsym;
207 action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
208 flags = (action & 0x400);
213 action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
215 flags = grammar_lines[mark++];
219 while (grammar_lines[mark] != 15) {
220 int toktype, tokdat, tokalt;
222 toktype = grammar_lines[mark] & 0x0F;
223 tokalt = (grammar_lines[mark] >> 4) & 0x03;
225 tokdat = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
229 toktype = grammar_lines[mark] & 0x0F;
230 tokalt = (grammar_lines[mark] >> 4) & 0x03;
232 tokdat = (grammar_lines[mark] << 24) | (grammar_lines[mark+1] << 16) | (grammar_lines[mark+2] << 8) | (grammar_lines[mark+3]);
236 if (tokalt == 3 || tokalt == 1)
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;
257 print_dict_word(tokdat);
261 printf(" noun=%d", tokdat);
264 printf(" attr=%d", tokdat);
267 printf(" scope=%d", tokdat);
270 printf(" routine=%d", tokdat);
273 printf(" ???%d:%d", toktype, tokdat);
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)");
286 extern void list_verb_table(void)
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) {
297 list_grammar_line_v1(mark);
300 list_grammar_line_v2(mark);
307 /* ------------------------------------------------------------------------- */
309 /* ------------------------------------------------------------------------- */
311 static void new_action(char *b, int c)
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. */
317 if (printactions_switch)
318 printf("%s: Action '%s' is numbered %d\n", current_location_text(), b, c);
321 /* Note that fake actions are numbered from a high base point upwards;
322 real actions are numbered from 0 upward in GV2. */
324 extern void make_fake_action(void)
327 debug_location_beginning beginning_debug_location =
328 get_token_location_beginning();
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;
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");
343 /* Action symbols (including fake_actions) may collide with other kinds of symbols. So we don't check that. */
345 i = symbol_index(action_sub, -1, NULL);
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;
354 assign_symbol(i, ((grammar_version_number==1)?256:4096)+no_fake_actions++,
357 new_action(token_text, i);
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);
364 write_debug_locations
365 (get_token_location_end(beginning_debug_location));
367 debug_file_printf("</fake-action>");
373 extern assembly_operand action_of_name(char *name)
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. */
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");
388 j = symbol_index(action_sub, -1, NULL);
390 if (symbols[j].type == FAKE_ACTION_T)
392 AO.value = symbols[j].value;
394 AO.type = LONG_CONSTANT_OT;
396 set_constant_ot(&AO);
397 symbols[j].flags |= USED_SFLAG;
401 if (symbols[j].flags & UNKNOWN_SFLAG)
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;
410 symbols[j].flags |= USED_SFLAG;
413 AO.value = symbols[j].value;
414 AO.marker = ACTION_MV;
416 AO.type = SHORT_CONSTANT_OT;
417 if (symbols[j].value >= 256) AO.type = LONG_CONSTANT_OT;
420 AO.type = CONSTANT_OT;
425 extern void find_the_actions(void)
428 for (i=0; i<no_actions; i++)
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);
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)
445 error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
447 else if (symbols[j].type != ROUTINE_T)
449 ebf_symbol_error("action's ...Sub routine", action_sub, typename(symbols[j].type), symbols[j].line);
452 { actions[i].byte_offset = symbols[j].value;
453 symbols[j].flags |= USED_SFLAG;
458 /* ------------------------------------------------------------------------- */
460 /* ------------------------------------------------------------------------- */
462 static int make_adjective(char *English_word)
464 /* Returns adjective number of the English word supplied, creating
465 a new adjective number if need be.
467 Note that (partly for historical reasons) adjectives are numbered
468 from 0xff downwards. (And partly to make them stand out as tokens.)
470 This routine is used only in grammar version 1: the corresponding
471 table is left empty in GV2. */
473 uchar *new_sort_code;
476 if (no_adjectives >= 255) {
477 error("Grammar version 1 cannot support more than 255 prepositions");
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");
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);
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)
497 adjectives[no_adjectives]
498 = dictionary_add(English_word,8,0,0xff-no_adjectives);
499 return(0xff-no_adjectives++);
502 /* ------------------------------------------------------------------------- */
503 /* Parsing routines. */
504 /* ------------------------------------------------------------------------- */
506 static int make_parsing_routine(int32 routine_address)
508 /* This routine is used only in grammar version 1: the corresponding
509 table is left empty in GV2. */
512 for (l=0; l<no_grammar_token_routines; l++)
513 if (grammar_token_routine[l] == routine_address)
516 ensure_memory_list_available(&grammar_token_routine_memlist, no_grammar_token_routines+1);
518 grammar_token_routine[no_grammar_token_routines] = routine_address;
519 return(no_grammar_token_routines++);
522 /* ------------------------------------------------------------------------- */
523 /* The English-verb list. */
524 /* ------------------------------------------------------------------------- */
526 static int find_or_renumber_verb(char *English_verb, int *new_number)
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
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) */
540 while (p < English_verb_list+English_verb_list_size)
541 { if (strcmp(English_verb, p+3) == 0)
543 { p[1] = (*new_number)/256;
544 p[2] = (*new_number)%256;
547 return(256*((uchar)p[1]))+((uchar)p[2]);
554 static char *find_verb_by_number(int num)
556 /* Find the English verb string with the given verb number. */
559 while (p < English_verb_list+English_verb_list_size)
561 int val = ((uchar)p[1] << 8) | (uchar)p[2];
570 static void register_verb(char *English_verb, int number)
572 /* Registers a new English verb as referring to the given Inform-verb
573 number. (See comments above for format of the list.) */
577 if (find_or_renumber_verb(English_verb, NULL) != -1)
578 { error_named("Two different verb definitions refer to", English_verb);
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;
595 strcpy(top+3, English_verb);
598 static int get_verb(void)
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. */
606 if ((token_type == DQ_TT) || (token_type == SQ_TT))
607 { j = find_or_renumber_verb(token_text, NULL);
609 error_named("There is no previous grammar for the verb",
614 ebf_curtoken_error("an English verb in quotes");
619 void locate_dead_grammar_lines()
621 /* Run through the grammar table and check whether each entry is
622 associated with a verb word. (Some might have been detached by
628 for (verb=0; verb<no_Inform_verbs; verb++) {
629 Inform_verbs[verb].used = FALSE;
633 while (p < English_verb_list+English_verb_list_size)
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);
640 Inform_verbs[verb].used = TRUE;
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);
652 /* ------------------------------------------------------------------------- */
653 /* Grammar lines for Verb/Extend directives. */
654 /* ------------------------------------------------------------------------- */
656 static void ensure_grammar_lines_available(int verbnum, int num)
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;
666 static int grammar_line(int verbnum, int line)
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
672 This stores the line position in Inform_verbs[verbnum].l[line].
673 (It does not increment Inform_verbs[verbnum].lines; the caller
676 Syntax: * <token1> ... <token-n> -> <action>
678 is compiled to a table in the form:
680 <action number : word>
681 <token 1> ... <token n> <ENDIT>
683 where <ENDIT> is the byte 15, and each <token> is 3 bytes long.
685 If grammar_version_number is 1, the token holds
689 and otherwise a GV2 token.
691 Return TRUE if grammar continues after the line, FALSE if the
692 directive comes to an end. */
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();
701 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
702 { discard_token_location(beginning_debug_location);
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();
712 mark = grammar_lines_top;
714 ensure_grammar_lines_available(verbnum, line+1);
715 Inform_verbs[verbnum].l[line] = mark;
725 ensure_memory_list_available(&grammar_lines_memlist, mark);
727 grammar_token = 0; last_was_slash = TRUE; slash_mode = FALSE;
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");
738 if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
739 { if (last_was_slash && (grammar_token>0))
740 ebf_curtoken_error("grammar token");
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");
749 ebf_curtoken_error("grammar token or '->'");
751 { last_was_slash = 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;
759 else last_was_slash = FALSE;
761 if ((token_type == DQ_TT) || (token_type == SQ_TT))
762 { if (grammar_version_number == 1)
763 bytecode = make_adjective(token_text);
766 wordcode = dictionary_add(token_text, 8, 0, 0);
769 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NOUN_DK))
771 if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
773 /* noun = <routine> */
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();
783 if (grammar_version_number == 1)
785 = 16 + make_parsing_routine(symbols[token_value].value);
788 wordcode = symbols[token_value].value;
790 symbols[token_value].flags |= USED_SFLAG;
794 if (grammar_version_number == 1) bytecode=0;
795 else { bytecode = 1; wordcode = 0; }
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))
829 /* scope = <routine> */
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();
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();
848 if (grammar_version_number == 1)
850 make_parsing_routine(symbols[token_value].value);
851 else { bytecode = 0x85; wordcode = symbols[token_value].value; }
852 symbols[token_value].flags |= USED_SFLAG;
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();
860 else { /* <attribute> or <general-parsing-routine> tokens */
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();
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; }
876 { if (grammar_version_number == 1)
878 make_parsing_routine(symbols[token_value].value);
879 else { bytecode = 0x86; wordcode = symbols[token_value].value; }
881 symbols[token_value].flags |= USED_SFLAG;
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)");
892 { if (bytecode != 0x42)
893 error("'/' can only be applied to prepositions");
896 ensure_memory_list_available(&grammar_lines_memlist, mark+5);
897 grammar_lines[mark++] = bytecode;
899 grammar_lines[mark++] = wordcode/256;
900 grammar_lines[mark++] = wordcode%256;
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);
912 ensure_memory_list_available(&grammar_lines_memlist, mark+1);
913 grammar_lines[mark++] = 15;
914 grammar_lines_top = mark;
916 dont_enter_into_symbol_table = TRUE;
918 dont_enter_into_symbol_table = FALSE;
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();
927 { assembly_operand AO = action_of_name(token_text);
929 if (j >= ((grammar_version_number==1)?256:4096))
930 error_named("This is a fake action, not a real one:", token_text);
933 reverse_action = FALSE;
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;
941 else put_token_back();
943 mark = Inform_verbs[verbnum].l[line];
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>");
959 ensure_memory_list_available(&grammar_lines_memlist, mark+3);
963 grammar_lines[mark++] = j/256;
964 grammar_lines[mark++] = j%256;
967 grammar_lines[mark++] = ((j >> 8) & 0xFF);
968 grammar_lines[mark++] = ((j) & 0xFF);
969 grammar_lines[mark++] = (reverse_action ? 1 : 0);
975 /* ------------------------------------------------------------------------- */
976 /* The Verb directive: */
978 /* Verb [meta] "word-1" ... "word-n" | = "existing-English-verb" */
979 /* | <grammar-line-1> ... <g-line-n> */
981 /* ------------------------------------------------------------------------- */
983 extern void make_verb(void)
985 /* Parse an entire Verb ... directive. */
987 int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
989 int no_given = 0, verbs_given_pos = 0;
992 directive_keywords.enabled = TRUE;
996 if ((token_type == DIR_KEYWORD_TT) && (token_value == META_DK))
997 { meta_verb_flag = TRUE;
1001 while ((token_type == DQ_TT) || (token_type == SQ_TT))
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;
1012 { ebf_curtoken_error("English verb in quotes");
1013 panic_mode_error_recovery(); return;
1016 if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
1017 { verb_equals_form = TRUE;
1019 Inform_verb = get_verb();
1020 if (Inform_verb == -1) return;
1022 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1023 ebf_curtoken_error("';' after English verb");
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;
1031 if (no_Inform_verbs >= 65535) {
1032 error("Inform is limited to 65535 verbs.");
1033 panic_mode_error_recovery(); return;
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;
1044 for (i=0, pos=0; i<no_given; i++) {
1045 char *wd = English_verbs_given+pos;
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);
1053 if (!verb_equals_form)
1056 while (grammar_line(no_Inform_verbs, lines++)) ;
1057 Inform_verbs[no_Inform_verbs++].lines = --lines;
1060 directive_keywords.enabled = FALSE;
1063 /* ------------------------------------------------------------------------- */
1064 /* The Extend directive: */
1066 /* Extend | only "verb-1" ... "verb-n" | <grammar-lines> */
1067 /* | "verb" | "replace" */
1071 /* ------------------------------------------------------------------------- */
1073 #define EXTEND_REPLACE 1
1074 #define EXTEND_FIRST 2
1075 #define EXTEND_LAST 3
1077 extern void extend_verb(void)
1079 /* Parse an entire Extend ... directive. */
1081 int Inform_verb = -1, k, l, lines, extend_mode;
1083 directive_keywords.enabled = TRUE;
1084 directives.enabled = FALSE;
1087 if ((token_type == DIR_KEYWORD_TT) && (token_value == ONLY_DK))
1089 if (!glulx_mode && no_Inform_verbs >= 255) {
1090 error("Z-code is limited to 255 verbs.");
1091 panic_mode_error_recovery(); return;
1093 if (no_Inform_verbs >= 65535) {
1094 error("Inform is limited to 65535 verbs.");
1095 panic_mode_error_recovery(); return;
1097 ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+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);
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:",
1114 /* Copy the old Inform-verb into a new one which the list of
1115 English-verbs given have had their dictionary entries modified
1117 /* (We are copying entry Inform_verb to no_Inform_verbs here.) */
1119 l = Inform_verbs[Inform_verb].lines; /* number of lines to copy */
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");
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++;
1131 { Inform_verb = get_verb();
1132 if (Inform_verb == -1) return;
1136 /* Inform_verb now contains the number of the Inform-verb to extend... */
1138 extend_mode = EXTEND_LAST;
1139 if ((token_type == SEP_TT) && (token_value == TIMES_SEP))
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;
1151 { ebf_curtoken_error("'replace', 'last', 'first' or '*'");
1152 extend_mode = EXTEND_LAST;
1156 l = Inform_verbs[Inform_verb].lines;
1158 if (extend_mode == EXTEND_LAST) lines=l;
1161 if (extend_mode == EXTEND_FIRST) {
1162 ensure_grammar_lines_available(Inform_verb, l+lines+1);
1164 Inform_verbs[Inform_verb].l[k+lines]
1165 = Inform_verbs[Inform_verb].l[k-1+lines];
1167 } while (grammar_line(Inform_verb, lines++));
1169 if (extend_mode == EXTEND_FIRST)
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];
1178 else Inform_verbs[Inform_verb].lines = --lines;
1180 directive_keywords.enabled = FALSE;
1181 directives.enabled = TRUE;
1184 /* ========================================================================= */
1185 /* Data structure management routines */
1186 /* ------------------------------------------------------------------------- */
1188 extern void init_verbs_vars(void)
1190 no_fake_actions = 0;
1192 no_grammar_lines = 0;
1193 no_grammar_tokens = 0;
1194 English_verb_list_size = 0;
1196 Inform_verbs = NULL;
1198 grammar_lines = NULL;
1199 grammar_token_routine = NULL;
1201 adjective_sort_code = NULL;
1202 English_verb_list = NULL;
1203 English_verbs_given = NULL;
1206 grammar_version_number = 1;
1208 grammar_version_number = 2;
1211 extern void verbs_begin_pass(void)
1213 no_Inform_verbs=0; no_adjectives=0;
1214 no_grammar_token_routines=0;
1218 grammar_lines_top = 0;
1221 extern void verbs_allocate_arrays(void)
1223 initialise_memory_list(&Inform_verbs_memlist,
1224 sizeof(verbt), 128, (void**)&Inform_verbs,
1227 initialise_memory_list(&grammar_lines_memlist,
1228 sizeof(uchar), 4000, (void**)&grammar_lines,
1231 initialise_memory_list(&actions_memlist,
1232 sizeof(actioninfo), 128, (void**)&actions,
1235 initialise_memory_list(&grammar_token_routine_memlist,
1236 sizeof(int32), 50, (void**)&grammar_token_routine,
1237 "grammar token routines");
1239 initialise_memory_list(&adjectives_memlist,
1240 sizeof(int32), 50, (void**)&adjectives,
1242 initialise_memory_list(&adjective_sort_code_memlist,
1243 sizeof(uchar), 50*DICT_WORD_BYTES, (void**)&adjective_sort_code,
1244 "adjective sort codes");
1246 initialise_memory_list(&action_symname_memlist,
1247 sizeof(uchar), 32, NULL,
1248 "action temporary symbols");
1250 initialise_memory_list(&English_verb_list_memlist,
1251 sizeof(char), 2048, (void**)&English_verb_list,
1252 "register of verbs");
1254 initialise_memory_list(&English_verbs_given_memlist,
1255 sizeof(char), 80, (void**)&English_verbs_given,
1256 "verb words within a single definition");
1259 extern void verbs_free_arrays(void)
1262 for (ix=0; ix<no_Inform_verbs; ix++)
1264 my_free(&Inform_verbs[ix].l, "grammar lines for one verb");
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);
1277 /* ========================================================================= */