Update to Inform v6.42
[inform.git] / src / veneer.c
index 519e08552617f3547d5122dfcf8837f66784c6d9..e065d04d360240e9cbb4b39f1b77266cee9ff435 100644 (file)
@@ -3,9 +3,8 @@
 /*              by the compiler (e.g. DefArt) which the program doesn't      */
 /*              provide                                                      */
 /*                                                                           */
-/* Copyright (c) Graham Nelson 1993 - 2020                                   */
-/*                                                                           */
-/* This file is part of Inform.                                              */
+/*   Part of Inform 6.42                                                     */
+/*   copyright (c) Graham Nelson 1993 - 2024                                 */
 /*                                                                           */
 /* Inform is free software: you can redistribute it and/or modify            */
 /* it under the terms of the GNU General Public License as published by      */
@@ -28,7 +27,7 @@ int veneer_mode;                      /*  Is the code currently being
                                           compiled from the veneer?          */
 
 static debug_locations null_debug_locations =
-    { { 0, 0, 0, 0, 0, 0, 0 }, NULL, 0 };
+    { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, NULL, 0 };
 
 extern void compile_initial_routine(void)
 {
@@ -37,18 +36,23 @@ extern void compile_initial_routine(void)
         (since the interpreter begins execution with an empty stack frame):
         and it must "quit" rather than "return".
 
+        (Pedantically, in Z-code 1-5, this is not a routine at all. It's
+        a sequence of opcodes which ends with "quit". The one-byte
+        header generated by assemble_routine_header() is a dummy.)
+
         In order not to impose these restrictions on "Main", we compile a
         trivial routine consisting of a call to "Main" followed by "quit".   */
 
   int32 j;
     assembly_operand AO;
 
-    j = symbol_index("Main__", -1);
+    j = symbol_index("Main__", -1, NULL);
+    clear_local_variables();
     assign_symbol(j,
-        assemble_routine_header(0, FALSE, "Main__", FALSE, j),
+        assemble_routine_header(FALSE, "Main__", FALSE, j),
         ROUTINE_T);
-    sflags[j] |= SYSTEM_SFLAG + USED_SFLAG;
-    if (trace_fns_setting==3) sflags[j] |= STAR_SFLAG;
+    symbols[j].flags |= SYSTEM_SFLAG + USED_SFLAG;
+    if (trace_fns_setting==3) symbols[j].flags |= STAR_SFLAG;
 
     if (!glulx_mode) {
 
@@ -121,6 +125,7 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
          w = 0 -> 33;\
          if (w == 0) w=80;\
          w2 = (w - maxw)/2;\
+         if (w2 < 3) w2 = 3;\
          style reverse;\
          @sub w2 2 -> w;\
          line = 5;\
@@ -208,11 +213,16 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
                  prop = (i-->0) & $7fff;\
              }\
          }",
-        "p = #identifiers_table;\
+        "#IFDEF OMIT_SYMBOL_TABLE;\
+         p = size = 0;\
+         print \"<number \", prop, \">\";\
+         #IFNOT;\
+         p = #identifiers_table;\
          size = p-->0;\
          if (prop<=0 || prop>=size || p-->prop==0)\
              print \"<number \", prop, \">\";\
          else print (string) p-->prop;\
+         #ENDIF;\
          ]", "", "", "", ""
     },
 
@@ -263,6 +273,10 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
 
         "CA__Pr",
         "obj id a b c d e f x y z s s2 n m;\
+         #IFV3;\
+         #Message error \"Object message calls are not supported in v3.\";\
+         obj = id = a = b = c = d = e = f = x = y = z = s = s2 = n = m = 0;\
+         #IFNOT;\
          if (obj < 1 || obj > #largest_object-255)\
          {   switch(Z__Region(obj))\
              { 2: if (id == call)\
@@ -324,6 +338,7 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
         default: return x-->m;\
             }\
          }\
+         #ENDIF;\
          rfalse;\
          ]"
     },
