X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=src%2Fverbs.c;h=de35f3039dd6ceefebc483d94a5e59b434da9536;hb=HEAD;hp=2caa67cb4d4e2998b042299c0a50d3c100ffdcda;hpb=c881aa3386c00d7021ffabf2f66275d6c110c1c1;p=inform.git diff --git a/src/verbs.c b/src/verbs.c index 2caa67c..de35f30 100644 --- a/src/verbs.c +++ b/src/verbs.c @@ -2,8 +2,8 @@ /* "verbs" : Manages actions and grammar tables; parses the directives */ /* Verb and Extend. */ /* */ -/* Part of Inform 6.35 */ -/* copyright (c) Graham Nelson 1993 - 2021 */ +/* Part of Inform 6.42 */ +/* copyright (c) Graham Nelson 1993 - 2024 */ /* */ /* Inform is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -31,13 +31,8 @@ int32 grammar_version_symbol; /* Index of "Grammar__Version" /* ------------------------------------------------------------------------- */ /* Array defined below: */ /* */ -/* int32 action_byte_offset[n] The (byte) offset in the Z-machine */ -/* code area of the ...Sub routine */ -/* for action n. (NB: This is left */ -/* blank until the end of the */ -/* compilation pass.) */ -/* int32 action_symbol[n] The symbol table index of the n-th */ -/* action's name. */ +/* actioninfo actions[n] Symbol table index and byte offset */ +/* of the ...Sub routine */ /* ------------------------------------------------------------------------- */ int no_actions, /* Number of actions made so far */ @@ -61,6 +56,8 @@ int no_adjectives; /* Number of adjectives made so far */ /* for example the English verbs "take" and "drop" both normally */ /* correspond in a game's dictionary to the same Inform verb. An */ /* Inform verb is essentially a list of grammar lines. */ +/* (Calling them "English verbs" is of course out of date. Read */ +/* this as jargon for "dict words which are verbs". */ /* ------------------------------------------------------------------------- */ /* Arrays defined below: */ /* */ @@ -81,39 +78,230 @@ int no_Inform_verbs, /* Number of Inform-verbs made so far */ /* The format of this list is a sequence of variable-length records: */ /* */ /* Byte offset to start of next record (1 byte) */ -/* Inform verb number this word corresponds to (1 byte) */ +/* Inform verb number this word corresponds to (2 bytes) */ /* The English verb-word (reduced to lower case), null-terminated */ /* ------------------------------------------------------------------------- */ -static char *English_verb_list, /* First byte of first record */ - *English_verb_list_top; /* Next byte free for new record */ +static char *English_verb_list; /* Allocated to English_verb_list_size */ +static memory_list English_verb_list_memlist; -static int English_verb_list_size; /* Size of the list in bytes - (redundant but convenient) */ +static int English_verb_list_size; /* Size of the list in bytes */ + +static char *English_verbs_given; /* Allocated to verbs_given_pos + (Used only within make_verb()) */ +static memory_list English_verbs_given_memlist; /* ------------------------------------------------------------------------- */ /* Arrays used by this file */ /* ------------------------------------------------------------------------- */ - verbt *Inform_verbs; - uchar *grammar_lines; + verbt *Inform_verbs; /* Allocated up to no_Inform_verbs */ + static memory_list Inform_verbs_memlist; + uchar *grammar_lines; /* Allocated to grammar_lines_top */ + static memory_list grammar_lines_memlist; int32 grammar_lines_top; int no_grammar_lines, no_grammar_tokens; - int32 *action_byte_offset, - *action_symbol, - *grammar_token_routine, - *adjectives; - static uchar *adjective_sort_code; + actioninfo *actions; /* Allocated to no_actions */ + memory_list actions_memlist; + int32 *grammar_token_routine; /* Allocated to no_grammar_token_routines */ + static memory_list grammar_token_routine_memlist; + + int32 *adjectives; /* Allocated to no_adjectives */ + static memory_list adjectives_memlist; + + 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 */ + static memory_list adjective_sort_code_memlist; + + static memory_list action_symname_memlist; /* Used for temporary symbols */ /* ------------------------------------------------------------------------- */ /* Tracing for compiler maintenance */ /* ------------------------------------------------------------------------- */ +static char *find_verb_by_number(int num); + +static void list_grammar_line_v1(int mark) +{ + int action, actsym; + int ix, len; + char *str; + + /* There is no GV1 for Glulx. */ + if (glulx_mode) + return; + + action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]); + mark += 2; + + printf(" *"); + while (grammar_lines[mark] != 15) { + uchar tok = grammar_lines[mark]; + mark += 3; + + switch (tok) { + case 0: + printf(" noun"); + break; + case 1: + printf(" held"); + break; + case 2: + printf(" multi"); + break; + case 3: + printf(" multiheld"); + break; + case 4: + printf(" multiexcept"); + break; + case 5: + printf(" multiinside"); + break; + case 6: + printf(" creature"); + break; + case 7: + printf(" special"); + break; + case 8: + printf(" number"); + break; + default: + if (tok >= 16 && tok < 48) { + printf(" noun=%d", tok-16); + } + else if (tok >= 48 && tok < 80) { + printf(" routine=%d", tok-48); + } + else if (tok >= 80 && tok < 128) { + printf(" scope=%d", tok-80); + } + else if (tok >= 128 && tok < 160) { + printf(" attr=%d", tok-128); + } + else if (tok >= 160) { + printf(" prep=%d", tok); + } + else { + printf(" ???"); + } + } + } + + printf(" -> "); + actsym = actions[action].symbol; + str = (symbols[actsym].name); + len = strlen(str) - 3; /* remove "__A" */ + for (ix=0; ix> 4) & 0x03; + mark += 1; + tokdat = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]); + mark += 2; + } + else { + toktype = grammar_lines[mark] & 0x0F; + tokalt = (grammar_lines[mark] >> 4) & 0x03; + mark += 1; + tokdat = (grammar_lines[mark] << 24) | (grammar_lines[mark+1] << 16) | (grammar_lines[mark+2] << 8) | (grammar_lines[mark+3]); + mark += 4; + } + + if (tokalt == 3 || tokalt == 1) + printf(" /"); + + switch (toktype) { + case 1: + switch (tokdat) { + case 0: printf(" noun"); break; + case 1: printf(" held"); break; + case 2: printf(" multi"); break; + case 3: printf(" multiheld"); break; + case 4: printf(" multiexcept"); break; + case 5: printf(" multiinside"); break; + case 6: printf(" creature"); break; + case 7: printf(" special"); break; + case 8: printf(" number"); break; + case 9: printf(" topic"); break; + default: printf(" ???"); break; + } + break; + case 2: + printf(" '"); + print_dict_word(tokdat); + printf("'"); + break; + case 3: + printf(" noun=%d", tokdat); + break; + case 4: + printf(" attr=%d", tokdat); + break; + case 5: + printf(" scope=%d", tokdat); + break; + case 6: + printf(" routine=%d", tokdat); + break; + default: + printf(" ???%d:%d", toktype, tokdat); + break; + } + } + printf(" -> "); + actsym = actions[action].symbol; + str = (symbols[actsym].name); + len = strlen(str) - 3; /* remove "__A" */ + for (ix=0; ix"); debug_file_printf("##%s", token_text); - debug_file_printf("%d", svals[i]); + debug_file_printf("%d", symbols[i].value); get_next_token(); write_debug_locations (get_token_location_end(beginning_debug_location)); @@ -181,40 +375,46 @@ extern assembly_operand action_of_name(char *name) /* Returns the action number of the given name, creating it as a new action name if it isn't already known as such. */ - char action_sub[MAX_IDENTIFIER_LENGTH+4]; + char *action_sub; int j; assembly_operand AO; - snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", name); - j = symbol_index(action_sub, -1); + /* Enough space for "name__A". */ + ensure_memory_list_available(&action_symname_memlist, strlen(name)+4); + action_sub = action_symname_memlist.data; + strcpy(action_sub, name); + strcat(action_sub, "__A"); + + j = symbol_index(action_sub, -1, NULL); - if (stypes[j] == FAKE_ACTION_T) + if (symbols[j].type == FAKE_ACTION_T) { INITAO(&AO); - AO.value = svals[j]; + AO.value = symbols[j].value; if (!glulx_mode) AO.type = LONG_CONSTANT_OT; else set_constant_ot(&AO); - sflags[j] |= USED_SFLAG; + symbols[j].flags |= USED_SFLAG; return AO; } - if (sflags[j] & UNKNOWN_SFLAG) + if (symbols[j].flags & UNKNOWN_SFLAG) { - if (no_actions>=MAX_ACTIONS) memoryerror("MAX_ACTIONS",MAX_ACTIONS); + ensure_memory_list_available(&actions_memlist, no_actions+1); new_action(name, no_actions); - action_symbol[no_actions] = j; + actions[no_actions].symbol = j; + actions[no_actions].byte_offset = 0; /* fill in later */ assign_symbol(j, no_actions++, CONSTANT_T); - sflags[j] |= ACTION_SFLAG; + symbols[j].flags |= ACTION_SFLAG; } - sflags[j] |= USED_SFLAG; + symbols[j].flags |= USED_SFLAG; INITAO(&AO); - AO.value = svals[j]; + AO.value = symbols[j].value; AO.marker = ACTION_MV; if (!glulx_mode) { - AO.type = (module_switch)?LONG_CONSTANT_OT:SHORT_CONSTANT_OT; - if (svals[j] >= 256) AO.type = LONG_CONSTANT_OT; + AO.type = SHORT_CONSTANT_OT; + if (symbols[j].value >= 256) AO.type = LONG_CONSTANT_OT; } else { AO.type = CONSTANT_OT; @@ -224,31 +424,33 @@ extern assembly_operand action_of_name(char *name) extern void find_the_actions(void) { int i; int32 j; - char action_name[MAX_IDENTIFIER_LENGTH+4]; - char action_sub[MAX_IDENTIFIER_LENGTH+4]; - if (module_switch) - for (i=0; i= MAX_ADJECTIVES) - memoryerror("MAX_ADJECTIVES", MAX_ADJECTIVES); + if (no_adjectives >= 255) { + error("Grammar version 1 cannot support more than 255 prepositions"); + return 0; + } + if (ZCODE_LESS_DICT_DATA && !glulx_mode) { + /* We need to use #dict_par3 for the preposition number. */ + error("Grammar version 1 cannot be used with ZCODE_LESS_DICT_DATA"); + return 0; + } + /* Allocate the extra space even though we might not need it. We'll use + the prospective new adjective_sort_code slot as a workspace. */ + ensure_memory_list_available(&adjectives_memlist, no_adjectives+1); + ensure_memory_list_available(&adjective_sort_code_memlist, (no_adjectives+1) * DICT_WORD_BYTES); + + new_sort_code = adjective_sort_code+no_adjectives*DICT_WORD_BYTES; dictionary_prepare(English_word, new_sort_code); for (i=0; i MAX_VERB_WORD_SIZE+4) - error_numbered("Verb word is too long -- max length is", MAX_VERB_WORD_SIZE); + error_fmt("Verb word is too long -- max length is %d", MAX_VERB_WORD_SIZE); + ensure_memory_list_available(&English_verb_list_memlist, English_verb_list_size + entrysize); + top = English_verb_list + English_verb_list_size; English_verb_list_size += entrysize; - if (English_verb_list_size >= MAX_VERBSPACE) - memoryerror("MAX_VERBSPACE", MAX_VERBSPACE); - - English_verb_list_top[0] = entrysize; - English_verb_list_top[1] = number/256; - English_verb_list_top[2] = number%256; - strcpy(English_verb_list_top+3, English_verb); - English_verb_list_top += entrysize; + + top[0] = entrysize; + top[1] = number/256; + top[2] = number%256; + strcpy(top+3, English_verb); } static int get_verb(void) @@ -381,18 +611,67 @@ static int get_verb(void) return j; } - ebf_error("an English verb in quotes", token_text); + ebf_curtoken_error("an English verb in quotes"); return -1; } +void locate_dead_grammar_lines() +{ + /* Run through the grammar table and check whether each entry is + associated with a verb word. (Some might have been detached by + "Extend only".) + */ + int verb; + char *p; + + for (verb=0; verb= no_Inform_verbs) { + error_named("An entry in the English verb list had an invalid verb number", p+3); + } + else { + Inform_verbs[verb].used = TRUE; + } + p=p+(uchar)p[0]; + } + + for (verb=0; verb Inform_verbs[verbnum].size) { + int newsize = 2*num+4; + my_realloc(&Inform_verbs[verbnum].l, sizeof(int) * Inform_verbs[verbnum].size, sizeof(int) * newsize, "grammar lines for one verb"); + Inform_verbs[verbnum].size = newsize; + } +} + static int grammar_line(int verbnum, int line) { - /* Parse a grammar line, to be written into grammar_lines[mark] onward. + /* Parse a grammar line, to be written into grammar_lines[] starting + at grammar_lines_top. grammar_lines_top is left at the end + of the new line. + + This stores the line position in Inform_verbs[verbnum].l[line]. + (It does not increment Inform_verbs[verbnum].lines; the caller + must do that.) Syntax: * ... -> @@ -425,37 +704,14 @@ static int grammar_line(int verbnum, int line) } if (!((token_type == SEP_TT) && (token_value == TIMES_SEP))) { discard_token_location(beginning_debug_location); - ebf_error("'*' divider", token_text); + ebf_curtoken_error("'*' divider"); panic_mode_error_recovery(); return FALSE; } - /* Have we run out of lines or token space? */ - - if (line >= MAX_LINES_PER_VERB) - { discard_token_location(beginning_debug_location); - error("Too many lines of grammar for verb. This maximum is built \ -into Inform, so suggest rewriting grammar using general parsing routines"); - return(FALSE); - } - - /* Internally, a line can be up to 3*32 + 1 + 2 = 99 bytes long */ - /* In Glulx, that's 5*32 + 4 = 164 bytes */ - mark = grammar_lines_top; - if (!glulx_mode) { - if (mark + 100 >= MAX_LINESPACE) - { discard_token_location(beginning_debug_location); - memoryerror("MAX_LINESPACE", MAX_LINESPACE); - } - } - else { - if (mark + 165 >= MAX_LINESPACE) - { discard_token_location(beginning_debug_location); - memoryerror("MAX_LINESPACE", MAX_LINESPACE); - } - } + ensure_grammar_lines_available(verbnum, line+1); Inform_verbs[verbnum].l[line] = mark; if (!glulx_mode) { @@ -466,6 +722,7 @@ into Inform, so suggest rewriting grammar using general parsing routines"); mark = mark + 3; TOKEN_SIZE = 5; } + ensure_memory_list_available(&grammar_lines_memlist, mark); grammar_token = 0; last_was_slash = TRUE; slash_mode = FALSE; no_grammar_lines++; @@ -475,12 +732,12 @@ into Inform, so suggest rewriting grammar using general parsing routines"); bytecode = 0; wordcode = 0; if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) { discard_token_location(beginning_debug_location); - ebf_error("'->' clause", token_text); + ebf_curtoken_error("'->' clause"); return FALSE; } if ((token_type == SEP_TT) && (token_value == ARROW_SEP)) { if (last_was_slash && (grammar_token>0)) - ebf_error("grammar token", token_text); + ebf_curtoken_error("grammar token"); break; } @@ -489,7 +746,7 @@ into Inform, so suggest rewriting grammar using general parsing routines"); { if (grammar_version_number == 1) error("'/' can only be used with Library 6/3 or later"); if (last_was_slash) - ebf_error("grammar token or '->'", token_text); + ebf_curtoken_error("grammar token or '->'"); else { last_was_slash = TRUE; slash_mode = TRUE; @@ -517,20 +774,20 @@ into Inform, so suggest rewriting grammar using general parsing routines"); get_next_token(); if ((token_type != SYMBOL_TT) - || (stypes[token_value] != ROUTINE_T)) + || (symbols[token_value].type != ROUTINE_T)) { discard_token_location(beginning_debug_location); - ebf_error("routine name after 'noun='", token_text); + ebf_curtoken_error("routine name after 'noun='"); panic_mode_error_recovery(); return FALSE; } if (grammar_version_number == 1) bytecode - = 16 + make_parsing_routine(svals[token_value]); + = 16 + make_parsing_routine(symbols[token_value].value); else { bytecode = 0x83; - wordcode = svals[token_value]; + wordcode = symbols[token_value].value; } - sflags[token_value] |= USED_SFLAG; + symbols[token_value].flags |= USED_SFLAG; } else { put_token_back(); @@ -574,25 +831,25 @@ are using Library 6/3 or later"); get_next_token(); if (!((token_type==SEP_TT)&&(token_value==SETEQUALS_SEP))) { discard_token_location(beginning_debug_location); - ebf_error("'=' after 'scope'", token_text); + ebf_curtoken_error("'=' after 'scope'"); panic_mode_error_recovery(); return FALSE; } get_next_token(); if ((token_type != SYMBOL_TT) - || (stypes[token_value] != ROUTINE_T)) + || (symbols[token_value].type != ROUTINE_T)) { discard_token_location(beginning_debug_location); - ebf_error("routine name after 'scope='", token_text); + ebf_curtoken_error("routine name after 'scope='"); panic_mode_error_recovery(); return FALSE; } if (grammar_version_number == 1) bytecode = 80 + - make_parsing_routine(svals[token_value]); - else { bytecode = 0x85; wordcode = svals[token_value]; } - sflags[token_value] |= USED_SFLAG; + make_parsing_routine(symbols[token_value].value); + else { bytecode = 0x85; wordcode = symbols[token_value].value; } + symbols[token_value].flags |= USED_SFLAG; } else if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)) { discard_token_location(beginning_debug_location); @@ -603,25 +860,25 @@ are using Library 6/3 or later"); else { /* or tokens */ if ((token_type != SYMBOL_TT) - || ((stypes[token_value] != ATTRIBUTE_T) - && (stypes[token_value] != ROUTINE_T))) + || ((symbols[token_value].type != ATTRIBUTE_T) + && (symbols[token_value].type != ROUTINE_T))) { discard_token_location(beginning_debug_location); error_named("No such grammar token as", token_text); panic_mode_error_recovery(); return FALSE; } - if (stypes[token_value]==ATTRIBUTE_T) + if (symbols[token_value].type==ATTRIBUTE_T) { if (grammar_version_number == 1) - bytecode = 128 + svals[token_value]; - else { bytecode = 4; wordcode = svals[token_value]; } + bytecode = 128 + symbols[token_value].value; + else { bytecode = 4; wordcode = symbols[token_value].value; } } else { if (grammar_version_number == 1) bytecode = 48 + - make_parsing_routine(svals[token_value]); - else { bytecode = 0x86; wordcode = svals[token_value]; } + make_parsing_routine(symbols[token_value].value); + else { bytecode = 0x86; wordcode = symbols[token_value].value; } } - sflags[token_value] |= USED_SFLAG; + symbols[token_value].flags |= USED_SFLAG; } grammar_token++; no_grammar_tokens++; @@ -636,6 +893,7 @@ tokens in any line (unless you're compiling with library 6/3 or later)"); error("'/' can only be applied to prepositions"); bytecode |= 0x10; } + ensure_memory_list_available(&grammar_lines_memlist, mark+5); grammar_lines[mark++] = bytecode; if (!glulx_mode) { grammar_lines[mark++] = wordcode/256; @@ -651,6 +909,7 @@ tokens in any line (unless you're compiling with library 6/3 or later)"); } while (TRUE); + ensure_memory_list_available(&grammar_lines_memlist, mark+1); grammar_lines[mark++] = 15; grammar_lines_top = mark; @@ -658,9 +917,9 @@ tokens in any line (unless you're compiling with library 6/3 or later)"); get_next_token(); dont_enter_into_symbol_table = FALSE; - if (token_type != DQ_TT) + if (token_type != UQ_TT) { discard_token_location(beginning_debug_location); - ebf_error("name of new or existing action", token_text); + ebf_curtoken_error("name of new or existing action"); panic_mode_error_recovery(); return FALSE; } @@ -697,6 +956,7 @@ Library 6/3 or later"); debug_file_printf(""); } + ensure_memory_list_available(&grammar_lines_memlist, mark+3); if (!glulx_mode) { if (reverse_action) j = j + 0x400; @@ -726,7 +986,8 @@ extern void make_verb(void) int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE; - char *English_verbs_given[32]; int no_given = 0, i; + int no_given = 0, verbs_given_pos = 0; + int i, pos; directive_keywords.enabled = TRUE; @@ -738,12 +999,17 @@ extern void make_verb(void) } while ((token_type == DQ_TT) || (token_type == SQ_TT)) - { English_verbs_given[no_given++] = token_text; + { + int len = strlen(token_text) + 1; + ensure_memory_list_available(&English_verbs_given_memlist, verbs_given_pos + len); + strcpy(English_verbs_given+verbs_given_pos, token_text); + verbs_given_pos += len; + no_given++; get_next_token(); } if (no_given == 0) - { ebf_error("English verb in quotes", token_text); + { ebf_curtoken_error("English verb in quotes"); panic_mode_error_recovery(); return; } @@ -754,19 +1020,34 @@ extern void make_verb(void) if (Inform_verb == -1) return; get_next_token(); if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) - ebf_error("';' after English verb", token_text); + ebf_curtoken_error("';' after English verb"); } else - { Inform_verb = no_Inform_verbs; - if (no_Inform_verbs == MAX_VERBS) - memoryerror("MAX_VERBS",MAX_VERBS); + { verb_equals_form = FALSE; + if (!glulx_mode && no_Inform_verbs >= 255) { + error("Z-code is limited to 255 verbs."); + panic_mode_error_recovery(); return; + } + if (no_Inform_verbs >= 65535) { + error("Inform is limited to 65535 verbs."); + panic_mode_error_recovery(); return; + } + ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1); + Inform_verb = no_Inform_verbs; + Inform_verbs[no_Inform_verbs].lines = 0; + Inform_verbs[no_Inform_verbs].size = 4; + Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb"); + Inform_verbs[no_Inform_verbs].line = get_brief_location(&ErrorReport); + Inform_verbs[no_Inform_verbs].used = FALSE; } - for (i=0; i= 255) { + error("Z-code is limited to 255 verbs."); + panic_mode_error_recovery(); return; + } + if (no_Inform_verbs >= 65535) { + error("Inform is limited to 65535 verbs."); + panic_mode_error_recovery(); return; + } + ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1); + l = -1; while (get_next_token(), ((token_type == DQ_TT) || (token_type == SQ_TT))) { Inform_verb = get_verb(); @@ -825,8 +1114,17 @@ extern void extend_verb(void) /* Copy the old Inform-verb into a new one which the list of English-verbs given have had their dictionary entries modified to point to */ + /* (We are copying entry Inform_verb to no_Inform_verbs here.) */ - Inform_verbs[no_Inform_verbs] = Inform_verbs[Inform_verb]; + l = Inform_verbs[Inform_verb].lines; /* number of lines to copy */ + + Inform_verbs[no_Inform_verbs].lines = l; + Inform_verbs[no_Inform_verbs].size = l+4; + Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb"); + for (k=0; k0; k--) Inform_verbs[Inform_verb].l[k+lines] = Inform_verbs[Inform_verb].l[k-1+lines]; + } } while (grammar_line(Inform_verb, lines++)); if (extend_mode == EXTEND_FIRST) - { Inform_verbs[Inform_verb].lines = l+lines-1; - for (k=0; k