/* "verbs" : Manages actions and grammar tables; parses the directives */
/* Verb and Extend. */
/* */
-/* Copyright (c) Graham Nelson 1993 - 2018 */
-/* */
-/* This file is part of Inform. */
+/* 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 */
/* ------------------------------------------------------------------------- */
/* 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 */
/* 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: */
/* */
/* 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 */
-static int English_verb_list_size; /* Size of the list in bytes
- (redundant but convenient) */
+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<len; ix++) putchar(str[ix]);
+ printf("\n");
+}
+
+static void list_grammar_line_v2(int mark)
+{
+ int action, flags, actsym;
+ int ix, len;
+ char *str;
+
+ if (!glulx_mode) {
+ action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
+ flags = (action & 0x400);
+ action &= 0x3FF;
+ mark += 2;
+ }
+ else {
+ action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
+ mark += 2;
+ flags = grammar_lines[mark++];
+ }
+
+ printf(" *");
+ while (grammar_lines[mark] != 15) {
+ int toktype, tokdat, tokalt;
+ if (!glulx_mode) {
+ toktype = grammar_lines[mark] & 0x0F;
+ tokalt = (grammar_lines[mark] >> 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<len; ix++) putchar(str[ix]);
+ if (flags) printf(" (reversed)");
+ printf("\n");
+}
+
extern void list_verb_table(void)
-{ int i;
- for (i=0; i<no_Inform_verbs; i++)
- printf("Verb %2d has %d lines\n", i, Inform_verbs[i].lines);
+{
+ int verb, lx;
+ printf("Grammar table: %d verbs\n", no_Inform_verbs);
+ for (verb=0; verb<no_Inform_verbs; verb++) {
+ char *verbword = find_verb_by_number(verb);
+ printf("Verb '%s'\n", verbword);
+ for (lx=0; lx<Inform_verbs[verb].lines; lx++) {
+ int mark = Inform_verbs[verb].l[lx];
+ switch (grammar_version_number) {
+ case 1:
+ list_grammar_line_v1(mark);
+ break;
+ case 2:
+ list_grammar_line_v2(mark);
+ break;
+ }
+ }
+ }
}
/* ------------------------------------------------------------------------- */
static void new_action(char *b, int c)
{
/* Called whenever a new action (or fake action) is created (either
- by using make_action above, or the Fake_Action directive, or by
- the linker). At present just a hook for some tracing code. */
+ by using make_action above, or the Fake_Action directive).
+ At present just a hook for some tracing code. */
- if (printprops_switch)
- printf("Action '%s' is numbered %d\n",b,c);
+ if (printactions_switch)
+ printf("%s: Action '%s' is numbered %d\n", current_location_text(), b, c);
}
/* Note that fake actions are numbered from a high base point upwards;
real actions are numbered from 0 upward in GV2. */
extern void make_fake_action(void)
-{ int i;
- char action_sub[MAX_IDENTIFIER_LENGTH+4];
+{ char *action_sub;
+ int i;
debug_location_beginning beginning_debug_location =
get_token_location_beginning();
get_next_token();
if (token_type != SYMBOL_TT)
{ discard_token_location(beginning_debug_location);
- ebf_error("new fake action name", token_text);
+ ebf_curtoken_error("new fake action name");
panic_mode_error_recovery(); return;
}
- snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", token_text);
- i = symbol_index(action_sub, -1);
+ /* Enough space for "token__A". */
+ ensure_memory_list_available(&action_symname_memlist, strlen(token_text)+4);
+ action_sub = action_symname_memlist.data;
+ strcpy(action_sub, token_text);
+ strcat(action_sub, "__A");
+
+ /* Action symbols (including fake_actions) may collide with other kinds of symbols. So we don't check that. */
- if (!(sflags[i] & UNKNOWN_SFLAG))
+ i = symbol_index(action_sub, -1, NULL);
+
+ if (!(symbols[i].flags & UNKNOWN_SFLAG))
{ discard_token_location(beginning_debug_location);
- ebf_error("new fake action name", token_text);
+ /* The user didn't know they were defining FOO__A, but they were and it's a problem. */
+ ebf_symbol_error("new fake action name", action_sub, typename(symbols[i].type), symbols[i].line);
panic_mode_error_recovery(); return;
}
if (debugfile_switch)
{ debug_file_printf("<fake-action>");
debug_file_printf("<identifier>##%s</identifier>", token_text);
- debug_file_printf("<value>%d</value>", svals[i]);
+ debug_file_printf("<value>%d</value>", symbols[i].value);
get_next_token();
write_debug_locations
(get_token_location_end(beginning_debug_location));
/* 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;
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<no_actions; i++) action_byte_offset[i] = 0;
- else
for (i=0; i<no_actions; i++)
- { strcpy(action_name, (char *) symbs[action_symbol[i]]);
- action_name[strlen(action_name) - 3] = '\0'; /* remove "__A" */
+ {
+ /* The name looks like "action__A". We're going to convert that to
+ "actionSub". Allocate enough space for both. */
+ int namelen = strlen(symbols[actions[i].symbol].name);
+ char *action_sub, *action_name;
+ ensure_memory_list_available(&action_symname_memlist, 2*(namelen+1));
+ action_sub = action_symname_memlist.data;
+ action_name = (char *)action_symname_memlist.data + (namelen+1);
+
+ strcpy(action_name, symbols[actions[i].symbol].name);
+ action_name[namelen - 3] = '\0'; /* remove "__A" */
strcpy(action_sub, action_name);
strcat(action_sub, "Sub");
- j = symbol_index(action_sub, -1);
- if (sflags[j] & UNKNOWN_SFLAG)
+ j = symbol_index(action_sub, -1, NULL);
+ if (symbols[j].flags & UNKNOWN_SFLAG)
{
- error_named_at("No ...Sub action routine found for action:", action_name, slines[action_symbol[i]]);
+ error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
}
- else
- if (stypes[j] != ROUTINE_T)
+ else if (symbols[j].type != ROUTINE_T)
{
- error_named_at("No ...Sub action routine found for action:", action_name, slines[action_symbol[i]]);
- error_named_at("-- ...Sub symbol found, but not a routine:", action_sub, slines[j]);
+ ebf_symbol_error("action's ...Sub routine", action_sub, typename(symbols[j].type), symbols[j].line);
}
else
- { action_byte_offset[i] = svals[j];
- sflags[j] |= USED_SFLAG;
+ { actions[i].byte_offset = symbols[j].value;
+ symbols[j].flags |= USED_SFLAG;
}
}
}
This routine is used only in grammar version 1: the corresponding
table is left empty in GV2. */
+ uchar *new_sort_code;
int i;
- uchar new_sort_code[MAX_DICT_WORD_BYTES];
- if (no_adjectives >= 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<no_adjectives; i++)
if (compare_sorts(new_sort_code,
return(0xff-i);
adjectives[no_adjectives]
= dictionary_add(English_word,8,0,0xff-no_adjectives);
- copy_sorts(adjective_sort_code+no_adjectives*DICT_WORD_BYTES,
- new_sort_code);
return(0xff-no_adjectives++);
}
if (grammar_token_routine[l] == routine_address)
return l;
- grammar_token_routine[l] = routine_address;
+ ensure_memory_list_available(&grammar_token_routine_memlist, no_grammar_token_routines+1);
+
+ grammar_token_routine[no_grammar_token_routines] = routine_address;
return(no_grammar_token_routines++);
}
char *p;
p=English_verb_list;
- while (p < English_verb_list_top)
+ while (p < English_verb_list+English_verb_list_size)
{ if (strcmp(English_verb, p+3) == 0)
{ if (new_number)
{ p[1] = (*new_number)/256;
return(-1);
}
+static char *find_verb_by_number(int num)
+{
+ /* Find the English verb string with the given verb number. */
+ char *p;
+ p=English_verb_list;
+ while (p < English_verb_list+English_verb_list_size)
+ {
+ int val = ((uchar)p[1] << 8) | (uchar)p[2];
+ if (val == num) {
+ return p+3;
+ }
+ p=p+(uchar)p[0];
+ }
+ return "???";
+}
+
static void register_verb(char *English_verb, int number)
{
/* Registers a new English verb as referring to the given Inform-verb
number. (See comments above for format of the list.) */
+ char *top;
int entrysize;
if (find_or_renumber_verb(English_verb, NULL) != -1)
/* We set a hard limit of MAX_VERB_WORD_SIZE=120 because the
English_verb_list table stores length in a leading byte. (We could
- raise that to 250, really, but there's little point when
- MAX_DICT_WORD_SIZE is 40.) */
+ raise that to 250, really.) */
entrysize = strlen(English_verb)+4;
if (entrysize > 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)
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; verb++) {
+ Inform_verbs[verb].used = FALSE;
+ }
+
+ p=English_verb_list;
+ while (p < English_verb_list+English_verb_list_size)
+ {
+ verb = ((uchar)p[1] << 8) | (uchar)p[2];
+ if (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<no_Inform_verbs; verb++) {
+ if (!Inform_verbs[verb].used) {
+ warning_at("Verb declaration no longer has any verbs associated. Use \"Extend replace\" instead of \"Extend only\"?", Inform_verbs[verb].line);
+ }
+ }
+}
+
/* ------------------------------------------------------------------------- */
/* Grammar lines for Verb/Extend directives. */
/* ------------------------------------------------------------------------- */
+static void ensure_grammar_lines_available(int verbnum, int num)
+{
+ /* Note that the size field always starts positive. */
+ if (num > 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: * <token1> ... <token-n> -> <action>
}
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) {
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++;
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;
}
{ 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;
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();
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);
else { /* <attribute> or <general-parsing-routine> 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++;
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;
} while (TRUE);
+ ensure_memory_list_available(&grammar_lines_memlist, mark+1);
grammar_lines[mark++] = 15;
grammar_lines_top = mark;
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;
}
debug_file_printf("</table-entry>");
}
+ ensure_memory_list_available(&grammar_lines_memlist, mark+3);
if (!glulx_mode) {
if (reverse_action)
j = j + 0x400;
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;
}
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;
}
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<no_given; i++)
- { dictionary_add(English_verbs_given[i],
+ for (i=0, pos=0; i<no_given; i++) {
+ char *wd = English_verbs_given+pos;
+ dictionary_add(wd,
0x41 + ((meta_verb_flag)?0x02:0x00),
(glulx_mode)?(0xffff-Inform_verb):(0xff-Inform_verb), 0);
- register_verb(English_verbs_given[i], Inform_verb);
+ register_verb(wd, Inform_verb);
+ pos += (strlen(wd) + 1);
}
if (!verb_equals_form)
get_next_token();
if ((token_type == DIR_KEYWORD_TT) && (token_value == ONLY_DK))
- { l = -1;
- if (no_Inform_verbs == MAX_VERBS)
- memoryerror("MAX_VERBS", MAX_VERBS);
+ {
+ 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);
+ l = -1;
while (get_next_token(),
((token_type == DQ_TT) || (token_type == SQ_TT)))
{ Inform_verb = get_verb();
/* 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; k<l; k++)
+ Inform_verbs[no_Inform_verbs].l[k] = Inform_verbs[Inform_verb].l[k];
+ Inform_verbs[no_Inform_verbs].line = get_brief_location(&ErrorReport);
+ Inform_verbs[no_Inform_verbs].used = FALSE;
Inform_verb = no_Inform_verbs++;
}
else
extend_mode = EXTEND_LAST;
if (extend_mode==0)
- { ebf_error("'replace', 'last', 'first' or '*'", token_text);
+ { ebf_curtoken_error("'replace', 'last', 'first' or '*'");
extend_mode = EXTEND_LAST;
}
}
lines = 0;
if (extend_mode == EXTEND_LAST) lines=l;
do
- { if (extend_mode == EXTEND_FIRST)
+ {
+ if (extend_mode == EXTEND_FIRST) {
+ ensure_grammar_lines_available(Inform_verb, l+lines+1);
for (k=l; k>0; 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<l; k++)
+ {
+ ensure_grammar_lines_available(Inform_verb, l+lines+1);
+ Inform_verbs[Inform_verb].lines = l+lines-1;
+ for (k=0; k<l; k++) {
Inform_verbs[Inform_verb].l[k+lines-1]
= Inform_verbs[Inform_verb].l[k+lines];
+ }
}
else Inform_verbs[Inform_verb].lines = --lines;
English_verb_list_size = 0;
Inform_verbs = NULL;
- action_byte_offset = NULL;
+ actions = NULL;
+ grammar_lines = NULL;
grammar_token_routine = NULL;
adjectives = NULL;
adjective_sort_code = NULL;
English_verb_list = NULL;
+ English_verbs_given = NULL;
if (!glulx_mode)
grammar_version_number = 1;
extern void verbs_allocate_arrays(void)
{
- Inform_verbs = my_calloc(sizeof(verbt), MAX_VERBS, "verbs");
- grammar_lines = my_malloc(MAX_LINESPACE, "grammar lines");
- action_byte_offset = my_calloc(sizeof(int32), MAX_ACTIONS, "actions");
- action_symbol = my_calloc(sizeof(int32), MAX_ACTIONS,
- "action symbols");
- grammar_token_routine = my_calloc(sizeof(int32), MAX_ACTIONS,
- "grammar token routines");
- adjectives = my_calloc(sizeof(int32), MAX_ADJECTIVES,
- "adjectives");
- adjective_sort_code = my_calloc(DICT_WORD_BYTES, MAX_ADJECTIVES,
- "adjective sort codes");
-
- English_verb_list = my_malloc(MAX_VERBSPACE, "register of verbs");
- English_verb_list_top = English_verb_list;
+ initialise_memory_list(&Inform_verbs_memlist,
+ sizeof(verbt), 128, (void**)&Inform_verbs,
+ "verbs");
+
+ initialise_memory_list(&grammar_lines_memlist,
+ sizeof(uchar), 4000, (void**)&grammar_lines,
+ "grammar lines");
+
+ initialise_memory_list(&actions_memlist,
+ sizeof(actioninfo), 128, (void**)&actions,
+ "actions");
+
+ initialise_memory_list(&grammar_token_routine_memlist,
+ sizeof(int32), 50, (void**)&grammar_token_routine,
+ "grammar token routines");
+
+ initialise_memory_list(&adjectives_memlist,
+ sizeof(int32), 50, (void**)&adjectives,
+ "adjectives");
+ initialise_memory_list(&adjective_sort_code_memlist,
+ sizeof(uchar), 50*DICT_WORD_BYTES, (void**)&adjective_sort_code,
+ "adjective sort codes");
+
+ initialise_memory_list(&action_symname_memlist,
+ sizeof(uchar), 32, NULL,
+ "action temporary symbols");
+
+ initialise_memory_list(&English_verb_list_memlist,
+ sizeof(char), 2048, (void**)&English_verb_list,
+ "register of verbs");
+
+ initialise_memory_list(&English_verbs_given_memlist,
+ sizeof(char), 80, (void**)&English_verbs_given,
+ "verb words within a single definition");
}
extern void verbs_free_arrays(void)
{
- my_free(&Inform_verbs, "verbs");
- my_free(&grammar_lines, "grammar lines");
- my_free(&action_byte_offset, "actions");
- my_free(&action_symbol, "action symbols");
- my_free(&grammar_token_routine, "grammar token routines");
- my_free(&adjectives, "adjectives");
- my_free(&adjective_sort_code, "adjective sort codes");
- my_free(&English_verb_list, "register of verbs");
+ int ix;
+ for (ix=0; ix<no_Inform_verbs; ix++)
+ {
+ my_free(&Inform_verbs[ix].l, "grammar lines for one verb");
+ }
+ deallocate_memory_list(&Inform_verbs_memlist);
+ deallocate_memory_list(&grammar_lines_memlist);
+ deallocate_memory_list(&actions_memlist);
+ deallocate_memory_list(&grammar_token_routine_memlist);
+ deallocate_memory_list(&adjectives_memlist);
+ deallocate_memory_list(&adjective_sort_code_memlist);
+ deallocate_memory_list(&action_symname_memlist);
+ deallocate_memory_list(&English_verb_list_memlist);
+ deallocate_memory_list(&English_verbs_given_memlist);
}
/* ========================================================================= */