Update to Inform v6.42
[inform.git] / src / directs.c
index d8374c367a6e8863eae86cb5d2f5e59826c877fc..b9d26d2f4d8045a597982f572e871788340780e7 100644 (file)
@@ -1,8 +1,8 @@
 /* ------------------------------------------------------------------------- */
 /*   "directs" : Directives (# commands)                                     */
 /*                                                                           */
-/*   Part of Inform 6.41                                                     */
-/*   copyright (c) Graham Nelson 1993 - 2022                                 */
+/*   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      */
@@ -23,7 +23,6 @@
 
 int no_routines,                   /* Number of routines compiled so far     */
     no_named_routines,             /* Number not embedded in objects         */
-    no_locals,                     /* Number of locals in current routine    */
     no_termcs;                     /* Number of terminating characters       */
 int terminating_characters[32];
 
@@ -39,23 +38,23 @@ static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
 
 /* ------------------------------------------------------------------------- */
 
-static int ebf_error_recover(char *s1, char *s2)
+static int ebf_error_recover(char *s1)
 {
-    /* Display an "expected... but found..." error, then skim forward
-       to the next semicolon and return FALSE. This is such a common
-       case in parse_given_directive() that it's worth a utility
-       function. You will see many error paths that look like:
+    /* Display an "expected... but found (current token)" error, then
+       skim forward to the next semicolon and return FALSE. This is
+       such a common case in parse_given_directive() that it's worth a
+       utility function. You will see many error paths that look like:
           return ebf_error_recover(...);
     */
-    ebf_error(s1, s2);
+    ebf_curtoken_error(s1);
     panic_mode_error_recovery();
     return FALSE;
 }
 
-static int ebf_symbol_error_recover(char *s1, char *name, char *type, brief_location report_line)
+static int ebf_symbol_error_recover(char *s1, char *type, brief_location report_line)
 {
     /* Same for ebf_symbol_error(). */
-    ebf_symbol_error(s1, name, type, report_line);
+    ebf_symbol_error(s1, token_text, type, report_line);
     panic_mode_error_recovery();
     return FALSE;
 }
@@ -122,13 +121,7 @@ extern int parse_given_directive(int internal_flag)
                panic_mode_error_recovery(); return FALSE;
            }
            if (token_type != DQ_TT)
-           {   return ebf_error_recover("abbreviation string", token_text);
-           }
-           /* Abbreviation string with null must fit in a MAX_ABBREV_LENGTH
-              array. */
-           if (strlen(token_text)>=MAX_ABBREV_LENGTH)
-           {   error_named("Abbreviation too long", token_text);
-               continue;
+           {   return ebf_error_recover("abbreviation string");
            }
            make_abbreviation(token_text);
         } while (TRUE);
