Implement a Makefile for Inform.
[inform.git] / verbs.c
diff --git a/verbs.c b/verbs.c
deleted file mode 100644 (file)
index 1116e09..0000000
--- a/verbs.c
+++ /dev/null
@@ -1,944 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/*   "verbs" :  Manages actions and grammar tables; parses the directives    */
-/*              Verb and Extend.                                             */
-/*                                                                           */
-/*  Copyright (c) Graham Nelson 1993 - 2018                                  */
-/*                                                                           */
-/* This file is part of Inform.                                              */
-/*                                                                           */
-/* Inform is free software: you can redistribute it and/or modify            */
-/* it under the terms of the GNU General Public License as published by      */
-/* the Free Software Foundation, either version 3 of the License, or         */
-/* (at your option) any later version.                                       */
-/*                                                                           */
-/* Inform is distributed in the hope that it will be useful,                 */
-/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
-/* GNU General Public License for more details.                              */
-/*                                                                           */
-/* You should have received a copy of the GNU General Public License         */
-/* along with Inform. If not, see https://gnu.org/licenses/                  */
-/*                                                                           */
-/* ------------------------------------------------------------------------- */
-
-#include "header.h"
-
-int grammar_version_number;            /* 1 for pre-Inform 6.06 table format */
-int32 grammar_version_symbol;          /* Index of "Grammar__Version"
-                                          within symbols table               */
-
-/* ------------------------------------------------------------------------- */
-/*   Actions.                                                                */
-/* ------------------------------------------------------------------------- */
-/*   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.                     */
-/* ------------------------------------------------------------------------- */
-
-int no_actions,                        /* Number of actions made so far      */
-    no_fake_actions;                   /* Number of fake actions made so far */
-
-/* ------------------------------------------------------------------------- */
-/*   Adjectives.  (The term "adjective" is traditional; they are mainly      */
-/*                prepositions, such as "onto".)                             */
-/* ------------------------------------------------------------------------- */
-/*   Arrays defined below:                                                   */
-/*                                                                           */
-/*    int32 adjectives[n]                 Byte address of dictionary entry   */
-/*                                        for the nth adjective              */
-/*    dict_word adjective_sort_code[n]    Dictionary sort code of nth adj    */
-/* ------------------------------------------------------------------------- */
-
-int no_adjectives;                     /* Number of adjectives made so far   */
-
-/* ------------------------------------------------------------------------- */
-/*   Verbs.  Note that Inform-verbs are not quite the same as English verbs: */
-/*           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.             */
-/* ------------------------------------------------------------------------- */
-/*   Arrays defined below:                                                   */
-/*                                                                           */
-/*    verbt Inform_verbs[n]               The n-th grammar line sequence:    */
-/*                                        see "header.h" for the definition  */
-/*                                        of the typedef struct verbt        */
-/*    int32 grammar_token_routine[n]      The byte offset from start of code */
-/*                                        area of the n-th one               */
-/* ------------------------------------------------------------------------- */
-
-int no_Inform_verbs,                   /* Number of Inform-verbs made so far */
-    no_grammar_token_routines;         /* Number of routines given in tokens */
-
-/* ------------------------------------------------------------------------- */
-/*   We keep a list of English verb-words known (e.g. "take" or "eat") and   */
-/*   which Inform-verbs they correspond to.  (This list is needed for some   */
-/*   of the grammar extension operations.)                                   */
-/*   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)                 */
-/*     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 int English_verb_list_size;     /* Size of the list in bytes
-                                          (redundant but convenient)         */
-
-/* ------------------------------------------------------------------------- */
-/*   Arrays used by this file                                                */
-/* ------------------------------------------------------------------------- */
-
-  verbt   *Inform_verbs;
-  uchar   *grammar_lines;
-  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;
-
-/* ------------------------------------------------------------------------- */
-/*   Tracing for compiler maintenance                                        */
-/* ------------------------------------------------------------------------- */
-
-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);
-}
-
-/* ------------------------------------------------------------------------- */
-/*   Actions.                                                                */
-/* ------------------------------------------------------------------------- */
-
-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.          */
-
-    if (printprops_switch)
-        printf("Action '%s' is numbered %d\n",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];
-    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);
-        panic_mode_error_recovery(); return;
-    }
-
-    snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", token_text);
-    i = symbol_index(action_sub, -1);
-
-    if (!(sflags[i] & UNKNOWN_SFLAG))
-    {   discard_token_location(beginning_debug_location);
-        ebf_error("new fake action name", token_text);
-        panic_mode_error_recovery(); return;
-    }
-
-    assign_symbol(i, ((grammar_version_number==1)?256:4096)+no_fake_actions++,
-        FAKE_ACTION_T);
-
-    new_action(token_text, i);
-
-    if (debugfile_switch)
-    {   debug_file_printf("<fake-action>");
-        debug_file_printf("<identifier>##%s</identifier>", token_text);
-        debug_file_printf("<value>%d</value>", svals[i]);
-        get_next_token();
-        write_debug_locations
-            (get_token_location_end(beginning_debug_location));
-        put_token_back();
-        debug_file_printf("</fake-action>");
-    }
-
-    return;
-}
-
-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];
-    int j;
-    assembly_operand AO;
-
-    snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", name);
-    j = symbol_index(action_sub, -1);
-
-    if (stypes[j] == FAKE_ACTION_T)
-    {   INITAO(&AO);
-        AO.value = svals[j];
-        if (!glulx_mode)
-          AO.type = LONG_CONSTANT_OT;
-        else
-          set_constant_ot(&AO);
-        sflags[j] |= USED_SFLAG;
-        return AO;
-    }
-
-    if (sflags[j] & UNKNOWN_SFLAG)
-    {
-        if (no_actions>=MAX_ACTIONS) memoryerror("MAX_ACTIONS",MAX_ACTIONS);
-        new_action(name, no_actions);
-        action_symbol[no_actions] = j;
-        assign_symbol(j, no_actions++, CONSTANT_T);
-        sflags[j] |= ACTION_SFLAG;
-    }
-    sflags[j] |= USED_SFLAG;
-
-    INITAO(&AO);
-    AO.value = svals[j];
-    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;
-    }
-    else {
-      AO.type = CONSTANT_OT;
-    }
-    return AO;
-}
-
-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" */
-        strcpy(action_sub, action_name);
-        strcat(action_sub, "Sub");
-        j = symbol_index(action_sub, -1);
-        if (sflags[j] & UNKNOWN_SFLAG)
-        {
-            error_named_at("No ...Sub action routine found for action:", action_name, slines[action_symbol[i]]);
-        }
-        else
-        if (stypes[j] != 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]);
-        }
-        else
-        {   action_byte_offset[i] = svals[j];
-            sflags[j] |= USED_SFLAG;
-        }
-    }
-}
-
-/* ------------------------------------------------------------------------- */
-/*   Adjectives.                                                             */
-/* ------------------------------------------------------------------------- */
-
-static int make_adjective(char *English_word)
-{
-    /*  Returns adjective number of the English word supplied, creating
-        a new adjective number if need be.
-
-        Note that (partly for historical reasons) adjectives are numbered
-        from 0xff downwards.  (And partly to make them stand out as tokens.)
-
-        This routine is used only in grammar version 1: the corresponding
-        table is left empty in GV2.                                          */
-
-    int i; 
-    uchar new_sort_code[MAX_DICT_WORD_BYTES];
-
-    if (no_adjectives >= MAX_ADJECTIVES)
-        memoryerror("MAX_ADJECTIVES", MAX_ADJECTIVES);
-
-    dictionary_prepare(English_word, new_sort_code);
-    for (i=0; i<no_adjectives; i++)
-        if (compare_sorts(new_sort_code,
-          adjective_sort_code+i*DICT_WORD_BYTES) == 0)
-            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++);
-}
-
-/* ------------------------------------------------------------------------- */
-/*   Parsing routines.                                                       */
-/* ------------------------------------------------------------------------- */
-
-static int make_parsing_routine(int32 routine_address)
-{
-    /*  This routine is used only in grammar version 1: the corresponding
-        table is left empty in GV2.                                          */
-
-    int l;
-    for (l=0; l<no_grammar_token_routines; l++)
-        if (grammar_token_routine[l] == routine_address)
-            return l;
-
-    grammar_token_routine[l] = routine_address;
-    return(no_grammar_token_routines++);
-}
-
-/* ------------------------------------------------------------------------- */
-/*   The English-verb list.                                                  */
-/* ------------------------------------------------------------------------- */
-
-static int find_or_renumber_verb(char *English_verb, int *new_number)
-{
-    /*  If new_number is null, returns the Inform-verb number which the
-     *  given English verb causes, or -1 if the given verb is not in the
-     *  dictionary                     */
-
-    /*  If new_number is non-null, renumbers the Inform-verb number which
-     *  English_verb matches in English_verb_list to account for the case
-     *  when we are extending a verb.  Returns 0 if successful, or -1 if
-     *  the given verb is not in the dictionary (which shouldn't happen as
-     *  get_verb has already run) */
-
-    char *p;
-    p=English_verb_list;
-    while (p < English_verb_list_top)
-    {   if (strcmp(English_verb, p+3) == 0)
-        {   if (new_number)
-            {   p[1] = (*new_number)/256;
-                p[2] = (*new_number)%256;
-                return 0;
-            }
-            return(256*((uchar)p[1]))+((uchar)p[2]);
-        }
-        p=p+(uchar)p[0];
-    }
-    return(-1);
-}
-
-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.)                */
-    int entrysize;
-
-    if (find_or_renumber_verb(English_verb, NULL) != -1)
-    {   error_named("Two different verb definitions refer to", English_verb);
-        return;
-    }
-
-    /* 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.) */
-    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);
-    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;
-}
-
-static int get_verb(void)
-{
-    /*  Look at the last-read token: if it's the name of an English verb
-        understood by Inform, in double-quotes, then return the Inform-verb
-        that word refers to: otherwise give an error and return -1.          */
-
-    int j;
-
-    if ((token_type == DQ_TT) || (token_type == SQ_TT))
-    {   j = find_or_renumber_verb(token_text, NULL);
-        if (j==-1)
-            error_named("There is no previous grammar for the verb",
-                token_text);
-        return j;
-    }
-
-    ebf_error("an English verb in quotes", token_text);
-
-    return -1;
-}
-
-/* ------------------------------------------------------------------------- */
-/*   Grammar lines for Verb/Extend directives.                               */
-/* ------------------------------------------------------------------------- */
-
-static int grammar_line(int verbnum, int line)
-{
-    /*  Parse a grammar line, to be written into grammar_lines[mark] onward.
-
-        Syntax: * <token1> ... <token-n> -> <action>
-
-        is compiled to a table in the form:
-
-                <action number : word>
-                <token 1> ... <token n> <ENDIT>
-
-        where <ENDIT> is the byte 15, and each <token> is 3 bytes long.
-
-        If grammar_version_number is 1, the token holds
-
-                <bytecode> 00 00
-
-        and otherwise a GV2 token.
-
-        Return TRUE if grammar continues after the line, FALSE if the
-        directive comes to an end.                                           */
-
-    int j, bytecode, mark; int32 wordcode;
-    int grammar_token, slash_mode, last_was_slash;
-    int reverse_action, TOKEN_SIZE;
-    debug_location_beginning beginning_debug_location =
-        get_token_location_beginning();
-
-    get_next_token();
-    if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
-    {   discard_token_location(beginning_debug_location);
-        return FALSE;
-    }
-    if (!((token_type == SEP_TT) && (token_value == TIMES_SEP)))
-    {   discard_token_location(beginning_debug_location);
-        ebf_error("'*' divider", token_text);
-        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);
-        }
-    }
-
-    Inform_verbs[verbnum].l[line] = mark;
-
-    if (!glulx_mode) {
-        mark = mark + 2;
-        TOKEN_SIZE = 3;
-    }
-    else {
-        mark = mark + 3;
-        TOKEN_SIZE = 5;
-    }
-
-    grammar_token = 0; last_was_slash = TRUE; slash_mode = FALSE;
-    no_grammar_lines++;
-
-    do
-    {   get_next_token();
-        bytecode = 0; wordcode = 0;
-        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
-        {   discard_token_location(beginning_debug_location);
-            ebf_error("'->' clause", token_text);
-            return FALSE;
-        }
-        if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
-        {   if (last_was_slash && (grammar_token>0))
-                ebf_error("grammar token", token_text);
-            break;
-        }
-
-        if (!last_was_slash) slash_mode = FALSE;
-        if ((token_type == SEP_TT) && (token_value == DIVIDE_SEP))
-        {   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);
-            else
-            {   last_was_slash = TRUE;
-                slash_mode = TRUE;
-                if (((grammar_lines[mark-TOKEN_SIZE]) & 0x0f) != 2)
-                    error("'/' can only be applied to prepositions");
-                grammar_lines[mark-TOKEN_SIZE] |= 0x20;
-                continue;
-            }
-        }
-        else last_was_slash = FALSE;
-
-        if ((token_type == DQ_TT) || (token_type == SQ_TT))
-        {    if (grammar_version_number == 1)
-                 bytecode = make_adjective(token_text);
-             else
-             {   bytecode = 0x42;
-                 wordcode = dictionary_add(token_text, 8, 0, 0);
-             }
-        }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NOUN_DK))
-             {   get_next_token();
-                 if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
-                 {
-                     /*  noun = <routine>                                    */
-
-                     get_next_token();
-                     if ((token_type != SYMBOL_TT)
-                         || (stypes[token_value] != ROUTINE_T))
-                     {   discard_token_location(beginning_debug_location);
-                         ebf_error("routine name after 'noun='", token_text);
-                         panic_mode_error_recovery();
-                         return FALSE;
-                     }
-                     if (grammar_version_number == 1)
-                         bytecode
-                             = 16 + make_parsing_routine(svals[token_value]);
-                     else
-                     {   bytecode = 0x83;
-                         wordcode = svals[token_value];
-                     }
-                     sflags[token_value] |= USED_SFLAG;
-                 }
-                 else
-                 {   put_token_back();
-                     if (grammar_version_number == 1) bytecode=0;
-                     else { bytecode = 1; wordcode = 0; }
-                 }
-             }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==HELD_DK))
-             {   if (grammar_version_number==1) bytecode=1;
-                 else { bytecode=1; wordcode=1; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTI_DK))
-             {   if (grammar_version_number==1) bytecode=2;
-                 else { bytecode=1; wordcode=2; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIHELD_DK))
-             {   if (grammar_version_number==1) bytecode=3;
-                 else { bytecode=1; wordcode=3; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIEXCEPT_DK))
-             {   if (grammar_version_number==1) bytecode=4;
-                 else { bytecode=1; wordcode=4; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==MULTIINSIDE_DK))
-             {   if (grammar_version_number==1) bytecode=5;
-                 else { bytecode=1; wordcode=5; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==CREATURE_DK))
-             {   if (grammar_version_number==1) bytecode=6;
-                 else { bytecode=1; wordcode=6; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==SPECIAL_DK))
-             {   if (grammar_version_number==1) bytecode=7;
-                 else { bytecode=1; wordcode=7; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==NUMBER_DK))
-             {   if (grammar_version_number==1) bytecode=8;
-                 else { bytecode=1; wordcode=8; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TOPIC_DK))
-             {   if (grammar_version_number==1)
-                     error("The 'topic' token is only available if you \
-are using Library 6/3 or later");
-                 else { bytecode=1; wordcode=9; } }
-        else if ((token_type==DIR_KEYWORD_TT)&&(token_value==SCOPE_DK))
-             {
-                 /*  scope = <routine> */
-
-                 get_next_token();
-                 if (!((token_type==SEP_TT)&&(token_value==SETEQUALS_SEP)))
-                 {   discard_token_location(beginning_debug_location);
-                     ebf_error("'=' after 'scope'", token_text);
-                     panic_mode_error_recovery();
-                     return FALSE;
-                 }
-
-                 get_next_token();
-                 if ((token_type != SYMBOL_TT)
-                     || (stypes[token_value] != ROUTINE_T))
-                 {   discard_token_location(beginning_debug_location);
-                     ebf_error("routine name after 'scope='", token_text);
-                     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;
-             }
-        else if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
-             {   discard_token_location(beginning_debug_location);
-                 error("'=' is only legal here as 'noun=Routine'");
-                 panic_mode_error_recovery();
-                 return FALSE;
-             }
-        else {   /*  <attribute>  or  <general-parsing-routine>  tokens      */
-
-                 if ((token_type != SYMBOL_TT)
-                     || ((stypes[token_value] != ATTRIBUTE_T)
-                         && (stypes[token_value] != 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 (grammar_version_number == 1)
-                         bytecode = 128 + svals[token_value];
-                     else { bytecode = 4; wordcode = svals[token_value]; }
-                 }
-                 else
-                 {   if (grammar_version_number == 1)
-                         bytecode = 48 +
-                             make_parsing_routine(svals[token_value]);
-                     else { bytecode = 0x86; wordcode = svals[token_value]; }
-                 }
-                 sflags[token_value] |= USED_SFLAG;
-             }
-
-        grammar_token++; no_grammar_tokens++;
-        if ((grammar_version_number == 1) && (grammar_token > 6))
-        {   if (grammar_token == 7)
-                warning("Grammar line cut short: you can only have up to 6 \
-tokens in any line (unless you're compiling with library 6/3 or later)");
-        }
-        else
-        {   if (slash_mode)
-            {   if (bytecode != 0x42)
-                    error("'/' can only be applied to prepositions");
-                bytecode |= 0x10;
-            }
-            grammar_lines[mark++] = bytecode;
-            if (!glulx_mode) {
-                grammar_lines[mark++] = wordcode/256;
-                grammar_lines[mark++] = wordcode%256;
-            }
-            else {
-                grammar_lines[mark++] = ((wordcode >> 24) & 0xFF);
-                grammar_lines[mark++] = ((wordcode >> 16) & 0xFF);
-                grammar_lines[mark++] = ((wordcode >> 8) & 0xFF);
-                grammar_lines[mark++] = ((wordcode) & 0xFF);
-            }
-        }
-
-    } while (TRUE);
-
-    grammar_lines[mark++] = 15;
-    grammar_lines_top = mark;
-
-    dont_enter_into_symbol_table = TRUE;
-    get_next_token();
-    dont_enter_into_symbol_table = FALSE;
-
-    if (token_type != DQ_TT)
-    {   discard_token_location(beginning_debug_location);
-        ebf_error("name of new or existing action", token_text);
-        panic_mode_error_recovery();
-        return FALSE;
-    }
-
-    {   assembly_operand AO = action_of_name(token_text);
-        j = AO.value;
-        if (j >= ((grammar_version_number==1)?256:4096))
-            error_named("This is a fake action, not a real one:", token_text);
-    }
-
-    reverse_action = FALSE;
-    get_next_token();
-    if ((token_type == DIR_KEYWORD_TT) && (token_value == REVERSE_DK))
-    {   if (grammar_version_number == 1)
-            error("'reverse' actions can only be used with \
-Library 6/3 or later");
-        reverse_action = TRUE;
-    }
-    else put_token_back();
-
-    mark = Inform_verbs[verbnum].l[line];
-
-    if (debugfile_switch)
-    {   debug_file_printf("<table-entry>");
-        debug_file_printf("<type>grammar line</type>");
-        debug_file_printf("<address>");
-        write_debug_grammar_backpatch(mark);
-        debug_file_printf("</address>");
-        debug_file_printf("<end-address>");
-        write_debug_grammar_backpatch(grammar_lines_top);
-        debug_file_printf("</end-address>");
-        write_debug_locations
-            (get_token_location_end(beginning_debug_location));
-        debug_file_printf("</table-entry>");
-    }
-
-    if (!glulx_mode) {
-        if (reverse_action)
-            j = j + 0x400;
-        grammar_lines[mark++] = j/256;
-        grammar_lines[mark++] = j%256;
-    }
-    else {
-        grammar_lines[mark++] = ((j >> 8) & 0xFF);
-        grammar_lines[mark++] = ((j) & 0xFF);
-        grammar_lines[mark++] = (reverse_action ? 1 : 0);
-    }
-
-    return TRUE;
-}
-
-/* ------------------------------------------------------------------------- */
-/*   The Verb directive:                                                     */
-/*                                                                           */
-/*       Verb [meta] "word-1" ... "word-n" | = "existing-English-verb"       */
-/*                                         | <grammar-line-1> ... <g-line-n> */
-/*                                                                           */
-/* ------------------------------------------------------------------------- */
-
-extern void make_verb(void)
-{
-    /*  Parse an entire Verb ... directive.                                  */
-
-    int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
-
-    char *English_verbs_given[32]; int no_given = 0, i;
-
-    directive_keywords.enabled = TRUE;
-
-    get_next_token();
-
-    if ((token_type == DIR_KEYWORD_TT) && (token_value == META_DK))
-    {   meta_verb_flag = TRUE;
-        get_next_token();
-    }
-
-    while ((token_type == DQ_TT) || (token_type == SQ_TT))
-    {   English_verbs_given[no_given++] = token_text;
-        get_next_token();
-    }
-
-    if (no_given == 0)
-    {   ebf_error("English verb in quotes", token_text);
-        panic_mode_error_recovery(); return;
-    }
-
-    if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
-    {   verb_equals_form = TRUE;
-        get_next_token();
-        Inform_verb = get_verb();
-        if (Inform_verb == -1) return;
-        get_next_token();
-        if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
-            ebf_error("';' after English verb", token_text);
-    }
-    else
-    {   Inform_verb = no_Inform_verbs;
-        if (no_Inform_verbs == MAX_VERBS)
-            memoryerror("MAX_VERBS",MAX_VERBS);
-    }
-
-    for (i=0; i<no_given; i++)
-    {   dictionary_add(English_verbs_given[i],
-            0x41 + ((meta_verb_flag)?0x02:0x00),
-            (glulx_mode)?(0xffff-Inform_verb):(0xff-Inform_verb), 0);
-        register_verb(English_verbs_given[i], Inform_verb);
-    }
-
-    if (!verb_equals_form)
-    {   int lines = 0;
-        put_token_back();
-        while (grammar_line(no_Inform_verbs, lines++)) ;
-        Inform_verbs[no_Inform_verbs++].lines = --lines;
-    }
-
-    directive_keywords.enabled = FALSE;
-}
-
-/* ------------------------------------------------------------------------- */
-/*   The Extend directive:                                                   */
-/*                                                                           */
-/*      Extend | only "verb-1" ... "verb-n"  |             <grammar-lines>   */
-/*             | "verb"                      | "replace"                     */
-/*                                           | "first"                       */
-/*                                           | "last"                        */
-/*                                                                           */
-/* ------------------------------------------------------------------------- */
-
-#define EXTEND_REPLACE 1
-#define EXTEND_FIRST   2
-#define EXTEND_LAST    3
-
-extern void extend_verb(void)
-{
-    /*  Parse an entire Extend ... directive.                                */
-
-    int Inform_verb = -1, k, l, lines, extend_mode;
-
-    directive_keywords.enabled = TRUE;
-    directives.enabled = FALSE;
-
-    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);
-        while (get_next_token(),
-               ((token_type == DQ_TT) || (token_type == SQ_TT)))
-        {   Inform_verb = get_verb();
-            if (Inform_verb == -1) return;
-            if ((l!=-1) && (Inform_verb!=l))
-              warning_named("Verb disagrees with previous verbs:", token_text);
-            l = Inform_verb;
-            dictionary_set_verb_number(token_text,
-              (glulx_mode)?(0xffff-no_Inform_verbs):(0xff-no_Inform_verbs));
-            /* make call to renumber verb in English_verb_list too */
-            if (find_or_renumber_verb(token_text, &no_Inform_verbs) == -1)
-              warning_named("Verb to extend not found in English_verb_list:",
-                 token_text);
-        }
-
-        /*  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                                                      */
-
-        Inform_verbs[no_Inform_verbs] = Inform_verbs[Inform_verb];
-        Inform_verb = no_Inform_verbs++;
-    }
-    else
-    {   Inform_verb = get_verb();
-        if (Inform_verb == -1) return;
-        get_next_token();
-    }
-
-    /*  Inform_verb now contains the number of the Inform-verb to extend...  */
-
-    extend_mode = EXTEND_LAST;
-    if ((token_type == SEP_TT) && (token_value == TIMES_SEP))
-        put_token_back();
-    else
-    {   extend_mode = 0;
-        if ((token_type == DIR_KEYWORD_TT) && (token_value == REPLACE_DK))
-            extend_mode = EXTEND_REPLACE;
-        if ((token_type == DIR_KEYWORD_TT) && (token_value == FIRST_DK))
-            extend_mode = EXTEND_FIRST;
-        if ((token_type == DIR_KEYWORD_TT) && (token_value == LAST_DK))
-            extend_mode = EXTEND_LAST;
-
-        if (extend_mode==0)
-        {   ebf_error("'replace', 'last', 'first' or '*'", token_text);
-            extend_mode = EXTEND_LAST;
-        }
-    }
-
-    l = Inform_verbs[Inform_verb].lines;
-    lines = 0;
-    if (extend_mode == EXTEND_LAST) lines=l;
-    do
-    {   if (extend_mode == EXTEND_FIRST)
-            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++)
-            Inform_verbs[Inform_verb].l[k+lines-1]
-                = Inform_verbs[Inform_verb].l[k+lines];
-    }
-    else Inform_verbs[Inform_verb].lines = --lines;
-
-    directive_keywords.enabled = FALSE;
-    directives.enabled = TRUE;
-}
-
-/* ========================================================================= */
-/*   Data structure management routines                                      */
-/* ------------------------------------------------------------------------- */
-
-extern void init_verbs_vars(void)
-{
-    no_fake_actions = 0;
-    no_actions = 0;
-    no_grammar_lines = 0;
-    no_grammar_tokens = 0;
-    English_verb_list_size = 0;
-
-    Inform_verbs = NULL;
-    action_byte_offset = NULL;
-    grammar_token_routine = NULL;
-    adjectives = NULL;
-    adjective_sort_code = NULL;
-    English_verb_list = NULL;
-
-    if (!glulx_mode)
-        grammar_version_number = 1;
-    else
-        grammar_version_number = 2;
-}
-
-extern void verbs_begin_pass(void)
-{
-    no_Inform_verbs=0; no_adjectives=0;
-    no_grammar_token_routines=0;
-    no_actions=0;
-
-    no_fake_actions=0;
-    grammar_lines_top = 0;
-}
-
-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;
-}
-
-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");
-}
-
-/* ========================================================================= */