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