@@ -167,12 +160,12 @@ extern int parse_given_directive(int internal_flag)
 
         if (token_type != SYMBOL_TT)
         {   discard_token_location(beginning_debug_location);
-            return ebf_error_recover("new constant name", token_text);
+            return ebf_error_recover("new constant name");
         }
 
         if (!(symbols[i].flags & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
         {   discard_token_location(beginning_debug_location);
-            return ebf_symbol_error_recover("new constant name", token_text, typename(symbols[i].type), symbols[i].line);
+            return ebf_symbol_error_recover("new constant name", typename(symbols[i].type), symbols[i].line);
         }
 
         assign_symbol(i, 0, CONSTANT_T);
@@ -250,7 +243,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     case DEFAULT_CODE:
         get_next_token();
         if (token_type != SYMBOL_TT)
-            return ebf_error_recover("name", token_text);
+            return ebf_error_recover("name");
 
         i = -1;
         if (symbols[token_value].flags & UNKNOWN_SFLAG)
@@ -296,7 +289,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
          */
         get_next_token();
         if (token_type != SQ_TT && token_type != DQ_TT)
-            return ebf_error_recover("dictionary word", token_text);
+            return ebf_error_recover("dictionary word");
 
         {
             char *wd = token_text;
@@ -400,7 +393,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
       DefCondition:
         get_next_token();
         if (token_type != SYMBOL_TT)
-            return ebf_error_recover("symbol name", token_text);
+            return ebf_error_recover("symbol name");
 
         /* Special case: a symbol of the form "VN_nnnn" is considered
            defined if the compiler version number is at least nnnn.
@@ -506,7 +499,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     HashIfCondition:
         get_next_token();
         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
-            return ebf_error_recover("semicolon after 'If...' condition", token_text);
+            return ebf_error_recover("semicolon after 'If...' condition");
 
         if (ifdef_sp >= MAX_IFDEF_STACK) {
             error("'If' directives nested too deeply");
@@ -570,13 +563,13 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     case INCLUDE_CODE:
         get_next_token();
         if (token_type != DQ_TT)
-            return ebf_error_recover("filename in double-quotes", token_text);
+            return ebf_error_recover("filename in double-quotes");
 
         {   char *name = token_text;
 
             get_next_token();
             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
-                ebf_error("semicolon ';' after Include filename", token_text);
+                ebf_curtoken_error("semicolon ';' after Include filename");
 
             if (strcmp(name, "language__") == 0)
                  load_sourcefile(Language_Name, 0);
@@ -610,13 +603,13 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         }
         get_next_token(); i = token_value;
         if (token_type != SYMBOL_TT)
-            return ebf_error_recover("new low string name", token_text);
+            return ebf_error_recover("new low string name");
         if (!(symbols[i].flags & UNKNOWN_SFLAG))
-            return ebf_symbol_error_recover("new low string name", token_text, typename(symbols[i].type), symbols[i].line);
+            return ebf_symbol_error_recover("new low string name", typename(symbols[i].type), symbols[i].line);
 
         get_next_token();
         if (token_type != DQ_TT)
-            return ebf_error_recover("literal string in double-quotes", token_text);
+            return ebf_error_recover("literal string in double-quotes");
 
         assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
         break;
@@ -647,26 +640,25 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
         {   get_next_token();
             if (token_type != DQ_TT)
-            {   return ebf_error_recover("error message in double-quotes", token_text);
+            {   return ebf_error_recover("error message in double-quotes");
             }
             error(token_text); break;
         }
         if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
         {   get_next_token();
             if (token_type != DQ_TT)
-            {   return ebf_error_recover("fatal error message in double-quotes", token_text);
+            {   return ebf_error_recover("fatal error message in double-quotes");
             }
             fatalerror(token_text); break;
         }
         if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
         {   get_next_token();
             if (token_type != DQ_TT)
-            {   return ebf_error_recover("warning message in double-quotes", token_text);
+            {   return ebf_error_recover("warning message in double-quotes");
             }
             warning(token_text); break;
         }
-        return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
-            token_text);
+        return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'");
         break;
 
     /* --------------------------------------------------------------------- */
@@ -715,16 +707,14 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
             get_next_token();
             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
                 if (token_type != DQ_TT) {
-                    return ebf_error_recover("a file name in double-quotes",
-                        token_text);
+                    return ebf_error_recover("a file name in double-quotes");
                 }
                 origsource_file = token_text;
 
                 get_next_token();
                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
                     if (token_type != NUMBER_TT) {
-                        return ebf_error_recover("a file line number",
-                            token_text);
+                        return ebf_error_recover("a file line number");
                     }
                     origsource_line = token_value;
                     if (origsource_line < 0)
@@ -733,8 +723,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                     get_next_token();
                     if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
                         if (token_type != NUMBER_TT) {
-                            return ebf_error_recover("a file line number",
-                                token_text);
+                            return ebf_error_recover("a file line number");
                         }
                         origsource_char = token_value;
                         if (origsource_char < 0)
@@ -805,9 +794,9 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         }
 
         if (token_type != SYMBOL_TT)
-            return ebf_error_recover("name of routine to replace", token_text);
+            return ebf_error_recover("name of routine to replace");
         if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
-            return ebf_error_recover("name of routine not yet defined", token_text);
+            return ebf_error_recover("name of routine not yet defined");
 
         symbols[token_value].flags |= REPLACE_SFLAG;
 
@@ -824,7 +813,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         }
 
         if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG))
-            return ebf_error_recover("semicolon ';' or new routine name", token_text);
+            return ebf_error_recover("semicolon ';' or new routine name");
 
         /* Define the original-form symbol as a zero constant. Its
            value will be overwritten later, when we define the
@@ -862,7 +851,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         directive_keywords.enabled = FALSE;
         if ((token_type != DIR_KEYWORD_TT)
             || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
-            return ebf_error_recover("'score' or 'time' after 'statusline'", token_text);
+            return ebf_error_recover("'score' or 'time' after 'statusline'");
         if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
         else statusline_flag = TIME_STYLE;
         break;
@@ -878,7 +867,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         get_next_token();
         df_dont_note_global_symbols = FALSE;
         if (token_type != SYMBOL_TT)
-            return ebf_error_recover("routine name to stub", token_text);
+            return ebf_error_recover("routine name to stub");
 
         i = token_value; flag = FALSE;
 
@@ -889,7 +878,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
 
         get_next_token(); k = token_value;
         if (token_type != NUMBER_TT)
-            return ebf_error_recover("number of local variables", token_text);
+            return ebf_error_recover("number of local variables");
         if ((k>4) || (k<0))
         {   error("Must specify 0 to 4 local variables for 'Stub' routine");
             k = 0;
@@ -903,13 +892,14 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                 (We don't set local_variable.keywords because we're not
                 going to be parsing any code.)                               */
 
