1 /* ------------------------------------------------------------------------- */
2 /* "expressc" : The expression code generator */
4 /* Part of Inform 6.35 */
5 /* copyright (c) Graham Nelson 1993 - 2021 */
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. */
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. */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with Inform. If not, see https://gnu.org/licenses/ */
20 /* ------------------------------------------------------------------------- */
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 */
32 /* These data structures are global, because they're too useful to be
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;
38 static void make_operands(void)
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);
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);
68 /* ------------------------------------------------------------------------- */
69 /* The table of conditionals. (Only used in Glulx) */
72 #define EQUAL_CC (502)
77 #define OFCLASS_CC (512)
78 #define PROVIDES_CC (514)
80 #define FIRST_CC (500)
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. */
88 condclass condclasses[] = {
99 /* ------------------------------------------------------------------------- */
100 /* The table of operators.
102 The ordering in this table is not significant except that it must match
103 the #define's in "header.h" */
105 operator operators[NUM_OPERATORS] =
107 /* ------------------------ */
109 /* ------------------------ */
111 { 0, SEP_TT, COMMA_SEP, IN_U, L_A, 0, -1, -1, 0, 0, "comma" },
113 /* ------------------------ */
115 /* ------------------------ */
117 { 1, SEP_TT, SETEQUALS_SEP, IN_U, R_A, 1, -1, -1, 1, 0,
118 "assignment operator '='" },
120 /* ------------------------ */
121 /* Level 2: ~~ && || */
122 /* ------------------------ */
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 '~~'" },
131 /* ------------------------ */
138 /* ------------------------ */
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,
146 { 3, SEP_TT, NOTEQUAL_SEP, IN_U, 0, 0, 800 + je_zc, EQUAL_CC+1, 0, CONDEQUALS_OP,
148 { 3, SEP_TT, GE_SEP, IN_U, 0, 0, 800 + jl_zc, LT_CC+1, 0, LESS_OP,
150 { 3, SEP_TT, GREATER_SEP, IN_U, 0, 0, 400 + jg_zc, GT_CC+0, 0, LE_OP,
152 { 3, SEP_TT, LE_SEP, IN_U, 0, 0, 800 + jg_zc, GT_CC+1, 0, GREATER_OP,
154 { 3, SEP_TT, LESS_SEP, IN_U, 0, 0, 400 + jl_zc, LT_CC+0, 0, GE_OP,
156 { 3, CND_TT, HAS_COND, IN_U, 0, 0, 400 + test_attr_zc, HAS_CC+0, 0, HASNT_OP,
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,
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" },
173 /* ------------------------ */
175 /* ------------------------ */
177 { 4, CND_TT, OR_COND, IN_U, L_A, 0, -1, -1, 0, 0, "'or'" },
179 /* ------------------------ */
180 /* Level 5: + binary - */
181 /* ------------------------ */
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, "'-'" },
186 /* ------------------------ */
189 /* ------------------------ */
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,
197 { 6, SEP_TT, ARTOR_SEP, IN_U, L_A, 0, or_zc, bitor_gc, 0, 0,
199 { 6, SEP_TT, ARTNOT_SEP, PRE_U, R_A, 0, -1, bitnot_gc, 0, 0,
202 /* ------------------------ */
203 /* Level 7: -> --> */
204 /* ------------------------ */
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 '-->'" },
211 /* ------------------------ */
212 /* Level 8: unary - */
213 /* ------------------------ */
215 { 8, SEP_TT, UNARY_MINUS_SEP, PRE_U, R_A, 0, -1, neg_gc, 0, 0,
218 /* ------------------------ */
220 /* (prefix or postfix) */
221 /* ------------------------ */
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 '--'" },
232 /* ------------------------ */
233 /* Level 10: .& .# */
235 /* ------------------------ */
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 '..#'" },
246 /* ------------------------ */
247 /* Level 11: function ( */
248 /* ------------------------ */
250 {11, SEP_TT, OPENB_SEP, IN_U, L_A, 0, -1, -1, 1, 0,
253 /* ------------------------ */
255 /* ------------------------ */
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 '.'" },
262 /* ------------------------ */
264 /* ------------------------ */
266 {13, SEP_TT, SUPERCLASS_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
267 "superclass operator '::'" },
269 /* ------------------------ */
270 /* Miscellaneous operators */
271 /* generated at lvalue */
273 /* ------------------------ */
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" },
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" },
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" },
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" },
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" },
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" },
325 /* ------------------------ */
326 /* And one Glulx-only op */
327 /* which just pushes its */
328 /* argument on the stack, */
330 /* ------------------------ */
332 {14, -1, -1, -1, -1, 0, -1, -1, 1, 0,
336 /* --- Condition annotater ------------------------------------------------- */
338 static void annotate_for_conditions(int n, int a, int b)
339 { int i, opnum = ET[n].operator_number;
341 ET[n].label_after = -1;
342 ET[n].to_expression = FALSE;
343 ET[n].true_label = a;
344 ET[n].false_label = b;
346 if (ET[n].down == -1) return;
348 if ((operators[opnum].precedence == 2)
349 || (operators[opnum].precedence == 3))
350 { if ((a == -1) && (b == -1))
351 { if (opnum == LOGAND_OP)
353 ET[n].false_label = b;
354 ET[n].to_expression = TRUE;
358 ET[n].true_label = a;
359 ET[n].to_expression = TRUE;
368 ET[n].false_label = b;
369 ET[n].label_after = b;
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);
379 ET[n].true_label = a;
380 ET[n].label_after = a;
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);
391 { annotate_for_conditions(i, -1, -1); i = ET[i].right; }
394 /* --- Code generator ------------------------------------------------------ */
396 static void value_in_void_context_z(assembly_operand AO)
402 { case LONG_CONSTANT_OT:
403 case SHORT_CONSTANT_OT:
405 if (AO.marker == SYMBOL_MV)
406 t = (char *) (symbs[AO.value]);
409 t = variable_name(AO.value);
412 compiler_error("Unable to print value in void context");
418 if (strcmp(t, "print_paddr") == 0)
419 obsolete_warning("ignoring 'print_paddr': use 'print (string)' instead");
421 if (strcmp(t, "print_addr") == 0)
422 obsolete_warning("ignoring 'print_addr': use 'print (address)' instead");
424 if (strcmp(t, "print_char") == 0)
425 obsolete_warning("ignoring 'print_char': use 'print (char)' instead");
427 ebf_error("expression with side-effects", t);
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);
436 static void pop_zm_stack(void)
437 { assembly_operand st;
438 if (version_number < 5) assemblez_0(pop_zc);
440 { INITAOTV(&st, VARIABLE_OT, 0);
441 assemblez_1_branch(jz_zc, st, -2, TRUE);
445 static void access_memory_z(int oc, assembly_operand AO1, assembly_operand AO2,
446 assembly_operand AO3)
449 assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
451 int x = 0, y = 0, byte_flag = FALSE, read_flag = FALSE, from_module = FALSE;
453 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
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;
462 zero_ao.type = SHORT_CONSTANT_OT;
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;
473 if (array_locs[y] && !read_flag) {
474 error("Cannot write to a static array");
477 if (size_ao.value==-1)
481 type_ao = zero_ao; type_ao.value = array_types[y];
483 if ((!is_systemfile()))
486 if ((array_types[y] == WORD_ARRAY)
487 || (array_types[y] == TABLE_ARRAY))
488 warning("Using '->' to access a --> or table array");
492 if ((array_types[y] == BYTE_ARRAY)
493 || (array_types[y] == STRING_ARRAY))
494 warning("Using '-->' to access a -> or string array");
501 if ((!runtime_error_checking_switch) || (veneer_mode))
502 { if ((oc == loadb_zc) || (oc == loadw_zc))
503 assemblez_2_to(oc, AO1, AO2, AO3);
505 assemblez_3(oc, AO1, AO2, AO3);
509 /* If we recognise AO1 as arising textually from a declared
510 array, we can check bounds explicitly. */
512 if ((AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV) && (!from_module))
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 */
521 && ((array_types[y] == WORD_ARRAY)
522 || (array_types[y] == TABLE_ARRAY)))
523 { max_ao.value = size_ao.value*2 + 1;
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;
537 if (size_ao.value >= 256) size_ao.type = LONG_CONSTANT_OT;
538 if (max_ao.value >= 256) max_ao.type = LONG_CONSTANT_OT;
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))
544 { if ((array_types[y] == TABLE_ARRAY) && byte_flag)
546 else zero_ao.value = 1;
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; }
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;
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);
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 */
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);
580 assemblez_jump(final_label);
582 assemble_label_no(passed_label);
583 if ((oc == loadb_zc) || (oc == loadw_zc))
584 assemblez_2_to(oc, AO1, AO2, AO3);
586 assemblez_3(oc, AO1, AO2, AO3);
587 assemble_label_no(final_label);
591 /* Otherwise, compile a call to the veneer which verifies that
592 the proposed read/write is within dynamic Z-machine memory. */
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");
601 if ((oc == loadb_zc) || (oc == loadw_zc))
602 assemblez_3_to(call_vs_zc, veneer_routine(vr), AO1, AO2, AO3);
604 assemblez_4(call_vn_zc, veneer_routine(vr), AO1, AO2, AO3);
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;
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.
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. */
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))
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);
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 */
642 if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
643 { /* That is, if AO1 is the stack pointer */
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);
651 { assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
652 assemblez_2_branch(jg_zc, AO1, AO2, passed_label, FALSE);
656 { if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
657 { /* That is, if AO1 is the stack pointer */
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);
664 assemblez_2_branch(jin_zc, temp_var2, AO3, passed_label, FALSE);
667 { assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
668 assemblez_2_branch(jg_zc, AO1, AO2, failed_label, TRUE);
670 assemblez_2_branch(jin_zc, AO1, AO3, passed_label, FALSE);
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);
679 assemblez_3_to(call_zc, veneer_routine(RT__Err_VR), AO2, AO1, temp_var2);
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);
689 { /* Push the short constant 2 */
690 INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
691 assemblez_store(AO1, AO2);
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);
706 assemble_label_no(passed_label);
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;
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);
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);
726 { case SHORT_CONSTANT_OT:
727 case LONG_CONSTANT_OT:
729 { if ((AO2.value < 0) || (AO2.value > 47))
730 error("'has'/'hasnt' applied to illegal attribute number");
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);
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);
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);
763 INITAOTV(&AO3, VARIABLE_OT, 0);
765 the_zc = (version_number == 3)?call_zc:call_vs_zc;
767 assemblez_3_to(the_zc, veneer_routine(OP__Pr_VR), AO1, AO2, AO3);
769 assemblez_3_to(the_zc, veneer_routine(OC__Cl_VR), AO1, AO2, AO3);
771 assemblez_1_branch(jz_zc, AO3, label, !flag);
774 static void value_in_void_context_g(assembly_operand AO)
781 case HALFCONSTANT_OT:
782 case BYTECONSTANT_OT:
783 case ZEROCONSTANT_OT:
785 if (AO.marker == SYMBOL_MV)
786 t = (char *) (symbs[AO.value]);
790 t = variable_name(AO.value);
793 compiler_error("Unable to print value in void context");
799 ebf_error("expression with side-effects", t);
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);
807 static void access_memory_g(int oc, assembly_operand AO1, assembly_operand AO2,
808 assembly_operand AO3)
810 int data_len, read_flag;
811 assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
813 int passed_label, failed_label, final_label, x = 0, y = 0;
815 if ((oc == aloadb_gc) || (oc == astoreb_gc)) data_len = 1;
816 else if ((oc == aloads_gc) || (oc == astores_gc)) data_len = 2;
819 if ((oc == aloadb_gc) || (oc == aloads_gc) || (oc == aload_gc))
824 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
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;
835 if (size_ao.value==-1) compiler_error("Array size can't be found");
837 type_ao = zero_ao; type_ao.value = array_types[y];
839 if (array_locs[y] && !read_flag) {
840 error("Cannot write to a static array");
843 if ((!is_systemfile()))
846 if ((array_types[y] == WORD_ARRAY)
847 || (array_types[y] == TABLE_ARRAY))
848 warning("Using '->' to access a --> or table array");
852 if ((array_types[y] == BYTE_ARRAY)
853 || (array_types[y] == STRING_ARRAY))
854 warning("Using '-->' to access a -> or string array");
860 if ((!runtime_error_checking_switch) || (veneer_mode))
862 assembleg_3(oc, AO1, AO2, AO3);
866 /* If we recognise AO1 as arising textually from a declared
867 array, we can check bounds explicitly. */
869 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
871 /* Calculate the largest permitted array entry + 1
872 Here "size_ao.value" = largest permitted entry of its own kind */
875 && ((array_types[y] == WORD_ARRAY)
876 || (array_types[y] == TABLE_ARRAY)))
877 { max_ao.value = size_ao.value*4 + 3;
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;
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))
893 { if ((array_types[y] == TABLE_ARRAY) && data_len == 1)
895 else zero_ao.value = 1;
898 en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
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; }
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);
911 /* If we recognize A02 as a constant, we can do the test right
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");
917 assembleg_3(oc, AO1, AO2, AO3);
921 passed_label = next_label++;
922 failed_label = next_label++;
923 final_label = next_label++;
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;
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);
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);
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);
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 */
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);
961 else assembleg_2(copy_gc, stack_pointer, zero_operand);
963 assembleg_jump(final_label);
965 assemble_label_no(passed_label);
966 assembleg_3(oc, AO1, AO2, AO3);
967 assemble_label_no(final_label);
971 /* Otherwise, compile a call to the veneer which verifies that
972 the proposed read/write is within dynamic Z-machine memory. */
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");
982 if ((oc == aloadb_gc) || (oc == aload_gc))
983 assembleg_call_2(veneer_routine(vr), AO1, AO2, AO3);
985 assembleg_call_3(veneer_routine(vr), AO1, AO2, AO3, zero_operand);
988 static assembly_operand check_nonzero_at_runtime_g(assembly_operand AO1,
989 int error_label, int rte_number)
991 assembly_operand AO, AO2, AO3;
993 int check_sp = FALSE, passed_label, failed_label, last_label;
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.
1007 The Object has no parent, child or sibling, so that the
1008 built-in tree functions will safely return 0 on this object. */
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))) {
1016 passed_label = next_label++;
1017 failed_label = next_label++;
1019 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0) && (AO1.marker == 0)) {
1020 /* That is, if AO1 is the stack pointer */
1022 assembleg_store(temp_var2, stack_pointer);
1023 assembleg_store(stack_pointer, temp_var2);
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)) {
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);
1039 AO3.value = 0x70; /* type byte -- object */
1040 set_constant_ot(&AO3);
1041 assembleg_2_branch(jeq_gc, stack_pointer, AO3, passed_label);
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);
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);
1062 assemble_label_no(failed_label);
1064 AO2.value = rte_number;
1065 set_constant_ot(&AO2);
1066 assembleg_call_2(veneer_routine(RT__Err_VR), AO2, AO1, zero_operand);
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);
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;
1082 assembleg_store(AO1, AO2);
1085 /* Store either "Object" or the operand's value in the temporary
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);
1097 assemble_label_no(passed_label);
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;
1109 the_zc = (flag ? cc->posform : cc->negform);
1112 switch ((cc-condclasses)*2 + 500) {
1115 if (runtime_error_checking_switch) {
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");
1125 int pa_label = next_label++, fa_label = next_label++;
1126 assembly_operand en_ao, max_ao;
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);
1134 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1135 assembleg_store(temp_var2, AO2);
1139 assembleg_store(temp_var1, AO1);
1140 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1141 assembleg_2(stkpeek_gc, zero_operand, temp_var2);
1144 assembleg_store(temp_var2, AO2);
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);
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);
1163 va_label = next_label++;
1164 assembleg_jump(va_label);
1165 assemble_label_no(pa_label);
1168 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1170 set_constant_ot(&AO2);
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);
1183 assembleg_3(add_gc, AO2, AO4, stack_pointer);
1185 AO2 = stack_pointer;
1187 assembleg_3(aloadbit_gc, AO1, AO2, stack_pointer);
1188 the_zc = (flag ? jnz_gc : jz_gc);
1189 AO1 = stack_pointer;
1193 if (runtime_error_checking_switch) {
1195 error_label = next_label++;
1196 AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
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);
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;
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;
1219 error("condition not yet supported in Glulx");
1224 if (the_zc == jnz_gc || the_zc == jz_gc)
1225 assembleg_1_branch(the_zc, AO1, label);
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);
1232 static void value_in_void_context(assembly_operand AO)
1235 value_in_void_context_z(AO);
1237 value_in_void_context_g(AO);
1241 extern assembly_operand check_nonzero_at_runtime(assembly_operand AO1,
1242 int error_label, int rte_number)
1245 return check_nonzero_at_runtime_z(AO1, error_label, rte_number);
1247 return check_nonzero_at_runtime_g(AO1, error_label, rte_number);
1250 static void generate_code_from(int n, int void_flag)
1252 /* When void, this must not leave anything on the stack. */
1254 int i, j, below, above, opnum, arity; assembly_operand Result;
1256 below = ET[n].down; above = ET[n].up;
1258 { if ((void_flag) && (ET[n].value.type != OMITTED_OT))
1259 value_in_void_context(ET[n].value);
1263 opnum = ET[n].operator_number;
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;
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;
1280 /* Signifies a SETEQUALS_OP which has already been done */
1282 ET[n].down = -1; return;
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:
1291 (for instance) pulls to the first operand, then the second. So
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.) */
1303 /* And the Glulx machine follows the Z-machine in this respect. */
1307 { i = ET[i].right; arity++;
1309 for (j=arity;j>0;j--)
1313 { k++; i = ET[i].right;
1315 generate_code_from(i, FALSE);
1319 /* Check this again, because code generation lower down may have
1320 stubbed it into -1 */
1322 if (ET[n].operator_number == -1)
1323 { ET[n].down = -1; return;
1328 if (operators[opnum].opcode_number_z >= 400)
1330 /* Conditional terms such as '==': */
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;
1337 if (oc >= 400) { oc = oc - 400; flag = FALSE; }
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))
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".
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.
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.
1359 /* Reduce to the case where the branch_away label does exist: */
1361 if (a == -1) { a = b; b = -1; flag = !flag; }
1363 branch_away = a; branch_other = b;
1364 if (branch_other != -1) make_jump_away = TRUE;
1366 if ((((oc != je_zc)&&(arity > 2)) || (arity > 4)) && (flag == FALSE))
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.
1372 if not (A cond B or C or D) then branch_away
1374 which we transform into
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
1381 if (branch_other == -1)
1382 { branch_other = next_label++; make_branch_label = TRUE;
1387 assemblez_1_branch(jz_zc, ET[below].value, branch_away, flag);
1389 { assembly_operand left_operand;
1392 compile_conditional_z(oc, ET[below].value,
1393 ET[ET[below].right].value, branch_away, flag);
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
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);
1407 else left_operand = ET[below].value;
1408 i = ET[below].right; arity--;
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. */
1415 { if ((oc == je_zc) && (arity>1))
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! */
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--;
1429 { if ((arity == 3) || flag)
1430 assemblez_4_branch(je_zc, left_operand,
1432 ET[ET[i].right].value,
1433 ET[ET[ET[i].right].right].value,
1436 assemblez_4_branch(je_zc, left_operand,
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;
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
1450 if ((arity == 1) || flag)
1451 compile_conditional_z(oc, left_operand,
1452 ET[i].value, branch_away, flag);
1454 compile_conditional_z(oc, left_operand,
1455 ET[i].value, branch_other, !flag);
1457 i = ET[i].right; arity--;
1463 /* NB: These two conditions cannot both occur, fortunately! */
1465 if (make_branch_label) assemble_label_no(branch_other);
1466 if (make_jump_away) assemblez_jump(branch_other);
1468 goto OperatorGenerated;
1473 if (operators[opnum].opcode_number_g >= FIRST_CC
1474 && operators[opnum].opcode_number_g <= LAST_CC) {
1475 /* Conditional terms such as '==': */
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;
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. */
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];
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".
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.
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.
1511 /* Reduce to the case where the branch_away label does exist: */
1513 if (a == -1) { a = b; b = -1; flag = !flag; }
1515 branch_away = a; branch_other = b;
1516 if (branch_other != -1) make_jump_away = TRUE;
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.
1523 if not (A cond B or C or D) then branch_away
1525 which we transform into
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
1532 if (branch_other == -1) {
1533 branch_other = next_label++; make_branch_label = TRUE;
1537 if (cc == &condclasses[0]) {
1538 assembleg_1_branch((flag ? cc->posform : cc->negform),
1539 ET[below].value, branch_away);
1543 compile_conditional_g(cc, ET[below].value,
1544 ET[ET[below].right].value, branch_away, flag);
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
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;
1560 left_operand = ET[below].value;
1562 i = ET[below].right;
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. */
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
1575 if ((arity == 1) || flag)
1576 compile_conditional_g(cc, left_operand,
1577 ET[i].value, branch_away, flag);
1579 compile_conditional_g(cc, left_operand,
1580 ET[i].value, branch_other, !flag);
1588 /* NB: These two conditions cannot both occur, fortunately! */
1590 if (make_branch_label) assemble_label_no(branch_other);
1591 if (make_jump_away) assembleg_jump(branch_other);
1593 goto OperatorGenerated;
1598 /* The operator is now definitely one which produces a value */
1600 if (void_flag && (!(operators[opnum].side_effect)))
1601 error_named("Evaluating this has no effect:",
1602 operators[opnum].description);
1604 /* Where shall we put the resulting value? (In Glulx, this could
1605 be smarter, and peg the result into ZEROCONSTANT.) */
1607 if (void_flag) Result = temp_var1; /* Throw it away */
1609 { if ((above != -1) && (ET[above].operator_number == SETEQUALS_OP))
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. */
1616 ET[above].operator_number = -1;
1617 Result = ET[ET[above].down].value;
1618 ET[above].value = Result;
1620 else Result = stack_pointer; /* Otherwise, put it on the stack */
1625 if (operators[opnum].opcode_number_z != -1)
1627 /* Operators directly translatable into Z-code opcodes: infix ops
1628 take two operands whereas pre/postfix operators take only one */
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,
1643 assemblez_store(temp_var1, ET[below].value);
1644 assemblez_store(temp_var2, by_ao);
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),
1651 assemblez_inc(temp_var2);
1652 assemble_label_no(ln);
1653 assemblez_2_to(o_n, temp_var1, temp_var2, Result);
1657 assemblez_2_to(o_n, ET[below].value,
1658 ET[ET[below].right].value, Result);
1662 assemblez_1_to(operators[opnum].opcode_number_z, ET[below].value,
1668 access_memory_z(loadb_zc, ET[below].value,
1669 ET[ET[below].right].value, Result);
1672 access_memory_z(loadw_zc, ET[below].value,
1673 ET[ET[below].right].value, Result);
1675 case UNARY_MINUS_OP:
1676 assemblez_2_to(sub_zc, zero_operand, ET[below].value, Result);
1679 assemblez_1_to(not_zc, ET[below].value, Result);
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);
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);
1706 { assembly_operand AO = ET[below].value;
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);
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);
1719 j=1; AI.operand[0] = veneer_routine(RV__Pr_VR);
1720 goto GenFunctionCallZ;
1722 j=1; AI.operand[0] = veneer_routine(RA__Pr_VR);
1723 goto GenFunctionCallZ;
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;
1743 j=1; AI.operand[0] = veneer_routine(RA__Sc_VR);
1744 goto GenFunctionCallZ;
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;
1756 if ((ET[below].value.type == VARIABLE_OT)
1757 && (ET[below].value.value >= 256))
1758 { int sf_number = ET[below].value.value - 256;
1760 i = ET[below].right;
1762 { error("Argument to system function missing");
1763 AI.operand[0] = one_operand;
1764 AI.operand_count = 1;
1768 while (i != -1) { j++; i = ET[i].right; }
1770 if (((sf_number != INDIRECT_SYSF) &&
1771 (sf_number != RANDOM_SYSF) && (j > 1))
1772 || ((sf_number == INDIRECT_SYSF) && (j>7)))
1774 error("System function given with too many arguments");
1776 if (sf_number != RANDOM_SYSF)
1778 i = ET[below].right;
1779 for (jcount = 0; jcount < j; jcount++)
1780 { AI.operand[jcount] = ET[i].value;
1783 AI.operand_count = j;
1786 AI.store_variable_number = Result.value;
1787 AI.branch_label_number = -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;
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);
1804 finish_array(arg_c, FALSE);
1806 assemblez_1_to(random_zc, AO, temp_var1);
1807 assemblez_dec(temp_var1);
1808 assemblez_2_to(loadw_zc, AO2, temp_var1, Result);
1811 assemblez_1_to(random_zc,
1812 ET[ET[below].right].value, Result);
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,
1821 assemblez_1_to(get_parent_zc, AO, Result);
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);
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);
1851 j=0; i = ET[below].right;
1852 goto IndirectFunctionCallZ;
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,
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,
1868 assemble_label_no(next_label+1);
1869 assemblez_store(temp_var2, stack_pointer);
1870 if (!void_flag) write_result_z(Result, temp_var1);
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,
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);
1895 assemblez_store(temp_var1, ET[ET[below].right].value);
1896 if (runtime_error_checking_switch)
1897 check_nonzero_at_runtime(temp_var1, -1,
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,
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);
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);
1922 error("The glk() system function does not exist in Z-code");
1932 IndirectFunctionCallZ:
1934 while ((i != -1) && (j<8))
1935 { AI.operand[j++] = ET[i].value;
1939 if ((j > 4) && (version_number == 3))
1940 { error("A function may be called with at most 3 arguments");
1943 if ((j==8) && (i != -1))
1944 { error("A function may be called with at most 7 arguments");
1947 AI.operand_count = j;
1949 if ((void_flag) && (version_number >= 5))
1950 { AI.store_variable_number = -1;
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;
1960 { AI.store_variable_number = Result.value;
1961 if (version_number == 3)
1962 AI.internal_number = call_zc;
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;
1973 AI.branch_label_number = -1;
1974 assemblez_instruction(&AI);
1978 assemblez_store(ET[below].value,
1979 ET[ET[below].right].value);
1980 if (!void_flag) write_result_z(Result, ET[below].value);
1983 case PROPERTY_SETEQUALS_OP:
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);
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,
1995 write_result_z(Result, temp_var1);
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);
2008 case ARROW_SETEQUALS_OP:
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,
2015 write_result_z(Result, temp_var1);
2017 else access_memory_z(storeb_zc, ET[below].value,
2018 ET[ET[below].right].value,
2019 ET[ET[ET[below].right].right].value);
2022 case DARROW_SETEQUALS_OP:
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,
2029 write_result_z(Result, temp_var1);
2032 access_memory_z(storew_zc, ET[below].value,
2033 ET[ET[below].right].value,
2034 ET[ET[ET[below].right].right].value);
2038 assemblez_inc(ET[below].value);
2039 if (!void_flag) write_result_z(Result, ET[below].value);
2042 assemblez_dec(ET[below].value);
2043 if (!void_flag) write_result_z(Result, ET[below].value);
2046 if (!void_flag) write_result_z(Result, ET[below].value);
2047 assemblez_inc(ET[below].value);
2050 if (!void_flag) write_result_z(Result, ET[below].value);
2051 assemblez_dec(ET[below].value);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2175 printf("** Trouble op = %d i.e. '%s' **\n",
2176 opnum, operators[opnum].description);
2177 compiler_error("Expr code gen: Can't generate yet");
2181 assembly_operand AO, AO2;
2182 if (operators[opnum].opcode_number_g != -1)
2184 /* Operators directly translatable into opcodes: infix ops
2185 take two operands whereas pre/postfix operators take only one */
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,
2198 { assembleg_store(temp_var1, ET[below].value);
2199 assembleg_store(temp_var2, by_ao);
2201 assembleg_1_branch(jnz_gc, temp_var2, ln);
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);
2213 assembleg_3(o_n, ET[below].value,
2214 ET[ET[below].right].value, Result);
2217 assembleg_2(operators[opnum].opcode_number_g, ET[below].value,
2225 if (ET[below].value.type == Result.type
2226 && ET[below].value.value == Result.value
2227 && ET[below].value.marker == Result.marker)
2229 assembleg_2(copy_gc, ET[below].value, Result);
2232 case UNARY_MINUS_OP:
2233 assembleg_2(neg_gc, ET[below].value, Result);
2236 assembleg_2(bitnot_gc, ET[below].value, Result);
2240 access_memory_g(aloadb_gc, ET[below].value,
2241 ET[ET[below].right].value, Result);
2244 access_memory_g(aload_gc, ET[below].value,
2245 ET[ET[below].right].value, Result);
2249 assembleg_store(ET[below].value,
2250 ET[ET[below].right].value);
2251 if (!void_flag) write_result_g(Result, ET[below].value);
2254 case ARROW_SETEQUALS_OP:
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,
2261 write_result_g(Result, temp_var1);
2263 else access_memory_g(astoreb_gc, ET[below].value,
2264 ET[ET[below].right].value,
2265 ET[ET[ET[below].right].right].value);
2268 case DARROW_SETEQUALS_OP:
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,
2275 write_result_g(Result, temp_var1);
2278 access_memory_g(astore_gc, ET[below].value,
2279 ET[ET[below].right].value,
2280 ET[ET[ET[below].right].right].value);
2284 assembleg_inc(ET[below].value);
2285 if (!void_flag) write_result_g(Result, ET[below].value);
2288 assembleg_dec(ET[below].value);
2289 if (!void_flag) write_result_g(Result, ET[below].value);
2292 if (!void_flag) write_result_g(Result, ET[below].value);
2293 assembleg_inc(ET[below].value);
2296 if (!void_flag) write_result_g(Result, ET[below].value);
2297 assembleg_dec(ET[below].value);
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);
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);
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);
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);
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);
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);
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);
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);
2374 AO = veneer_routine(RV__Pr_VR);
2375 goto TwoArgFunctionCall;
2378 AO = veneer_routine(RA__Pr_VR);
2379 goto TwoArgFunctionCall;
2382 AO = veneer_routine(RL__Pr_VR);
2383 goto TwoArgFunctionCall;
2386 case MESSAGE_CALL_OP:
2387 AO2 = veneer_routine(CA__Pr_VR);
2389 goto DoFunctionCall;
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;
2408 AO = veneer_routine(RA__Sc_VR);
2409 goto TwoArgFunctionCall;
2413 assembly_operand AO2 = ET[below].value;
2414 assembly_operand AO3 = ET[ET[below].right].value;
2416 assembleg_call_2(AO, AO2, AO3, zero_operand);
2418 assembleg_call_2(AO, AO2, AO3, Result);
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);
2427 AO = veneer_routine(WV__Pr_VR);
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. */
2440 assembleg_store(stack_pointer, AO3);
2441 assembleg_0(stkswap_gc);
2445 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2446 assembleg_store(stack_pointer, AO2);
2449 assembleg_store(stack_pointer, AO3);
2450 assembleg_store(stack_pointer, AO2);
2455 /* We have to get the rightmost on the stack, below the
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);
2463 assembleg_store(stack_pointer, AO4);
2464 assembleg_0(stkswap_gc);
2465 assembleg_store(stack_pointer, AO2);
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);
2475 assembleg_store(stack_pointer, AO4);
2476 assembleg_store(stack_pointer, AO3);
2477 assembleg_store(stack_pointer, AO2);
2482 assembleg_3(call_gc, AO, three_operand, zero_operand);
2484 assembleg_3(call_gc, AO, three_operand, Result);
2491 if (ET[below].value.type == SYSFUN_OT)
2492 { int sf_number = ET[below].value.value;
2494 i = ET[below].right;
2496 { error("Argument to system function missing");
2497 AI.operand[0] = one_operand;
2498 AI.operand_count = 1;
2502 while (i != -1) { j++; i = ET[i].right; }
2504 if (((sf_number != INDIRECT_SYSF) &&
2505 (sf_number != GLK_SYSF) &&
2506 (sf_number != RANDOM_SYSF) && (j > 1)))
2508 error("System function given with too many arguments");
2510 if (sf_number != RANDOM_SYSF)
2512 i = ET[below].right;
2513 for (jcount = 0; jcount < j; jcount++)
2514 { AI.operand[jcount] = ET[i].value;
2517 AI.operand_count = j;
2525 { assembly_operand AO, AO2;
2529 set_constant_ot(&AO);
2530 INITAOTV(&AO2, CONSTANT_OT, begin_word_array());
2531 AO2.marker = ARRAY_MV;
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);
2540 finish_array(arg_c, FALSE);
2542 assembleg_2(random_gc, AO, stack_pointer);
2543 assembleg_3(aload_gc, AO2, stack_pointer, Result);
2546 assembleg_2(random_gc,
2547 ET[ET[below].right].value, stack_pointer);
2548 assembleg_3(add_gc, stack_pointer, one_operand,
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,
2559 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2560 assembleg_3(aload_gc, AO, AO2, Result);
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);
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);
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,
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,
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);
2608 write_result_g(Result, temp_var1);
2613 i = ET[below].right;
2614 goto IndirectFunctionCallG;
2617 AO2 = veneer_routine(Glk__Wrap_VR);
2618 i = ET[below].right;
2619 goto DoFunctionCall;
2621 case METACLASS_SYSF:
2622 assembleg_call_1(veneer_routine(Metaclass_VR),
2623 ET[ET[below].right].value, Result);
2627 AO = ET[ET[below].right].value;
2628 if (runtime_error_checking_switch)
2629 AO = check_nonzero_at_runtime(AO, -1,
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);
2642 write_result_g(Result, temp_var1);
2647 AO = ET[ET[below].right].value;
2648 if (runtime_error_checking_switch)
2649 AO = check_nonzero_at_runtime(AO, -1,
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,
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,
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);
2671 write_result_g(Result, temp_var1);
2676 error("*** system function not implemented ***");
2685 IndirectFunctionCallG:
2687 /* Get the function address. */
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.
2704 /* begin part of patch G03701 */
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);
2729 if (ET[i].value.type == LOCALVAR_OT
2730 && ET[i].value.value == 0) {
2734 assembleg_store(stack_pointer, ET[i].value);
2741 if (onstack && offstack)
2742 error("*** Function call cannot be generated with mixed arguments ***");
2744 error("*** Function call cannot be generated with more than one nonstack argument ***");
2748 set_constant_ot(&AO);
2751 assembleg_3(call_gc, AO2, AO, zero_operand);
2753 assembleg_3(call_gc, AO2, AO, Result);
2755 } /* else nargs>=4 */
2756 } /* DoFunctionCall: */
2761 printf("** Trouble op = %d i.e. '%s' **\n",
2762 opnum, operators[opnum].description);
2763 compiler_error("Expr code gen: Can't generate yet");
2767 ET[n].value = Result;
2773 if (ET[n].to_expression)
2776 warning("Logical expression has no side-effects");
2777 if (ET[n].true_label != -1)
2778 assemble_label_no(ET[n].true_label);
2780 assemble_label_no(ET[n].false_label);
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);
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);
2796 ET[n].value = stack_pointer;
2799 if (ET[n].label_after != -1)
2800 assemble_label_no(ET[n].label_after);
2805 if (ET[n].to_expression)
2808 warning("Logical expression has no side-effects");
2809 if (ET[n].true_label != -1)
2810 assemble_label_no(ET[n].true_label);
2812 assemble_label_no(ET[n].false_label);
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);
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);
2828 ET[n].value = stack_pointer;
2831 if (ET[n].label_after != -1)
2832 assemble_label_no(ET[n].label_after);
2839 assembly_operand code_generate(assembly_operand AO, int context, int label)
2841 /* Used in three contexts: VOID_CONTEXT, CONDITION_CONTEXT and
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.)
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") */
2857 if (AO.type != EXPRESSION_OT)
2859 { case VOID_CONTEXT:
2860 value_in_void_context(AO);
2861 AO.type = OMITTED_OT;
2864 case CONDITION_CONTEXT:
2866 if (label < -2) assemblez_1_branch(jz_zc, AO, label, FALSE);
2867 else assemblez_1_branch(jz_zc, AO, label, TRUE);
2871 assembleg_1_branch(jnz_gc, AO, label);
2873 assembleg_1_branch(jz_gc, AO, label);
2875 AO.type = OMITTED_OT;
2882 if (expr_trace_level >= 2)
2883 { printf("Raw parse tree:\n"); show_tree(AO, FALSE);
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);
2890 else annotate_for_conditions(AO.value, -1, -1);
2892 if (expr_trace_level >= 1)
2893 { printf("Code generation for expression in ");
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;
2902 printf(" context with annotated tree:\n");
2903 show_tree(AO, TRUE);
2906 generate_code_from(AO.value, (context==VOID_CONTEXT));
2907 return ET[AO.value].value;
2910 /* ========================================================================= */
2911 /* Data structure management routines */
2912 /* ------------------------------------------------------------------------- */
2914 extern void init_expressc_vars(void)
2918 extern void expressc_begin_pass(void)
2922 extern void expressc_allocate_arrays(void)
2926 extern void expressc_free_arrays(void)
2930 /* ========================================================================= */