Update to commit a469d404a7dc4e87e18f367eb4d8e05fc32d20a7
[inform.git] / src / verbs.c
index 962b32f847a3e9a46962745549da8488547e0ece..31b42bb2ee999a5c92087c6c2c840f7e5ea9aa64 100644 (file)
@@ -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.40                                                     */
+/*   copyright (c) Graham Nelson 1993 - 2022                                 */
 /*                                                                           */
 /* 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      */
@@ -83,42 +78,228 @@ 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          */
 
-/* Maximum synonyms in a single Verb/Extend directive */
-#define MAX_VERB_SYNONYMS (32)
+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 */
+  static memory_list adjective_sort_code_memlist;
 
 /* ------------------------------------------------------------------------- */
 /*   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;
+            }
+        }
+    }
 }
 
 /* ------------------------------------------------------------------------- */
@@ -131,7 +312,7 @@ static void new_action(char *b, int c)
         by using make_action above, or the Fake_Action directive, or by
         the linker).  At present just a hook for some tracing code.          */
 
-    if (printprops_switch)
+    if (printactions_switch)
         printf("Action '%s' is numbered %d\n",b,c);
 }
 
@@ -155,10 +336,10 @@ extern void make_fake_action(void)
     snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", token_text);
     i = symbol_index(action_sub, -1);
 
-    if (!(sflags[i] & UNKNOWN_SFLAG))
+    if (!(symbols[i].flags & UNKNOWN_SFLAG))
     {   discard_token_location(beginning_debug_location);
         /* 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(stypes[i]), slines[i]);
+        ebf_symbol_error("new fake action name", action_sub, typename(symbols[i].type), symbols[i].line);
         panic_mode_error_recovery(); return;
     }
 
@@ -170,7 +351,7 @@ extern void make_fake_action(void)
     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));
@@ -193,33 +374,34 @@ extern assembly_operand action_of_name(char *name)
     snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", name);
     j = symbol_index(action_sub, -1);
 
-    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;
+      if (symbols[j].value >= 256) AO.type = LONG_CONSTANT_OT;
     }
     else {
       AO.type = CONSTANT_OT;
@@ -233,27 +415,27 @@ extern void find_the_actions(void)
     char action_sub[MAX_IDENTIFIER_LENGTH+4];
 
     if (module_switch)
-        for (i=0; i<no_actions; i++) action_byte_offset[i] = 0;
+        for (i=0; i<no_actions; i++) actions[i].byte_offset = 0;
     else
     for (i=0; i<no_actions; i++)
-    {   strcpy(action_name, (char *) symbs[action_symbol[i]]);
+    {   strcpy(action_name, symbols[actions[i].symbol].name);
         action_name[strlen(action_name) - 3] = '\0'; /* remove "__A" */
         strcpy(action_sub, action_name);
         strcat(action_sub, "Sub");
         j = symbol_index(action_sub, -1);
-        if (sflags[j] & UNKNOWN_SFLAG)
+        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)
+        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]);
+            error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
+            error_named_at("-- ...Sub symbol found, but not a routine:", action_sub, 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;
         }
     }
 }
@@ -276,8 +458,17 @@ static int make_adjective(char *English_word)
     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;
+    }
+    ensure_memory_list_available(&adjectives_memlist, no_adjectives+1);
+    ensure_memory_list_available(&adjective_sort_code_memlist, (no_adjectives+1) * DICT_WORD_BYTES);
 
     dictionary_prepare(English_word, new_sort_code);
     for (i=0; i<no_adjectives; i++)
@@ -305,7 +496,9 @@ static int make_parsing_routine(int32 routine_address)
         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++);
 }
 
@@ -327,7 +520,7 @@ static int find_or_renumber_verb(char *English_verb, int *new_number)
 
     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;
@@ -341,10 +534,27 @@ static int find_or_renumber_verb(char *English_verb, int *new_number)
     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 = (p[1] << 8) | 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)
@@ -359,15 +569,14 @@ static void register_verb(char *English_verb, int number)
     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);
+    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)
@@ -395,9 +604,25 @@ static int get_verb(void)
 /*   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>
 
@@ -435,32 +660,9 @@ static int grammar_line(int verbnum, int line)
         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) {
@@ -471,6 +673,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++;
@@ -522,7 +725,7 @@ 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);
                          panic_mode_error_recovery();
@@ -530,12 +733,12 @@ into Inform, so suggest rewriting grammar using general parsing routines");
                      }
                      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();
@@ -586,7 +789,7 @@ are using Library 6/3 or later");
 
                  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);
                      panic_mode_error_recovery();
@@ -595,9 +798,9 @@ are using Library 6/3 or later");
 
                  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);
@@ -608,25 +811,25 @@ are using Library 6/3 or later");
         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++;
@@ -641,6 +844,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;
@@ -656,6 +860,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;
 
@@ -702,6 +907,7 @@ Library 6/3 or later");
         debug_file_printf("</table-entry>");
     }
 
+    ensure_memory_list_available(&grammar_lines_memlist, mark+3);
     if (!glulx_mode) {
         if (reverse_action)
             j = j + 0x400;
@@ -731,8 +937,8 @@ extern void make_verb(void)
 
     int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
 
-    char *English_verbs_given[MAX_VERB_SYNONYMS];
-    int no_given = 0, i;
+    int no_given = 0, verbs_given_pos = 0;
+    int i, pos;
 
     directive_keywords.enabled = TRUE;
 
@@ -745,11 +951,11 @@ extern void make_verb(void)
 
     while ((token_type == DQ_TT) || (token_type == SQ_TT))
     {
-        if (no_given >= MAX_VERB_SYNONYMS) {
-            error("Too many synonyms in a Verb directive.");
-            panic_mode_error_recovery(); return;
-        }
-        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();
     }
 
@@ -768,16 +974,25 @@ extern void make_verb(void)
             ebf_error("';' after English verb", token_text);
     }
     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;
+        }
+        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");
     }
 
-    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)
@@ -815,9 +1030,13 @@ extern void extend_verb(void)
 
     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;
+        }
+        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();
@@ -836,8 +1055,15 @@ 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; k<l; k++)
+            Inform_verbs[no_Inform_verbs].l[k] = Inform_verbs[Inform_verb].l[k];
         Inform_verb = no_Inform_verbs++;
     }
     else
@@ -870,17 +1096,23 @@ extern void extend_verb(void)
     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;
 
@@ -901,11 +1133,13 @@ extern void init_verbs_vars(void)
     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;
@@ -925,32 +1159,53 @@ extern void verbs_begin_pass(void)
 
 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(&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(&English_verb_list_memlist);
+    deallocate_memory_list(&English_verbs_given_memlist);
 }
 
 /* ========================================================================= */