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