@@ -414,7 +429,11 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
              identifier = (identifier & $3f00) / $100;\
              if (~~(obj ofclass cla)) rfalse; i=0-->5;\
              if (cla == 2) return i+2*identifier-2;\
+             #IFV3;\
+             i = (i+60+cla*9)-->0;\
+             #IFNOT;\
              i = 0-->((i+124+cla*14)/2);\
+             #ENDIF;\
              i = CP__Tab(i + 2*(0->i) + 1, -1)+6;\
              return CP__Tab(i, identifier);\
          }\
@@ -435,16 +454,23 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
     },
     {
         /*  RL__Pr:  read the property length of an individual property value,
-                     returning 0 if it isn't provided by the given object    */
+                     returning 0 if it isn't provided by the given object.
+                     This is also used for inherited values (of the form
+                     class::prop). */
 
         "RL__Pr",
         "obj identifier x;\
          if (identifier<64 && identifier>0) return obj.#identifier;\
          x = obj..&identifier;\
          if (x==0) rfalse;\
-         if (identifier&$C000==$4000)\
+         if (identifier&$C000==$4000) {\
+             #IFV3;\
+             return 1+((x-1)->0)/$20;\
+             #IFNOT;\
              switch (((x-1)->0)&$C0)\
              {  0: return 1;  $40: return 2;  $80: return ((x-1)->0)&$3F; }\
+             #ENDIF;\
+         }\
          return (x-1)->0;\
          ]", "", "", "", "", ""
     },
@@ -580,8 +606,13 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
          \" in the\"; switch(size&7){0,1:q=0; 2:print \" string\";\
          q=1; 3:print \" table\";q=1; 4:print \" buffer\";q=WORDSIZE;} \
          if(size&16) print\" (->)\"; if(size&8) print\" (-->)\";\
+         #IFDEF OMIT_SYMBOL_TABLE;\
+         \" array which has entries \", q, \" up to \",id,\" **]\";\
+         #IFNOT;\
          \" array ~\", (string) #array_names_offset-->p,\
-         \"~, which has entries \", q, \" up to \",id,\" **]\"; }\
+         \"~, which has entries \", q, \" up to \",id,\" **]\";\
+         #ENDIF;\
+         }\
          if (crime >= 24 && crime <=27) { if (crime<=25) print \"read\";\
          else print \"write\"; print \" outside memory using \";\
          switch(crime) { 24,26:\"-> **]\"; 25,27:\"--> **]\"; } }\
@@ -615,10 +646,12 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
          \", but it is longer than 2 bytes so you cannot use ~.~\";\
          else\
          {   print \" has no property \", (property) id;\
+             #IFNDEF OMIT_SYMBOL_TABLE;\
              p = #identifiers_table;\
              size = p-->0;\
              if (id<0 || id>=size)\
                  print \" (and nor has any other object)\";\
+             #ENDIF;\
          }\
          print \" to \", (string) crime, \" **]^\";\
          ]", ""
@@ -684,6 +717,16 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
 
         "CP__Tab",
         "x id n l;\
+         #IFV3;\
+         while (1)\
+         {   n = x->0;\
+             if (n == 0) break;\
+             x++;\
+             if (id == (n & $1f)) return x;\
+             l = (n/$20)+1;\
+             x = x + l;\
+         }\
+         #IFNOT;\
          while ((n=0->x) ~= 0)\
          {   if (n & $80) { x++; l = (0->x) & $3f; }\
              else { if (n & $40) l=2; else l=1; }\
@@ -691,12 +734,17 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
              if ((n & $3f) == id) return x;\
              x = x + l;\
          }\
