Update to Inform v6.35
[inform.git] / src / expressc.c
1 /* ------------------------------------------------------------------------- */
2 /*   "expressc" :  The expression code generator                             */
3 /*                                                                           */
4 /*   Part of Inform 6.35                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2021                                 */
6 /*                                                                           */
7 /* Inform is free software: you can redistribute it and/or modify            */
8 /* it under the terms of the GNU General Public License as published by      */
9 /* the Free Software Foundation, either version 3 of the License, or         */
10 /* (at your option) any later version.                                       */
11 /*                                                                           */
12 /* Inform is distributed in the hope that it will be useful,                 */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
15 /* GNU General Public License for more details.                              */
16 /*                                                                           */
17 /* You should have received a copy of the GNU General Public License         */
18 /* along with Inform. If not, see https://gnu.org/licenses/                  */
19 /*                                                                           */
20 /* ------------------------------------------------------------------------- */
21
22 #include "header.h"
23
24 int vivc_flag;                      /*  TRUE if the last code-generated
25                                         expression produced a "value in void
26                                         context" error: used to help the syntax
27                                         analyser recover from unknown-keyword
28                                         errors, since unknown keywords are
29                                         treated as yet-to-be-defined constants
30                                         and thus as values in void context  */
31
32 /* These data structures are global, because they're too useful to be
33    static. */
34 assembly_operand stack_pointer, temp_var1, temp_var2, temp_var3,
35   temp_var4, zero_operand, one_operand, two_operand, three_operand,
36   four_operand, valueless_operand;
37
38 static void make_operands(void)
39 {
40   if (!glulx_mode) {
41     INITAOTV(&stack_pointer, VARIABLE_OT, 0);
42     INITAOTV(&temp_var1, VARIABLE_OT, 255);
43     INITAOTV(&temp_var2, VARIABLE_OT, 254);
44     INITAOTV(&temp_var3, VARIABLE_OT, 253);
45     INITAOTV(&temp_var4, VARIABLE_OT, 252);
46     INITAOTV(&zero_operand, SHORT_CONSTANT_OT, 0);
47     INITAOTV(&one_operand, SHORT_CONSTANT_OT, 1);
48     INITAOTV(&two_operand, SHORT_CONSTANT_OT, 2);
49     INITAOTV(&three_operand, SHORT_CONSTANT_OT, 3);
50     INITAOTV(&four_operand, SHORT_CONSTANT_OT, 4);
51     INITAOTV(&valueless_operand, OMITTED_OT, 0);
52   }
53   else {
54     INITAOTV(&stack_pointer, LOCALVAR_OT, 0);
55     INITAOTV(&temp_var1, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+0);
56     INITAOTV(&temp_var2, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+1);
57     INITAOTV(&temp_var3, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+2);
58     INITAOTV(&temp_var4, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+3);
59     INITAOTV(&zero_operand, ZEROCONSTANT_OT, 0);
60     INITAOTV(&one_operand, BYTECONSTANT_OT, 1);
61     INITAOTV(&two_operand, BYTECONSTANT_OT, 2);
62     INITAOTV(&three_operand, BYTECONSTANT_OT, 3);
63     INITAOTV(&four_operand, BYTECONSTANT_OT, 4);
64     INITAOTV(&valueless_operand, OMITTED_OT, 0);
65   }
66 }
67
68 /* ------------------------------------------------------------------------- */
69 /*  The table of conditionals. (Only used in Glulx)                          */
70
71 #define ZERO_CC (500)
72 #define EQUAL_CC (502)
73 #define LT_CC (504)
74 #define GT_CC (506)
75 #define HAS_CC (508)
76 #define IN_CC (510)
77 #define OFCLASS_CC (512)
78 #define PROVIDES_CC (514)
79
80 #define FIRST_CC (500)
81 #define LAST_CC (515)
82
83 typedef struct condclass_s {
84   int32 posform; /* Opcode for the conditional in its positive form. */
85   int32 negform; /* Opcode for the conditional in its negated form. */
86 } condclass;
87
88 condclass condclasses[] = {
89   { jz_gc, jnz_gc },
90   { jeq_gc, jne_gc },
91   { jlt_gc, jge_gc },
92   { jgt_gc, jle_gc },
93   { -1, -1 },
94   { -1, -1 },
95   { -1, -1 },
96   { -1, -1 }
97 };
98
99 /* ------------------------------------------------------------------------- */
100 /*  The table of operators.
101
102     The ordering in this table is not significant except that it must match
103     the #define's in "header.h"                                              */
104
105 operator operators[NUM_OPERATORS] =
106 {
107                          /* ------------------------ */
108                          /*  Level 0:  ,             */
109                          /* ------------------------ */
110
111   { 0, SEP_TT, COMMA_SEP,       IN_U, L_A, 0, -1, -1, 0, 0, "comma" },
112
113                          /* ------------------------ */
114                          /*  Level 1:  =             */
115                          /* ------------------------ */
116
117   { 1, SEP_TT, SETEQUALS_SEP,   IN_U, R_A, 1, -1, -1, 1, 0,
118       "assignment operator '='" },
119
120                          /* ------------------------ */
121                          /*  Level 2:  ~~  &&  ||    */
122                          /* ------------------------ */
123
124   { 2, SEP_TT, LOGAND_SEP,      IN_U, L_A, 0, -1, -1, 0, LOGOR_OP,
125       "logical conjunction '&&'" },
126   { 2, SEP_TT, LOGOR_SEP,       IN_U, L_A, 0, -1, -1, 0, LOGAND_OP,
127       "logical disjunction '||'" },
128   { 2, SEP_TT, LOGNOT_SEP,     PRE_U, R_A, 0, -1, -1, 0, LOGNOT_OP,
129       "logical negation '~~'" },
130
131                          /* ------------------------ */
132                          /*  Level 3:  ==  ~=        */
133                          /*            >  >=  <  <=  */
134                          /*            has  hasnt    */
135                          /*            in  notin     */
136                          /*            provides      */
137                          /*            ofclass       */
138                          /* ------------------------ */
139
140   { 3,     -1, -1,                -1, 0, 0, 400 + jz_zc, ZERO_CC+0, 0, NONZERO_OP,
141       "expression used as condition then negated" },
142   { 3,     -1, -1,                -1, 0, 0, 800 + jz_zc, ZERO_CC+1, 0, ZERO_OP,
143       "expression used as condition" },
144   { 3, SEP_TT, CONDEQUALS_SEP,  IN_U, 0, 0, 400 + je_zc, EQUAL_CC+0, 0, NOTEQUAL_OP,
145       "'==' condition" },
146   { 3, SEP_TT, NOTEQUAL_SEP,    IN_U, 0, 0, 800 + je_zc, EQUAL_CC+1, 0, CONDEQUALS_OP,
147       "'~=' condition" },
148   { 3, SEP_TT, GE_SEP,          IN_U, 0, 0, 800 + jl_zc, LT_CC+1, 0, LESS_OP,
149       "'>=' condition" },
150   { 3, SEP_TT, GREATER_SEP,     IN_U, 0, 0, 400 + jg_zc, GT_CC+0, 0, LE_OP,
151       "'>' condition" },
152   { 3, SEP_TT, LE_SEP,          IN_U, 0, 0, 800 + jg_zc, GT_CC+1, 0, GREATER_OP,
153       "'<=' condition" },
154   { 3, SEP_TT, LESS_SEP,        IN_U, 0, 0, 400 + jl_zc, LT_CC+0, 0, GE_OP,
155       "'<' condition" },
156   { 3, CND_TT, HAS_COND,        IN_U, 0, 0, 400 + test_attr_zc, HAS_CC+0, 0, HASNT_OP,
157       "'has' condition" },
158   { 3, CND_TT, HASNT_COND,      IN_U, 0, 0, 800 + test_attr_zc, HAS_CC+1, 0, HAS_OP,
159       "'hasnt' condition" },
160   { 3, CND_TT, IN_COND,         IN_U, 0, 0, 400 + jin_zc, IN_CC+0, 0, NOTIN_OP,
161       "'in' condition" },
162   { 3, CND_TT, NOTIN_COND,      IN_U, 0, 0, 800 + jin_zc, IN_CC+1, 0, IN_OP,
163       "'notin' condition" },
164   { 3, CND_TT, OFCLASS_COND,    IN_U, 0, 0, 600, OFCLASS_CC+0, 0, NOTOFCLASS_OP,
165       "'ofclass' condition" },
166   { 3, CND_TT, PROVIDES_COND,   IN_U, 0, 0, 601, PROVIDES_CC+0, 0, NOTPROVIDES_OP,
167       "'provides' condition" },
168   { 3,     -1, -1,                -1, 0, 0, 1000, OFCLASS_CC+1, 0, OFCLASS_OP,
169       "negated 'ofclass' condition" },
170   { 3,     -1, -1,                -1, 0, 0, 1001, PROVIDES_CC+1, 0, PROVIDES_OP,
171       "negated 'provides' condition" },
172
173                          /* ------------------------ */
174                          /*  Level 4:  or            */
175                          /* ------------------------ */
176
177   { 4, CND_TT, OR_COND,         IN_U, L_A, 0, -1, -1, 0, 0, "'or'" },
178
179                          /* ------------------------ */
180                          /*  Level 5:  +  binary -   */
181                          /* ------------------------ */
182
183   { 5, SEP_TT, PLUS_SEP,        IN_U, L_A, 0, add_zc, add_gc, 0, 0, "'+'" },
184   { 5, SEP_TT, MINUS_SEP,       IN_U, L_A, 0, sub_zc, sub_gc, 0, 0, "'-'" },
185
186                          /* ------------------------ */
187                          /*  Level 6:  *  /  %       */
188                          /*            &  |  ~       */
189                          /* ------------------------ */
190
191   { 6, SEP_TT, TIMES_SEP,       IN_U, L_A, 0, mul_zc, mul_gc, 0, 0, "'*'" },
192   { 6, SEP_TT, DIVIDE_SEP,      IN_U, L_A, 0, div_zc, div_gc, 0, 0, "'/'" },
193   { 6, SEP_TT, REMAINDER_SEP,   IN_U, L_A, 0, mod_zc, mod_gc, 0, 0,
194       "remainder after division '%'" },
195   { 6, SEP_TT, ARTAND_SEP,      IN_U, L_A, 0, and_zc, bitand_gc, 0, 0,
196       "bitwise AND '&'" },
197   { 6, SEP_TT, ARTOR_SEP,       IN_U, L_A, 0, or_zc, bitor_gc, 0, 0,
198       "bitwise OR '|'" },
199   { 6, SEP_TT, ARTNOT_SEP,     PRE_U, R_A, 0, -1, bitnot_gc, 0, 0,
200       "bitwise NOT '~'" },
201
202                          /* ------------------------ */
203                          /*  Level 7:  ->  -->       */
204                          /* ------------------------ */
205
206   { 7, SEP_TT, ARROW_SEP,       IN_U, L_A, 0, -1, -1, 0, 0,
207       "byte array operator '->'" },
208   { 7, SEP_TT, DARROW_SEP,      IN_U, L_A, 0, -1, -1, 0, 0,
209       "word array operator '-->'" },
210
211                          /* ------------------------ */
212                          /*  Level 8:  unary -       */
213                          /* ------------------------ */
214
215   { 8, SEP_TT, UNARY_MINUS_SEP, PRE_U, R_A, 0, -1, neg_gc, 0, 0,
216       "unary minus" },
217
218                          /* ------------------------ */
219                          /*  Level 9:  ++  --        */
220                          /*  (prefix or postfix)     */
221                          /* ------------------------ */
222
223   { 9, SEP_TT, INC_SEP,         PRE_U, R_A, 2, -1, -1, 1, 0,
224       "pre-increment operator '++'" },
225   { 9, SEP_TT, POST_INC_SEP,   POST_U, R_A, 3, -1, -1, 1, 0,
226       "post-increment operator '++'" },
227   { 9, SEP_TT, DEC_SEP,         PRE_U, R_A, 4, -1, -1, 1, 0,
228       "pre-decrement operator '--'" },
229   { 9, SEP_TT, POST_DEC_SEP,   POST_U, R_A, 5, -1, -1, 1, 0,
230       "post-decrement operator '--'" },
231
232                          /* ------------------------ */
233                          /*  Level 10: .&  .#        */
234                          /*            ..&  ..#      */
235                          /* ------------------------ */
236
237   {10, SEP_TT, PROPADD_SEP,     IN_U, L_A, 0, -1, -1, 0, 0,
238       "property address operator '.&'" },
239   {10, SEP_TT, PROPNUM_SEP,     IN_U, L_A, 0, -1, -1, 0, 0,
240       "property length operator '.#'" },
241   {10, SEP_TT, MPROPADD_SEP,    IN_U, L_A, 0, -1, -1, 0, 0,
242       "individual property address operator '..&'" },
243   {10, SEP_TT, MPROPNUM_SEP,    IN_U, L_A, 0, -1, -1, 0, 0,
244       "individual property length operator '..#'" },
245
246                          /* ------------------------ */
247                          /*  Level 11:  function (   */
248                          /* ------------------------ */
249
250   {11, SEP_TT, OPENB_SEP,       IN_U, L_A, 0, -1, -1, 1, 0,
251       "function call" },
252
253                          /* ------------------------ */
254                          /*  Level 12:  .  ..        */
255                          /* ------------------------ */
256
257   {12, SEP_TT, MESSAGE_SEP,     IN_U, L_A, 0, -1, -1, 0, 0,
258       "individual property selector '..'" },
259   {12, SEP_TT, PROPERTY_SEP,    IN_U, L_A, 0, -1, -1, 0, 0,
260       "property selector '.'" },
261
262                          /* ------------------------ */
263                          /*  Level 13:  ::           */
264                          /* ------------------------ */
265
266   {13, SEP_TT, SUPERCLASS_SEP,  IN_U, L_A, 0, -1, -1, 0, 0,
267       "superclass operator '::'" },
268
269                          /* ------------------------ */
270                          /*  Miscellaneous operators */
271                          /*  generated at lvalue     */
272                          /*  checking time           */
273                          /* ------------------------ */
274
275   { 1,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      ->   =   */
276       "byte array entry assignment" },
277   { 1,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      -->  =   */
278       "word array entry assignment" },
279   { 1,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      ..   =   */
280       "individual property assignment" },
281   { 1,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      .    =   */
282       "common property assignment" },
283
284   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   ++ ->       */
285       "byte array entry preincrement" },
286   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   ++ -->      */
287       "word array entry preincrement" },
288   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   ++ ..       */
289       "individual property preincrement" },
290   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   ++ .        */
291       "common property preincrement" },
292
293   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   -- ->       */
294       "byte array entry predecrement" },
295   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   -- -->      */
296       "word array entry predecrement" },
297   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   -- ..       */
298       "individual property predecrement" },
299   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   -- .        */
300       "common property predecrement" },
301
302   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      ->  ++   */
303       "byte array entry postincrement" },
304   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      --> ++   */
305       "word array entry postincrement" },
306   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      ..  ++   */
307       "individual property postincrement" },
308   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      .   ++   */
309       "common property postincrement" },
310
311   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      ->  --   */
312       "byte array entry postdecrement" },
313   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      --> --   */
314       "word array entry postdecrement" },
315   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      ..  --   */
316       "individual property postdecrement" },
317   { 9,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*      .   --   */
318       "common property postdecrement" },
319
320   {11,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   x.y(args)   */
321       "call to common property" },
322   {11,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0, /*   x..y(args)  */
323       "call to individual property" },
324
325                          /* ------------------------ */
326                          /*  And one Glulx-only op   */
327                          /*  which just pushes its   */
328                          /*  argument on the stack,  */
329                          /*  unchanged.              */
330                          /* ------------------------ */
331
332   {14,     -1, -1,              -1,   -1,  0, -1, -1, 1, 0,     
333       "push on stack" }
334 };
335
336 /* --- Condition annotater ------------------------------------------------- */
337
338 static void annotate_for_conditions(int n, int a, int b)
339 {   int i, opnum = ET[n].operator_number;
340
341     ET[n].label_after = -1;
342     ET[n].to_expression = FALSE;
343     ET[n].true_label = a;
344     ET[n].false_label = b;
345
346     if (ET[n].down == -1) return;
347
348     if ((operators[opnum].precedence == 2)
349         || (operators[opnum].precedence == 3))
350     {   if ((a == -1) && (b == -1))
351         {   if (opnum == LOGAND_OP)
352             {   b = next_label++;
353                 ET[n].false_label = b;
354                 ET[n].to_expression = TRUE;
355             }
356             else
357             {   a = next_label++;
358                 ET[n].true_label = a;
359                 ET[n].to_expression = TRUE;
360             }
361         }
362     }
363
364     switch(opnum)
365     {   case LOGAND_OP:
366             if (b == -1)
367             {   b = next_label++;
368                 ET[n].false_label = b;
369                 ET[n].label_after = b;
370             }
371             annotate_for_conditions(ET[n].down, -1, b);
372             if (b == ET[n].label_after)
373                  annotate_for_conditions(ET[ET[n].down].right, a, -1);
374             else annotate_for_conditions(ET[ET[n].down].right, a, b);
375             return;
376         case LOGOR_OP:
377             if (a == -1)
378             {   a = next_label++;
379                 ET[n].true_label = a;
380                 ET[n].label_after = a;
381             }
382             annotate_for_conditions(ET[n].down, a, -1);
383             if (a == ET[n].label_after)
384                  annotate_for_conditions(ET[ET[n].down].right, -1, b);
385             else annotate_for_conditions(ET[ET[n].down].right, a, b);
386             return;
387     }
388
389     i = ET[n].down;
390     while (i != -1)
391     {   annotate_for_conditions(i, -1, -1); i = ET[i].right; }
392 }
393
394 /* --- Code generator ------------------------------------------------------ */
395
396 static void value_in_void_context_z(assembly_operand AO)
397 {   char *t;
398
399     ASSERT_ZCODE(); 
400  
401     switch(AO.type)
402     {   case LONG_CONSTANT_OT:
403         case SHORT_CONSTANT_OT:
404             t = "<constant>";
405             if (AO.marker == SYMBOL_MV)
406                 t = (char *) (symbs[AO.value]);
407             break;
408         case VARIABLE_OT:
409             t = variable_name(AO.value);
410             break;
411         default:
412             compiler_error("Unable to print value in void context");
413             t = "<expression>";
414             break;
415     }
416     vivc_flag = TRUE;
417
418     if (strcmp(t, "print_paddr") == 0)
419     obsolete_warning("ignoring 'print_paddr': use 'print (string)' instead");
420     else
421     if (strcmp(t, "print_addr") == 0)
422     obsolete_warning("ignoring 'print_addr': use 'print (address)' instead");
423     else
424     if (strcmp(t, "print_char") == 0)
425     obsolete_warning("ignoring 'print_char': use 'print (char)' instead");
426     else
427     ebf_error("expression with side-effects", t);
428 }
429
430 static void write_result_z(assembly_operand to, assembly_operand from)
431 {   if (to.value == from.value) return;
432     if (to.value == 0) assemblez_1(push_zc, from);
433     else               assemblez_store(to, from);
434 }
435
436 static void pop_zm_stack(void)
437 {   assembly_operand st;
438     if (version_number < 5) assemblez_0(pop_zc);
439     else
440     {   INITAOTV(&st, VARIABLE_OT, 0);
441         assemblez_1_branch(jz_zc, st, -2, TRUE);
442     }
443 }
444
445 static void access_memory_z(int oc, assembly_operand AO1, assembly_operand AO2,
446     assembly_operand AO3)
447 {   int vr = 0;
448
449     assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
450         index_ao;
451     int x = 0, y = 0, byte_flag = FALSE, read_flag = FALSE, from_module = FALSE;
452
453     INITAO(&zero_ao);
454     INITAO(&size_ao);
455     INITAO(&type_ao);
456
457     if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
458     {   
459         if ((oc == loadb_zc) || (oc == storeb_zc)) byte_flag=TRUE;
460         else byte_flag = FALSE;
461         if ((oc == loadb_zc) || (oc == loadw_zc)) read_flag=TRUE;
462         else read_flag = FALSE;
463
464         zero_ao.type = SHORT_CONSTANT_OT;
465         zero_ao.value = 0;
466
467         size_ao = zero_ao; size_ao.value = -1;
468         for (x=0; x<no_arrays; x++)
469         {   if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
470                 && (AO1.value == svals[array_symbols[x]]))
471             {   size_ao.value = array_sizes[x]; y=x;
472             }
473         }
474         
475         if (array_locs[y] && !read_flag) {
476             error("Cannot write to a static array");
477         }
478
479         if (size_ao.value==-1) 
480             from_module=TRUE;
481         else {
482             from_module=FALSE;
483             type_ao = zero_ao; type_ao.value = array_types[y];
484
485             if ((!is_systemfile()))
486             {   if (byte_flag)
487                 {
488                     if ((array_types[y] == WORD_ARRAY)
489                         || (array_types[y] == TABLE_ARRAY))
490                         warning("Using '->' to access a --> or table array");
491                 }
492                 else
493                 {
494                     if ((array_types[y] == BYTE_ARRAY)
495                         || (array_types[y] == STRING_ARRAY))
496                     warning("Using '-->' to access a -> or string array");
497                 }
498             }
499         }
500     }
501
502
503     if ((!runtime_error_checking_switch) || (veneer_mode))
504     {   if ((oc == loadb_zc) || (oc == loadw_zc))
505             assemblez_2_to(oc, AO1, AO2, AO3);
506         else
507             assemblez_3(oc, AO1, AO2, AO3);
508         return;
509     }
510
511     /* If we recognise AO1 as arising textually from a declared
512        array, we can check bounds explicitly. */
513
514     if ((AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV) && (!from_module))
515     {   
516         int passed_label = next_label++, failed_label = next_label++,
517             final_label = next_label++; 
518         /* Calculate the largest permitted array entry + 1
519            Here "size_ao.value" = largest permitted entry of its own kind */
520         max_ao = size_ao;
521
522         if (byte_flag
523             && ((array_types[y] == WORD_ARRAY)
524                 || (array_types[y] == TABLE_ARRAY)))
525         {   max_ao.value = size_ao.value*2 + 1;
526             type_ao.value += 8;
527         }
528         if ((!byte_flag)
529             && ((array_types[y] == BYTE_ARRAY)
530                 || (array_types[y] == STRING_ARRAY) 
531                 || (array_types[y] == BUFFER_ARRAY)))
532         {   if ((size_ao.value % 2) == 0)
533                  max_ao.value = size_ao.value/2 - 1;
534             else max_ao.value = (size_ao.value-1)/2;
535             type_ao.value += 16;
536         }
537         max_ao.value++;
538
539         if (size_ao.value >= 256) size_ao.type = LONG_CONSTANT_OT;
540         if (max_ao.value >= 256) max_ao.type = LONG_CONSTANT_OT;
541
542         /* Can't write to the size entry in a string or table */
543         if (((array_types[y] == STRING_ARRAY)
544              || (array_types[y] == TABLE_ARRAY))
545             && (!read_flag))
546         {   if ((array_types[y] == TABLE_ARRAY) && byte_flag)
547                 zero_ao.value = 2;
548             else zero_ao.value = 1;
549         }
550
551         en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
552         switch(oc) { case loadb_zc:  en_ao.value = ABOUNDS_RTE; break;
553                      case loadw_zc:  en_ao.value = ABOUNDS_RTE+1; break;
554                      case storeb_zc: en_ao.value = ABOUNDS_RTE+2; break;
555                      case storew_zc: en_ao.value = ABOUNDS_RTE+3; break; }
556
557         index_ao = AO2;
558         if ((AO2.type == VARIABLE_OT)&&(AO2.value == 0))
559         {   assemblez_store(temp_var2, AO2);
560             assemblez_store(AO2, temp_var2);
561             index_ao = temp_var2;
562         }
563         assemblez_2_branch(jl_zc, index_ao, zero_ao, failed_label, TRUE);
564         assemblez_2_branch(jl_zc, index_ao, max_ao, passed_label, TRUE);
565         assemble_label_no(failed_label);
566         an_ao = zero_ao; an_ao.value = y;
567         assemblez_6(call_vn2_zc, veneer_routine(RT__Err_VR), en_ao,
568             index_ao, size_ao, type_ao, an_ao);
569
570         /* We have to clear any of AO1, AO2, AO3 off the stack if
571            present, so that we can achieve the same effect on the stack
572            that executing the opcode would have had */
573
574         if ((AO1.type == VARIABLE_OT) && (AO1.value == 0)) pop_zm_stack();
575         if ((AO2.type == VARIABLE_OT) && (AO2.value == 0)) pop_zm_stack();
576         if ((AO3.type == VARIABLE_OT) && (AO3.value == 0))
577         {   if ((oc == loadb_zc) || (oc == loadw_zc))
578             {   assemblez_store(AO3, zero_ao);
579             }
580             else pop_zm_stack();
581         }
582         assemblez_jump(final_label);
583
584         assemble_label_no(passed_label);
585         if ((oc == loadb_zc) || (oc == loadw_zc))
586             assemblez_2_to(oc, AO1, AO2, AO3);
587         else
588             assemblez_3(oc, AO1, AO2, AO3);
589         assemble_label_no(final_label);
590         return;
591     }
592
593     /* Otherwise, compile a call to the veneer which verifies that
594        the proposed read/write is within dynamic Z-machine memory. */
595
596     switch(oc) { case loadb_zc: vr = RT__ChLDB_VR; break;
597                  case loadw_zc: vr = RT__ChLDW_VR; break;
598                  case storeb_zc: vr = RT__ChSTB_VR; break;
599                  case storew_zc: vr = RT__ChSTW_VR; break;
600                  default: compiler_error("unknown array opcode");
601     }
602
603     if ((oc == loadb_zc) || (oc == loadw_zc))
604         assemblez_3_to(call_vs_zc, veneer_routine(vr), AO1, AO2, AO3);
605     else
606         assemblez_4(call_vn_zc, veneer_routine(vr), AO1, AO2, AO3);
607 }
608
609 static assembly_operand check_nonzero_at_runtime_z(assembly_operand AO1,
610         int error_label, int rte_number)
611 {   assembly_operand AO2, AO3;
612     int check_sp = FALSE, passed_label, failed_label, last_label;
613     if (veneer_mode) return AO1;
614
615     /*  Assemble to code to check that the operand AO1 is ofclass Object:
616         if it is, execution should continue and the stack should be
617         unchanged.  Otherwise, call the veneer's run-time-error routine
618         with the given error number, and then: if the label isn't -1,
619         switch execution to this label, with the value popped from
620         the stack if it was on the stack in the first place;
621         if the label is -1, either replace the top of the stack with
622         the constant 2, or return the operand (short constant) 2.
623
624         The point of 2 is that object 2 is the class-object Object
625         and therefore has no parent, child or sibling, so that the
626         built-in tree functions will safely return 0 on this object. */
627
628     /*  Sometimes we can already see that the object number is valid. */
629     if (((AO1.type == LONG_CONSTANT_OT) || (AO1.type == SHORT_CONSTANT_OT))
630         && (AO1.marker == 0) && (AO1.value >= 1) && (AO1.value < no_objects))
631         return AO1;
632
633     passed_label = next_label++;
634     failed_label = next_label++;
635     INITAOTV(&AO2, LONG_CONSTANT_OT, actual_largest_object_SC);
636     AO2.marker = INCON_MV;
637     INITAOTV(&AO3, SHORT_CONSTANT_OT, 5);
638
639     if ((rte_number == IN_RTE) || (rte_number == HAS_RTE)
640         || (rte_number == PROPERTY_RTE) || (rte_number == PROP_NUM_RTE)
641         || (rte_number == PROP_ADD_RTE))
642     {   /* Allow classes */
643         AO3.value = 1;
644         if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
645         {   /* That is, if AO1 is the stack pointer */
646             check_sp = TRUE;
647             assemblez_store(temp_var2, AO1);
648             assemblez_store(AO1, temp_var2);
649             assemblez_2_branch(jg_zc, AO3, temp_var2, failed_label, TRUE);
650             assemblez_2_branch(jg_zc, temp_var2, AO2, passed_label, FALSE);
651         }
652         else
653         {   assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
654             assemblez_2_branch(jg_zc, AO1, AO2, passed_label, FALSE);
655         }
656     }
657     else
658     {   if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
659         {   /* That is, if AO1 is the stack pointer */
660             check_sp = TRUE;
661             assemblez_store(temp_var2, AO1);
662             assemblez_store(AO1, temp_var2);
663             assemblez_2_branch(jg_zc, AO3, temp_var2, failed_label, TRUE);
664             assemblez_2_branch(jg_zc, temp_var2, AO2, failed_label, TRUE);
665             AO3.value = 1;
666             assemblez_2_branch(jin_zc, temp_var2, AO3, passed_label, FALSE);
667         }
668         else
669         {   assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
670             assemblez_2_branch(jg_zc, AO1, AO2, failed_label, TRUE);
671             AO3.value = 1;
672             assemblez_2_branch(jin_zc, AO1, AO3, passed_label, FALSE);
673         }
674     }
675
676     assemble_label_no(failed_label);
677     INITAOTV(&AO2, SHORT_CONSTANT_OT, rte_number);
678     if (version_number >= 5)
679       assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR), AO2, AO1);
680     else
681       assemblez_3_to(call_zc, veneer_routine(RT__Err_VR), AO2, AO1, temp_var2);
682
683     if (error_label != -1)
684     {   /* Jump to the error label */
685         if (error_label == -3) assemblez_0(rfalse_zc);
686         else if (error_label == -4) assemblez_0(rtrue_zc);
687         else assemblez_jump(error_label);
688     }
689     else
690     {   if (check_sp)
691         {   /* Push the short constant 2 */
692             INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
693             assemblez_store(AO1, AO2);
694         }
695         else
696         {   /* Store either short constant 2 or the operand's value in
697                the temporary variable */
698             INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
699             AO3 = temp_var2; assemblez_store(AO3, AO2);
700             last_label = next_label++;
701             assemblez_jump(last_label);
702             assemble_label_no(passed_label);
703             assemblez_store(AO3, AO1);
704             assemble_label_no(last_label);
705             return AO3;
706         }
707     }
708     assemble_label_no(passed_label);
709     return AO1;
710 }
711
712 static void compile_conditional_z(int oc,
713     assembly_operand AO1, assembly_operand AO2, int label, int flag)
714 {   assembly_operand AO3; int the_zc, error_label = label,
715     va_flag = FALSE, va_label = 0;
716
717     ASSERT_ZCODE(); 
718
719     if (oc<200)
720     {   if ((runtime_error_checking_switch) && (oc == jin_zc))
721         {   if (flag) error_label = next_label++;
722             AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
723         }
724         if ((runtime_error_checking_switch) && (oc == test_attr_zc))
725         {   if (flag) error_label = next_label++;
726             AO1 = check_nonzero_at_runtime(AO1, error_label, HAS_RTE);
727             switch(AO2.type)
728             {   case SHORT_CONSTANT_OT:
729                 case LONG_CONSTANT_OT:
730                     if (AO2.marker == 0)
731                     {   if ((AO2.value < 0) || (AO2.value > 47))
732                 error("'has'/'hasnt' applied to illegal attribute number");
733                         break;
734                     }
735                 case VARIABLE_OT:
736                 {   int pa_label = next_label++, fa_label = next_label++;
737                     assembly_operand en_ao, zero_ao, max_ao;
738                     assemblez_store(temp_var1, AO1);
739                     if ((AO1.type == VARIABLE_OT)&&(AO1.value == 0))
740                         assemblez_store(AO1, temp_var1);
741                     assemblez_store(temp_var2, AO2);
742                     if ((AO2.type == VARIABLE_OT)&&(AO2.value == 0))
743                         assemblez_store(AO2, temp_var2);
744                     INITAOT(&zero_ao, SHORT_CONSTANT_OT);
745                     zero_ao.value = 0; 
746                     max_ao = zero_ao; max_ao.value = 48;
747                     assemblez_2_branch(jl_zc,temp_var2,zero_ao,fa_label,TRUE);
748                     assemblez_2_branch(jl_zc,temp_var2,max_ao,pa_label,TRUE);
749                     assemble_label_no(fa_label);
750                     en_ao = zero_ao; en_ao.value = 19;
751                     assemblez_4(call_vn_zc, veneer_routine(RT__Err_VR),
752                         en_ao, temp_var1, temp_var2);
753                     va_flag = TRUE; va_label = next_label++;
754                     assemblez_jump(va_label);
755                     assemble_label_no(pa_label);
756                 }
757             }
758         }
759         assemblez_2_branch(oc, AO1, AO2, label, flag);
760         if (error_label != label) assemble_label_no(error_label);
761         if (va_flag) assemble_label_no(va_label);
762         return;
763     }
764
765     INITAOTV(&AO3, VARIABLE_OT, 0);
766
767     the_zc = (version_number == 3)?call_zc:call_vs_zc;
768     if (oc == 201)
769     assemblez_3_to(the_zc, veneer_routine(OP__Pr_VR), AO1, AO2, AO3);
770     else
771     assemblez_3_to(the_zc, veneer_routine(OC__Cl_VR), AO1, AO2, AO3);
772
773     assemblez_1_branch(jz_zc, AO3, label, !flag);
774 }
775
776 static void value_in_void_context_g(assembly_operand AO)
777 {   char *t;
778
779     ASSERT_GLULX(); 
780
781     switch(AO.type)
782     {   case CONSTANT_OT:
783         case HALFCONSTANT_OT:
784         case BYTECONSTANT_OT:
785         case ZEROCONSTANT_OT:
786             t = "<constant>";
787             if (AO.marker == SYMBOL_MV)
788                 t = (char *) (symbs[AO.value]);
789             break;
790         case GLOBALVAR_OT:
791         case LOCALVAR_OT:
792             t = variable_name(AO.value);
793             break;
794         default:
795             compiler_error("Unable to print value in void context");
796             t = "<expression>";
797             break;
798     }
799     vivc_flag = TRUE;
800
801     ebf_error("expression with side-effects", t);
802 }
803
804 static void write_result_g(assembly_operand to, assembly_operand from)
805 {   if (to.value == from.value && to.type == from.type) return;
806     assembleg_store(to, from);
807 }
808
809 static void access_memory_g(int oc, assembly_operand AO1, assembly_operand AO2,
810     assembly_operand AO3)
811 {   int vr = 0;
812     int data_len, read_flag; 
813     assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
814         index_ao, five_ao;
815     int passed_label, failed_label, final_label, x = 0, y = 0;
816
817     if ((oc == aloadb_gc) || (oc == astoreb_gc)) data_len = 1;
818     else if ((oc == aloads_gc) || (oc == astores_gc)) data_len = 2;
819     else data_len = 4;
820
821     if ((oc == aloadb_gc) || (oc == aloads_gc) || (oc == aload_gc)) 
822       read_flag = TRUE;
823     else 
824       read_flag = FALSE;
825
826     INITAO(&zero_ao);
827     INITAO(&size_ao);
828     INITAO(&type_ao);
829     
830     if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
831     {   
832         size_ao = zero_ao; size_ao.value = -1;
833         for (x=0; x<no_arrays; x++)
834         {   if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
835                 && (AO1.value == svals[array_symbols[x]]))
836             {   size_ao.value = array_sizes[x]; y=x;
837             }
838         }
839         if (size_ao.value==-1) compiler_error("Array size can't be found");
840
841         type_ao = zero_ao; type_ao.value = array_types[y];
842
843         if (array_locs[y] && !read_flag) {
844             error("Cannot write to a static array");
845         }
846
847         if ((!is_systemfile()))
848         {   if (data_len == 1)
849             {
850                 if ((array_types[y] == WORD_ARRAY)
851                     || (array_types[y] == TABLE_ARRAY))
852                     warning("Using '->' to access a --> or table array");
853             }
854             else
855             {
856                 if ((array_types[y] == BYTE_ARRAY)
857                     || (array_types[y] == STRING_ARRAY))
858                  warning("Using '-->' to access a -> or string array");
859             }
860         }
861     }
862
863
864     if ((!runtime_error_checking_switch) || (veneer_mode))
865     {
866         assembleg_3(oc, AO1, AO2, AO3);
867         return;
868     }
869
870     /* If we recognise AO1 as arising textually from a declared
871        array, we can check bounds explicitly. */
872
873     if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
874     {   
875         /* Calculate the largest permitted array entry + 1
876            Here "size_ao.value" = largest permitted entry of its own kind */
877         max_ao = size_ao;
878         if (data_len == 1
879             && ((array_types[y] == WORD_ARRAY)
880                 || (array_types[y] == TABLE_ARRAY)))
881         {   max_ao.value = size_ao.value*4 + 3;
882             type_ao.value += 8;
883         }
884         if (data_len == 4
885             && ((array_types[y] == BYTE_ARRAY)
886                 || (array_types[y] == STRING_ARRAY)
887                 || (array_types[y] == BUFFER_ARRAY)))
888         {   max_ao.value = (size_ao.value-3)/4;
889             type_ao.value += 16;
890         }
891         max_ao.value++;
892
893         /* Can't write to the size entry in a string or table */
894         if (((array_types[y] == STRING_ARRAY)
895              || (array_types[y] == TABLE_ARRAY))
896             && (!read_flag))
897         {   if ((array_types[y] == TABLE_ARRAY) && data_len == 1)
898                 zero_ao.value = 4;
899             else zero_ao.value = 1;
900         }
901
902         en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
903
904         switch(oc) { case aloadb_gc:  en_ao.value = ABOUNDS_RTE; break;
905                      case aload_gc:  en_ao.value = ABOUNDS_RTE+1; break;
906                      case astoreb_gc: en_ao.value = ABOUNDS_RTE+2; break;
907                      case astore_gc: en_ao.value = ABOUNDS_RTE+3; break; }
908
909         set_constant_ot(&zero_ao);
910         set_constant_ot(&size_ao);
911         set_constant_ot(&max_ao);
912         set_constant_ot(&type_ao);
913         set_constant_ot(&en_ao);
914
915         /* If we recognize A02 as a constant, we can do the test right
916            now. */
917         if (is_constant_ot(AO2.type) && AO2.marker == 0) {
918             if (AO2.value < zero_ao.value || AO2.value >= max_ao.value) {
919               error("Array reference is out-of-bounds");
920             }
921             assembleg_3(oc, AO1, AO2, AO3);
922             return;
923         }
924
925         passed_label = next_label++; 
926         failed_label = next_label++;
927         final_label = next_label++;
928
929         index_ao = AO2;
930         if ((AO2.type == LOCALVAR_OT)&&(AO2.value == 0))
931         {   assembleg_store(temp_var2, AO2); /* ### could peek */
932             assembleg_store(AO2, temp_var2);
933             index_ao = temp_var2;
934         }
935         assembleg_2_branch(jlt_gc, index_ao, zero_ao, failed_label);
936         assembleg_2_branch(jlt_gc, index_ao, max_ao, passed_label);
937         assemble_label_no(failed_label);
938
939         an_ao = zero_ao; an_ao.value = y;
940         set_constant_ot(&an_ao);
941         five_ao = zero_ao; five_ao.value = 5;
942         set_constant_ot(&five_ao);
943
944         /* Call the error veneer routine. */
945         assembleg_store(stack_pointer, an_ao);
946         assembleg_store(stack_pointer, type_ao);
947         assembleg_store(stack_pointer, size_ao);
948         assembleg_store(stack_pointer, index_ao);
949         assembleg_store(stack_pointer, en_ao);
950         assembleg_3(call_gc, veneer_routine(RT__Err_VR),
951             five_ao, zero_operand);
952
953         /* We have to clear any of AO1, AO2, AO3 off the stack if
954            present, so that we can achieve the same effect on the stack
955            that executing the opcode would have had */
956
957         if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) 
958             assembleg_2(copy_gc, stack_pointer, zero_operand);
959         if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) 
960             assembleg_2(copy_gc, stack_pointer, zero_operand);
961         if ((AO3.type == LOCALVAR_OT) && (AO3.value == 0))
962         {   if ((oc == aloadb_gc) || (oc == aload_gc))
963             {   assembleg_store(AO3, zero_ao);
964             }
965             else assembleg_2(copy_gc, stack_pointer, zero_operand);
966         }
967         assembleg_jump(final_label);
968
969         assemble_label_no(passed_label);
970         assembleg_3(oc, AO1, AO2, AO3);
971         assemble_label_no(final_label);
972         return;
973     }
974
975     /* Otherwise, compile a call to the veneer which verifies that
976        the proposed read/write is within dynamic Z-machine memory. */
977
978     switch(oc) { 
979         case aloadb_gc: vr = RT__ChLDB_VR; break;
980         case aload_gc: vr = RT__ChLDW_VR; break;
981         case astoreb_gc: vr = RT__ChSTB_VR; break;
982         case astore_gc: vr = RT__ChSTW_VR; break;
983         default: compiler_error("unknown array opcode");
984     }
985
986     if ((oc == aloadb_gc) || (oc == aload_gc)) 
987       assembleg_call_2(veneer_routine(vr), AO1, AO2, AO3);
988     else
989       assembleg_call_3(veneer_routine(vr), AO1, AO2, AO3, zero_operand);
990 }
991
992 static assembly_operand check_nonzero_at_runtime_g(assembly_operand AO1,
993         int error_label, int rte_number)
994 {
995   assembly_operand AO, AO2, AO3;
996   int ln;
997   int check_sp = FALSE, passed_label, failed_label, last_label;
998
999   if (veneer_mode) 
1000     return AO1;
1001
1002   /*  Assemble to code to check that the operand AO1 is ofclass Object:
1003       if it is, execution should continue and the stack should be
1004       unchanged.  Otherwise, call the veneer's run-time-error routine
1005       with the given error number, and then: if the label isn't -1,
1006       switch execution to this label, with the value popped from
1007       the stack if it was on the stack in the first place;
1008       if the label is -1, either replace the top of the stack with
1009       the constant symbol (class-object) Object.
1010
1011       The Object has no parent, child or sibling, so that the
1012       built-in tree functions will safely return 0 on this object. */
1013
1014   /*  Sometimes we can already see that the object number is valid. */
1015   if (AO1.marker == OBJECT_MV && 
1016     ((AO1.value >= 1) && (AO1.value <= no_objects))) {
1017     return AO1;
1018   }
1019
1020   passed_label = next_label++;
1021   failed_label = next_label++;  
1022
1023   if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0) && (AO1.marker == 0)) {
1024     /* That is, if AO1 is the stack pointer */
1025     check_sp = TRUE;
1026     assembleg_store(temp_var2, stack_pointer);
1027     assembleg_store(stack_pointer, temp_var2);
1028     AO = temp_var2;
1029   }
1030   else {
1031     AO = AO1;
1032   }
1033   
1034   if ((rte_number == IN_RTE) || (rte_number == HAS_RTE)
1035     || (rte_number == PROPERTY_RTE) || (rte_number == PROP_NUM_RTE)
1036     || (rte_number == PROP_ADD_RTE)) {   
1037     /* Allow classes */
1038     /* Test if zero... */
1039     assembleg_1_branch(jz_gc, AO, failed_label);
1040     /* Test if first byte is 0x70... */
1041     assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
1042     INITAO(&AO3);
1043     AO3.value = 0x70; /* type byte -- object */
1044     set_constant_ot(&AO3);
1045     assembleg_2_branch(jeq_gc, stack_pointer, AO3, passed_label);
1046   }
1047   else {
1048     /* Test if zero... */
1049     assembleg_1_branch(jz_gc, AO, failed_label);
1050     /* Test if first byte is 0x70... */
1051     assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
1052     INITAO(&AO3);
1053     AO3.value = 0x70; /* type byte -- object */
1054     set_constant_ot(&AO3);
1055     assembleg_2_branch(jne_gc, stack_pointer, AO3, failed_label);
1056     /* Test if inside the "Class" object... */
1057     INITAOTV(&AO3, BYTECONSTANT_OT, GOBJFIELD_PARENT());
1058     assembleg_3(aload_gc, AO, AO3, stack_pointer);
1059     ln = symbol_index("Class", -1);
1060     AO3.value = svals[ln];
1061     AO3.marker = OBJECT_MV;
1062     AO3.type = CONSTANT_OT;
1063     assembleg_2_branch(jne_gc, stack_pointer, AO3, passed_label);
1064   }
1065   
1066   assemble_label_no(failed_label);
1067   INITAO(&AO2);
1068   AO2.value = rte_number; 
1069   set_constant_ot(&AO2);
1070   assembleg_call_2(veneer_routine(RT__Err_VR), AO2, AO1, zero_operand);
1071   
1072   if (error_label != -1) {
1073     /* Jump to the error label */
1074     if (error_label == -3) assembleg_1(return_gc, zero_operand);
1075     else if (error_label == -4) assembleg_1(return_gc, one_operand);
1076     else assembleg_jump(error_label);
1077   }
1078   else {
1079     /* Build the symbol for "Object" */
1080     ln = symbol_index("Object", -1);
1081     AO2.value = svals[ln];
1082     AO2.marker = OBJECT_MV;
1083     AO2.type = CONSTANT_OT;
1084     if (check_sp) {
1085       /* Push "Object" */
1086       assembleg_store(AO1, AO2);
1087     }
1088     else {
1089       /* Store either "Object" or the operand's value in the temporary
1090          variable. */
1091       assembleg_store(temp_var2, AO2);
1092       last_label = next_label++;
1093       assembleg_jump(last_label);
1094       assemble_label_no(passed_label);
1095       assembleg_store(temp_var2, AO1);
1096       assemble_label_no(last_label);
1097       return temp_var2;
1098     }
1099   }
1100     
1101   assemble_label_no(passed_label);
1102   return AO1;
1103 }
1104
1105 static void compile_conditional_g(condclass *cc,
1106     assembly_operand AO1, assembly_operand AO2, int label, int flag)
1107 {   assembly_operand AO4; 
1108     int the_zc, error_label = label,
1109     va_flag = FALSE, va_label = 0;
1110
1111     ASSERT_GLULX(); 
1112
1113     the_zc = (flag ? cc->posform : cc->negform);
1114
1115     if (the_zc == -1) {
1116       switch ((cc-condclasses)*2 + 500) {
1117
1118       case HAS_CC:
1119         if (runtime_error_checking_switch) {
1120           if (flag) 
1121             error_label = next_label++;
1122           AO1 = check_nonzero_at_runtime(AO1, error_label, HAS_RTE);
1123           if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1124             if ((AO2.value < 0) || (AO2.value >= NUM_ATTR_BYTES*8)) {
1125               error("'has'/'hasnt' applied to illegal attribute number");
1126             }
1127           }
1128           else {
1129             int pa_label = next_label++, fa_label = next_label++;
1130             assembly_operand en_ao, max_ao;
1131
1132             if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) {
1133               if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1134                 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1135                 assembleg_2(stkpeek_gc, one_operand, temp_var2);
1136               }
1137               else {
1138                 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1139                 assembleg_store(temp_var2, AO2);
1140               }
1141             }
1142             else {
1143               assembleg_store(temp_var1, AO1);
1144               if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1145                 assembleg_2(stkpeek_gc, zero_operand, temp_var2);
1146               }
1147               else {
1148                 assembleg_store(temp_var2, AO2);
1149               }
1150             }
1151
1152             INITAO(&max_ao);
1153             max_ao.value = NUM_ATTR_BYTES*8;
1154             set_constant_ot(&max_ao);
1155             assembleg_2_branch(jlt_gc, temp_var2, zero_operand, fa_label);
1156             assembleg_2_branch(jlt_gc, temp_var2, max_ao, pa_label);
1157             assemble_label_no(fa_label);
1158             INITAO(&en_ao);
1159             en_ao.value = 19; /* INVALIDATTR_RTE */
1160             set_constant_ot(&en_ao);
1161             assembleg_store(stack_pointer, temp_var2);
1162             assembleg_store(stack_pointer, temp_var1);
1163             assembleg_store(stack_pointer, en_ao);
1164             assembleg_3(call_gc, veneer_routine(RT__Err_VR),
1165               three_operand, zero_operand);
1166             va_flag = TRUE; 
1167             va_label = next_label++;
1168             assembleg_jump(va_label);
1169             assemble_label_no(pa_label);
1170           }
1171         }
1172         if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1173           AO2.value += 8;
1174           set_constant_ot(&AO2);
1175         }
1176         else {
1177           INITAO(&AO4);
1178           AO4.value = 8;
1179           AO4.type = BYTECONSTANT_OT;
1180           if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) {
1181             if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) 
1182               assembleg_0(stkswap_gc);
1183             assembleg_3(add_gc, AO2, AO4, stack_pointer);
1184             assembleg_0(stkswap_gc);
1185           }
1186           else {
1187             assembleg_3(add_gc, AO2, AO4, stack_pointer);
1188           }
1189           AO2 = stack_pointer;
1190         }
1191         assembleg_3(aloadbit_gc, AO1, AO2, stack_pointer);
1192         the_zc = (flag ? jnz_gc : jz_gc);
1193         AO1 = stack_pointer;
1194         break;
1195
1196       case IN_CC:
1197         if (runtime_error_checking_switch) {
1198           if (flag) 
1199             error_label = next_label++;
1200           AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
1201         }
1202         INITAO(&AO4);
1203         AO4.value = GOBJFIELD_PARENT();
1204         AO4.type = BYTECONSTANT_OT;
1205         assembleg_3(aload_gc, AO1, AO4, stack_pointer);
1206         AO1 = stack_pointer;
1207         the_zc = (flag ? jeq_gc : jne_gc);
1208         break;
1209
1210       case OFCLASS_CC:
1211         assembleg_call_2(veneer_routine(OC__Cl_VR), AO1, AO2, stack_pointer);
1212         the_zc = (flag ? jnz_gc : jz_gc);
1213         AO1 = stack_pointer;
1214         break;
1215
1216       case PROVIDES_CC:
1217         assembleg_call_2(veneer_routine(OP__Pr_VR), AO1, AO2, stack_pointer);
1218         the_zc = (flag ? jnz_gc : jz_gc);
1219         AO1 = stack_pointer;
1220         break;
1221
1222       default:
1223         error("condition not yet supported in Glulx");
1224         return;
1225       }
1226     }
1227
1228     if (the_zc == jnz_gc || the_zc == jz_gc)
1229       assembleg_1_branch(the_zc, AO1, label);
1230     else
1231       assembleg_2_branch(the_zc, AO1, AO2, label);
1232     if (error_label != label) assemble_label_no(error_label);
1233     if (va_flag) assemble_label_no(va_label);
1234 }
1235
1236 static void value_in_void_context(assembly_operand AO)
1237 {
1238   if (!glulx_mode)
1239     value_in_void_context_z(AO);
1240   else
1241     value_in_void_context_g(AO);
1242 }
1243
1244
1245 extern assembly_operand check_nonzero_at_runtime(assembly_operand AO1,
1246   int error_label, int rte_number)
1247 {
1248   if (!glulx_mode)
1249     return check_nonzero_at_runtime_z(AO1, error_label, rte_number);
1250   else
1251     return check_nonzero_at_runtime_g(AO1, error_label, rte_number);
1252 }
1253
1254 static void generate_code_from(int n, int void_flag)
1255 {
1256     /*  When void, this must not leave anything on the stack. */
1257
1258     int i, j, below, above, opnum, arity; assembly_operand Result;
1259
1260     below = ET[n].down; above = ET[n].up;
1261     if (below == -1)
1262     {   if ((void_flag) && (ET[n].value.type != OMITTED_OT))
1263             value_in_void_context(ET[n].value);
1264         return;
1265     }
1266
1267     opnum = ET[n].operator_number;
1268
1269     if (opnum == COMMA_OP)
1270     {   generate_code_from(below, TRUE);
1271         generate_code_from(ET[below].right, void_flag);
1272         ET[n].value = ET[ET[below].right].value;
1273         goto OperatorGenerated;
1274     }
1275
1276     if ((opnum == LOGAND_OP) || (opnum == LOGOR_OP))
1277     {   generate_code_from(below, FALSE);
1278         generate_code_from(ET[below].right, FALSE);
1279         goto OperatorGenerated;
1280     }
1281
1282     if (opnum == -1)
1283     {
1284         /*  Signifies a SETEQUALS_OP which has already been done */
1285
1286         ET[n].down = -1; return;
1287     }
1288
1289     /*  Note that (except in the cases of comma and logical and/or) it
1290         is essential to code generate the operands right to left, because
1291         of the peculiar way the Z-machine's stack works:
1292
1293             @sub sp sp -> a;
1294
1295         (for instance) pulls to the first operand, then the second.  So
1296
1297             @mul a 2 -> sp;
1298             @add b 7 -> sp;
1299             @sub sp sp -> a;
1300
1301         calculates (b+7)-(a*2), not the other way around (as would be more
1302         usual in stack machines evaluating expressions written in reverse
1303         Polish notation).  (Basically this is because the Z-machine was
1304         designed to implement a LISP-like language naturally expressed
1305         in forward Polish notation: (PLUS 3 4), for instance.)               */
1306
1307     /*  And the Glulx machine follows the Z-machine in this respect. */
1308
1309     i=below; arity = 0;
1310     while (i != -1)
1311     {   i = ET[i].right; arity++;
1312     }
1313     for (j=arity;j>0;j--)
1314     {   int k = 1;
1315         i = below;
1316         while (k<j)
1317         {   k++; i = ET[i].right;
1318         }
1319         generate_code_from(i, FALSE);
1320     }
1321
1322
1323     /*  Check this again, because code generation lower down may have
1324         stubbed it into -1  */
1325
1326     if (ET[n].operator_number == -1)
1327     {   ET[n].down = -1; return;
1328     }
1329
1330   if (!glulx_mode) {
1331
1332     if (operators[opnum].opcode_number_z >= 400)
1333     {
1334         /*  Conditional terms such as '==': */
1335
1336         int a = ET[n].true_label, b = ET[n].false_label,
1337             branch_away, branch_other,
1338             make_jump_away = FALSE, make_branch_label = FALSE;
1339         int oc = operators[opnum].opcode_number_z-400, flag = TRUE;
1340
1341         if (oc >= 400) { oc = oc - 400; flag = FALSE; }
1342
1343         if ((oc == je_zc) && (arity == 2))
1344         {   i = ET[ET[n].down].right;
1345             if ((ET[i].value.value == zero_operand.value)
1346                 && (ET[i].value.type == zero_operand.type))
1347                 oc = jz_zc;
1348         }
1349
1350         /*  If the condition has truth state flag, branch to
1351             label a, and if not, to label b.  Possibly one of a, b
1352             equals -1, meaning "continue from this instruction".
1353
1354             branch_away is the label which is a branch away (the one
1355             which isn't immediately after) and flag is the truth
1356             state to branch there.
1357
1358             Note that when multiple instructions are needed (because
1359             of the use of the 'or' operator) the branch_other label
1360             is created if need be.
1361         */
1362
1363         /*  Reduce to the case where the branch_away label does exist:  */
1364
1365         if (a == -1) { a = b; b = -1; flag = !flag; }
1366
1367         branch_away = a; branch_other = b;
1368         if (branch_other != -1) make_jump_away = TRUE;
1369
1370         if ((((oc != je_zc)&&(arity > 2)) || (arity > 4)) && (flag == FALSE))
1371         {
1372             /*  In this case, we have an 'or' situation where multiple
1373                 instructions are needed and where the overall condition
1374                 is negated.  That is, we have, e.g.
1375
1376                    if not (A cond B or C or D) then branch_away
1377
1378                 which we transform into
1379
1380                    if (A cond B) then branch_other
1381                    if (A cond C) then branch_other
1382                    if not (A cond D) then branch_away
1383                   .branch_other                                          */
1384
1385             if (branch_other == -1)
1386             {   branch_other = next_label++; make_branch_label = TRUE;
1387             }
1388         }
1389
1390         if (oc == jz_zc)
1391             assemblez_1_branch(jz_zc, ET[below].value, branch_away, flag);
1392         else
1393         {   assembly_operand left_operand;
1394
1395             if (arity == 2)
1396                 compile_conditional_z(oc, ET[below].value,
1397                     ET[ET[below].right].value, branch_away, flag);
1398             else
1399             {   /*  The case of a condition using "or".
1400                     First: if the condition tests the stack pointer,
1401                     and it can't always be done in a single test, move
1402                     the value off the stack and into temporary variable
1403                     storage.  */
1404
1405                 if (((ET[below].value.type == VARIABLE_OT)
1406                      && (ET[below].value.value == 0))
1407                     && ((oc != je_zc) || (arity>4)) )
1408                 {   INITAOTV(&left_operand, VARIABLE_OT, 255);
1409                     assemblez_store(left_operand, ET[below].value);
1410                 }
1411                 else left_operand = ET[below].value;
1412                 i = ET[below].right; arity--;
1413
1414                 /*  "left_operand" now holds the quantity to be tested;
1415                     "i" holds the right operand reached so far;
1416                     "arity" the number of right operands.  */
1417
1418                 while (i != -1)
1419                 {   if ((oc == je_zc) && (arity>1))
1420                     {
1421                         /*  je_zc is an especially good case since the
1422                             Z-machine implements "or" for up to three
1423                             right operands automatically, though it's an
1424                             especially bad case to generate code for!  */
1425
1426                         if (arity == 2)
1427                         {   assemblez_3_branch(je_zc,
1428                               left_operand, ET[i].value,
1429                               ET[ET[i].right].value, branch_away, flag);
1430                             i = ET[i].right; arity--;
1431                         }
1432                         else
1433                         {   if ((arity == 3) || flag)
1434                               assemblez_4_branch(je_zc, left_operand,
1435                                 ET[i].value,
1436                                 ET[ET[i].right].value,
1437                                 ET[ET[ET[i].right].right].value,
1438                                 branch_away, flag);
1439                             else
1440                               assemblez_4_branch(je_zc, left_operand,
1441                                 ET[i].value,
1442                                 ET[ET[i].right].value,
1443                                 ET[ET[ET[i].right].right].value,
1444                                 branch_other, !flag);
1445                             i = ET[ET[i].right].right; arity -= 2;
1446                         }
1447                     }
1448                     else
1449                     {   /*  Otherwise we can compare the left_operand with
1450                             only one right operand at the time.  There are
1451                             two cases: it's the last right operand, or it
1452                             isn't.  */
1453
1454                         if ((arity == 1) || flag)
1455                             compile_conditional_z(oc, left_operand,
1456                                 ET[i].value, branch_away, flag);
1457                         else
1458                             compile_conditional_z(oc, left_operand,
1459                                 ET[i].value, branch_other, !flag);
1460                     }
1461                     i = ET[i].right; arity--;
1462                 }
1463
1464             }
1465         }
1466
1467         /*  NB: These two conditions cannot both occur, fortunately!  */
1468
1469         if (make_branch_label) assemble_label_no(branch_other);
1470         if (make_jump_away) assemblez_jump(branch_other);
1471
1472         goto OperatorGenerated;
1473     }
1474
1475   }
1476   else {
1477     if (operators[opnum].opcode_number_g >= FIRST_CC 
1478       && operators[opnum].opcode_number_g <= LAST_CC) {
1479       /*  Conditional terms such as '==': */
1480
1481       int a = ET[n].true_label, b = ET[n].false_label;
1482       int branch_away, branch_other, flag,
1483         make_jump_away = FALSE, make_branch_label = FALSE;
1484       int ccode = operators[opnum].opcode_number_g;
1485       condclass *cc = &condclasses[(ccode-FIRST_CC) / 2];
1486       flag = (ccode & 1) ? 0 : 1;
1487
1488       /*  If the comparison is "equal to (constant) 0", change it
1489           to the simple "zero" test. Unfortunately, this doesn't
1490           work for the commutative form "(constant) 0 is equal to". 
1491           At least I don't think it does. */
1492
1493       if ((cc == &condclasses[1]) && (arity == 2)) {
1494         i = ET[ET[n].down].right;
1495         if ((ET[i].value.value == 0)
1496           && (ET[i].value.marker == 0) 
1497           && is_constant_ot(ET[i].value.type)) {
1498           cc = &condclasses[0];
1499         }
1500       }
1501
1502       /*  If the condition has truth state flag, branch to
1503           label a, and if not, to label b.  Possibly one of a, b
1504           equals -1, meaning "continue from this instruction".
1505           
1506           branch_away is the label which is a branch away (the one
1507           which isn't immediately after) and flag is the truth
1508           state to branch there.
1509
1510           Note that when multiple instructions are needed (because
1511           of the use of the 'or' operator) the branch_other label
1512           is created if need be.
1513       */
1514       
1515       /*  Reduce to the case where the branch_away label does exist:  */
1516
1517       if (a == -1) { a = b; b = -1; flag = !flag; }
1518
1519       branch_away = a; branch_other = b;
1520       if (branch_other != -1) make_jump_away = TRUE;
1521       
1522       if ((arity > 2) && (flag == FALSE)) {
1523         /*  In this case, we have an 'or' situation where multiple
1524             instructions are needed and where the overall condition
1525             is negated.  That is, we have, e.g.
1526             
1527             if not (A cond B or C or D) then branch_away
1528             
1529             which we transform into
1530             
1531             if (A cond B) then branch_other
1532             if (A cond C) then branch_other
1533             if not (A cond D) then branch_away
1534             .branch_other                                          */
1535         
1536         if (branch_other == -1) {
1537           branch_other = next_label++; make_branch_label = TRUE;
1538         }
1539       }
1540
1541       if (cc == &condclasses[0]) {
1542         assembleg_1_branch((flag ? cc->posform : cc->negform), 
1543           ET[below].value, branch_away);
1544       }
1545       else {
1546         if (arity == 2) {
1547           compile_conditional_g(cc, ET[below].value,
1548             ET[ET[below].right].value, branch_away, flag);
1549         }
1550         else {
1551           /*  The case of a condition using "or".
1552               First: if the condition tests the stack pointer,
1553               and it can't always be done in a single test, move
1554               the value off the stack and into temporary variable
1555               storage.  */
1556
1557           assembly_operand left_operand;
1558           if (((ET[below].value.type == LOCALVAR_OT)
1559             && (ET[below].value.value == 0))) {
1560             assembleg_store(temp_var1, ET[below].value);
1561             left_operand = temp_var1;
1562           }
1563           else {
1564             left_operand = ET[below].value;
1565           }
1566           i = ET[below].right; 
1567           arity--;
1568
1569           /*  "left_operand" now holds the quantity to be tested;
1570               "i" holds the right operand reached so far;
1571               "arity" the number of right operands.  */
1572
1573           while (i != -1) {
1574             /*  We can compare the left_operand with
1575             only one right operand at the time.  There are
1576             two cases: it's the last right operand, or it
1577             isn't.  */
1578
1579             if ((arity == 1) || flag)
1580               compile_conditional_g(cc, left_operand,
1581             ET[i].value, branch_away, flag);
1582             else
1583               compile_conditional_g(cc, left_operand,
1584             ET[i].value, branch_other, !flag);
1585
1586             i = ET[i].right; 
1587             arity--;
1588           }
1589         }
1590       }
1591       
1592       /*  NB: These two conditions cannot both occur, fortunately!  */
1593       
1594       if (make_branch_label) assemble_label_no(branch_other);
1595       if (make_jump_away) assembleg_jump(branch_other);
1596       
1597       goto OperatorGenerated;
1598     }
1599
1600   }
1601
1602     /*  The operator is now definitely one which produces a value  */
1603
1604     if (void_flag && (!(operators[opnum].side_effect)))
1605         error_named("Evaluating this has no effect:",
1606             operators[opnum].description);
1607
1608     /*  Where shall we put the resulting value? (In Glulx, this could 
1609         be smarter, and peg the result into ZEROCONSTANT.) */
1610
1611     if (void_flag) Result = temp_var1;  /*  Throw it away  */
1612     else
1613     {   if ((above != -1) && (ET[above].operator_number == SETEQUALS_OP))
1614         {
1615             /*  If the node above is "set variable equal to", then
1616                 make that variable the place to put the result, and
1617                 delete the SETEQUALS_OP node since its effect has already
1618                 been accomplished.  */
1619
1620             ET[above].operator_number = -1;
1621             Result = ET[ET[above].down].value;
1622             ET[above].value = Result;
1623         }
1624         else Result = stack_pointer;  /*  Otherwise, put it on the stack  */
1625     }
1626
1627   if (!glulx_mode) {
1628
1629     if (operators[opnum].opcode_number_z != -1)
1630     {
1631         /*  Operators directly translatable into Z-code opcodes: infix ops
1632             take two operands whereas pre/postfix operators take only one */
1633
1634         if (operators[opnum].usage == IN_U)
1635         {   int o_n = operators[opnum].opcode_number_z;
1636             if (runtime_error_checking_switch && (!veneer_mode)
1637                 && ((o_n == div_zc) || (o_n == mod_zc)))
1638             {   assembly_operand by_ao, error_ao; int ln;
1639                 by_ao = ET[ET[below].right].value;
1640                 if ((by_ao.value != 0) && (by_ao.marker == 0)
1641                     && ((by_ao.type == SHORT_CONSTANT_OT)
1642                         || (by_ao.type == LONG_CONSTANT_OT)))
1643                     assemblez_2_to(o_n, ET[below].value,
1644                         by_ao, Result);
1645                 else
1646                 {
1647                     assemblez_store(temp_var1, ET[below].value);
1648                     assemblez_store(temp_var2, by_ao);
1649                     ln = next_label++;
1650                     assemblez_1_branch(jz_zc, temp_var2, ln, FALSE);
1651                     INITAOT(&error_ao, SHORT_CONSTANT_OT);
1652                     error_ao.value = DBYZERO_RTE;
1653                     assemblez_2(call_vn_zc, veneer_routine(RT__Err_VR),
1654                         error_ao);
1655                     assemblez_inc(temp_var2);
1656                     assemble_label_no(ln);
1657                     assemblez_2_to(o_n, temp_var1, temp_var2, Result);
1658                 }
1659             }
1660             else {
1661             assemblez_2_to(o_n, ET[below].value,
1662                 ET[ET[below].right].value, Result);
1663             }
1664         }
1665         else
1666             assemblez_1_to(operators[opnum].opcode_number_z, ET[below].value,
1667                 Result);
1668     }
1669     else
1670     switch(opnum)
1671     {   case ARROW_OP:
1672              access_memory_z(loadb_zc, ET[below].value,
1673                                      ET[ET[below].right].value, Result);
1674              break;
1675         case DARROW_OP:
1676              access_memory_z(loadw_zc, ET[below].value,
1677                                      ET[ET[below].right].value, Result);
1678              break;
1679         case UNARY_MINUS_OP:
1680              assemblez_2_to(sub_zc, zero_operand, ET[below].value, Result);
1681              break;
1682         case ARTNOT_OP:
1683              assemblez_1_to(not_zc, ET[below].value, Result);
1684              break;
1685
1686         case PROP_ADD_OP:
1687              {   assembly_operand AO = ET[below].value;
1688                  if (runtime_error_checking_switch && (!veneer_mode))
1689                      AO = check_nonzero_at_runtime(AO, -1, PROP_ADD_RTE);
1690                  assemblez_2_to(get_prop_addr_zc, AO,
1691                      ET[ET[below].right].value, temp_var1);
1692                  if (!void_flag) write_result_z(Result, temp_var1);
1693              }
1694              break;
1695
1696         case PROP_NUM_OP:
1697              {   assembly_operand AO = ET[below].value;
1698                  if (runtime_error_checking_switch && (!veneer_mode))
1699                      AO = check_nonzero_at_runtime(AO, -1, PROP_NUM_RTE);
1700                  assemblez_2_to(get_prop_addr_zc, AO,
1701                      ET[ET[below].right].value, temp_var1);
1702                  assemblez_1_branch(jz_zc, temp_var1, next_label++, TRUE);
1703                  assemblez_1_to(get_prop_len_zc, temp_var1, temp_var1);
1704                  assemble_label_no(next_label-1);
1705                  if (!void_flag) write_result_z(Result, temp_var1);
1706              }
1707              break;
1708
1709         case PROPERTY_OP:
1710              {   assembly_operand AO = ET[below].value;
1711
1712                  if (runtime_error_checking_switch && (!veneer_mode))
1713                        assemblez_3_to(call_vs_zc, veneer_routine(RT__ChPR_VR),
1714                          AO, ET[ET[below].right].value, temp_var1);
1715                  else
1716                  assemblez_2_to(get_prop_zc, AO,
1717                      ET[ET[below].right].value, temp_var1);
1718                  if (!void_flag) write_result_z(Result, temp_var1);
1719              }
1720              break;
1721
1722         case MESSAGE_OP:
1723              j=1; AI.operand[0] = veneer_routine(RV__Pr_VR);
1724              goto GenFunctionCallZ;
1725         case MPROP_ADD_OP:
1726              j=1; AI.operand[0] = veneer_routine(RA__Pr_VR);
1727              goto GenFunctionCallZ;
1728         case MPROP_NUM_OP:
1729              j=1; AI.operand[0] = veneer_routine(RL__Pr_VR);
1730              goto GenFunctionCallZ;
1731         case MESSAGE_SETEQUALS_OP:
1732              j=1; AI.operand[0] = veneer_routine(WV__Pr_VR);
1733              goto GenFunctionCallZ;
1734         case MESSAGE_INC_OP:
1735              j=1; AI.operand[0] = veneer_routine(IB__Pr_VR);
1736              goto GenFunctionCallZ;
1737         case MESSAGE_DEC_OP:
1738              j=1; AI.operand[0] = veneer_routine(DB__Pr_VR);
1739              goto GenFunctionCallZ;
1740         case MESSAGE_POST_INC_OP:
1741              j=1; AI.operand[0] = veneer_routine(IA__Pr_VR);
1742              goto GenFunctionCallZ;
1743         case MESSAGE_POST_DEC_OP:
1744              j=1; AI.operand[0] = veneer_routine(DA__Pr_VR);
1745              goto GenFunctionCallZ;
1746         case SUPERCLASS_OP:
1747              j=1; AI.operand[0] = veneer_routine(RA__Sc_VR);
1748              goto GenFunctionCallZ;
1749         case PROP_CALL_OP:
1750              j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
1751              goto GenFunctionCallZ;
1752         case MESSAGE_CALL_OP:
1753              j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
1754              goto GenFunctionCallZ;
1755
1756
1757         case FCALL_OP:
1758              j = 0;
1759
1760              if ((ET[below].value.type == VARIABLE_OT)
1761                  && (ET[below].value.value >= 256))
1762              {   int sf_number = ET[below].value.value - 256;
1763
1764                  i = ET[below].right;
1765                  if (i == -1)
1766                  {   error("Argument to system function missing");
1767                      AI.operand[0] = one_operand;
1768                      AI.operand_count = 1;
1769                  }
1770                  else
1771                  {   j=0;
1772                      while (i != -1) { j++; i = ET[i].right; }
1773
1774                      if (((sf_number != INDIRECT_SYSF) &&
1775                          (sf_number != RANDOM_SYSF) && (j > 1))
1776                          || ((sf_number == INDIRECT_SYSF) && (j>7)))
1777                      {   j=1;
1778                          error("System function given with too many arguments");
1779                      }
1780                      if (sf_number != RANDOM_SYSF)
1781                      {   int jcount;
1782                          i = ET[below].right;
1783                          for (jcount = 0; jcount < j; jcount++)
1784                          {   AI.operand[jcount] = ET[i].value;
1785                              i = ET[i].right;
1786                          }
1787                          AI.operand_count = j;
1788                      }
1789                  }
1790                  AI.store_variable_number = Result.value;
1791                  AI.branch_label_number = -1;
1792
1793                  switch(sf_number)
1794                  {   case RANDOM_SYSF:
1795                          if (j>1)
1796                          {  assembly_operand AO, AO2; int arg_c, arg_et;
1797                             INITAOTV(&AO, SHORT_CONSTANT_OT, j);
1798                             INITAOT(&AO2, LONG_CONSTANT_OT);
1799                             AO2.value = begin_word_array();
1800                             AO2.marker = ARRAY_MV;
1801
1802                             for (arg_c=0, arg_et = ET[below].right;arg_c<j;
1803                                  arg_c++, arg_et = ET[arg_et].right)
1804                             {   if (ET[arg_et].value.type == VARIABLE_OT)
1805               error("Only constants can be used as possible 'random' results");
1806                                 array_entry(arg_c, FALSE, ET[arg_et].value);
1807                             }
1808                             finish_array(arg_c, FALSE);
1809
1810                             assemblez_1_to(random_zc, AO, temp_var1);
1811                             assemblez_dec(temp_var1);
1812                             assemblez_2_to(loadw_zc, AO2, temp_var1, Result);
1813                          }
1814                          else
1815                          assemblez_1_to(random_zc,
1816                              ET[ET[below].right].value, Result);
1817                          break;
1818
1819                      case PARENT_SYSF:
1820                          {  assembly_operand AO;
1821                             AO = ET[ET[below].right].value;
1822                             if (runtime_error_checking_switch)
1823                                 AO = check_nonzero_at_runtime(AO, -1,
1824                                     PARENT_RTE);
1825                             assemblez_1_to(get_parent_zc, AO, Result);
1826                          }
1827                          break;
1828
1829                      case ELDEST_SYSF:
1830                      case CHILD_SYSF:
1831                          {  assembly_operand AO;
1832                             AO = ET[ET[below].right].value;
1833                             if (runtime_error_checking_switch)
1834                                AO = check_nonzero_at_runtime(AO, -1,
1835                                (sf_number==CHILD_SYSF)?CHILD_RTE:ELDEST_RTE);
1836                             assemblez_objcode(get_child_zc,
1837                                AO, Result, -2, TRUE);
1838                          }
1839                          break;
1840
1841                      case YOUNGER_SYSF:
1842                      case SIBLING_SYSF:
1843                          {  assembly_operand AO;
1844                             AO = ET[ET[below].right].value;
1845                             if (runtime_error_checking_switch)
1846                                AO = check_nonzero_at_runtime(AO, -1,
1847                                (sf_number==SIBLING_SYSF)
1848                                    ?SIBLING_RTE:YOUNGER_RTE);
1849                             assemblez_objcode(get_sibling_zc,
1850                                AO, Result, -2, TRUE);
1851                          }
1852                          break;
1853
1854                      case INDIRECT_SYSF:
1855                          j=0; i = ET[below].right;
1856                          goto IndirectFunctionCallZ;
1857
1858                      case CHILDREN_SYSF:
1859                          {  assembly_operand AO;
1860                              AO = ET[ET[below].right].value;
1861                              if (runtime_error_checking_switch)
1862                                  AO = check_nonzero_at_runtime(AO, -1,
1863                                      CHILDREN_RTE);
1864                              assemblez_store(temp_var1, zero_operand);
1865                              assemblez_objcode(get_child_zc,
1866                                  AO, stack_pointer, next_label+1, FALSE);
1867                              assemble_label_no(next_label);
1868                              assemblez_inc(temp_var1);
1869                              assemblez_objcode(get_sibling_zc,
1870                                  stack_pointer, stack_pointer,
1871                                  next_label, TRUE);
1872                              assemble_label_no(next_label+1);
1873                              assemblez_store(temp_var2, stack_pointer);
1874                              if (!void_flag) write_result_z(Result, temp_var1);
1875                              next_label += 2;
1876                          }
1877                          break;
1878
1879                      case YOUNGEST_SYSF:
1880                          {  assembly_operand AO;
1881                              AO = ET[ET[below].right].value;
1882                              if (runtime_error_checking_switch)
1883                                  AO = check_nonzero_at_runtime(AO, -1,
1884                                      YOUNGEST_RTE);
1885                              assemblez_objcode(get_child_zc,
1886                                  AO, temp_var1, next_label+1, FALSE);
1887                              assemblez_1(push_zc, temp_var1);
1888                              assemble_label_no(next_label);
1889                              assemblez_store(temp_var1, stack_pointer);
1890                              assemblez_objcode(get_sibling_zc,
1891                                  temp_var1, stack_pointer, next_label, TRUE);
1892                              assemble_label_no(next_label+1);
1893                              if (!void_flag) write_result_z(Result, temp_var1);
1894                              next_label += 2;
1895                          }
1896                          break;
1897
1898                      case ELDER_SYSF:
1899                          assemblez_store(temp_var1, ET[ET[below].right].value);
1900                          if (runtime_error_checking_switch)
1901                              check_nonzero_at_runtime(temp_var1, -1,
1902                                  ELDER_RTE);
1903                          assemblez_1_to(get_parent_zc, temp_var1, temp_var3);
1904                          assemblez_1_branch(jz_zc, temp_var3,next_label+1,TRUE);
1905                          assemblez_store(temp_var2, temp_var3);
1906                          assemblez_store(temp_var3, zero_operand);
1907                          assemblez_objcode(get_child_zc,
1908                              temp_var2, temp_var2, next_label, TRUE);
1909                          assemble_label_no(next_label++);
1910                          assemblez_2_branch(je_zc, temp_var1, temp_var2,
1911                              next_label, TRUE);
1912                          assemblez_store(temp_var3, temp_var2);
1913                          assemblez_objcode(get_sibling_zc,
1914                              temp_var2, temp_var2, next_label - 1, TRUE);
1915                          assemble_label_no(next_label++);
1916                          if (!void_flag) write_result_z(Result, temp_var3);
1917                          break;
1918
1919                      case METACLASS_SYSF:
1920                          assemblez_2_to((version_number==3)?call_zc:call_vs_zc,
1921                              veneer_routine(Metaclass_VR),
1922                              ET[ET[below].right].value, Result);
1923                          break;
1924
1925                      case GLK_SYSF: 
1926                          error("The glk() system function does not exist in Z-code");
1927                          break;
1928                  }
1929                  break;
1930              }
1931
1932              GenFunctionCallZ:
1933
1934              i = below;
1935
1936              IndirectFunctionCallZ:
1937
1938              while ((i != -1) && (j<8))
1939              {   AI.operand[j++] = ET[i].value;
1940                  i = ET[i].right;
1941              }
1942
1943              if ((j > 4) && (version_number == 3))
1944              {   error("A function may be called with at most 3 arguments");
1945                  j = 4;
1946              }
1947              if ((j==8) && (i != -1))
1948              {   error("A function may be called with at most 7 arguments");
1949              }
1950
1951              AI.operand_count = j;
1952
1953              if ((void_flag) && (version_number >= 5))
1954              {   AI.store_variable_number = -1;
1955                  switch(j)
1956                  {   case 1: AI.internal_number = call_1n_zc; break;
1957                      case 2: AI.internal_number = call_2n_zc; break;
1958                      case 3: case 4: AI.internal_number = call_vn_zc; break;
1959                      case 5: case 6: case 7: case 8:
1960                          AI.internal_number = call_vn2_zc; break;
1961                  }
1962              }
1963              else
1964              {   AI.store_variable_number = Result.value;
1965                  if (version_number == 3)
1966                      AI.internal_number = call_zc;
1967                  else
1968                  switch(j)
1969                  {   case 1: AI.internal_number = call_1s_zc; break;
1970                      case 2: AI.internal_number = call_2s_zc; break;
1971                      case 3: case 4: AI.internal_number = call_vs_zc; break;
1972                      case 5: case 6: case 7: case 8:
1973                          AI.internal_number = call_vs2_zc; break;
1974                  }
1975              }
1976
1977              AI.branch_label_number = -1;
1978              assemblez_instruction(&AI);
1979              break;
1980
1981         case SETEQUALS_OP:
1982              assemblez_store(ET[below].value,
1983                  ET[ET[below].right].value);
1984              if (!void_flag) write_result_z(Result, ET[below].value);
1985              break;
1986
1987         case PROPERTY_SETEQUALS_OP:
1988              if (!void_flag)
1989              {   if (runtime_error_checking_switch)
1990                      assemblez_4_to(call_zc, veneer_routine(RT__ChPS_VR),
1991                          ET[below].value, ET[ET[below].right].value,
1992                          ET[ET[ET[below].right].right].value, Result);
1993                  else
1994                  {   assemblez_store(temp_var1,
1995                          ET[ET[ET[below].right].right].value);
1996                      assemblez_3(put_prop_zc, ET[below].value,
1997                          ET[ET[below].right].value,
1998                          temp_var1);
1999                      write_result_z(Result, temp_var1);
2000                  }
2001              }
2002              else
2003              {   if (runtime_error_checking_switch && (!veneer_mode))
2004                      assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2005                          ET[below].value, ET[ET[below].right].value,
2006                          ET[ET[ET[below].right].right].value);
2007                  else assemblez_3(put_prop_zc, ET[below].value,
2008                      ET[ET[below].right].value,
2009                      ET[ET[ET[below].right].right].value);
2010              }
2011              break;
2012         case ARROW_SETEQUALS_OP:
2013              if (!void_flag)
2014              {   assemblez_store(temp_var1,
2015                      ET[ET[ET[below].right].right].value);
2016                  access_memory_z(storeb_zc, ET[below].value,
2017                      ET[ET[below].right].value,
2018                      temp_var1);
2019                  write_result_z(Result, temp_var1);
2020              }
2021              else access_memory_z(storeb_zc, ET[below].value,
2022                      ET[ET[below].right].value,
2023                      ET[ET[ET[below].right].right].value);
2024              break;
2025
2026         case DARROW_SETEQUALS_OP:
2027              if (!void_flag)
2028              {   assemblez_store(temp_var1,
2029                      ET[ET[ET[below].right].right].value);
2030                  access_memory_z(storew_zc, ET[below].value,
2031                      ET[ET[below].right].value,
2032                      temp_var1);
2033                  write_result_z(Result, temp_var1);
2034              }
2035              else
2036                  access_memory_z(storew_zc, ET[below].value,
2037                      ET[ET[below].right].value,
2038                      ET[ET[ET[below].right].right].value);
2039              break;
2040
2041         case INC_OP:
2042              assemblez_inc(ET[below].value);
2043              if (!void_flag) write_result_z(Result, ET[below].value);
2044              break;
2045         case DEC_OP:
2046              assemblez_dec(ET[below].value);
2047              if (!void_flag) write_result_z(Result, ET[below].value);
2048              break;
2049         case POST_INC_OP:
2050              if (!void_flag) write_result_z(Result, ET[below].value);
2051              assemblez_inc(ET[below].value);
2052              break;
2053         case POST_DEC_OP:
2054              if (!void_flag) write_result_z(Result, ET[below].value);
2055              assemblez_dec(ET[below].value);
2056              break;
2057
2058         case ARROW_INC_OP:
2059              assemblez_store(temp_var1, ET[below].value);
2060              assemblez_store(temp_var2, ET[ET[below].right].value);
2061              access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2062              assemblez_inc(temp_var3);
2063              access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2064              if (!void_flag) write_result_z(Result, temp_var3);
2065              break;
2066
2067         case ARROW_DEC_OP:
2068              assemblez_store(temp_var1, ET[below].value);
2069              assemblez_store(temp_var2, ET[ET[below].right].value);
2070              access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2071              assemblez_dec(temp_var3);
2072              access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2073              if (!void_flag) write_result_z(Result, temp_var3);
2074              break;
2075
2076         case ARROW_POST_INC_OP:
2077              assemblez_store(temp_var1, ET[below].value);
2078              assemblez_store(temp_var2, ET[ET[below].right].value);
2079              access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2080              if (!void_flag) write_result_z(Result, temp_var3);
2081              assemblez_inc(temp_var3);
2082              access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2083              break;
2084
2085         case ARROW_POST_DEC_OP:
2086              assemblez_store(temp_var1, ET[below].value);
2087              assemblez_store(temp_var2, ET[ET[below].right].value);
2088              access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2089              if (!void_flag) write_result_z(Result, temp_var3);
2090              assemblez_dec(temp_var3);
2091              access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2092              break;
2093
2094         case DARROW_INC_OP:
2095              assemblez_store(temp_var1, ET[below].value);
2096              assemblez_store(temp_var2, ET[ET[below].right].value);
2097              access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2098              assemblez_inc(temp_var3);
2099              access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2100              if (!void_flag) write_result_z(Result, temp_var3);
2101              break;
2102
2103         case DARROW_DEC_OP:
2104              assemblez_store(temp_var1, ET[below].value);
2105              assemblez_store(temp_var2, ET[ET[below].right].value);
2106              access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2107              assemblez_dec(temp_var3);
2108              access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2109              if (!void_flag) write_result_z(Result, temp_var3);
2110              break;
2111
2112         case DARROW_POST_INC_OP:
2113              assemblez_store(temp_var1, ET[below].value);
2114              assemblez_store(temp_var2, ET[ET[below].right].value);
2115              access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2116              if (!void_flag) write_result_z(Result, temp_var3);
2117              assemblez_inc(temp_var3);
2118              access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2119              break;
2120
2121         case DARROW_POST_DEC_OP:
2122              assemblez_store(temp_var1, ET[below].value);
2123              assemblez_store(temp_var2, ET[ET[below].right].value);
2124              access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2125              if (!void_flag) write_result_z(Result, temp_var3);
2126              assemblez_dec(temp_var3);
2127              access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2128              break;
2129
2130         case PROPERTY_INC_OP:
2131              assemblez_store(temp_var1, ET[below].value);
2132              assemblez_store(temp_var2, ET[ET[below].right].value);
2133              assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2134              assemblez_inc(temp_var3);
2135              if (runtime_error_checking_switch && (!veneer_mode))
2136                   assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2137                          temp_var1, temp_var2, temp_var3);
2138              else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2139              if (!void_flag) write_result_z(Result, temp_var3);
2140              break;
2141
2142         case PROPERTY_DEC_OP:
2143              assemblez_store(temp_var1, ET[below].value);
2144              assemblez_store(temp_var2, ET[ET[below].right].value);
2145              assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2146              assemblez_dec(temp_var3);
2147              if (runtime_error_checking_switch && (!veneer_mode))
2148                   assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2149                          temp_var1, temp_var2, temp_var3);
2150              else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2151              if (!void_flag) write_result_z(Result, temp_var3);
2152              break;
2153
2154         case PROPERTY_POST_INC_OP:
2155              assemblez_store(temp_var1, ET[below].value);
2156              assemblez_store(temp_var2, ET[ET[below].right].value);
2157              assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2158              if (!void_flag) write_result_z(Result, temp_var3);
2159              assemblez_inc(temp_var3);
2160              if (runtime_error_checking_switch && (!veneer_mode))
2161                   assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2162                          temp_var1, temp_var2, temp_var3);
2163              else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2164              break;
2165
2166         case PROPERTY_POST_DEC_OP:
2167              assemblez_store(temp_var1, ET[below].value);
2168              assemblez_store(temp_var2, ET[ET[below].right].value);
2169              assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2170              if (!void_flag) write_result_z(Result, temp_var3);
2171              assemblez_dec(temp_var3);
2172              if (runtime_error_checking_switch && (!veneer_mode))
2173                   assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2174                          temp_var1, temp_var2, temp_var3);
2175              else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2176              break;
2177
2178         default:
2179             printf("** Trouble op = %d i.e. '%s' **\n",
2180                 opnum, operators[opnum].description);
2181             compiler_error("Expr code gen: Can't generate yet");
2182     }
2183   }
2184   else {
2185     assembly_operand AO, AO2;
2186     if (operators[opnum].opcode_number_g != -1)
2187     {
2188         /*  Operators directly translatable into opcodes: infix ops
2189             take two operands whereas pre/postfix operators take only one */
2190
2191         if (operators[opnum].usage == IN_U)
2192         {   int o_n = operators[opnum].opcode_number_g;
2193             if (runtime_error_checking_switch && (!veneer_mode)
2194                 && ((o_n == div_gc) || (o_n == mod_gc)))
2195             {   assembly_operand by_ao, error_ao; int ln;
2196                 by_ao = ET[ET[below].right].value;
2197                 if ((by_ao.value != 0) && (by_ao.marker == 0)
2198                     && is_constant_ot(by_ao.type))
2199                     assembleg_3(o_n, ET[below].value,
2200                         by_ao, Result);
2201                 else
2202                 {   assembleg_store(temp_var1, ET[below].value);
2203                     assembleg_store(temp_var2, by_ao);
2204                     ln = next_label++;
2205                     assembleg_1_branch(jnz_gc, temp_var2, ln);
2206                     INITAO(&error_ao);
2207                     error_ao.value = DBYZERO_RTE;
2208                     set_constant_ot(&error_ao);
2209                     assembleg_call_1(veneer_routine(RT__Err_VR),
2210                       error_ao, zero_operand);
2211                     assembleg_store(temp_var2, one_operand);
2212                     assemble_label_no(ln);
2213                     assembleg_3(o_n, temp_var1, temp_var2, Result);
2214                 }
2215             }
2216             else
2217             assembleg_3(o_n, ET[below].value,
2218                 ET[ET[below].right].value, Result);
2219         }
2220         else
2221             assembleg_2(operators[opnum].opcode_number_g, ET[below].value,
2222                 Result);
2223     }
2224     else
2225     switch(opnum)
2226     {
2227
2228         case PUSH_OP:
2229              if (ET[below].value.type == Result.type
2230                && ET[below].value.value == Result.value
2231                && ET[below].value.marker == Result.marker)
2232                break;
2233              assembleg_2(copy_gc, ET[below].value, Result);
2234              break;
2235
2236         case UNARY_MINUS_OP:
2237              assembleg_2(neg_gc, ET[below].value, Result);
2238              break;
2239         case ARTNOT_OP:
2240              assembleg_2(bitnot_gc, ET[below].value, Result);
2241              break;
2242
2243         case ARROW_OP:
2244              access_memory_g(aloadb_gc, ET[below].value,
2245                                       ET[ET[below].right].value, Result);
2246              break;
2247         case DARROW_OP:
2248              access_memory_g(aload_gc, ET[below].value,
2249                                      ET[ET[below].right].value, Result);
2250              break;
2251
2252         case SETEQUALS_OP:
2253              assembleg_store(ET[below].value,
2254                  ET[ET[below].right].value);
2255              if (!void_flag) write_result_g(Result, ET[below].value);
2256              break;
2257
2258         case ARROW_SETEQUALS_OP:
2259              if (!void_flag)
2260              {   assembleg_store(temp_var1,
2261                      ET[ET[ET[below].right].right].value);
2262                  access_memory_g(astoreb_gc, ET[below].value,
2263                      ET[ET[below].right].value,
2264                      temp_var1);
2265                  write_result_g(Result, temp_var1);
2266              }
2267              else access_memory_g(astoreb_gc, ET[below].value,
2268                      ET[ET[below].right].value,
2269                      ET[ET[ET[below].right].right].value);
2270              break;
2271
2272         case DARROW_SETEQUALS_OP:
2273              if (!void_flag)
2274              {   assembleg_store(temp_var1,
2275                      ET[ET[ET[below].right].right].value);
2276                  access_memory_g(astore_gc, ET[below].value,
2277                      ET[ET[below].right].value,
2278                      temp_var1);
2279                  write_result_g(Result, temp_var1);
2280              }
2281              else
2282                  access_memory_g(astore_gc, ET[below].value,
2283                      ET[ET[below].right].value,
2284                      ET[ET[ET[below].right].right].value);
2285              break;
2286
2287         case INC_OP:
2288              assembleg_inc(ET[below].value);
2289              if (!void_flag) write_result_g(Result, ET[below].value);
2290              break;
2291         case DEC_OP:
2292              assembleg_dec(ET[below].value);
2293              if (!void_flag) write_result_g(Result, ET[below].value);
2294              break;
2295         case POST_INC_OP:
2296              if (!void_flag) write_result_g(Result, ET[below].value);
2297              assembleg_inc(ET[below].value);
2298              break;
2299         case POST_DEC_OP:
2300              if (!void_flag) write_result_g(Result, ET[below].value);
2301              assembleg_dec(ET[below].value);
2302              break;
2303
2304         case ARROW_INC_OP:
2305              assembleg_store(temp_var1, ET[below].value);
2306              assembleg_store(temp_var2, ET[ET[below].right].value);
2307              access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2308              assembleg_inc(temp_var3);
2309              access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2310              if (!void_flag) write_result_g(Result, temp_var3);
2311              break;
2312
2313         case ARROW_DEC_OP:
2314              assembleg_store(temp_var1, ET[below].value);
2315              assembleg_store(temp_var2, ET[ET[below].right].value);
2316              access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2317              assembleg_dec(temp_var3);
2318              access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2319              if (!void_flag) write_result_g(Result, temp_var3);
2320              break;
2321
2322         case ARROW_POST_INC_OP:
2323              assembleg_store(temp_var1, ET[below].value);
2324              assembleg_store(temp_var2, ET[ET[below].right].value);
2325              access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2326              if (!void_flag) write_result_g(Result, temp_var3);
2327              assembleg_inc(temp_var3);
2328              access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2329              break;
2330
2331         case ARROW_POST_DEC_OP:
2332              assembleg_store(temp_var1, ET[below].value);
2333              assembleg_store(temp_var2, ET[ET[below].right].value);
2334              access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2335              if (!void_flag) write_result_g(Result, temp_var3);
2336              assembleg_dec(temp_var3);
2337              access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2338              break;
2339
2340         case DARROW_INC_OP:
2341              assembleg_store(temp_var1, ET[below].value);
2342              assembleg_store(temp_var2, ET[ET[below].right].value);
2343              access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2344              assembleg_inc(temp_var3);
2345              access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2346              if (!void_flag) write_result_g(Result, temp_var3);
2347              break;
2348
2349         case DARROW_DEC_OP:
2350              assembleg_store(temp_var1, ET[below].value);
2351              assembleg_store(temp_var2, ET[ET[below].right].value);
2352              access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2353              assembleg_dec(temp_var3);
2354              access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2355              if (!void_flag) write_result_g(Result, temp_var3);
2356              break;
2357
2358         case DARROW_POST_INC_OP:
2359              assembleg_store(temp_var1, ET[below].value);
2360              assembleg_store(temp_var2, ET[ET[below].right].value);
2361              access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2362              if (!void_flag) write_result_g(Result, temp_var3);
2363              assembleg_inc(temp_var3);
2364              access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2365              break;
2366
2367         case DARROW_POST_DEC_OP:
2368              assembleg_store(temp_var1, ET[below].value);
2369              assembleg_store(temp_var2, ET[ET[below].right].value);
2370              access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2371              if (!void_flag) write_result_g(Result, temp_var3);
2372              assembleg_dec(temp_var3);
2373              access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2374              break;
2375
2376         case PROPERTY_OP:
2377         case MESSAGE_OP:
2378              AO = veneer_routine(RV__Pr_VR);
2379              goto TwoArgFunctionCall;
2380         case MPROP_ADD_OP:
2381         case PROP_ADD_OP:
2382              AO = veneer_routine(RA__Pr_VR);
2383              goto TwoArgFunctionCall;
2384         case MPROP_NUM_OP:
2385         case PROP_NUM_OP:
2386              AO = veneer_routine(RL__Pr_VR);
2387              goto TwoArgFunctionCall;
2388
2389         case PROP_CALL_OP:
2390         case MESSAGE_CALL_OP:
2391              AO2 = veneer_routine(CA__Pr_VR);
2392              i = below;
2393              goto DoFunctionCall;
2394
2395         case MESSAGE_INC_OP:
2396         case PROPERTY_INC_OP:
2397              AO = veneer_routine(IB__Pr_VR);
2398              goto TwoArgFunctionCall;
2399         case MESSAGE_DEC_OP:
2400         case PROPERTY_DEC_OP:
2401              AO = veneer_routine(DB__Pr_VR);
2402              goto TwoArgFunctionCall;
2403         case MESSAGE_POST_INC_OP:
2404         case PROPERTY_POST_INC_OP:
2405              AO = veneer_routine(IA__Pr_VR);
2406              goto TwoArgFunctionCall;
2407         case MESSAGE_POST_DEC_OP:
2408         case PROPERTY_POST_DEC_OP:
2409              AO = veneer_routine(DA__Pr_VR);
2410              goto TwoArgFunctionCall;
2411         case SUPERCLASS_OP:
2412              AO = veneer_routine(RA__Sc_VR);
2413              goto TwoArgFunctionCall;
2414
2415              TwoArgFunctionCall:
2416              {
2417                assembly_operand AO2 = ET[below].value;
2418                assembly_operand AO3 = ET[ET[below].right].value;
2419                if (void_flag)
2420                  assembleg_call_2(AO, AO2, AO3, zero_operand);
2421                else
2422                  assembleg_call_2(AO, AO2, AO3, Result);
2423              }
2424              break;
2425
2426         case PROPERTY_SETEQUALS_OP:
2427         case MESSAGE_SETEQUALS_OP:
2428              if (runtime_error_checking_switch && (!veneer_mode))
2429                  AO = veneer_routine(RT__ChPS_VR);
2430                else
2431                  AO = veneer_routine(WV__Pr_VR);
2432
2433              {
2434                assembly_operand AO2 = ET[below].value;
2435                assembly_operand AO3 = ET[ET[below].right].value;
2436                assembly_operand AO4 = ET[ET[ET[below].right].right].value;
2437                if (AO4.type == LOCALVAR_OT && AO4.value == 0) {
2438                  /* Rightmost is on the stack; reduce to previous case. */
2439                  if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2440                    if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2441                      /* both already on stack. */
2442                    }
2443                    else {
2444                      assembleg_store(stack_pointer, AO3);
2445                      assembleg_0(stkswap_gc);
2446                    }
2447                  }
2448                  else {
2449                    if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2450                      assembleg_store(stack_pointer, AO2);
2451                    }
2452                    else {
2453                      assembleg_store(stack_pointer, AO3);
2454                      assembleg_store(stack_pointer, AO2);
2455                    }
2456                  }
2457                }
2458                else {
2459                  /* We have to get the rightmost on the stack, below the 
2460                     others. */
2461                  if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2462                    if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2463                      assembleg_store(stack_pointer, AO4);
2464                      assembleg_2(stkroll_gc, three_operand, one_operand);
2465                    }
2466                    else {
2467                      assembleg_store(stack_pointer, AO4);
2468                      assembleg_0(stkswap_gc);
2469                      assembleg_store(stack_pointer, AO2); 
2470                    }
2471                  }
2472                  else {
2473                    if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2474                      assembleg_store(stack_pointer, AO4);
2475                      assembleg_store(stack_pointer, AO3);
2476                      assembleg_2(stkroll_gc, three_operand, two_operand);
2477                    }
2478                    else {
2479                      assembleg_store(stack_pointer, AO4);
2480                      assembleg_store(stack_pointer, AO3);
2481                      assembleg_store(stack_pointer, AO2);
2482                    }
2483                  }
2484                }
2485                if (void_flag)
2486                  assembleg_3(call_gc, AO, three_operand, zero_operand);
2487                else
2488                  assembleg_3(call_gc, AO, three_operand, Result);
2489              }
2490              break;
2491
2492         case FCALL_OP:
2493              j = 0;
2494
2495              if (ET[below].value.type == SYSFUN_OT)
2496              {   int sf_number = ET[below].value.value;
2497
2498                  i = ET[below].right;
2499                  if (i == -1)
2500                  {   error("Argument to system function missing");
2501                      AI.operand[0] = one_operand;
2502                      AI.operand_count = 1;
2503                  }
2504                  else
2505                  {   j=0;
2506                      while (i != -1) { j++; i = ET[i].right; }
2507
2508                      if (((sf_number != INDIRECT_SYSF) &&
2509                          (sf_number != GLK_SYSF) &&
2510                          (sf_number != RANDOM_SYSF) && (j > 1)))
2511                      {   j=1;
2512                          error("System function given with too many arguments");
2513                      }
2514                      if (sf_number != RANDOM_SYSF)
2515                      {   int jcount;
2516                          i = ET[below].right;
2517                          for (jcount = 0; jcount < j; jcount++)
2518                          {   AI.operand[jcount] = ET[i].value;
2519                              i = ET[i].right;
2520                          }
2521                          AI.operand_count = j;
2522                      }
2523                  }
2524
2525                  switch(sf_number)
2526                  {
2527                      case RANDOM_SYSF:
2528                          if (j>1)
2529                          {  assembly_operand AO, AO2; 
2530                             int arg_c, arg_et;
2531                             INITAO(&AO);
2532                             AO.value = j; 
2533                             set_constant_ot(&AO);
2534                             INITAOTV(&AO2, CONSTANT_OT, begin_word_array());
2535                             AO2.marker = ARRAY_MV;
2536
2537                             for (arg_c=0, arg_et = ET[below].right;arg_c<j;
2538                                  arg_c++, arg_et = ET[arg_et].right)
2539                             {   if (ET[arg_et].value.type == LOCALVAR_OT
2540                                     || ET[arg_et].value.type == GLOBALVAR_OT)
2541               error("Only constants can be used as possible 'random' results");
2542                                 array_entry(arg_c, FALSE, ET[arg_et].value);
2543                             }
2544                             finish_array(arg_c, FALSE);
2545
2546                             assembleg_2(random_gc, AO, stack_pointer);
2547                             assembleg_3(aload_gc, AO2, stack_pointer, Result);
2548                          }
2549                          else {
2550                            assembleg_2(random_gc,
2551                              ET[ET[below].right].value, stack_pointer);
2552                            assembleg_3(add_gc, stack_pointer, one_operand,
2553                              Result);
2554                          }
2555                          break;
2556
2557                      case PARENT_SYSF:
2558                          {  assembly_operand AO;
2559                             AO = ET[ET[below].right].value;
2560                             if (runtime_error_checking_switch)
2561                                 AO = check_nonzero_at_runtime(AO, -1,
2562                                     PARENT_RTE);
2563                             INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2564                             assembleg_3(aload_gc, AO, AO2, Result);
2565                          }
2566                          break;
2567
2568                      case ELDEST_SYSF:
2569                      case CHILD_SYSF:
2570                          {  assembly_operand AO;
2571                             AO = ET[ET[below].right].value;
2572                             if (runtime_error_checking_switch)
2573                                AO = check_nonzero_at_runtime(AO, -1,
2574                                (sf_number==CHILD_SYSF)?CHILD_RTE:ELDEST_RTE);
2575                             INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2576                             assembleg_3(aload_gc, AO, AO2, Result);
2577                          }
2578                          break;
2579
2580                      case YOUNGER_SYSF:
2581                      case SIBLING_SYSF:
2582                          {  assembly_operand AO;
2583                             AO = ET[ET[below].right].value;
2584                             if (runtime_error_checking_switch)
2585                                AO = check_nonzero_at_runtime(AO, -1,
2586                                (sf_number==SIBLING_SYSF)
2587                                    ?SIBLING_RTE:YOUNGER_RTE);
2588                             INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2589                             assembleg_3(aload_gc, AO, AO2, Result);
2590                          }
2591                          break;
2592
2593                      case CHILDREN_SYSF:
2594                          {  assembly_operand AO;
2595                             AO = ET[ET[below].right].value;
2596                             if (runtime_error_checking_switch)
2597                                 AO = check_nonzero_at_runtime(AO, -1,
2598                                     CHILDREN_RTE);
2599                             INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2600                             assembleg_store(temp_var1, zero_operand);
2601                             assembleg_3(aload_gc, AO, AO2, temp_var2);
2602                             AO2.value = GOBJFIELD_SIBLING();
2603                             assemble_label_no(next_label);
2604                             assembleg_1_branch(jz_gc, temp_var2, next_label+1);
2605                             assembleg_3(add_gc, temp_var1, one_operand, 
2606                               temp_var1);
2607                             assembleg_3(aload_gc, temp_var2, AO2, temp_var2);
2608                             assembleg_0_branch(jump_gc, next_label);
2609                             assemble_label_no(next_label+1);
2610                             next_label += 2;
2611                             if (!void_flag) 
2612                               write_result_g(Result, temp_var1);
2613                          }
2614                          break;
2615
2616                      case INDIRECT_SYSF: 
2617                          i = ET[below].right;
2618                          goto IndirectFunctionCallG;
2619
2620                      case GLK_SYSF: 
2621                          AO2 = veneer_routine(Glk__Wrap_VR);
2622                          i = ET[below].right;
2623                          goto DoFunctionCall;
2624
2625                      case METACLASS_SYSF:
2626                          assembleg_call_1(veneer_routine(Metaclass_VR),
2627                              ET[ET[below].right].value, Result);
2628                          break;
2629
2630                      case YOUNGEST_SYSF:
2631                          AO = ET[ET[below].right].value;
2632                          if (runtime_error_checking_switch)
2633                            AO = check_nonzero_at_runtime(AO, -1,
2634                              YOUNGEST_RTE);
2635                          INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2636                          assembleg_3(aload_gc, AO, AO2, temp_var1);
2637                          AO2.value = GOBJFIELD_SIBLING();
2638                          assembleg_1_branch(jz_gc, temp_var1, next_label+1);
2639                          assemble_label_no(next_label);
2640                          assembleg_3(aload_gc, temp_var1, AO2, temp_var2);
2641                          assembleg_1_branch(jz_gc, temp_var2, next_label+1);
2642                          assembleg_store(temp_var1, temp_var2);
2643                          assembleg_0_branch(jump_gc, next_label);
2644                          assemble_label_no(next_label+1);
2645                          if (!void_flag) 
2646                            write_result_g(Result, temp_var1);
2647                          next_label += 2;
2648                          break;
2649
2650                      case ELDER_SYSF: 
2651                          AO = ET[ET[below].right].value;
2652                          if (runtime_error_checking_switch)
2653                            AO = check_nonzero_at_runtime(AO, -1,
2654                              YOUNGEST_RTE);
2655                          assembleg_store(temp_var3, AO);
2656                          INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2657                          assembleg_3(aload_gc, temp_var3, AO2, temp_var1);
2658                          assembleg_1_branch(jz_gc, temp_var1, next_label+2);
2659                          AO2.value = GOBJFIELD_CHILD();
2660                          assembleg_3(aload_gc, temp_var1, AO2, temp_var1);
2661                          assembleg_1_branch(jz_gc, temp_var1, next_label+2);
2662                          assembleg_2_branch(jeq_gc, temp_var3, temp_var1, 
2663                            next_label+1);
2664                          assemble_label_no(next_label);
2665                          AO2.value = GOBJFIELD_SIBLING();
2666                          assembleg_3(aload_gc, temp_var1, AO2, temp_var2);
2667                          assembleg_2_branch(jeq_gc, temp_var3, temp_var2,
2668                            next_label+2);
2669                          assembleg_store(temp_var1, temp_var2);
2670                          assembleg_0_branch(jump_gc, next_label);
2671                          assemble_label_no(next_label+1);
2672                          assembleg_store(temp_var1, zero_operand);
2673                          assemble_label_no(next_label+2);
2674                          if (!void_flag)
2675                            write_result_g(Result, temp_var1);
2676                          next_label += 3;
2677                          break;
2678
2679                      default:
2680                          error("*** system function not implemented ***");
2681                          break;
2682
2683                  }
2684                  break;
2685              }
2686
2687              i = below;
2688
2689              IndirectFunctionCallG:
2690
2691              /* Get the function address. */
2692              AO2 = ET[i].value;
2693              i = ET[i].right;
2694
2695              DoFunctionCall:
2696
2697              {
2698                /* If all the function arguments are in local/global
2699                   variables, we have to push them all on the stack.
2700                   If all of them are on the stack, we have to do nothing.
2701                   If some are and some aren't, we have a hopeless mess,
2702                   and we should throw a compiler error.
2703                */
2704
2705                int onstack = 0;
2706                int offstack = 0;
2707
2708                /* begin part of patch G03701 */
2709                int nargs = 0;
2710                j = i;
2711                while (j != -1) {
2712                  nargs++;
2713                  j = ET[j].right;
2714                }
2715
2716                if (nargs==0) {
2717                  assembleg_2(callf_gc, AO2, void_flag ? zero_operand : Result);
2718                } else if (nargs==1) {
2719                  assembleg_call_1(AO2, ET[i].value, void_flag ? zero_operand : Result);
2720                } else if (nargs==2) {
2721                  assembly_operand o1 = ET[i].value;
2722                  assembly_operand o2 = ET[ET[i].right].value;
2723                  assembleg_call_2(AO2, o1, o2, void_flag ? zero_operand : Result);
2724                } else if (nargs==3) {
2725                  assembly_operand o1 = ET[i].value;
2726                  assembly_operand o2 = ET[ET[i].right].value;
2727                  assembly_operand o3 = ET[ET[ET[i].right].right].value;
2728                  assembleg_call_3(AO2, o1, o2, o3, void_flag ? zero_operand : Result);
2729                } else {
2730
2731                  j = 0;
2732                  while (i != -1) {
2733                      if (ET[i].value.type == LOCALVAR_OT 
2734                        && ET[i].value.value == 0) {
2735                        onstack++;
2736                      }
2737                      else {
2738                        assembleg_store(stack_pointer, ET[i].value);
2739                        offstack++;
2740                      }
2741                      i = ET[i].right;
2742                      j++;
2743                  }
2744
2745                  if (onstack && offstack)
2746                      error("*** Function call cannot be generated with mixed arguments ***");
2747                  if (offstack > 1)
2748                      error("*** Function call cannot be generated with more than one nonstack argument ***");
2749
2750                  INITAO(&AO);
2751                  AO.value = j;
2752                  set_constant_ot(&AO);
2753
2754                  if (void_flag)
2755                    assembleg_3(call_gc, AO2, AO, zero_operand);
2756                  else
2757                    assembleg_3(call_gc, AO2, AO, Result);
2758
2759                } /* else nargs>=4 */
2760              } /* DoFunctionCall: */
2761
2762              break;
2763
2764         default:
2765             printf("** Trouble op = %d i.e. '%s' **\n",
2766                 opnum, operators[opnum].description);
2767             compiler_error("Expr code gen: Can't generate yet");
2768     }
2769   }
2770
2771     ET[n].value = Result;
2772
2773     OperatorGenerated:
2774
2775     if (!glulx_mode) {
2776
2777         if (ET[n].to_expression)
2778         {
2779             if (void_flag) {
2780                 warning("Logical expression has no side-effects");
2781                 if (ET[n].true_label != -1)
2782                     assemble_label_no(ET[n].true_label);
2783                 else
2784                     assemble_label_no(ET[n].false_label);
2785             }
2786             else if (ET[n].true_label != -1)
2787             {   assemblez_1(push_zc, zero_operand);
2788                 assemblez_jump(next_label++);
2789                 assemble_label_no(ET[n].true_label);
2790                 assemblez_1(push_zc, one_operand);
2791                 assemble_label_no(next_label-1);
2792             }
2793             else
2794             {   assemblez_1(push_zc, one_operand);
2795                 assemblez_jump(next_label++);
2796                 assemble_label_no(ET[n].false_label);
2797                 assemblez_1(push_zc, zero_operand);
2798                 assemble_label_no(next_label-1);
2799             }
2800             ET[n].value = stack_pointer;
2801         }
2802         else
2803             if (ET[n].label_after != -1)
2804                 assemble_label_no(ET[n].label_after);
2805
2806     }
2807     else {
2808
2809         if (ET[n].to_expression)
2810         {   
2811             if (void_flag) {
2812                 warning("Logical expression has no side-effects");
2813                 if (ET[n].true_label != -1)
2814                     assemble_label_no(ET[n].true_label);
2815                 else
2816                     assemble_label_no(ET[n].false_label);
2817             }
2818             else if (ET[n].true_label != -1)
2819             {   assembleg_store(stack_pointer, zero_operand);
2820                 assembleg_jump(next_label++);
2821                 assemble_label_no(ET[n].true_label);
2822                 assembleg_store(stack_pointer, one_operand);
2823                 assemble_label_no(next_label-1);
2824             }
2825             else
2826             {   assembleg_store(stack_pointer, one_operand);
2827                 assembleg_jump(next_label++);
2828                 assemble_label_no(ET[n].false_label);
2829                 assembleg_store(stack_pointer, zero_operand);
2830                 assemble_label_no(next_label-1);
2831             }
2832             ET[n].value = stack_pointer;
2833         }
2834         else
2835             if (ET[n].label_after != -1)
2836                 assemble_label_no(ET[n].label_after);
2837
2838     }
2839
2840     ET[n].down = -1;
2841 }
2842
2843 assembly_operand code_generate(assembly_operand AO, int context, int label)
2844 {
2845     /*  Used in three contexts: VOID_CONTEXT, CONDITION_CONTEXT and
2846             QUANTITY_CONTEXT.
2847
2848         If CONDITION_CONTEXT, then compile code branching to label number
2849             "label" if the condition is false: there's no return value.
2850         (Except that if label is -3 or -4 (internal codes for rfalse and
2851         rtrue rather than branch) then this is for branching when the
2852         condition is true.  This is used for optimising code generation
2853         for "if" statements.)
2854
2855         Otherwise return the assembly operand containing the result
2856         (probably the stack pointer variable but not necessarily:
2857          e.g. is would be short constant 2 from the expression "j++, 2")     */
2858
2859     vivc_flag = FALSE;
2860
2861     if (AO.type != EXPRESSION_OT)
2862     {   switch(context)
2863         {   case VOID_CONTEXT:
2864                 value_in_void_context(AO);
2865                 AO.type = OMITTED_OT;
2866                 AO.value = 0;
2867                 break;
2868             case CONDITION_CONTEXT:
2869                 if (!glulx_mode) {
2870                   if (label < -2) assemblez_1_branch(jz_zc, AO, label, FALSE);
2871                   else assemblez_1_branch(jz_zc, AO, label, TRUE);
2872                 }
2873                 else {
2874                   if (label < -2) 
2875                     assembleg_1_branch(jnz_gc, AO, label);
2876                   else 
2877                     assembleg_1_branch(jz_gc, AO, label);
2878                 }
2879                 AO.type = OMITTED_OT;
2880                 AO.value = 0;
2881                 break;
2882         }
2883         return AO;
2884     }
2885
2886     if (expr_trace_level >= 2)
2887     {   printf("Raw parse tree:\n"); show_tree(AO, FALSE);
2888     }
2889
2890     if (context == CONDITION_CONTEXT)
2891     {   if (label < -2) annotate_for_conditions(AO.value, label, -1);
2892         else annotate_for_conditions(AO.value, -1, label);
2893     }
2894     else annotate_for_conditions(AO.value, -1, -1);
2895
2896     if (expr_trace_level >= 1)
2897     {   printf("Code generation for expression in ");
2898         switch(context)
2899         {   case VOID_CONTEXT: printf("void"); break;
2900             case CONDITION_CONTEXT: printf("condition"); break;
2901             case QUANTITY_CONTEXT: printf("quantity"); break;
2902             case ASSEMBLY_CONTEXT: printf("assembly"); break;
2903             case ARRAY_CONTEXT: printf("array initialisation"); break;
2904             default: printf("* ILLEGAL *"); break;
2905         }
2906         printf(" context with annotated tree:\n");
2907         show_tree(AO, TRUE);
2908     }
2909
2910     generate_code_from(AO.value, (context==VOID_CONTEXT));
2911     return ET[AO.value].value;
2912 }
2913
2914 /* ========================================================================= */
2915 /*   Data structure management routines                                      */
2916 /* ------------------------------------------------------------------------- */
2917
2918 extern void init_expressc_vars(void)
2919 {   make_operands();
2920 }
2921
2922 extern void expressc_begin_pass(void)
2923 {
2924 }
2925
2926 extern void expressc_allocate_arrays(void)
2927 {
2928 }
2929
2930 extern void expressc_free_arrays(void)
2931 {
2932 }
2933
2934 /* ========================================================================= */