-            strcpy(local_variable_names[0].text, "dummy1");
-            strcpy(local_variable_names[1].text, "dummy2");
-            strcpy(local_variable_names[2].text, "dummy3");
-            strcpy(local_variable_names[3].text, "dummy4");
+            clear_local_variables();
+            if (k >= 1) add_local_variable("dummy1");
+            if (k >= 2) add_local_variable("dummy2");
+            if (k >= 3) add_local_variable("dummy3");
+            if (k >= 4) add_local_variable("dummy4");
 
             assign_symbol(i,
-                assemble_routine_header(k, FALSE, symbols[i].name, FALSE, i),
+                assemble_routine_header(FALSE, symbols[i].name, FALSE, i),
                 ROUTINE_T);
 
             /*  Ensure the return value of a stubbed routine is false,
@@ -937,8 +927,8 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         dont_enter_into_symbol_table = TRUE;
         get_next_token();
         dont_enter_into_symbol_table = FALSE;
-        if (token_type != DQ_TT)
-            return ebf_error_recover("string of switches", token_text);
+        if (token_type != UQ_TT)
+            return ebf_error_recover("string of switches");
         if (!ignore_switches_switch)
         {
             if (constant_made_yet) {
@@ -1010,7 +1000,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
            'on' and 'off' are trace keywords. */
         
         if (token_type != TRACE_KEYWORD_TT)
-            return ebf_error_recover("debugging keyword", token_text);
+            return ebf_error_recover("debugging keyword");
 
         trace_keywords.enabled = TRUE;
 
@@ -1100,7 +1090,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
     case UNDEF_CODE:
         get_next_token();
         if (token_type != SYMBOL_TT)
-            return ebf_error_recover("symbol name", token_text);
+            return ebf_error_recover("symbol name");
 
         if (symbols[token_value].flags & UNKNOWN_SFLAG)
         {   break; /* undef'ing an undefined constant is okay */
@@ -1114,7 +1104,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
         if (debugfile_switch)
         {   write_debug_undef(token_value);
         }
-        end_symbol_scope(token_value);
+        /* We remove it from the symbol table. But previous uses of the symbol
+           were valid, so we don't set neverused true. We also mark it
+           USED so that it can't trigger "symbol not used" warnings. */
+        end_symbol_scope(token_value, FALSE);
         symbols[token_value].flags |= USED_SFLAG;
         break;
 
@@ -1172,8 +1165,8 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                    version.
                    The calculation here is repeated from select_target(). */
                 DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0);
-                debtok = symbol_index("DICT_ENTRY_BYTES", -1);
-                if (!(symbols[debtok].flags & UNKNOWN_SFLAG))
+                debtok = get_symbol_index("DICT_ENTRY_BYTES");
+                if (debtok >= 0 && !(symbols[debtok].flags & UNKNOWN_SFLAG))
                 {
                     if (!(symbols[debtok].flags & REDEFINABLE_SFLAG))
                     {
@@ -1209,18 +1202,18 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                 new_alphabet(token_text, 0);
                 get_next_token();
                 if (token_type != DQ_TT)
-                    return ebf_error_recover("double-quoted alphabet string", token_text);
+                    return ebf_error_recover("double-quoted alphabet string");
                 new_alphabet(token_text, 1);
                 get_next_token();
                 if (token_type != DQ_TT)
-                    return ebf_error_recover("double-quoted alphabet string", token_text);
+                    return ebf_error_recover("double-quoted alphabet string");
                 new_alphabet(token_text, 2);
             break;
 
             case SQ_TT:
                 map_new_zchar(text_to_unicode(token_text));
                 if (token_text[textual_form_length] != 0)
-                    return ebf_error_recover("single character value", token_text);
+                    return ebf_error_recover("single character value");
             break;
 
             case DIR_KEYWORD_TT:
@@ -1241,13 +1234,11 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                                 new_zscii_character(text_to_unicode(token_text),
                                     plus_flag);
                                 if (token_text[textual_form_length] != 0)
-                                    return ebf_error_recover("single character value",
-                                        token_text);
+                                    return ebf_error_recover("single character value");
                                 plus_flag = TRUE;
                                 break;
                             default:
-                                return ebf_error_recover("character or Unicode number",
-                                    token_text);
+                                return ebf_error_recover("character or Unicode number");
                         }
                         get_next_token();
                     }
@@ -1264,8 +1255,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                                     = token_value;
                                 break;
                             default:
-                                return ebf_error_recover("ZSCII number",
-                                    token_text);
+                                return ebf_error_recover("ZSCII number");
                         }
                         get_next_token();
                     }
@@ -1273,13 +1263,12 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)");
                     break;
                 default:
                     return ebf_error_recover("'table', 'terminating', \
-a string or a constant",
-                        token_text);
+a string or a constant");
             }
                 break;
             default:
                 return ebf_error_recover("three alphabet strings, \
-a 'table' or 'terminating' command or a single character", token_text);
+a 'table' or 'terminating' command or a single character");
         }
         break;
 
@@ -1292,7 +1281,7 @@ a 'table' or 'terminating' command or a single character", token_text);
 
     get_next_token();
     if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
-    {   ebf_error("';'", token_text);
+    {   ebf_curtoken_error("';'");
         /* Put the non-semicolon back. We will continue parsing from
            that point, in hope that it's the start of a new directive.
            (This recovers cleanly from a missing semicolon at the end
@@ -1314,7 +1303,6 @@ extern void init_directs_vars(void)
 extern void directs_begin_pass(void)
 {   no_routines = 0;
     no_named_routines = 0;
-    no_locals = 0;
     no_termcs = 0;
     constant_made_yet = FALSE;
     ifdef_sp = 0;