Update to commit a469d404a7dc4e87e18f367eb4d8e05fc32d20a7
[inform.git] / src / expressp.c
index 5b3c0a714f99104d565625a5450fe06fe8ab0018..0e0cf6f2773002c9b501d693cba43d5b2832ef0e 100644 (file)
@@ -1,8 +1,8 @@
 /* ------------------------------------------------------------------------- */
 /*   "expressp" :  The expression parser                                     */
 /*                                                                           */
-/*   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      */
@@ -65,10 +65,7 @@ static int comma_allowed, arrow_allowed, superclass_allowed,
            array_init_ambiguity, action_ambiguity,
            etoken_count, inserting_token, bracket_level;
 
-extern int *variable_usage;
-
-/* Must be at least as many as keyword_group system_functions (currently 12) */
-int system_function_usage[32];
+int system_function_usage[NUMBER_SYSTEM_FUNCTIONS];
 
 static int get_next_etoken(void)
 {   int v, symbol = 0, mark_symbol_as_used = FALSE,
@@ -86,6 +83,7 @@ static int get_next_etoken(void)
         current_token.value = token_value;
         current_token.type = token_type;
         current_token.marker = 0;
+        current_token.symindex = -1;
         current_token.symtype = 0;
         current_token.symflags = -1;
     }