+         #ENDIF;\
          if (id<0) return x+1; rfalse; ]", "", "", "", "", ""
     },
     {   /*  Cl__Ms:   the five message-receiving properties of Classes       */
 
         "Cl__Ms",
         "obj id y a b c d x;\
+         #IFV3;\
+         #Message error \"Class messages are not supported in v3.\";\
+         obj = id = y = a = b = c = d = x = 0;\
+         #IFNOT;\
          switch(id)\
          {   create:\
                  if (children(obj)<=1) rfalse; x=child(obj);\
@@ -727,6 +775,7 @@ static VeneerRoutine VRs_z[VENEER_ROUTINES] =
                  { RT__Err(\"copy\", b, -obj); rfalse; }\
                  Copy__Primitive(a, b); rfalse;\
          }\
+         #ENDIF;\
          ]", "", "", ""
     },
     {   /*  RT__ChT:  check at run-time that a proposed object move is legal
@@ -983,6 +1032,10 @@ static VeneerRoutine VRs_g[VENEER_ROUTINES] =
              print (name) cla, \"::\";\
              @ushiftr prop 16 prop;\
            }\
+           #IFDEF OMIT_SYMBOL_TABLE;\
+           ptab = maxcom = minind = maxind = str = 0;\
+           print \"<number \", prop, \">\";\
+           #IFNOT;\
            ptab = #identifiers_table;\
            maxcom = ptab-->1;\
            minind = INDIV_PROP_START;\
@@ -998,6 +1051,7 @@ static VeneerRoutine VRs_g[VENEER_ROUTINES] =
              print (string) str;\
            else\
              print \"<number \", prop, \">\";\
+           #ENDIF;\
          ]", "", "", "", "", ""
     },
 
@@ -1426,8 +1480,13 @@ static VeneerRoutine VRs_g[VENEER_ROUTINES] =
          \" in the\"; switch(size&7){0,1:q=0; 2:print \" string\";\
          q=1; 3:print \" table\";q=1; 4:print \" buffer\";q=WORDSIZE;} \
          if(size&16) print\" (->)\"; if(size&8) print\" (-->)\";\
+         #IFDEF OMIT_SYMBOL_TABLE;\
+         \" array which has entries \", q, \" up to \",id,\" **]\";\
+         #IFNOT;\
          \" array ~\", (string) #array_names_offset-->(p+1),\
-         \"~, which has entries \", q, \" up to \",id,\" **]\"; }\
+         \"~, which has entries \", q, \" up to \",id,\" **]\";\
+         #ENDIF;\
+         }\
          if (crime >= 24 && crime <=27) { if (crime<=25) print \"read\";\
          else print \"write\"; print \" outside memory using \";\
          switch(crime) { 24,26:\"-> **]\"; 25,27:\"--> **]\"; } }\
@@ -1459,10 +1518,12 @@ static VeneerRoutine VRs_g[VENEER_ROUTINES] =
          if (id<0) print \"is not of class \", (name) -id;",
         "else\
          {   print \" has no property \", (property) id;\
+             #IFNDEF OMIT_SYMBOL_TABLE;\
              p = #identifiers_table;\
              size = INDIV_PROP_START + p-->3;\
              if (id<0 || id>=size)\
                  print \" (and nor has any other object)\";\
+             #ENDIF;\
          }\
          print \" to \", (string) crime, \" **]^\";\
          ]", ""
@@ -2183,28 +2244,43 @@ extern assembly_operand veneer_routine(int code)
     return(AO);
 }
 
+extern char *veneer_routine_name(int code)
+{
+    if (code < 0 || code >= VENEER_ROUTINES) {
+        return "???";
+    }
+    if (!glulx_mode) {
+        return VRs_z[code].name;
+    }
+    else {
+        return VRs_g[code].name;
+    }
+}
+
 static void compile_symbol_table_routine(void)
 {   int32 j, nl, arrays_l, routines_l, constants_l;
     assembly_operand AO, AO2, AO3;
 
+    clear_local_variables();
     /* Assign local var names for the benefit of the debugging information 
-       file. */
-    local_variable_texts[0] = "dummy1";
-    local_variable_texts[1] = "dummy2";
+       file. (We don't set local_variable.keywords because we're not
+       going to be parsing any code.) */
+    add_local_variable("dummy1");
+    add_local_variable("dummy2");
 
-    veneer_mode = TRUE; j = symbol_index("Symb__Tab", -1);
+    veneer_mode = TRUE; j = symbol_index("Symb__Tab", -1, NULL);
     assign_symbol(j,
-        assemble_routine_header(2, FALSE, "Symb__Tab", FALSE, j),
+        assemble_routine_header(FALSE, "Symb__Tab", FALSE, j),
         ROUTINE_T);
-    sflags[j] |= SYSTEM_SFLAG + USED_SFLAG;
-    if (trace_fns_setting==3) sflags[j] |= STAR_SFLAG;
+    symbols[j].flags |= SYSTEM_SFLAG + USED_SFLAG;
+    if (trace_fns_setting==3) symbols[j].flags |= STAR_SFLAG;
 
   if (!glulx_mode) {
 
     if (define_INFIX_switch == FALSE)
     {   assemblez_0(rfalse_zc);
-        variable_usage[1] = TRUE;
-        variable_usage[2] = TRUE;
+        variables[1].usage = TRUE;
+        variables[2].usage = TRUE;
         assemble_routine_end(FALSE, null_debug_locations);
         veneer_mode = FALSE;
         return;
@@ -2239,16 +2315,16 @@ static void compile_symbol_table_routine(void)
             nl = next_label++;
             sequence_point_follows = FALSE;
             assemblez_2_branch(je_zc, AO, AO2, nl, FALSE);
-            AO3.value = array_sizes[j];
+            AO3.value = arrays[j].size;
             AO3.marker = 0;
             assemblez_store(temp_var2, AO3);
-            AO3.value = array_types[j];
-            if (sflags[array_symbols[j]] & (INSF_SFLAG+SYSTEM_SFLAG))
+            AO3.value = arrays[j].type;
+            if (symbols[arrays[j].symbol].flags & (INSF_SFLAG+SYSTEM_SFLAG))
                 AO3.value = AO3.value + 16;
             AO3.marker = 0;
             assemblez_store(temp_var3, AO3);
-            AO3.value = svals[array_symbols[j]];
-            AO3.marker = (!array_locs[j] ? ARRAY_MV : STATIC_ARRAY_MV);
+            AO3.value = symbols[arrays[j].symbol].value;
+            AO3.marker = (!arrays[j].loc ? ARRAY_MV : STATIC_ARRAY_MV);
             assemblez_1(ret_zc, AO3);
             assemble_label_no(nl);
         }
@@ -2264,11 +2340,11 @@ static void compile_symbol_table_routine(void)
         sequence_point_follows = FALSE;
         assemblez_2_branch(je_zc, AO, AO2, nl, FALSE);
         AO3.value = 0;
-        if (sflags[named_routine_symbols[j]]
+        if (symbols[named_routine_symbols[j]].flags
             & (INSF_SFLAG+SYSTEM_SFLAG)) AO3.value = 16;
         AO3.marker = 0;
         assemblez_store(temp_var3, AO3);
-        AO3.value = svals[named_routine_symbols[j]];
+        AO3.value = symbols[named_routine_symbols[j]].value;
         AO3.marker = IROUTINE_MV;
         assemblez_1(ret_zc, AO3);
         assemble_label_no(nl);
@@ -2278,9 +2354,9 @@ static void compile_symbol_table_routine(void)
 
     assemble_label_no(constants_l);
     for (j=0, no_named_constants=0; j<no_symbols; j++)
-    {   if (((stypes[j] == OBJECT_T) || (stypes[j] == CLASS_T)
-            || (stypes[j] == CONSTANT_T))
-            && ((sflags[j] & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
+    {   if (((symbols[j].type == OBJECT_T) || (symbols[j].type == CLASS_T)
+            || (symbols[j].type == CONSTANT_T))
+            && ((symbols[j].flags & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
         {   AO2.value = no_named_constants++;
             if (AO2.value<256) AO2.type = SHORT_CONSTANT_OT;
             else AO2.type = LONG_CONSTANT_OT;
@@ -2288,9 +2364,9 @@ static void compile_symbol_table_routine(void)
             sequence_point_follows = FALSE;
             assemblez_2_branch(je_zc, AO, AO2, nl, FALSE);
             AO3.value = 0;
-            if (stypes[j] == OBJECT_T) AO3.value = 2;
-            if (stypes[j] == CLASS_T) AO3.value = 1;
-            if (sflags[j] & (INSF_SFLAG+SYSTEM_SFLAG))
+            if (symbols[j].type == OBJECT_T) AO3.value = 2;
+            if (symbols[j].type == CLASS_T) AO3.value = 1;
+            if (symbols[j].flags & (INSF_SFLAG+SYSTEM_SFLAG))
                 AO3.value = AO3.value + 16;
             AO3.marker = 0;
             assemblez_store(temp_var3, AO3);
@@ -2304,8 +2380,8 @@ static void compile_symbol_table_routine(void)
 
     sequence_point_follows = FALSE;
     assemblez_0(rfalse_zc);
-    variable_usage[1] = TRUE;
-    variable_usage[2] = TRUE;
+    variables[1].usage = TRUE;
+    variables[2].usage = TRUE;
     assemble_routine_end(FALSE, null_debug_locations);
     veneer_mode = FALSE;
   }
@@ -2313,8 +2389,8 @@ static void compile_symbol_table_routine(void)
 
     if (define_INFIX_switch == FALSE)
     {   assembleg_1(return_gc, zero_operand);
-        variable_usage[1] = TRUE;
-        variable_usage[2] = TRUE;
+        variables[1].usage = TRUE;
+        variables[2].usage = TRUE;
         assemble_routine_end(FALSE, null_debug_locations);
         veneer_mode = FALSE;
         return;
@@ -2328,8 +2404,6 @@ extern void compile_veneer(void)
 {   int i, j, try_veneer_again;
     VeneerRoutine *VRs; 
 
-    if (module_switch) return;
-
     VRs = (!glulx_mode) ? VRs_z : VRs_g;
 
     /*  Called at the end of the pass to insert as much of the veneer as is
@@ -2348,8 +2422,8 @@ extern void compile_veneer(void)
     {   try_veneer_again = FALSE;
         for (i=0; i<VENEER_ROUTINES; i++)
         {   if (veneer_routine_needs_compilation[i] == VR_CALLED)
-            {   j = symbol_index(VRs[i].name, -1);
-                if (sflags[j] & UNKNOWN_SFLAG)
+            {   j = symbol_index(VRs[i].name, -1, NULL);
+                if (symbols[j].flags & UNKNOWN_SFLAG)
                 {   veneer_mode = TRUE;
                     strcpy(veneer_source_area, VRs[i].source1);
                     strcat(veneer_source_area, VRs[i].source2);
@@ -2362,18 +2436,18 @@ extern void compile_veneer(void)
                             VRs[i].name, TRUE, j),
                         ROUTINE_T);
                     veneer_mode = FALSE;
-                    if (trace_fns_setting==3) sflags[j] |= STAR_SFLAG;
+                    if (trace_fns_setting==3) symbols[j].flags |= STAR_SFLAG;
                 }
                 else
-                {   if (stypes[j] != ROUTINE_T)
+                {   if (symbols[j].type != ROUTINE_T)
                 error_named("The following name is reserved by Inform for its \
 own use as a routine name; you can use it as a routine name yourself (to \
 override the standard definition) but cannot use it for anything else:",
                         VRs[i].name);
                     else
-                        sflags[j] |= USED_SFLAG;
+                        symbols[j].flags |= USED_SFLAG;
                 }
-                veneer_routine_address[i] = svals[j];
+                veneer_routine_address[i] = symbols[j].value;
                 veneer_routine_needs_compilation[i] = VR_COMPILED;
                 try_veneer_again = TRUE;
             }