@@ -93,7 +91,7 @@ static int get_next_etoken(void)
     switch(current_token.type)
     {   case LOCAL_VARIABLE_TT:
             current_token.type = VARIABLE_TT;
-            variable_usage[current_token.value] = TRUE;
+            variables[current_token.value].usage = TRUE;
             break;
 
         case DQ_TT:
@@ -136,15 +134,16 @@ but not used as a value:", unicode);
 
             mark_symbol_as_used = TRUE;
 
-            v = svals[symbol];
+            v = symbols[symbol].value;
 
-            current_token.symtype = stypes[symbol];
-            current_token.symflags = sflags[symbol];
-            switch(stypes[symbol])
+            current_token.symindex = symbol;
+            current_token.symtype = symbols[symbol].type;
+            current_token.symflags = symbols[symbol].flags;
+            switch(symbols[symbol].type)
             {   case ROUTINE_T:
                     /* Replaced functions must always be backpatched
                        because there could be another definition coming. */
-                    if (sflags[symbol] & REPLACE_SFLAG)
+                    if (symbols[symbol].flags & REPLACE_SFLAG)
                     {   current_token.marker = SYMBOL_MV;
                         if (module_switch) import_symbol(symbol);
                         v = symbol;
@@ -171,7 +170,7 @@ but not used as a value:", unicode);
                     if (module_switch) current_token.marker = IDENT_MV;
                     break;
                 case CONSTANT_T:
-                    if (sflags[symbol] & (UNKNOWN_SFLAG + CHANGE_SFLAG))
+                    if (symbols[symbol].flags & (UNKNOWN_SFLAG + CHANGE_SFLAG))
                     {   current_token.marker = SYMBOL_MV;
                         if (module_switch) import_symbol(symbol);
                         v = symbol;
@@ -185,7 +184,7 @@ but not used as a value:", unicode);
                     current_token.marker = 0;
                     break;
             }
-            if (sflags[symbol] & SYSTEM_SFLAG)
+            if (symbols[symbol].flags & SYSTEM_SFLAG)
                 current_token.marker = 0;
 
             current_token.value = v;
@@ -205,9 +204,9 @@ but not used as a value:", unicode);
                 else current_token.type = SMALL_NUMBER_TT;
             }
 
-            if (stypes[symbol] == GLOBAL_VARIABLE_T)
+            if (symbols[symbol].type == GLOBAL_VARIABLE_T)
             {   current_token.type = VARIABLE_TT;
-                variable_usage[current_token.value] = TRUE;
+                variables[current_token.value].usage = TRUE;
             }
             break;
 
@@ -329,7 +328,7 @@ but not used as a value:", unicode);
                     current_token.text += 3;
                     current_token.type = SYMBOL_TT;
                     symbol = symbol_index(current_token.text, -1);
-                    if (stypes[symbol] != GLOBAL_VARIABLE_T) {
+                    if (symbols[symbol].type != GLOBAL_VARIABLE_T) {
                         ebf_error(
                         "global variable name after '#g$'",
                         current_token.text);
@@ -339,7 +338,7 @@ but not used as a value:", unicode);
                         break;
                     }
                     mark_symbol_as_used = TRUE;
-                    current_token.value = svals[symbol] - MAX_LOCAL_VARIABLES;
+                    current_token.value = symbols[symbol].value - MAX_LOCAL_VARIABLES;
                     current_token.marker = 0;
                     if (!glulx_mode) {
                         if (current_token.value >= 0x100)
@@ -439,7 +438,7 @@ but not used as a value:", unicode);
     if (token_type_allowable[current_token.type]==0)
     {   if (expr_trace_level >= 3)
         {   printf("Discarding as not allowable: '%s' ", current_token.text);
-            describe_token(current_token);
+            describe_token(&current_token);
             printf("\n");
         }
         current_token.type = ENDEXP_TT;
@@ -454,16 +453,16 @@ but not used as a value:", unicode);
             || (operators[current_token.value].usage == PRE_U)))
     {   if (expr_trace_level >= 3)
         {   printf("Discarding as no longer part: '%s' ", current_token.text);
-            describe_token(current_token);
+            describe_token(&current_token);
             printf("\n");
         }
         current_token.type = ENDEXP_TT;
     }
     else
-    {   if (mark_symbol_as_used) sflags[symbol] |= USED_SFLAG;
+    {   if (mark_symbol_as_used) symbols[symbol].flags |= USED_SFLAG;
         if (expr_trace_level >= 3)
         {   printf("Expr token = '%s' ", current_token.text);
-            describe_token(current_token);
+            describe_token(&current_token);
             printf("\n");
         }
     }
@@ -500,7 +499,7 @@ const int prec_table[] = {
 
 };
 
-static int find_prec(token_data a, token_data b)
+static int find_prec(const token_data *a, const token_data *b)
 {
     /*  We are comparing the precedence of tokens  a  and  b
         (where a occurs to the left of b).  If the expression is correct,
@@ -518,14 +517,14 @@ static int find_prec(token_data a, token_data b)
 
     int i, j, l1, l2;
 
-    switch(a.type)
+    switch(a->type)
     {   case SUBOPEN_TT:  i=0; break;
         case SUBCLOSE_TT: i=1; break;
         case ENDEXP_TT:   i=2; break;
         case OP_TT:       i=3; break;
         default:          i=4; break;
     }
-    switch(b.type)
+    switch(b->type)
     {   case SUBOPEN_TT:  i+=0; break;
         case SUBCLOSE_TT: i+=5; break;
         case ENDEXP_TT:   i+=10; break;
@@ -535,10 +534,10 @@ static int find_prec(token_data a, token_data b)
 
     j = prec_table[i]; if (j != -1) return j;
 
-    l1 = operators[a.value].precedence;
-    l2 = operators[b.value].precedence;
-    if (operators[b.value].usage == PRE_U) return LOWER_P;
-    if (operators[a.value].usage == POST_U) return GREATER_P;
+    l1 = operators[a->value].precedence;
+    l2 = operators[b->value].precedence;
+    if (operators[b->value].usage == PRE_U) return LOWER_P;
+    if (operators[a->value].usage == POST_U) return GREATER_P;
 
     /*  Anomalous rule to resolve the function call precedence, which is
         different on the right from on the left, e.g., in:
@@ -551,7 +550,7 @@ static int find_prec(token_data a, token_data b)
 
     if (l1 < l2)  return LOWER_P;
     if (l1 > l2)  return GREATER_P;
-    switch(operators[a.value].associativity)
+    switch(operators[a->value].associativity)
     {   case L_A: return GREATER_P;
         case R_A: return LOWER_P;
         case 0:   return e5;
@@ -561,7 +560,8 @@ static int find_prec(token_data a, token_data b)
 
 /* --- Converting token to operand ----------------------------------------- */
 
-/* Must match the switch statement below */
+/* List used to generate gameinfo.dbg.
+   Must match the switch statement below. */
 int z_system_constant_list[] =
     { adjectives_table_SC,
       actions_table_SC,
@@ -605,6 +605,8 @@ int z_system_constant_list[] =
       highest_class_number_SC,
       class_objects_array_SC,
       highest_object_number_SC,
+      dictionary_table_SC,
+      grammar_table_SC,
       -1 };
 
 static int32 value_of_system_constant_z(int t)
@@ -642,9 +644,13 @@ static int32 value_of_system_constant_z(int t)
         case ipv__end_SC:
             return variables_offset;
         case array__start_SC:
-            return variables_offset + (MAX_GLOBAL_VARIABLES*WORDSIZE);
+            return variables_offset + (MAX_ZCODE_GLOBAL_VARS*WORDSIZE);
         case array__end_SC:
             return static_memory_offset;
+        case dictionary_table_SC:
+            return dictionary_offset;
+        case grammar_table_SC:
+            return static_memory_offset;
 
         case highest_attribute_number_SC:
             return no_attributes-1;
@@ -706,7 +712,8 @@ static int32 value_of_system_constant_z(int t)
     return(0);
 }
 
-/* Must match the switch statement below */
+/* List used to generate gameinfo.dbg.
+   Must match the switch statement below. */
 int glulx_system_constant_list[] =
     { classes_table_SC,
       identifiers_table_SC,
@@ -765,7 +772,15 @@ extern int32 value_of_system_constant(int t)
     return value_of_system_constant_g(t);    
 }
 
-static int evaluate_term(token_data t, assembly_operand *o)
+extern char *name_of_system_constant(int t)
+{
+  if (t < 0 || t >= NO_SYSTEM_CONSTANTS) {
+    return "???";
+  }
+  return system_constants.keywords[t];
+}
+
+static int evaluate_term(const token_data *t, assembly_operand *o)
 {
     /*  If the given token is a constant, evaluate it into the operand.
         For now, the identifiers are considered variables.
@@ -774,13 +789,12 @@ static int evaluate_term(token_data t, assembly_operand *o)
 
     int32 v;
 
-    o->marker = t.marker;
-    o->symtype = t.symtype;
-    o->symflags = t.symflags;
+    o->marker = t->marker;
+    o->symindex = t->symindex;
 
-    switch(t.type)
+    switch(t->type)
     {   case LARGE_NUMBER_TT:
-             v = t.value;
+             v = t->value;
              if (!glulx_mode) {
                  if (v < 0) v = v + 0x10000;
                  o->type = LONG_CONSTANT_OT;
@@ -792,7 +806,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
              }
              return(TRUE);
         case SMALL_NUMBER_TT:
-             v = t.value;
+             v = t->value;
              if (!glulx_mode) {
                  if (v < 0) v = v + 0x10000;
                  o->type = SHORT_CONSTANT_OT;
@@ -809,7 +823,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
                  o->type = LONG_CONSTANT_OT;
              else
                  o->type = CONSTANT_OT;
-             o->value = dictionary_add(t.text, 0x80, 0, 0);
+             o->value = dictionary_add(t->text, 0x80, 0, 0);
              return(TRUE);
         case DQ_TT:
              /*  Create as a static string  */
@@ -817,14 +831,14 @@ static int evaluate_term(token_data t, assembly_operand *o)
                  o->type = LONG_CONSTANT_OT;
              else
                  o->type = CONSTANT_OT;
-             o->value = compile_string(t.text, STRCTX_GAME);
+             o->value = compile_string(t->text, STRCTX_GAME);
              return(TRUE);
         case VARIABLE_TT:
              if (!glulx_mode) {
                  o->type = VARIABLE_OT;
              }
              else {
-                 if (t.value >= MAX_LOCAL_VARIABLES) {
+                 if (t->value >= MAX_LOCAL_VARIABLES) {
                      o->type = GLOBALVAR_OT;
                  }
                  else {
@@ -833,21 +847,21 @@ static int evaluate_term(token_data t, assembly_operand *o)
                      o->type = LOCALVAR_OT;
                  }
              }
-             o->value = t.value;
+             o->value = t->value;
              return(TRUE);
         case SYSFUN_TT:
              if (!glulx_mode) {
                  o->type = VARIABLE_OT;
-                 o->value = t.value + 256;
+                 o->value = t->value + 256;
              }
              else {
                  o->type = SYSFUN_OT;
-                 o->value = t.value;
+                 o->value = t->value;
              }
-             system_function_usage[t.value] = 1;
+             system_function_usage[t->value] = 1;
              return(TRUE);
         case ACTION_TT:
-             *o = action_of_name(t.text);
+             *o = action_of_name(t->text);
              return(TRUE);
         case SYSTEM_CONSTANT_TT:
              /*  Certain system constants depend only on the
@@ -856,7 +870,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
                  them immediately.  */
              if (!glulx_mode) {
                  o->type = LONG_CONSTANT_OT;
-                 switch(t.value)
+                 switch(t->value)
                  {   
                  case version_number_SC:
                      o->type = SHORT_CONSTANT_OT;
@@ -873,6 +887,8 @@ static int evaluate_term(token_data t, assembly_operand *o)
                  case dict_par3_SC:
                      o->type = SHORT_CONSTANT_OT;
                      o->marker = 0;
+                     if (ZCODE_LESS_DICT_DATA)
+                         error("#dict_par3 is unavailable when ZCODE_LESS_DICT_DATA is set");
                      v = (version_number==3)?6:8; break;
                  case lowest_attribute_number_SC:
                  case lowest_action_number_SC:
@@ -893,7 +909,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
                      o->type = SHORT_CONSTANT_OT; o->marker = 0;
                      v = oddeven_packing_switch; break;
                  default:
-                     v = t.value;
+                     v = t->value;
                      o->marker = INCON_MV;
                      break;
                  }
@@ -901,7 +917,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
              }
              else {
                  o->type = CONSTANT_OT;
-                 switch(t.value)
+                 switch(t->value)
                  {
                  /* The three dict_par flags point at the lower byte
                     of the flag field, because the library is written
@@ -943,7 +959,7 @@ static int evaluate_term(token_data t, assembly_operand *o)
                  /* ###fix: need to fill more of these in! */
 
                  default:
-                     v = t.value;
+                     v = t->value;
                      o->marker = INCON_MV;
                      break;
                  }
@@ -957,35 +973,40 @@ static int evaluate_term(token_data t, assembly_operand *o)
 
 /* --- Emitter ------------------------------------------------------------- */
 
-expression_tree_node *ET;
+expression_tree_node *ET; /* Allocated to ET_used */
+static memory_list ET_memlist;
 static int ET_used;
 
 extern void clear_expression_space(void)
 {   ET_used = 0;
 }
 
-static assembly_operand *emitter_stack;
-static int *emitter_markers;
-static int *emitter_bracket_counts;
+typedef struct emitterstackinfo_s {
+    assembly_operand op;
+    int marker;
+    int bracket_count;
+} emitterstackinfo;
 
 #define FUNCTION_VALUE_MARKER 1
 #define ARGUMENT_VALUE_MARKER 2
 #define OR_VALUE_MARKER 3
 
+static emitterstackinfo *emitter_stack; /* Allocated to emitter_sp */
+static memory_list emitter_stack_memlist;
 static int emitter_sp;
 
 static int is_property_t(int symbol_type)
 {   return ((symbol_type == PROPERTY_T) || (symbol_type == INDIVIDUAL_PROPERTY_T));
 }
 
-static void mark_top_of_emitter_stack(int marker, token_data t)
+static void mark_top_of_emitter_stack(int marker, const token_data *t)
 {   if (emitter_sp < 1)
     {   compiler_error("SR error: Attempt to add a marker to the top of an empty emitter stack");
         return;
     }
     if (expr_trace_level >= 2)
     {   printf("Marking top of emitter stack (which is ");
-        print_operand(emitter_stack[emitter_sp-1]);
+        print_operand(&emitter_stack[emitter_sp-1].op, FALSE);
         printf(") as ");
         switch(marker)
         {
@@ -1004,21 +1025,20 @@ static void mark_top_of_emitter_stack(int marker, token_data t)
         }
         printf("\n");
     }
-    if (emitter_markers[emitter_sp-1])
+    if (emitter_stack[emitter_sp-1].marker)
     {   if (marker == ARGUMENT_VALUE_MARKER)
         {
             warning("Ignoring spurious leading comma");
             return;
         }
-        error_named("Missing operand for", t.text);
-        if (emitter_sp == MAX_EXPRESSION_NODES)
-            memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
-        emitter_markers[emitter_sp] = 0;
-        emitter_bracket_counts[emitter_sp] = 0;
-        emitter_stack[emitter_sp] = zero_operand;
+        error_named("Missing operand for", t->text);
+        ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+        emitter_stack[emitter_sp].marker = 0;
+        emitter_stack[emitter_sp].bracket_count = 0;
+        emitter_stack[emitter_sp].op = zero_operand;
         emitter_sp++;
     }
-    emitter_markers[emitter_sp-1] = marker;
+    emitter_stack[emitter_sp-1].marker = marker;
 }
 
 static void add_bracket_layer_to_emitter_stack(int depth)
@@ -1026,7 +1046,7 @@ static void add_bracket_layer_to_emitter_stack(int depth)
     if (emitter_sp < depth + 1) return;
     if (expr_trace_level >= 2)
         printf("Adding bracket layer\n");
-    ++emitter_bracket_counts[emitter_sp-depth-1];
+    ++emitter_stack[emitter_sp-depth-1].bracket_count;
 }
 
 static void remove_bracket_layer_from_emitter_stack()
@@ -1034,46 +1054,47 @@ static void remove_bracket_layer_from_emitter_stack()
     if (emitter_sp < 2) return;
     if (expr_trace_level >= 2)
         printf("Removing bracket layer\n");
-    if (emitter_bracket_counts[emitter_sp-2] <= 0)
+    if (emitter_stack[emitter_sp-2].bracket_count <= 0)
     {   compiler_error("SR error: Attempt to remove a nonexistent bracket layer from the emitter stack");
         return;
     }
-    --emitter_bracket_counts[emitter_sp-2];
+    --emitter_stack[emitter_sp-2].bracket_count;
 }
 
-static void emit_token(token_data t)
+static void emit_token(const token_data *t)
 {   assembly_operand o1, o2; int arity, stack_size, i;
     int op_node_number, operand_node_number, previous_node_number;
     int32 x = 0;
 
     if (expr_trace_level >= 2)
-    {   printf("Output: %-19s%21s ", t.text, "");
+    {   printf("Output: %-19s%21s ", t->text, "");
         for (i=0; i<emitter_sp; i++)
-        {   print_operand(emitter_stack[i]); printf(" ");
-            if (emitter_markers[i] == FUNCTION_VALUE_MARKER) printf(":FUNCTION ");
-            if (emitter_markers[i] == ARGUMENT_VALUE_MARKER) printf(":ARGUMENT ");
-            if (emitter_markers[i] == OR_VALUE_MARKER) printf(":OR ");
-            if (emitter_bracket_counts[i]) printf(":BRACKETS(%d) ", emitter_bracket_counts[i]);
+        {   print_operand(&emitter_stack[i].op, FALSE); printf(" ");
+            if (emitter_stack[i].marker == FUNCTION_VALUE_MARKER) printf(":FUNCTION ");
+            if (emitter_stack[i].marker == ARGUMENT_VALUE_MARKER) printf(":ARGUMENT ");
+            if (emitter_stack[i].marker == OR_VALUE_MARKER) printf(":OR ");
+            if (emitter_stack[i].bracket_count) printf(":BRACKETS(%d) ", emitter_stack[i].bracket_count);
         }
         printf("\n");
     }
 
-    if (t.type == SUBOPEN_TT) return;
+    if (t->type == SUBOPEN_TT) return;
 
     stack_size = 0;
     while ((stack_size < emitter_sp) &&
-           !emitter_markers[emitter_sp-stack_size-1] &&
-           !emitter_bracket_counts[emitter_sp-stack_size-1])
+           !emitter_stack[emitter_sp-stack_size-1].marker &&
+           !emitter_stack[emitter_sp-stack_size-1].bracket_count)
         stack_size++;
 
-    if (t.type == SUBCLOSE_TT)
-    {   if (stack_size < emitter_sp && emitter_bracket_counts[emitter_sp-stack_size-1])
+    if (t->type == SUBCLOSE_TT)
+    {   if (stack_size < emitter_sp && emitter_stack[emitter_sp-stack_size-1].bracket_count)
         {   if (stack_size == 0)
             {   error("No expression between brackets '(' and ')'");
-                emitter_stack[emitter_sp] = zero_operand;
-                emitter_markers[emitter_sp] = 0;
-                emitter_bracket_counts[emitter_sp] = 0;
-                ++emitter_sp;
+                ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+                emitter_stack[emitter_sp].op = zero_operand;
+                emitter_stack[emitter_sp].marker = 0;
+                emitter_stack[emitter_sp].bracket_count = 0;
+                emitter_sp++;
             }
             else if (stack_size < 1)
                 compiler_error("SR error: emitter stack empty in subexpression");
@@ -1084,14 +1105,14 @@ static void emit_token(token_data t)
         return;
     }
 
-    if (t.type != OP_TT)
-    {   emitter_markers[emitter_sp] = 0;
-        emitter_bracket_counts[emitter_sp] = 0;
+    if (t->type != OP_TT)
+    {
+        ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+        emitter_stack[emitter_sp].marker = 0;
+        emitter_stack[emitter_sp].bracket_count = 0;
 
-        if (emitter_sp == MAX_EXPRESSION_NODES)
-            memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
-        if (!evaluate_term(t, &(emitter_stack[emitter_sp++])))
-            compiler_error_named("Emit token error:", t.text);
+        if (!evaluate_term(t, &(emitter_stack[emitter_sp++].op)))
+            compiler_error_named("Emit token error:", t->text);
         return;
     }
 
@@ -1099,85 +1120,85 @@ static void emit_token(token_data t)
        call, since we ignore spurious leading commas in function argument lists)
        with no intervening brackets.  Function calls are variadic, so we don't
        apply argument-separating commas. */
-    if (t.value == COMMA_OP &&
+    if (t->value == COMMA_OP &&
         stack_size < emitter_sp &&
-        (emitter_markers[emitter_sp-stack_size-1] == ARGUMENT_VALUE_MARKER ||
-         emitter_markers[emitter_sp-stack_size-1] == FUNCTION_VALUE_MARKER) &&
-        !emitter_bracket_counts[emitter_sp-stack_size-1])
+        (emitter_stack[emitter_sp-stack_size-1].marker == ARGUMENT_VALUE_MARKER ||
+         emitter_stack[emitter_sp-stack_size-1].marker == FUNCTION_VALUE_MARKER) &&
+        !emitter_stack[emitter_sp-stack_size-1].bracket_count)
     {   if (expr_trace_level >= 2)
             printf("Treating comma as argument-separating\n");
         return;
     }
 
-    if (t.value == OR_OP)
+    if (t->value == OR_OP)
         return;
 
     arity = 1;
-    if (t.value == FCALL_OP)
+    if (t->value == FCALL_OP)
     {   if (expr_trace_level >= 3)
         {   printf("FCALL_OP finds marker stack: ");
-            for (x=0; x<emitter_sp; x++) printf("%d ", emitter_markers[x]);
+            for (x=0; x<emitter_sp; x++) printf("%d ", emitter_stack[x].marker);
             printf("\n");
         }
-        if (emitter_markers[emitter_sp-1] == ARGUMENT_VALUE_MARKER)
+        if (emitter_stack[emitter_sp-1].marker == ARGUMENT_VALUE_MARKER)
             warning("Ignoring spurious trailing comma");
-        while (emitter_markers[emitter_sp-arity] != FUNCTION_VALUE_MARKER)
+        while (emitter_stack[emitter_sp-arity].marker != FUNCTION_VALUE_MARKER)
         {
             if ((glulx_mode &&
-                 emitter_stack[emitter_sp-arity].type == SYSFUN_OT) ||
+                 emitter_stack[emitter_sp-arity].op.type == SYSFUN_OT) ||
                 (!glulx_mode &&
-                 emitter_stack[emitter_sp-arity].type == VARIABLE_OT &&
-                 emitter_stack[emitter_sp-arity].value >= 256 &&
-                 emitter_stack[emitter_sp-arity].value < 288))
-            {   int index = emitter_stack[emitter_sp-arity].value;
+                 emitter_stack[emitter_sp-arity].op.type == VARIABLE_OT &&
+                 emitter_stack[emitter_sp-arity].op.value >= 256 &&
+                 emitter_stack[emitter_sp-arity].op.value < 288))
+            {   int index = emitter_stack[emitter_sp-arity].op.value;
                 if(!glulx_mode)
                     index -= 256;
                 if(index >= 0 && index < NUMBER_SYSTEM_FUNCTIONS)
                     error_named("System function name used as a value:", system_functions.keywords[index]);
                 else
                     compiler_error("Found unnamed system function used as a value");
-                emitter_stack[emitter_sp-arity] = zero_operand;
+                emitter_stack[emitter_sp-arity].op = zero_operand;
             }
             ++arity;
         }
     }
     else
     {   arity = 1;
-        if (operators[t.value].usage == IN_U) arity = 2;
+        if (operators[t->value].usage == IN_U) arity = 2;
 
-        if (operators[t.value].precedence == 3)
+        if (operators[t->value].precedence == 3)
         {   arity = 2;
             x = emitter_sp-1;
-            if(!emitter_markers[x] && !emitter_bracket_counts[x])
-            {   for (--x; emitter_markers[x] == OR_VALUE_MARKER && !emitter_bracket_counts[x]; --x)
+            if(!emitter_stack[x].marker && !emitter_stack[x].bracket_count)
+            {   for (--x; emitter_stack[x].marker == OR_VALUE_MARKER && !emitter_stack[x].bracket_count; --x)
                 {   ++arity;
                     ++stack_size;
                 }
-                for (;x >= 0 && !emitter_markers[x] && !emitter_bracket_counts[x]; --x)
+                for (;x >= 0 && !emitter_stack[x].marker && !emitter_stack[x].bracket_count; --x)
                     ++stack_size;
             }
         }
 
         if (arity > stack_size)
-        {   error_named("Missing operand for", t.text);
+        {   error_named("Missing operand for", t->text);
             while (arity > stack_size)
-            {   if (emitter_sp == MAX_EXPRESSION_NODES)
-                    memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
-                emitter_markers[emitter_sp] = 0;
-                emitter_bracket_counts[emitter_sp] = 0;
-                emitter_stack[emitter_sp] = zero_operand;
+            {   ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+                emitter_stack[emitter_sp].marker = 0;
+                emitter_stack[emitter_sp].bracket_count = 0;
+                emitter_stack[emitter_sp].op = zero_operand;
                 emitter_sp++;
                 stack_size++;
             }
         }
     }
 
-    /* pseudo-typecheck in 6.30 */
+    /* pseudo-typecheck in 6.30: catch an unqualified property name */
     for (i = 1; i <= arity; i++)
     {
-        o1 = emitter_stack[emitter_sp - i];
-        if (is_property_t(o1.symtype) ) {
-            switch(t.value) 
+        o1 = emitter_stack[emitter_sp - i].op;
+        if ((o1.symindex >= 0)
+            && is_property_t(symbols[o1.symindex].type)) {
+            switch(t->value) 
             {
                 case FCALL_OP:
                 case SETEQUALS_OP: case NOTEQUAL_OP: 
@@ -1189,7 +1210,11 @@ static void emit_token(token_data t)
                 case PROPERTY_OP:
                     if (i < arity) break;
                 case GE_OP: case LE_OP:
-                    if ((i < arity) && (o1.symflags & STAR_SFLAG)) break;
+                    /* Direction properties "n_to", etc *are* compared
+                       in some libraries. They have STAR_SFLAG to tell us
+                       to skip the warning. */
+                    if ((i < arity)
+                        && (symbols[o1.symindex].flags & STAR_SFLAG)) break;
                 default:
                     warning("Property name in expression is not qualified by object");
             }
@@ -1198,9 +1223,9 @@ static void emit_token(token_data t)
 
     switch(arity)
     {   case 1:
-            o1 = emitter_stack[emitter_sp - 1];
+            o1 = emitter_stack[emitter_sp - 1].op;
             if ((o1.marker == 0) && is_constant_ot(o1.type))
-            {   switch(t.value)
+            {   switch(t->value)
                 {   case UNARY_MINUS_OP: x = -o1.value; goto FoldConstant;
                     case ARTNOT_OP: 
                          if (!glulx_mode)
@@ -1216,8 +1241,8 @@ static void emit_token(token_data t)
             break;
 
         case 2:
-            o1 = emitter_stack[emitter_sp - 2];
-            o2 = emitter_stack[emitter_sp - 1];
+            o1 = emitter_stack[emitter_sp - 2].op;
+            o2 = emitter_stack[emitter_sp - 1].op;
 
             if ((o1.marker == 0) && (o2.marker == 0)
                 && is_constant_ot(o1.type) && is_constant_ot(o2.type))
@@ -1232,7 +1257,7 @@ static void emit_token(token_data t)
                   ov2 = (o2.value >= 0x8000) ? (o2.value - 0x10000) : o2.value;
                 }
 
-                switch(t.value)
+                switch(t->value)
                 {
                     case PLUS_OP: x = ov1 + ov2; goto FoldConstantC;
                     case MINUS_OP: x = ov1 - ov2; goto FoldConstantC;
@@ -1242,7 +1267,7 @@ static void emit_token(token_data t)
                         if (ov2 == 0)
                           error("Division of constant by zero");
                         else
-                        if (t.value == DIVIDE_OP) {
+                        if (t->value == DIVIDE_OP) {
                           if (ov2 < 0) {
                             ov1 = -ov1;
                             ov2 = -ov2;
@@ -1291,13 +1316,32 @@ static void emit_token(token_data t)
                 }
 
             }
+
+            /* We can also fold logical operations if they are certain
+               to short-circuit. The right-hand argument is skipped even
+               if it's non-constant or has side effects. */
+            
+            if ((o1.marker == 0)
+                && is_constant_ot(o1.type)) {
+                
+                if (t->value == LOGAND_OP && o1.value == 0)
+                {
+                    x = 0;
+                    goto FoldConstant;
+                }
+
+                if (t->value == LOGOR_OP && o1.value != 0)
+                {
+                    x = 1;
+                    goto FoldConstant;
+                }
+            }
     }
 
+    ensure_memory_list_available(&ET_memlist, ET_used+1);
     op_node_number = ET_used++;
-    if (op_node_number == MAX_EXPRESSION_NODES)
-        memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
 
-    ET[op_node_number].operator_number = t.value;
+    ET[op_node_number].operator_number = t->value;
     ET[op_node_number].up = -1;
     ET[op_node_number].down = -1;
     ET[op_node_number].right = -1;
@@ -1311,14 +1355,14 @@ static void emit_token(token_data t)
         if (expr_trace_level >= 3)
             printf("i=%d, emitter_sp=%d, arity=%d, ETU=%d\n",
                 i, emitter_sp, arity, ET_used);
-        if (emitter_stack[i].type == EXPRESSION_OT)
-            operand_node_number = emitter_stack[i].value;
+        if (emitter_stack[i].op.type == EXPRESSION_OT)
+            operand_node_number = emitter_stack[i].op.value;
         else
-        {   operand_node_number = ET_used++;
-            if (operand_node_number == MAX_EXPRESSION_NODES)
-                memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
+        {
+            ensure_memory_list_available(&ET_memlist, ET_used+1);
+            operand_node_number = ET_used++;
             ET[operand_node_number].down = -1;
-            ET[operand_node_number].value = emitter_stack[i];
+            ET[operand_node_number].value = emitter_stack[i].op;
         }
         ET[operand_node_number].up = op_node_number;
         ET[operand_node_number].right = -1;
@@ -1333,11 +1377,11 @@ static void emit_token(token_data t)
 
     emitter_sp = emitter_sp - arity + 1;
 
-    emitter_stack[emitter_sp - 1].type = EXPRESSION_OT;
-    emitter_stack[emitter_sp - 1].value = op_node_number;
+    emitter_stack[emitter_sp - 1].op.type = EXPRESSION_OT;
+    emitter_stack[emitter_sp - 1].op.value = op_node_number;
+    emitter_stack[emitter_sp - 1].op.marker = 0;
     emitter_stack[emitter_sp - 1].marker = 0;
-    emitter_markers[emitter_sp - 1] = 0;
-    emitter_bracket_counts[emitter_sp - 1] = 0;
+    emitter_stack[emitter_sp - 1].bracket_count = 0;
     /* Remove the marker for the brackets implied by operator precedence */
     remove_bracket_layer_from_emitter_stack();
 
@@ -1352,7 +1396,7 @@ static void emit_token(token_data t)
     {   char folding_error[40];
         int32 ov1 = (o1.value >= 0x8000) ? (o1.value - 0x10000) : o1.value;
         int32 ov2 = (o2.value >= 0x8000) ? (o2.value - 0x10000) : o2.value;
-        switch(t.value)
+        switch(t->value)
         {
             case PLUS_OP:
                 sprintf(folding_error, "%d + %d = %d", ov1, ov2, x);
@@ -1382,28 +1426,28 @@ the range -32768 to +32767:", folding_error);
 
     if (!glulx_mode) {
         if (x<256)
-            emitter_stack[emitter_sp - 1].type = SHORT_CONSTANT_OT;
-        else emitter_stack[emitter_sp - 1].type = LONG_CONSTANT_OT;
+            emitter_stack[emitter_sp - 1].op.type = SHORT_CONSTANT_OT;
+        else emitter_stack[emitter_sp - 1].op.type = LONG_CONSTANT_OT;
     }
     else {
         if (x == 0)
-            emitter_stack[emitter_sp - 1].type = ZEROCONSTANT_OT;
+            emitter_stack[emitter_sp - 1].op.type = ZEROCONSTANT_OT;
         else if (x >= -128 && x <= 127) 
-            emitter_stack[emitter_sp - 1].type = BYTECONSTANT_OT;
+            emitter_stack[emitter_sp - 1].op.type = BYTECONSTANT_OT;
         else if (x >= -32768 && x <= 32767) 
-            emitter_stack[emitter_sp - 1].type = HALFCONSTANT_OT;
+            emitter_stack[emitter_sp - 1].op.type = HALFCONSTANT_OT;
         else
-            emitter_stack[emitter_sp - 1].type = CONSTANT_OT;
+            emitter_stack[emitter_sp - 1].op.type = CONSTANT_OT;
     }
 
-    emitter_stack[emitter_sp - 1].value = x;
+    emitter_stack[emitter_sp - 1].op.value = x;
+    emitter_stack[emitter_sp - 1].op.marker = 0;
     emitter_stack[emitter_sp - 1].marker = 0;
-    emitter_markers[emitter_sp - 1] = 0;
-    emitter_bracket_counts[emitter_sp - 1] = 0;
+    emitter_stack[emitter_sp - 1].bracket_count = 0;
 
     if (expr_trace_level >= 2)
     {   printf("Folding constant to: ");
-        print_operand(emitter_stack[emitter_sp - 1]);
+        print_operand(&emitter_stack[emitter_sp - 1].op, FALSE);
         printf("\n");
     }
 
@@ -1419,9 +1463,7 @@ static void show_node(int n, int depth, int annotate)
     for (j=0; j<2*depth+2; j++) printf(" ");
 
     if (ET[n].down == -1)
-    {   print_operand(ET[n].value);
-        if (annotate && (ET[n].value.marker != 0))
-            printf(" [%s]", describe_mv(ET[n].value.marker));
+    {   print_operand(&ET[n].value, annotate);
         printf("\n");
     }
     else
@@ -1443,9 +1485,7 @@ static void show_node(int n, int depth, int annotate)
 extern void show_tree(assembly_operand AO, int annotate)
 {   if (AO.type == EXPRESSION_OT) show_node(AO.value, 0, annotate);
     else
-    {   printf("Constant: "); print_operand(AO);
-        if (annotate && (AO.marker != 0))
-            printf(" [%s]", describe_mv(AO.marker));
+    {   printf("Constant: "); print_operand(&AO, annotate);
         printf("\n");
     }
 }
@@ -1624,10 +1664,25 @@ static void delete_negations(int n, int context)
 
         (etc) to delete the ~~ operator from the tree.  Since this is
         depth first, the ~~ being deleted has no ~~s beneath it, which
-        is important to make "negate_condition" work.                        */
+        is important to make "negate_condition" work.
+
+        We also do the check for (x <= y or z) here. This must be done
+        before negate_condition.
+    */
 
     int i;
 
+    if (ET[n].operator_number == LE_OP || ET[n].operator_number == GE_OP) {
+        if (ET[n].down != -1
+            && ET[ET[n].down].right != -1
+            && ET[ET[ET[n].down].right].right != -1) {
+            if (ET[n].operator_number == LE_OP)
+                warning("The behavior of (<= or) may be unexpected.");
+            else
+                warning("The behavior of (>= or) may be unexpected.");
+        }
+    }
+
     if (ET[n].right != -1) delete_negations(ET[n].right, context);
     if (ET[n].down == -1) return;
     delete_negations(ET[n].down, context);
@@ -1654,9 +1709,9 @@ static void insert_exp_to_cond(int n, int context)
 
     if (ET[n].down == -1)
     {   if (context==CONDITION_CONTEXT)
-        {   new = ET_used++;
-            if (new == MAX_EXPRESSION_NODES)
-                memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
+        {
+            ensure_memory_list_available(&ET_memlist, ET_used+1);
+            new = ET_used++;
             ET[new] = ET[n];
             ET[n].down = new; ET[n].operator_number = NONZERO_OP;
             ET[new].up = n; ET[new].right = -1;
@@ -1677,9 +1732,8 @@ static void insert_exp_to_cond(int n, int context)
         default:
             if (context != CONDITION_CONTEXT) break;
 
+            ensure_memory_list_available(&ET_memlist, ET_used+1);
             new = ET_used++;
-            if (new == MAX_EXPRESSION_NODES)
-                memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
             ET[new] = ET[n];
             ET[n].down = new; ET[n].operator_number = NONZERO_OP;
             ET[new].up = n; ET[new].right = -1;
@@ -1736,9 +1790,8 @@ static void func_args_on_stack(int n, int context)
               || ET[fnaddr].value.value == INDIRECT_SYSF
               || ET[fnaddr].value.value == GLK_SYSF))) {
         if (etoken_num_children(pn) > (unsigned int)(opnum == FCALL_OP ? 4:3)) {
+          ensure_memory_list_available(&ET_memlist, ET_used+1);
           new = ET_used++;
-          if (new == MAX_EXPRESSION_NODES)
-            memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
           ET[new] = ET[n];
           ET[n].down = new; 
           ET[n].operator_number = PUSH_OP;
@@ -1759,9 +1812,8 @@ static assembly_operand check_conditions(assembly_operand AO, int context)
 
     if (AO.type != EXPRESSION_OT)
     {   if (context != CONDITION_CONTEXT) return AO;
+        ensure_memory_list_available(&ET_memlist, ET_used+1);
         n = ET_used++;
-        if (n == MAX_EXPRESSION_NODES)
-            memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
         ET[n].down = -1;
         ET[n].up = -1;
         ET[n].right = -1;
@@ -1782,7 +1834,8 @@ static assembly_operand check_conditions(assembly_operand AO, int context)
 /* --- Shift-reduce parser ------------------------------------------------- */
 
 static int sr_sp;
-static token_data *sr_stack;
+static token_data *sr_stack; /* Allocated to sr_sp */
+static memory_list sr_stack_memlist;
 
 extern assembly_operand parse_expression(int context)
 {
@@ -1866,6 +1919,7 @@ extern assembly_operand parse_expression(int context)
     previous_token.type = ENDEXP_TT;
     previous_token.value = 0;
 
+    ensure_memory_list_available(&sr_stack_memlist, 1);
     sr_sp = 1;
     sr_stack[0] = previous_token;
 
@@ -1905,7 +1959,7 @@ extern assembly_operand parse_expression(int context)
                 return AO;
             }
 
-            AO = emitter_stack[0];
+            AO = emitter_stack[0].op;
             if (AO.type == EXPRESSION_OT)
             {   if (expr_trace_level >= 3)
                 {   printf("Tree before lvalue checking:\n");
@@ -1917,7 +1971,9 @@ extern assembly_operand parse_expression(int context)
                 ET[AO.value].up = -1;
             }
             else {
-                if ((context != CONSTANT_CONTEXT) && is_property_t(AO.symtype) 
+                if ((context != CONSTANT_CONTEXT)
+                    && (AO.symindex >= 0)
+                    && is_property_t(symbols[AO.symindex].type) 
                     && (arrow_allowed) && (!bare_prop_allowed))
                     warning("Bare property name found. \"self.prop\" intended?");
             }
@@ -1934,7 +1990,7 @@ extern assembly_operand parse_expression(int context)
             return(AO);
         }
 
-        switch(find_prec(a,b))
+        switch(find_prec(&a,&b))
         {
             case e5:                 /* Associativity error                  */
                 error_named("Brackets mandatory to clarify order of:",
@@ -1942,14 +1998,13 @@ extern assembly_operand parse_expression(int context)
 
             case LOWER_P:
             case EQUAL_P:
-                if (sr_sp == MAX_EXPRESSION_NODES)
-                    memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
+                ensure_memory_list_available(&sr_stack_memlist, sr_sp+1);
                 sr_stack[sr_sp++] = b;
                 switch(b.type)
                 {
                     case SUBOPEN_TT:
                         if (sr_sp >= 2 && sr_stack[sr_sp-2].type == OP_TT && sr_stack[sr_sp-2].value == FCALL_OP)
-                            mark_top_of_emitter_stack(FUNCTION_VALUE_MARKER, b);
+                            mark_top_of_emitter_stack(FUNCTION_VALUE_MARKER, &b);
                         else
                             add_bracket_layer_to_emitter_stack(0);
                         break;
@@ -1958,7 +2013,7 @@ extern assembly_operand parse_expression(int context)
                             case OR_OP:
                                 if (sr_stack[sr_sp-2].type == OP_TT &&
                                     operators[sr_stack[sr_sp-2].value].precedence == 3)
-                                    mark_top_of_emitter_stack(OR_VALUE_MARKER, b);
+                                    mark_top_of_emitter_stack(OR_VALUE_MARKER, &b);
                                 else
                                 {   error("'or' not between values to the right of a condition");
                                     /* Convert to + for error recovery purposes */
@@ -1974,7 +2029,7 @@ extern assembly_operand parse_expression(int context)
                                     if (shallowest_open_bracket_index > 0 &&
                                         sr_stack[shallowest_open_bracket_index-1].type == OP_TT &&
                                         sr_stack[shallowest_open_bracket_index-1].value == FCALL_OP)
-                                    {   mark_top_of_emitter_stack(ARGUMENT_VALUE_MARKER, b);
+                                    {   mark_top_of_emitter_stack(ARGUMENT_VALUE_MARKER, &b);
                                         break;
                                     }
                                     /* Non-argument-separating commas get treated like any other operator; we fall through to the default case. */
@@ -1992,9 +2047,9 @@ extern assembly_operand parse_expression(int context)
             case GREATER_P:
                 do
                 {   pop = sr_stack[sr_sp - 1];
-                    emit_token(pop);
+                    emit_token(&pop);
                     sr_sp--;
-                } while (find_prec(sr_stack[sr_sp-1], pop) != LOWER_P);
+                } while (find_prec(&sr_stack[sr_sp-1], &pop) != LOWER_P);
                 break;
 
             case e1:                 /* Missing operand error                */
@@ -2056,7 +2111,12 @@ extern void init_expressp_vars(void)
 {   int i;
     /* make_operands(); */
     make_lexical_interface_tables();
-    for (i=0;i<32;i++) system_function_usage[i] = 0;
+    for (i=0; i<NUMBER_SYSTEM_FUNCTIONS; i++)
+        system_function_usage[i] = 0;
+
+    ET = NULL;
+    emitter_stack = NULL;
+    sr_stack = NULL;
 }
 
 extern void expressp_begin_pass(void)
@@ -2064,24 +2124,27 @@ extern void expressp_begin_pass(void)
 }
 
 extern void expressp_allocate_arrays(void)
-{   ET = my_calloc(sizeof(expression_tree_node), MAX_EXPRESSION_NODES,
+{
+    initialise_memory_list(&ET_memlist,
+        sizeof(expression_tree_node), 100, (void**)&ET,
         "expression parse trees");
-    emitter_markers = my_calloc(sizeof(int), MAX_EXPRESSION_NODES,
-        "emitter markers");
-    emitter_bracket_counts = my_calloc(sizeof(int), MAX_EXPRESSION_NODES,
-        "emitter bracket layer counts");
-    emitter_stack = my_calloc(sizeof(assembly_operand), MAX_EXPRESSION_NODES,
-        "emitter stack");
-    sr_stack = my_calloc(sizeof(token_data), MAX_EXPRESSION_NODES,
+
+    initialise_memory_list(&emitter_stack_memlist,
+        sizeof(emitterstackinfo), 100, (void**)&emitter_stack,
+        "expression stack");
+
+    initialise_memory_list(&sr_stack_memlist,
+        sizeof(token_data), 100, (void**)&sr_stack,
         "shift-reduce parser stack");
 }
 
 extern void expressp_free_arrays(void)
-{   my_free(&ET, "expression parse trees");
-    my_free(&emitter_markers, "emitter markers");
-    my_free(&emitter_bracket_counts, "emitter bracket layer counts");
-    my_free(&emitter_stack, "emitter stack");
-    my_free(&sr_stack, "shift-reduce parser stack");
+{
+    deallocate_memory_list(&ET_memlist);
+    
+    deallocate_memory_list(&emitter_stack_memlist);
+
+    deallocate_memory_list(&sr_stack_memlist);
 }
 
 /* ========================================================================= */