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;
457 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
459 if ((oc == loadb_zc) || (oc == storeb_zc)) byte_flag=TRUE;
460 else byte_flag = FALSE;
461 if ((oc == loadb_zc) || (oc == loadw_zc)) read_flag=TRUE;
462 else read_flag = FALSE;
464 zero_ao.type = SHORT_CONSTANT_OT;
467 size_ao = zero_ao; size_ao.value = -1;
468 for (x=0; x<no_arrays; x++)
469 { if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
470 && (AO1.value == svals[array_symbols[x]]))
471 { size_ao.value = array_sizes[x]; y=x;
475 if (array_locs[y] && !read_flag) {
476 error("Cannot write to a static array");
479 if (size_ao.value==-1)
483 type_ao = zero_ao; type_ao.value = array_types[y];
485 if ((!is_systemfile()))
488 if ((array_types[y] == WORD_ARRAY)
489 || (array_types[y] == TABLE_ARRAY))
490 warning("Using '->' to access a --> or table array");
494 if ((array_types[y] == BYTE_ARRAY)
495 || (array_types[y] == STRING_ARRAY))
496 warning("Using '-->' to access a -> or string array");
503 if ((!runtime_error_checking_switch) || (veneer_mode))
504 { if ((oc == loadb_zc) || (oc == loadw_zc))
505 assemblez_2_to(oc, AO1, AO2, AO3);
507 assemblez_3(oc, AO1, AO2, AO3);
511 /* If we recognise AO1 as arising textually from a declared
512 array, we can check bounds explicitly. */
514 if ((AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV) && (!from_module))
516 int passed_label = next_label++, failed_label = next_label++,
517 final_label = next_label++;
518 /* Calculate the largest permitted array entry + 1
519 Here "size_ao.value" = largest permitted entry of its own kind */
523 && ((array_types[y] == WORD_ARRAY)
524 || (array_types[y] == TABLE_ARRAY)))
525 { max_ao.value = size_ao.value*2 + 1;
529 && ((array_types[y] == BYTE_ARRAY)
530 || (array_types[y] == STRING_ARRAY)
531 || (array_types[y] == BUFFER_ARRAY)))
532 { if ((size_ao.value % 2) == 0)
533 max_ao.value = size_ao.value/2 - 1;
534 else max_ao.value = (size_ao.value-1)/2;
539 if (size_ao.value >= 256) size_ao.type = LONG_CONSTANT_OT;
540 if (max_ao.value >= 256) max_ao.type = LONG_CONSTANT_OT;
542 /* Can't write to the size entry in a string or table */
543 if (((array_types[y] == STRING_ARRAY)
544 || (array_types[y] == TABLE_ARRAY))
546 { if ((array_types[y] == TABLE_ARRAY) && byte_flag)
548 else zero_ao.value = 1;
551 en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
552 switch(oc) { case loadb_zc: en_ao.value = ABOUNDS_RTE; break;
553 case loadw_zc: en_ao.value = ABOUNDS_RTE+1; break;
554 case storeb_zc: en_ao.value = ABOUNDS_RTE+2; break;
555 case storew_zc: en_ao.value = ABOUNDS_RTE+3; break; }
558 if ((AO2.type == VARIABLE_OT)&&(AO2.value == 0))
559 { assemblez_store(temp_var2, AO2);
560 assemblez_store(AO2, temp_var2);
561 index_ao = temp_var2;
563 assemblez_2_branch(jl_zc, index_ao, zero_ao, failed_label, TRUE);
564 assemblez_2_branch(jl_zc, index_ao, max_ao, passed_label, TRUE);
565 assemble_label_no(failed_label);
566 an_ao = zero_ao; an_ao.value = y;
567 assemblez_6(call_vn2_zc, veneer_routine(RT__Err_VR), en_ao,
568 index_ao, size_ao, type_ao, an_ao);
570 /* We have to clear any of AO1, AO2, AO3 off the stack if
571 present, so that we can achieve the same effect on the stack
572 that executing the opcode would have had */
574 if ((AO1.type == VARIABLE_OT) && (AO1.value == 0)) pop_zm_stack();
575 if ((AO2.type == VARIABLE_OT) && (AO2.value == 0)) pop_zm_stack();
576 if ((AO3.type == VARIABLE_OT) && (AO3.value == 0))
577 { if ((oc == loadb_zc) || (oc == loadw_zc))
578 { assemblez_store(AO3, zero_ao);
582 assemblez_jump(final_label);
584 assemble_label_no(passed_label);
585 if ((oc == loadb_zc) || (oc == loadw_zc))
586 assemblez_2_to(oc, AO1, AO2, AO3);
588 assemblez_3(oc, AO1, AO2, AO3);
589 assemble_label_no(final_label);
593 /* Otherwise, compile a call to the veneer which verifies that
594 the proposed read/write is within dynamic Z-machine memory. */
596 switch(oc) { case loadb_zc: vr = RT__ChLDB_VR; break;
597 case loadw_zc: vr = RT__ChLDW_VR; break;
598 case storeb_zc: vr = RT__ChSTB_VR; break;
599 case storew_zc: vr = RT__ChSTW_VR; break;
600 default: compiler_error("unknown array opcode");
603 if ((oc == loadb_zc) || (oc == loadw_zc))
604 assemblez_3_to(call_vs_zc, veneer_routine(vr), AO1, AO2, AO3);
606 assemblez_4(call_vn_zc, veneer_routine(vr), AO1, AO2, AO3);
609 static assembly_operand check_nonzero_at_runtime_z(assembly_operand AO1,
610 int error_label, int rte_number)
611 { assembly_operand AO2, AO3;
612 int check_sp = FALSE, passed_label, failed_label, last_label;
613 if (veneer_mode) return AO1;
615 /* Assemble to code to check that the operand AO1 is ofclass Object:
616 if it is, execution should continue and the stack should be
617 unchanged. Otherwise, call the veneer's run-time-error routine
618 with the given error number, and then: if the label isn't -1,
619 switch execution to this label, with the value popped from
620 the stack if it was on the stack in the first place;
621 if the label is -1, either replace the top of the stack with
622 the constant 2, or return the operand (short constant) 2.
624 The point of 2 is that object 2 is the class-object Object
625 and therefore has no parent, child or sibling, so that the
626 built-in tree functions will safely return 0 on this object. */
628 /* Sometimes we can already see that the object number is valid. */
629 if (((AO1.type == LONG_CONSTANT_OT) || (AO1.type == SHORT_CONSTANT_OT))
630 && (AO1.marker == 0) && (AO1.value >= 1) && (AO1.value < no_objects))
633 passed_label = next_label++;
634 failed_label = next_label++;
635 INITAOTV(&AO2, LONG_CONSTANT_OT, actual_largest_object_SC);
636 AO2.marker = INCON_MV;
637 INITAOTV(&AO3, SHORT_CONSTANT_OT, 5);
639 if ((rte_number == IN_RTE) || (rte_number == HAS_RTE)
640 || (rte_number == PROPERTY_RTE) || (rte_number == PROP_NUM_RTE)
641 || (rte_number == PROP_ADD_RTE))
642 { /* Allow classes */
644 if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
645 { /* That is, if AO1 is the stack pointer */
647 assemblez_store(temp_var2, AO1);
648 assemblez_store(AO1, temp_var2);
649 assemblez_2_branch(jg_zc, AO3, temp_var2, failed_label, TRUE);
650 assemblez_2_branch(jg_zc, temp_var2, AO2, passed_label, FALSE);
653 { assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
654 assemblez_2_branch(jg_zc, AO1, AO2, passed_label, FALSE);
658 { if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
659 { /* That is, if AO1 is the stack pointer */
661 assemblez_store(temp_var2, AO1);
662 assemblez_store(AO1, temp_var2);
663 assemblez_2_branch(jg_zc, AO3, temp_var2, failed_label, TRUE);
664 assemblez_2_branch(jg_zc, temp_var2, AO2, failed_label, TRUE);
666 assemblez_2_branch(jin_zc, temp_var2, AO3, passed_label, FALSE);
669 { assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
670 assemblez_2_branch(jg_zc, AO1, AO2, failed_label, TRUE);
672 assemblez_2_branch(jin_zc, AO1, AO3, passed_label, FALSE);
676 assemble_label_no(failed_label);
677 INITAOTV(&AO2, SHORT_CONSTANT_OT, rte_number);
678 if (version_number >= 5)
679 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR), AO2, AO1);
681 assemblez_3_to(call_zc, veneer_routine(RT__Err_VR), AO2, AO1, temp_var2);
683 if (error_label != -1)
684 { /* Jump to the error label */
685 if (error_label == -3) assemblez_0(rfalse_zc);
686 else if (error_label == -4) assemblez_0(rtrue_zc);
687 else assemblez_jump(error_label);
691 { /* Push the short constant 2 */
692 INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
693 assemblez_store(AO1, AO2);
696 { /* Store either short constant 2 or the operand's value in
697 the temporary variable */
698 INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
699 AO3 = temp_var2; assemblez_store(AO3, AO2);
700 last_label = next_label++;
701 assemblez_jump(last_label);
702 assemble_label_no(passed_label);
703 assemblez_store(AO3, AO1);
704 assemble_label_no(last_label);
708 assemble_label_no(passed_label);
712 static void compile_conditional_z(int oc,
713 assembly_operand AO1, assembly_operand AO2, int label, int flag)
714 { assembly_operand AO3; int the_zc, error_label = label,
715 va_flag = FALSE, va_label = 0;
720 { if ((runtime_error_checking_switch) && (oc == jin_zc))
721 { if (flag) error_label = next_label++;
722 AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
724 if ((runtime_error_checking_switch) && (oc == test_attr_zc))
725 { if (flag) error_label = next_label++;
726 AO1 = check_nonzero_at_runtime(AO1, error_label, HAS_RTE);
728 { case SHORT_CONSTANT_OT:
729 case LONG_CONSTANT_OT:
731 { if ((AO2.value < 0) || (AO2.value > 47))
732 error("'has'/'hasnt' applied to illegal attribute number");
736 { int pa_label = next_label++, fa_label = next_label++;
737 assembly_operand en_ao, zero_ao, max_ao;
738 assemblez_store(temp_var1, AO1);
739 if ((AO1.type == VARIABLE_OT)&&(AO1.value == 0))
740 assemblez_store(AO1, temp_var1);
741 assemblez_store(temp_var2, AO2);
742 if ((AO2.type == VARIABLE_OT)&&(AO2.value == 0))
743 assemblez_store(AO2, temp_var2);
744 INITAOT(&zero_ao, SHORT_CONSTANT_OT);
746 max_ao = zero_ao; max_ao.value = 48;
747 assemblez_2_branch(jl_zc,temp_var2,zero_ao,fa_label,TRUE);
748 assemblez_2_branch(jl_zc,temp_var2,max_ao,pa_label,TRUE);
749 assemble_label_no(fa_label);
750 en_ao = zero_ao; en_ao.value = 19;
751 assemblez_4(call_vn_zc, veneer_routine(RT__Err_VR),
752 en_ao, temp_var1, temp_var2);
753 va_flag = TRUE; va_label = next_label++;
754 assemblez_jump(va_label);
755 assemble_label_no(pa_label);
759 assemblez_2_branch(oc, AO1, AO2, label, flag);
760 if (error_label != label) assemble_label_no(error_label);
761 if (va_flag) assemble_label_no(va_label);
765 INITAOTV(&AO3, VARIABLE_OT, 0);
767 the_zc = (version_number == 3)?call_zc:call_vs_zc;
769 assemblez_3_to(the_zc, veneer_routine(OP__Pr_VR), AO1, AO2, AO3);
771 assemblez_3_to(the_zc, veneer_routine(OC__Cl_VR), AO1, AO2, AO3);
773 assemblez_1_branch(jz_zc, AO3, label, !flag);
776 static void value_in_void_context_g(assembly_operand AO)
783 case HALFCONSTANT_OT:
784 case BYTECONSTANT_OT:
785 case ZEROCONSTANT_OT:
787 if (AO.marker == SYMBOL_MV)
788 t = (char *) (symbs[AO.value]);
792 t = variable_name(AO.value);
795 compiler_error("Unable to print value in void context");
801 ebf_error("expression with side-effects", t);
804 static void write_result_g(assembly_operand to, assembly_operand from)
805 { if (to.value == from.value && to.type == from.type) return;
806 assembleg_store(to, from);
809 static void access_memory_g(int oc, assembly_operand AO1, assembly_operand AO2,
810 assembly_operand AO3)
812 int data_len, read_flag;
813 assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
815 int passed_label, failed_label, final_label, x = 0, y = 0;
817 if ((oc == aloadb_gc) || (oc == astoreb_gc)) data_len = 1;
818 else if ((oc == aloads_gc) || (oc == astores_gc)) data_len = 2;
821 if ((oc == aloadb_gc) || (oc == aloads_gc) || (oc == aload_gc))
830 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
832 size_ao = zero_ao; size_ao.value = -1;
833 for (x=0; x<no_arrays; x++)
834 { if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
835 && (AO1.value == svals[array_symbols[x]]))
836 { size_ao.value = array_sizes[x]; y=x;
839 if (size_ao.value==-1) compiler_error("Array size can't be found");
841 type_ao = zero_ao; type_ao.value = array_types[y];
843 if (array_locs[y] && !read_flag) {
844 error("Cannot write to a static array");
847 if ((!is_systemfile()))
850 if ((array_types[y] == WORD_ARRAY)
851 || (array_types[y] == TABLE_ARRAY))
852 warning("Using '->' to access a --> or table array");
856 if ((array_types[y] == BYTE_ARRAY)
857 || (array_types[y] == STRING_ARRAY))
858 warning("Using '-->' to access a -> or string array");
864 if ((!runtime_error_checking_switch) || (veneer_mode))
866 assembleg_3(oc, AO1, AO2, AO3);
870 /* If we recognise AO1 as arising textually from a declared
871 array, we can check bounds explicitly. */
873 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
875 /* Calculate the largest permitted array entry + 1
876 Here "size_ao.value" = largest permitted entry of its own kind */
879 && ((array_types[y] == WORD_ARRAY)
880 || (array_types[y] == TABLE_ARRAY)))
881 { max_ao.value = size_ao.value*4 + 3;
885 && ((array_types[y] == BYTE_ARRAY)
886 || (array_types[y] == STRING_ARRAY)
887 || (array_types[y] == BUFFER_ARRAY)))
888 { max_ao.value = (size_ao.value-3)/4;
893 /* Can't write to the size entry in a string or table */
894 if (((array_types[y] == STRING_ARRAY)
895 || (array_types[y] == TABLE_ARRAY))
897 { if ((array_types[y] == TABLE_ARRAY) && data_len == 1)
899 else zero_ao.value = 1;
902 en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
904 switch(oc) { case aloadb_gc: en_ao.value = ABOUNDS_RTE; break;
905 case aload_gc: en_ao.value = ABOUNDS_RTE+1; break;
906 case astoreb_gc: en_ao.value = ABOUNDS_RTE+2; break;
907 case astore_gc: en_ao.value = ABOUNDS_RTE+3; break; }
909 set_constant_ot(&zero_ao);
910 set_constant_ot(&size_ao);
911 set_constant_ot(&max_ao);
912 set_constant_ot(&type_ao);
913 set_constant_ot(&en_ao);
915 /* If we recognize A02 as a constant, we can do the test right
917 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
918 if (AO2.value < zero_ao.value || AO2.value >= max_ao.value) {
919 error("Array reference is out-of-bounds");
921 assembleg_3(oc, AO1, AO2, AO3);
925 passed_label = next_label++;
926 failed_label = next_label++;
927 final_label = next_label++;
930 if ((AO2.type == LOCALVAR_OT)&&(AO2.value == 0))
931 { assembleg_store(temp_var2, AO2); /* ### could peek */
932 assembleg_store(AO2, temp_var2);
933 index_ao = temp_var2;
935 assembleg_2_branch(jlt_gc, index_ao, zero_ao, failed_label);
936 assembleg_2_branch(jlt_gc, index_ao, max_ao, passed_label);
937 assemble_label_no(failed_label);
939 an_ao = zero_ao; an_ao.value = y;
940 set_constant_ot(&an_ao);
941 five_ao = zero_ao; five_ao.value = 5;
942 set_constant_ot(&five_ao);
944 /* Call the error veneer routine. */
945 assembleg_store(stack_pointer, an_ao);
946 assembleg_store(stack_pointer, type_ao);
947 assembleg_store(stack_pointer, size_ao);
948 assembleg_store(stack_pointer, index_ao);
949 assembleg_store(stack_pointer, en_ao);
950 assembleg_3(call_gc, veneer_routine(RT__Err_VR),
951 five_ao, zero_operand);
953 /* We have to clear any of AO1, AO2, AO3 off the stack if
954 present, so that we can achieve the same effect on the stack
955 that executing the opcode would have had */
957 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
958 assembleg_2(copy_gc, stack_pointer, zero_operand);
959 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
960 assembleg_2(copy_gc, stack_pointer, zero_operand);
961 if ((AO3.type == LOCALVAR_OT) && (AO3.value == 0))
962 { if ((oc == aloadb_gc) || (oc == aload_gc))
963 { assembleg_store(AO3, zero_ao);
965 else assembleg_2(copy_gc, stack_pointer, zero_operand);
967 assembleg_jump(final_label);
969 assemble_label_no(passed_label);
970 assembleg_3(oc, AO1, AO2, AO3);
971 assemble_label_no(final_label);
975 /* Otherwise, compile a call to the veneer which verifies that
976 the proposed read/write is within dynamic Z-machine memory. */
979 case aloadb_gc: vr = RT__ChLDB_VR; break;
980 case aload_gc: vr = RT__ChLDW_VR; break;
981 case astoreb_gc: vr = RT__ChSTB_VR; break;
982 case astore_gc: vr = RT__ChSTW_VR; break;
983 default: compiler_error("unknown array opcode");
986 if ((oc == aloadb_gc) || (oc == aload_gc))
987 assembleg_call_2(veneer_routine(vr), AO1, AO2, AO3);
989 assembleg_call_3(veneer_routine(vr), AO1, AO2, AO3, zero_operand);
992 static assembly_operand check_nonzero_at_runtime_g(assembly_operand AO1,
993 int error_label, int rte_number)
995 assembly_operand AO, AO2, AO3;
997 int check_sp = FALSE, passed_label, failed_label, last_label;
1002 /* Assemble to code to check that the operand AO1 is ofclass Object:
1003 if it is, execution should continue and the stack should be
1004 unchanged. Otherwise, call the veneer's run-time-error routine
1005 with the given error number, and then: if the label isn't -1,
1006 switch execution to this label, with the value popped from
1007 the stack if it was on the stack in the first place;
1008 if the label is -1, either replace the top of the stack with
1009 the constant symbol (class-object) Object.
1011 The Object has no parent, child or sibling, so that the
1012 built-in tree functions will safely return 0 on this object. */
1014 /* Sometimes we can already see that the object number is valid. */
1015 if (AO1.marker == OBJECT_MV &&
1016 ((AO1.value >= 1) && (AO1.value <= no_objects))) {
1020 passed_label = next_label++;
1021 failed_label = next_label++;
1023 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0) && (AO1.marker == 0)) {
1024 /* That is, if AO1 is the stack pointer */
1026 assembleg_store(temp_var2, stack_pointer);
1027 assembleg_store(stack_pointer, temp_var2);
1034 if ((rte_number == IN_RTE) || (rte_number == HAS_RTE)
1035 || (rte_number == PROPERTY_RTE) || (rte_number == PROP_NUM_RTE)
1036 || (rte_number == PROP_ADD_RTE)) {
1038 /* Test if zero... */
1039 assembleg_1_branch(jz_gc, AO, failed_label);
1040 /* Test if first byte is 0x70... */
1041 assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
1043 AO3.value = 0x70; /* type byte -- object */
1044 set_constant_ot(&AO3);
1045 assembleg_2_branch(jeq_gc, stack_pointer, AO3, passed_label);
1048 /* Test if zero... */
1049 assembleg_1_branch(jz_gc, AO, failed_label);
1050 /* Test if first byte is 0x70... */
1051 assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
1053 AO3.value = 0x70; /* type byte -- object */
1054 set_constant_ot(&AO3);
1055 assembleg_2_branch(jne_gc, stack_pointer, AO3, failed_label);
1056 /* Test if inside the "Class" object... */
1057 INITAOTV(&AO3, BYTECONSTANT_OT, GOBJFIELD_PARENT());
1058 assembleg_3(aload_gc, AO, AO3, stack_pointer);
1059 ln = symbol_index("Class", -1);
1060 AO3.value = svals[ln];
1061 AO3.marker = OBJECT_MV;
1062 AO3.type = CONSTANT_OT;
1063 assembleg_2_branch(jne_gc, stack_pointer, AO3, passed_label);
1066 assemble_label_no(failed_label);
1068 AO2.value = rte_number;
1069 set_constant_ot(&AO2);
1070 assembleg_call_2(veneer_routine(RT__Err_VR), AO2, AO1, zero_operand);
1072 if (error_label != -1) {
1073 /* Jump to the error label */
1074 if (error_label == -3) assembleg_1(return_gc, zero_operand);
1075 else if (error_label == -4) assembleg_1(return_gc, one_operand);
1076 else assembleg_jump(error_label);
1079 /* Build the symbol for "Object" */
1080 ln = symbol_index("Object", -1);
1081 AO2.value = svals[ln];
1082 AO2.marker = OBJECT_MV;
1083 AO2.type = CONSTANT_OT;
1086 assembleg_store(AO1, AO2);
1089 /* Store either "Object" or the operand's value in the temporary
1091 assembleg_store(temp_var2, AO2);
1092 last_label = next_label++;
1093 assembleg_jump(last_label);
1094 assemble_label_no(passed_label);
1095 assembleg_store(temp_var2, AO1);
1096 assemble_label_no(last_label);
1101 assemble_label_no(passed_label);
1105 static void compile_conditional_g(condclass *cc,
1106 assembly_operand AO1, assembly_operand AO2, int label, int flag)
1107 { assembly_operand AO4;
1108 int the_zc, error_label = label,
1109 va_flag = FALSE, va_label = 0;
1113 the_zc = (flag ? cc->posform : cc->negform);
1116 switch ((cc-condclasses)*2 + 500) {
1119 if (runtime_error_checking_switch) {
1121 error_label = next_label++;
1122 AO1 = check_nonzero_at_runtime(AO1, error_label, HAS_RTE);
1123 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1124 if ((AO2.value < 0) || (AO2.value >= NUM_ATTR_BYTES*8)) {
1125 error("'has'/'hasnt' applied to illegal attribute number");
1129 int pa_label = next_label++, fa_label = next_label++;
1130 assembly_operand en_ao, max_ao;
1132 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) {
1133 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1134 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1135 assembleg_2(stkpeek_gc, one_operand, temp_var2);
1138 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1139 assembleg_store(temp_var2, AO2);
1143 assembleg_store(temp_var1, AO1);
1144 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1145 assembleg_2(stkpeek_gc, zero_operand, temp_var2);
1148 assembleg_store(temp_var2, AO2);
1153 max_ao.value = NUM_ATTR_BYTES*8;
1154 set_constant_ot(&max_ao);
1155 assembleg_2_branch(jlt_gc, temp_var2, zero_operand, fa_label);
1156 assembleg_2_branch(jlt_gc, temp_var2, max_ao, pa_label);
1157 assemble_label_no(fa_label);
1159 en_ao.value = 19; /* INVALIDATTR_RTE */
1160 set_constant_ot(&en_ao);
1161 assembleg_store(stack_pointer, temp_var2);
1162 assembleg_store(stack_pointer, temp_var1);
1163 assembleg_store(stack_pointer, en_ao);
1164 assembleg_3(call_gc, veneer_routine(RT__Err_VR),
1165 three_operand, zero_operand);
1167 va_label = next_label++;
1168 assembleg_jump(va_label);
1169 assemble_label_no(pa_label);
1172 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1174 set_constant_ot(&AO2);
1179 AO4.type = BYTECONSTANT_OT;
1180 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) {
1181 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
1182 assembleg_0(stkswap_gc);
1183 assembleg_3(add_gc, AO2, AO4, stack_pointer);
1184 assembleg_0(stkswap_gc);
1187 assembleg_3(add_gc, AO2, AO4, stack_pointer);
1189 AO2 = stack_pointer;
1191 assembleg_3(aloadbit_gc, AO1, AO2, stack_pointer);
1192 the_zc = (flag ? jnz_gc : jz_gc);
1193 AO1 = stack_pointer;
1197 if (runtime_error_checking_switch) {
1199 error_label = next_label++;
1200 AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
1203 AO4.value = GOBJFIELD_PARENT();
1204 AO4.type = BYTECONSTANT_OT;
1205 assembleg_3(aload_gc, AO1, AO4, stack_pointer);
1206 AO1 = stack_pointer;
1207 the_zc = (flag ? jeq_gc : jne_gc);
1211 assembleg_call_2(veneer_routine(OC__Cl_VR), AO1, AO2, stack_pointer);
1212 the_zc = (flag ? jnz_gc : jz_gc);
1213 AO1 = stack_pointer;
1217 assembleg_call_2(veneer_routine(OP__Pr_VR), AO1, AO2, stack_pointer);
1218 the_zc = (flag ? jnz_gc : jz_gc);
1219 AO1 = stack_pointer;
1223 error("condition not yet supported in Glulx");
1228 if (the_zc == jnz_gc || the_zc == jz_gc)
1229 assembleg_1_branch(the_zc, AO1, label);
1231 assembleg_2_branch(the_zc, AO1, AO2, label);
1232 if (error_label != label) assemble_label_no(error_label);
1233 if (va_flag) assemble_label_no(va_label);
1236 static void value_in_void_context(assembly_operand AO)
1239 value_in_void_context_z(AO);
1241 value_in_void_context_g(AO);
1245 extern assembly_operand check_nonzero_at_runtime(assembly_operand AO1,
1246 int error_label, int rte_number)
1249 return check_nonzero_at_runtime_z(AO1, error_label, rte_number);
1251 return check_nonzero_at_runtime_g(AO1, error_label, rte_number);
1254 static void generate_code_from(int n, int void_flag)
1256 /* When void, this must not leave anything on the stack. */
1258 int i, j, below, above, opnum, arity; assembly_operand Result;
1260 below = ET[n].down; above = ET[n].up;
1262 { if ((void_flag) && (ET[n].value.type != OMITTED_OT))
1263 value_in_void_context(ET[n].value);
1267 opnum = ET[n].operator_number;
1269 if (opnum == COMMA_OP)
1270 { generate_code_from(below, TRUE);
1271 generate_code_from(ET[below].right, void_flag);
1272 ET[n].value = ET[ET[below].right].value;
1273 goto OperatorGenerated;
1276 if ((opnum == LOGAND_OP) || (opnum == LOGOR_OP))
1277 { generate_code_from(below, FALSE);
1278 generate_code_from(ET[below].right, FALSE);
1279 goto OperatorGenerated;
1284 /* Signifies a SETEQUALS_OP which has already been done */
1286 ET[n].down = -1; return;
1289 /* Note that (except in the cases of comma and logical and/or) it
1290 is essential to code generate the operands right to left, because
1291 of the peculiar way the Z-machine's stack works:
1295 (for instance) pulls to the first operand, then the second. So
1301 calculates (b+7)-(a*2), not the other way around (as would be more
1302 usual in stack machines evaluating expressions written in reverse
1303 Polish notation). (Basically this is because the Z-machine was
1304 designed to implement a LISP-like language naturally expressed
1305 in forward Polish notation: (PLUS 3 4), for instance.) */
1307 /* And the Glulx machine follows the Z-machine in this respect. */
1311 { i = ET[i].right; arity++;
1313 for (j=arity;j>0;j--)
1317 { k++; i = ET[i].right;
1319 generate_code_from(i, FALSE);
1323 /* Check this again, because code generation lower down may have
1324 stubbed it into -1 */
1326 if (ET[n].operator_number == -1)
1327 { ET[n].down = -1; return;
1332 if (operators[opnum].opcode_number_z >= 400)
1334 /* Conditional terms such as '==': */
1336 int a = ET[n].true_label, b = ET[n].false_label,
1337 branch_away, branch_other,
1338 make_jump_away = FALSE, make_branch_label = FALSE;
1339 int oc = operators[opnum].opcode_number_z-400, flag = TRUE;
1341 if (oc >= 400) { oc = oc - 400; flag = FALSE; }
1343 if ((oc == je_zc) && (arity == 2))
1344 { i = ET[ET[n].down].right;
1345 if ((ET[i].value.value == zero_operand.value)
1346 && (ET[i].value.type == zero_operand.type))
1350 /* If the condition has truth state flag, branch to
1351 label a, and if not, to label b. Possibly one of a, b
1352 equals -1, meaning "continue from this instruction".
1354 branch_away is the label which is a branch away (the one
1355 which isn't immediately after) and flag is the truth
1356 state to branch there.
1358 Note that when multiple instructions are needed (because
1359 of the use of the 'or' operator) the branch_other label
1360 is created if need be.
1363 /* Reduce to the case where the branch_away label does exist: */
1365 if (a == -1) { a = b; b = -1; flag = !flag; }
1367 branch_away = a; branch_other = b;
1368 if (branch_other != -1) make_jump_away = TRUE;
1370 if ((((oc != je_zc)&&(arity > 2)) || (arity > 4)) && (flag == FALSE))
1372 /* In this case, we have an 'or' situation where multiple
1373 instructions are needed and where the overall condition
1374 is negated. That is, we have, e.g.
1376 if not (A cond B or C or D) then branch_away
1378 which we transform into
1380 if (A cond B) then branch_other
1381 if (A cond C) then branch_other
1382 if not (A cond D) then branch_away
1385 if (branch_other == -1)
1386 { branch_other = next_label++; make_branch_label = TRUE;
1391 assemblez_1_branch(jz_zc, ET[below].value, branch_away, flag);
1393 { assembly_operand left_operand;
1396 compile_conditional_z(oc, ET[below].value,
1397 ET[ET[below].right].value, branch_away, flag);
1399 { /* The case of a condition using "or".
1400 First: if the condition tests the stack pointer,
1401 and it can't always be done in a single test, move
1402 the value off the stack and into temporary variable
1405 if (((ET[below].value.type == VARIABLE_OT)
1406 && (ET[below].value.value == 0))
1407 && ((oc != je_zc) || (arity>4)) )
1408 { INITAOTV(&left_operand, VARIABLE_OT, 255);
1409 assemblez_store(left_operand, ET[below].value);
1411 else left_operand = ET[below].value;
1412 i = ET[below].right; arity--;
1414 /* "left_operand" now holds the quantity to be tested;
1415 "i" holds the right operand reached so far;
1416 "arity" the number of right operands. */
1419 { if ((oc == je_zc) && (arity>1))
1421 /* je_zc is an especially good case since the
1422 Z-machine implements "or" for up to three
1423 right operands automatically, though it's an
1424 especially bad case to generate code for! */
1427 { assemblez_3_branch(je_zc,
1428 left_operand, ET[i].value,
1429 ET[ET[i].right].value, branch_away, flag);
1430 i = ET[i].right; arity--;
1433 { if ((arity == 3) || flag)
1434 assemblez_4_branch(je_zc, left_operand,
1436 ET[ET[i].right].value,
1437 ET[ET[ET[i].right].right].value,
1440 assemblez_4_branch(je_zc, left_operand,
1442 ET[ET[i].right].value,
1443 ET[ET[ET[i].right].right].value,
1444 branch_other, !flag);
1445 i = ET[ET[i].right].right; arity -= 2;
1449 { /* Otherwise we can compare the left_operand with
1450 only one right operand at the time. There are
1451 two cases: it's the last right operand, or it
1454 if ((arity == 1) || flag)
1455 compile_conditional_z(oc, left_operand,
1456 ET[i].value, branch_away, flag);
1458 compile_conditional_z(oc, left_operand,
1459 ET[i].value, branch_other, !flag);
1461 i = ET[i].right; arity--;
1467 /* NB: These two conditions cannot both occur, fortunately! */
1469 if (make_branch_label) assemble_label_no(branch_other);
1470 if (make_jump_away) assemblez_jump(branch_other);
1472 goto OperatorGenerated;
1477 if (operators[opnum].opcode_number_g >= FIRST_CC
1478 && operators[opnum].opcode_number_g <= LAST_CC) {
1479 /* Conditional terms such as '==': */
1481 int a = ET[n].true_label, b = ET[n].false_label;
1482 int branch_away, branch_other, flag,
1483 make_jump_away = FALSE, make_branch_label = FALSE;
1484 int ccode = operators[opnum].opcode_number_g;
1485 condclass *cc = &condclasses[(ccode-FIRST_CC) / 2];
1486 flag = (ccode & 1) ? 0 : 1;
1488 /* If the comparison is "equal to (constant) 0", change it
1489 to the simple "zero" test. Unfortunately, this doesn't
1490 work for the commutative form "(constant) 0 is equal to".
1491 At least I don't think it does. */
1493 if ((cc == &condclasses[1]) && (arity == 2)) {
1494 i = ET[ET[n].down].right;
1495 if ((ET[i].value.value == 0)
1496 && (ET[i].value.marker == 0)
1497 && is_constant_ot(ET[i].value.type)) {
1498 cc = &condclasses[0];
1502 /* If the condition has truth state flag, branch to
1503 label a, and if not, to label b. Possibly one of a, b
1504 equals -1, meaning "continue from this instruction".
1506 branch_away is the label which is a branch away (the one
1507 which isn't immediately after) and flag is the truth
1508 state to branch there.
1510 Note that when multiple instructions are needed (because
1511 of the use of the 'or' operator) the branch_other label
1512 is created if need be.
1515 /* Reduce to the case where the branch_away label does exist: */
1517 if (a == -1) { a = b; b = -1; flag = !flag; }
1519 branch_away = a; branch_other = b;
1520 if (branch_other != -1) make_jump_away = TRUE;
1522 if ((arity > 2) && (flag == FALSE)) {
1523 /* In this case, we have an 'or' situation where multiple
1524 instructions are needed and where the overall condition
1525 is negated. That is, we have, e.g.
1527 if not (A cond B or C or D) then branch_away
1529 which we transform into
1531 if (A cond B) then branch_other
1532 if (A cond C) then branch_other
1533 if not (A cond D) then branch_away
1536 if (branch_other == -1) {
1537 branch_other = next_label++; make_branch_label = TRUE;
1541 if (cc == &condclasses[0]) {
1542 assembleg_1_branch((flag ? cc->posform : cc->negform),
1543 ET[below].value, branch_away);
1547 compile_conditional_g(cc, ET[below].value,
1548 ET[ET[below].right].value, branch_away, flag);
1551 /* The case of a condition using "or".
1552 First: if the condition tests the stack pointer,
1553 and it can't always be done in a single test, move
1554 the value off the stack and into temporary variable
1557 assembly_operand left_operand;
1558 if (((ET[below].value.type == LOCALVAR_OT)
1559 && (ET[below].value.value == 0))) {
1560 assembleg_store(temp_var1, ET[below].value);
1561 left_operand = temp_var1;
1564 left_operand = ET[below].value;
1566 i = ET[below].right;
1569 /* "left_operand" now holds the quantity to be tested;
1570 "i" holds the right operand reached so far;
1571 "arity" the number of right operands. */
1574 /* We can compare the left_operand with
1575 only one right operand at the time. There are
1576 two cases: it's the last right operand, or it
1579 if ((arity == 1) || flag)
1580 compile_conditional_g(cc, left_operand,
1581 ET[i].value, branch_away, flag);
1583 compile_conditional_g(cc, left_operand,
1584 ET[i].value, branch_other, !flag);
1592 /* NB: These two conditions cannot both occur, fortunately! */
1594 if (make_branch_label) assemble_label_no(branch_other);
1595 if (make_jump_away) assembleg_jump(branch_other);
1597 goto OperatorGenerated;
1602 /* The operator is now definitely one which produces a value */
1604 if (void_flag && (!(operators[opnum].side_effect)))
1605 error_named("Evaluating this has no effect:",
1606 operators[opnum].description);
1608 /* Where shall we put the resulting value? (In Glulx, this could
1609 be smarter, and peg the result into ZEROCONSTANT.) */
1611 if (void_flag) Result = temp_var1; /* Throw it away */
1613 { if ((above != -1) && (ET[above].operator_number == SETEQUALS_OP))
1615 /* If the node above is "set variable equal to", then
1616 make that variable the place to put the result, and
1617 delete the SETEQUALS_OP node since its effect has already
1618 been accomplished. */
1620 ET[above].operator_number = -1;
1621 Result = ET[ET[above].down].value;
1622 ET[above].value = Result;
1624 else Result = stack_pointer; /* Otherwise, put it on the stack */
1629 if (operators[opnum].opcode_number_z != -1)
1631 /* Operators directly translatable into Z-code opcodes: infix ops
1632 take two operands whereas pre/postfix operators take only one */
1634 if (operators[opnum].usage == IN_U)
1635 { int o_n = operators[opnum].opcode_number_z;
1636 if (runtime_error_checking_switch && (!veneer_mode)
1637 && ((o_n == div_zc) || (o_n == mod_zc)))
1638 { assembly_operand by_ao, error_ao; int ln;
1639 by_ao = ET[ET[below].right].value;
1640 if ((by_ao.value != 0) && (by_ao.marker == 0)
1641 && ((by_ao.type == SHORT_CONSTANT_OT)
1642 || (by_ao.type == LONG_CONSTANT_OT)))
1643 assemblez_2_to(o_n, ET[below].value,
1647 assemblez_store(temp_var1, ET[below].value);
1648 assemblez_store(temp_var2, by_ao);
1650 assemblez_1_branch(jz_zc, temp_var2, ln, FALSE);
1651 INITAOT(&error_ao, SHORT_CONSTANT_OT);
1652 error_ao.value = DBYZERO_RTE;
1653 assemblez_2(call_vn_zc, veneer_routine(RT__Err_VR),
1655 assemblez_inc(temp_var2);
1656 assemble_label_no(ln);
1657 assemblez_2_to(o_n, temp_var1, temp_var2, Result);
1661 assemblez_2_to(o_n, ET[below].value,
1662 ET[ET[below].right].value, Result);
1666 assemblez_1_to(operators[opnum].opcode_number_z, ET[below].value,
1672 access_memory_z(loadb_zc, ET[below].value,
1673 ET[ET[below].right].value, Result);
1676 access_memory_z(loadw_zc, ET[below].value,
1677 ET[ET[below].right].value, Result);
1679 case UNARY_MINUS_OP:
1680 assemblez_2_to(sub_zc, zero_operand, ET[below].value, Result);
1683 assemblez_1_to(not_zc, ET[below].value, Result);
1687 { assembly_operand AO = ET[below].value;
1688 if (runtime_error_checking_switch && (!veneer_mode))
1689 AO = check_nonzero_at_runtime(AO, -1, PROP_ADD_RTE);
1690 assemblez_2_to(get_prop_addr_zc, AO,
1691 ET[ET[below].right].value, temp_var1);
1692 if (!void_flag) write_result_z(Result, temp_var1);
1697 { assembly_operand AO = ET[below].value;
1698 if (runtime_error_checking_switch && (!veneer_mode))
1699 AO = check_nonzero_at_runtime(AO, -1, PROP_NUM_RTE);
1700 assemblez_2_to(get_prop_addr_zc, AO,
1701 ET[ET[below].right].value, temp_var1);
1702 assemblez_1_branch(jz_zc, temp_var1, next_label++, TRUE);
1703 assemblez_1_to(get_prop_len_zc, temp_var1, temp_var1);
1704 assemble_label_no(next_label-1);
1705 if (!void_flag) write_result_z(Result, temp_var1);
1710 { assembly_operand AO = ET[below].value;
1712 if (runtime_error_checking_switch && (!veneer_mode))
1713 assemblez_3_to(call_vs_zc, veneer_routine(RT__ChPR_VR),
1714 AO, ET[ET[below].right].value, temp_var1);
1716 assemblez_2_to(get_prop_zc, AO,
1717 ET[ET[below].right].value, temp_var1);
1718 if (!void_flag) write_result_z(Result, temp_var1);
1723 j=1; AI.operand[0] = veneer_routine(RV__Pr_VR);
1724 goto GenFunctionCallZ;
1726 j=1; AI.operand[0] = veneer_routine(RA__Pr_VR);
1727 goto GenFunctionCallZ;
1729 j=1; AI.operand[0] = veneer_routine(RL__Pr_VR);
1730 goto GenFunctionCallZ;
1731 case MESSAGE_SETEQUALS_OP:
1732 j=1; AI.operand[0] = veneer_routine(WV__Pr_VR);
1733 goto GenFunctionCallZ;
1734 case MESSAGE_INC_OP:
1735 j=1; AI.operand[0] = veneer_routine(IB__Pr_VR);
1736 goto GenFunctionCallZ;
1737 case MESSAGE_DEC_OP:
1738 j=1; AI.operand[0] = veneer_routine(DB__Pr_VR);
1739 goto GenFunctionCallZ;
1740 case MESSAGE_POST_INC_OP:
1741 j=1; AI.operand[0] = veneer_routine(IA__Pr_VR);
1742 goto GenFunctionCallZ;
1743 case MESSAGE_POST_DEC_OP:
1744 j=1; AI.operand[0] = veneer_routine(DA__Pr_VR);
1745 goto GenFunctionCallZ;
1747 j=1; AI.operand[0] = veneer_routine(RA__Sc_VR);
1748 goto GenFunctionCallZ;
1750 j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
1751 goto GenFunctionCallZ;
1752 case MESSAGE_CALL_OP:
1753 j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
1754 goto GenFunctionCallZ;
1760 if ((ET[below].value.type == VARIABLE_OT)
1761 && (ET[below].value.value >= 256))
1762 { int sf_number = ET[below].value.value - 256;
1764 i = ET[below].right;
1766 { error("Argument to system function missing");
1767 AI.operand[0] = one_operand;
1768 AI.operand_count = 1;
1772 while (i != -1) { j++; i = ET[i].right; }
1774 if (((sf_number != INDIRECT_SYSF) &&
1775 (sf_number != RANDOM_SYSF) && (j > 1))
1776 || ((sf_number == INDIRECT_SYSF) && (j>7)))
1778 error("System function given with too many arguments");
1780 if (sf_number != RANDOM_SYSF)
1782 i = ET[below].right;
1783 for (jcount = 0; jcount < j; jcount++)
1784 { AI.operand[jcount] = ET[i].value;
1787 AI.operand_count = j;
1790 AI.store_variable_number = Result.value;
1791 AI.branch_label_number = -1;
1796 { assembly_operand AO, AO2; int arg_c, arg_et;
1797 INITAOTV(&AO, SHORT_CONSTANT_OT, j);
1798 INITAOT(&AO2, LONG_CONSTANT_OT);
1799 AO2.value = begin_word_array();
1800 AO2.marker = ARRAY_MV;
1802 for (arg_c=0, arg_et = ET[below].right;arg_c<j;
1803 arg_c++, arg_et = ET[arg_et].right)
1804 { if (ET[arg_et].value.type == VARIABLE_OT)
1805 error("Only constants can be used as possible 'random' results");
1806 array_entry(arg_c, FALSE, ET[arg_et].value);
1808 finish_array(arg_c, FALSE);
1810 assemblez_1_to(random_zc, AO, temp_var1);
1811 assemblez_dec(temp_var1);
1812 assemblez_2_to(loadw_zc, AO2, temp_var1, Result);
1815 assemblez_1_to(random_zc,
1816 ET[ET[below].right].value, Result);
1820 { assembly_operand AO;
1821 AO = ET[ET[below].right].value;
1822 if (runtime_error_checking_switch)
1823 AO = check_nonzero_at_runtime(AO, -1,
1825 assemblez_1_to(get_parent_zc, AO, Result);
1831 { assembly_operand AO;
1832 AO = ET[ET[below].right].value;
1833 if (runtime_error_checking_switch)
1834 AO = check_nonzero_at_runtime(AO, -1,
1835 (sf_number==CHILD_SYSF)?CHILD_RTE:ELDEST_RTE);
1836 assemblez_objcode(get_child_zc,
1837 AO, Result, -2, TRUE);
1843 { assembly_operand AO;
1844 AO = ET[ET[below].right].value;
1845 if (runtime_error_checking_switch)
1846 AO = check_nonzero_at_runtime(AO, -1,
1847 (sf_number==SIBLING_SYSF)
1848 ?SIBLING_RTE:YOUNGER_RTE);
1849 assemblez_objcode(get_sibling_zc,
1850 AO, Result, -2, TRUE);
1855 j=0; i = ET[below].right;
1856 goto IndirectFunctionCallZ;
1859 { assembly_operand AO;
1860 AO = ET[ET[below].right].value;
1861 if (runtime_error_checking_switch)
1862 AO = check_nonzero_at_runtime(AO, -1,
1864 assemblez_store(temp_var1, zero_operand);
1865 assemblez_objcode(get_child_zc,
1866 AO, stack_pointer, next_label+1, FALSE);
1867 assemble_label_no(next_label);
1868 assemblez_inc(temp_var1);
1869 assemblez_objcode(get_sibling_zc,
1870 stack_pointer, stack_pointer,
1872 assemble_label_no(next_label+1);
1873 assemblez_store(temp_var2, stack_pointer);
1874 if (!void_flag) write_result_z(Result, temp_var1);
1880 { assembly_operand AO;
1881 AO = ET[ET[below].right].value;
1882 if (runtime_error_checking_switch)
1883 AO = check_nonzero_at_runtime(AO, -1,
1885 assemblez_objcode(get_child_zc,
1886 AO, temp_var1, next_label+1, FALSE);
1887 assemblez_1(push_zc, temp_var1);
1888 assemble_label_no(next_label);
1889 assemblez_store(temp_var1, stack_pointer);
1890 assemblez_objcode(get_sibling_zc,
1891 temp_var1, stack_pointer, next_label, TRUE);
1892 assemble_label_no(next_label+1);
1893 if (!void_flag) write_result_z(Result, temp_var1);
1899 assemblez_store(temp_var1, ET[ET[below].right].value);
1900 if (runtime_error_checking_switch)
1901 check_nonzero_at_runtime(temp_var1, -1,
1903 assemblez_1_to(get_parent_zc, temp_var1, temp_var3);
1904 assemblez_1_branch(jz_zc, temp_var3,next_label+1,TRUE);
1905 assemblez_store(temp_var2, temp_var3);
1906 assemblez_store(temp_var3, zero_operand);
1907 assemblez_objcode(get_child_zc,
1908 temp_var2, temp_var2, next_label, TRUE);
1909 assemble_label_no(next_label++);
1910 assemblez_2_branch(je_zc, temp_var1, temp_var2,
1912 assemblez_store(temp_var3, temp_var2);
1913 assemblez_objcode(get_sibling_zc,
1914 temp_var2, temp_var2, next_label - 1, TRUE);
1915 assemble_label_no(next_label++);
1916 if (!void_flag) write_result_z(Result, temp_var3);
1919 case METACLASS_SYSF:
1920 assemblez_2_to((version_number==3)?call_zc:call_vs_zc,
1921 veneer_routine(Metaclass_VR),
1922 ET[ET[below].right].value, Result);
1926 error("The glk() system function does not exist in Z-code");
1936 IndirectFunctionCallZ:
1938 while ((i != -1) && (j<8))
1939 { AI.operand[j++] = ET[i].value;
1943 if ((j > 4) && (version_number == 3))
1944 { error("A function may be called with at most 3 arguments");
1947 if ((j==8) && (i != -1))
1948 { error("A function may be called with at most 7 arguments");
1951 AI.operand_count = j;
1953 if ((void_flag) && (version_number >= 5))
1954 { AI.store_variable_number = -1;
1956 { case 1: AI.internal_number = call_1n_zc; break;
1957 case 2: AI.internal_number = call_2n_zc; break;
1958 case 3: case 4: AI.internal_number = call_vn_zc; break;
1959 case 5: case 6: case 7: case 8:
1960 AI.internal_number = call_vn2_zc; break;
1964 { AI.store_variable_number = Result.value;
1965 if (version_number == 3)
1966 AI.internal_number = call_zc;
1969 { case 1: AI.internal_number = call_1s_zc; break;
1970 case 2: AI.internal_number = call_2s_zc; break;
1971 case 3: case 4: AI.internal_number = call_vs_zc; break;
1972 case 5: case 6: case 7: case 8:
1973 AI.internal_number = call_vs2_zc; break;
1977 AI.branch_label_number = -1;
1978 assemblez_instruction(&AI);
1982 assemblez_store(ET[below].value,
1983 ET[ET[below].right].value);
1984 if (!void_flag) write_result_z(Result, ET[below].value);
1987 case PROPERTY_SETEQUALS_OP:
1989 { if (runtime_error_checking_switch)
1990 assemblez_4_to(call_zc, veneer_routine(RT__ChPS_VR),
1991 ET[below].value, ET[ET[below].right].value,
1992 ET[ET[ET[below].right].right].value, Result);
1994 { assemblez_store(temp_var1,
1995 ET[ET[ET[below].right].right].value);
1996 assemblez_3(put_prop_zc, ET[below].value,
1997 ET[ET[below].right].value,
1999 write_result_z(Result, temp_var1);
2003 { if (runtime_error_checking_switch && (!veneer_mode))
2004 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2005 ET[below].value, ET[ET[below].right].value,
2006 ET[ET[ET[below].right].right].value);
2007 else assemblez_3(put_prop_zc, ET[below].value,
2008 ET[ET[below].right].value,
2009 ET[ET[ET[below].right].right].value);
2012 case ARROW_SETEQUALS_OP:
2014 { assemblez_store(temp_var1,
2015 ET[ET[ET[below].right].right].value);
2016 access_memory_z(storeb_zc, ET[below].value,
2017 ET[ET[below].right].value,
2019 write_result_z(Result, temp_var1);
2021 else access_memory_z(storeb_zc, ET[below].value,
2022 ET[ET[below].right].value,
2023 ET[ET[ET[below].right].right].value);
2026 case DARROW_SETEQUALS_OP:
2028 { assemblez_store(temp_var1,
2029 ET[ET[ET[below].right].right].value);
2030 access_memory_z(storew_zc, ET[below].value,
2031 ET[ET[below].right].value,
2033 write_result_z(Result, temp_var1);
2036 access_memory_z(storew_zc, ET[below].value,
2037 ET[ET[below].right].value,
2038 ET[ET[ET[below].right].right].value);
2042 assemblez_inc(ET[below].value);
2043 if (!void_flag) write_result_z(Result, ET[below].value);
2046 assemblez_dec(ET[below].value);
2047 if (!void_flag) write_result_z(Result, ET[below].value);
2050 if (!void_flag) write_result_z(Result, ET[below].value);
2051 assemblez_inc(ET[below].value);
2054 if (!void_flag) write_result_z(Result, ET[below].value);
2055 assemblez_dec(ET[below].value);
2059 assemblez_store(temp_var1, ET[below].value);
2060 assemblez_store(temp_var2, ET[ET[below].right].value);
2061 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2062 assemblez_inc(temp_var3);
2063 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2064 if (!void_flag) write_result_z(Result, temp_var3);
2068 assemblez_store(temp_var1, ET[below].value);
2069 assemblez_store(temp_var2, ET[ET[below].right].value);
2070 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2071 assemblez_dec(temp_var3);
2072 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2073 if (!void_flag) write_result_z(Result, temp_var3);
2076 case ARROW_POST_INC_OP:
2077 assemblez_store(temp_var1, ET[below].value);
2078 assemblez_store(temp_var2, ET[ET[below].right].value);
2079 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2080 if (!void_flag) write_result_z(Result, temp_var3);
2081 assemblez_inc(temp_var3);
2082 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2085 case ARROW_POST_DEC_OP:
2086 assemblez_store(temp_var1, ET[below].value);
2087 assemblez_store(temp_var2, ET[ET[below].right].value);
2088 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2089 if (!void_flag) write_result_z(Result, temp_var3);
2090 assemblez_dec(temp_var3);
2091 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2095 assemblez_store(temp_var1, ET[below].value);
2096 assemblez_store(temp_var2, ET[ET[below].right].value);
2097 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2098 assemblez_inc(temp_var3);
2099 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2100 if (!void_flag) write_result_z(Result, temp_var3);
2104 assemblez_store(temp_var1, ET[below].value);
2105 assemblez_store(temp_var2, ET[ET[below].right].value);
2106 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2107 assemblez_dec(temp_var3);
2108 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2109 if (!void_flag) write_result_z(Result, temp_var3);
2112 case DARROW_POST_INC_OP:
2113 assemblez_store(temp_var1, ET[below].value);
2114 assemblez_store(temp_var2, ET[ET[below].right].value);
2115 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2116 if (!void_flag) write_result_z(Result, temp_var3);
2117 assemblez_inc(temp_var3);
2118 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2121 case DARROW_POST_DEC_OP:
2122 assemblez_store(temp_var1, ET[below].value);
2123 assemblez_store(temp_var2, ET[ET[below].right].value);
2124 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2125 if (!void_flag) write_result_z(Result, temp_var3);
2126 assemblez_dec(temp_var3);
2127 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2130 case PROPERTY_INC_OP:
2131 assemblez_store(temp_var1, ET[below].value);
2132 assemblez_store(temp_var2, ET[ET[below].right].value);
2133 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2134 assemblez_inc(temp_var3);
2135 if (runtime_error_checking_switch && (!veneer_mode))
2136 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2137 temp_var1, temp_var2, temp_var3);
2138 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2139 if (!void_flag) write_result_z(Result, temp_var3);
2142 case PROPERTY_DEC_OP:
2143 assemblez_store(temp_var1, ET[below].value);
2144 assemblez_store(temp_var2, ET[ET[below].right].value);
2145 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2146 assemblez_dec(temp_var3);
2147 if (runtime_error_checking_switch && (!veneer_mode))
2148 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2149 temp_var1, temp_var2, temp_var3);
2150 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2151 if (!void_flag) write_result_z(Result, temp_var3);
2154 case PROPERTY_POST_INC_OP:
2155 assemblez_store(temp_var1, ET[below].value);
2156 assemblez_store(temp_var2, ET[ET[below].right].value);
2157 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2158 if (!void_flag) write_result_z(Result, temp_var3);
2159 assemblez_inc(temp_var3);
2160 if (runtime_error_checking_switch && (!veneer_mode))
2161 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2162 temp_var1, temp_var2, temp_var3);
2163 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2166 case PROPERTY_POST_DEC_OP:
2167 assemblez_store(temp_var1, ET[below].value);
2168 assemblez_store(temp_var2, ET[ET[below].right].value);
2169 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2170 if (!void_flag) write_result_z(Result, temp_var3);
2171 assemblez_dec(temp_var3);
2172 if (runtime_error_checking_switch && (!veneer_mode))
2173 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2174 temp_var1, temp_var2, temp_var3);
2175 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2179 printf("** Trouble op = %d i.e. '%s' **\n",
2180 opnum, operators[opnum].description);
2181 compiler_error("Expr code gen: Can't generate yet");
2185 assembly_operand AO, AO2;
2186 if (operators[opnum].opcode_number_g != -1)
2188 /* Operators directly translatable into opcodes: infix ops
2189 take two operands whereas pre/postfix operators take only one */
2191 if (operators[opnum].usage == IN_U)
2192 { int o_n = operators[opnum].opcode_number_g;
2193 if (runtime_error_checking_switch && (!veneer_mode)
2194 && ((o_n == div_gc) || (o_n == mod_gc)))
2195 { assembly_operand by_ao, error_ao; int ln;
2196 by_ao = ET[ET[below].right].value;
2197 if ((by_ao.value != 0) && (by_ao.marker == 0)
2198 && is_constant_ot(by_ao.type))
2199 assembleg_3(o_n, ET[below].value,
2202 { assembleg_store(temp_var1, ET[below].value);
2203 assembleg_store(temp_var2, by_ao);
2205 assembleg_1_branch(jnz_gc, temp_var2, ln);
2207 error_ao.value = DBYZERO_RTE;
2208 set_constant_ot(&error_ao);
2209 assembleg_call_1(veneer_routine(RT__Err_VR),
2210 error_ao, zero_operand);
2211 assembleg_store(temp_var2, one_operand);
2212 assemble_label_no(ln);
2213 assembleg_3(o_n, temp_var1, temp_var2, Result);
2217 assembleg_3(o_n, ET[below].value,
2218 ET[ET[below].right].value, Result);
2221 assembleg_2(operators[opnum].opcode_number_g, ET[below].value,
2229 if (ET[below].value.type == Result.type
2230 && ET[below].value.value == Result.value
2231 && ET[below].value.marker == Result.marker)
2233 assembleg_2(copy_gc, ET[below].value, Result);
2236 case UNARY_MINUS_OP:
2237 assembleg_2(neg_gc, ET[below].value, Result);
2240 assembleg_2(bitnot_gc, ET[below].value, Result);
2244 access_memory_g(aloadb_gc, ET[below].value,
2245 ET[ET[below].right].value, Result);
2248 access_memory_g(aload_gc, ET[below].value,
2249 ET[ET[below].right].value, Result);
2253 assembleg_store(ET[below].value,
2254 ET[ET[below].right].value);
2255 if (!void_flag) write_result_g(Result, ET[below].value);
2258 case ARROW_SETEQUALS_OP:
2260 { assembleg_store(temp_var1,
2261 ET[ET[ET[below].right].right].value);
2262 access_memory_g(astoreb_gc, ET[below].value,
2263 ET[ET[below].right].value,
2265 write_result_g(Result, temp_var1);
2267 else access_memory_g(astoreb_gc, ET[below].value,
2268 ET[ET[below].right].value,
2269 ET[ET[ET[below].right].right].value);
2272 case DARROW_SETEQUALS_OP:
2274 { assembleg_store(temp_var1,
2275 ET[ET[ET[below].right].right].value);
2276 access_memory_g(astore_gc, ET[below].value,
2277 ET[ET[below].right].value,
2279 write_result_g(Result, temp_var1);
2282 access_memory_g(astore_gc, ET[below].value,
2283 ET[ET[below].right].value,
2284 ET[ET[ET[below].right].right].value);
2288 assembleg_inc(ET[below].value);
2289 if (!void_flag) write_result_g(Result, ET[below].value);
2292 assembleg_dec(ET[below].value);
2293 if (!void_flag) write_result_g(Result, ET[below].value);
2296 if (!void_flag) write_result_g(Result, ET[below].value);
2297 assembleg_inc(ET[below].value);
2300 if (!void_flag) write_result_g(Result, ET[below].value);
2301 assembleg_dec(ET[below].value);
2305 assembleg_store(temp_var1, ET[below].value);
2306 assembleg_store(temp_var2, ET[ET[below].right].value);
2307 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2308 assembleg_inc(temp_var3);
2309 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2310 if (!void_flag) write_result_g(Result, temp_var3);
2314 assembleg_store(temp_var1, ET[below].value);
2315 assembleg_store(temp_var2, ET[ET[below].right].value);
2316 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2317 assembleg_dec(temp_var3);
2318 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2319 if (!void_flag) write_result_g(Result, temp_var3);
2322 case ARROW_POST_INC_OP:
2323 assembleg_store(temp_var1, ET[below].value);
2324 assembleg_store(temp_var2, ET[ET[below].right].value);
2325 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2326 if (!void_flag) write_result_g(Result, temp_var3);
2327 assembleg_inc(temp_var3);
2328 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2331 case ARROW_POST_DEC_OP:
2332 assembleg_store(temp_var1, ET[below].value);
2333 assembleg_store(temp_var2, ET[ET[below].right].value);
2334 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2335 if (!void_flag) write_result_g(Result, temp_var3);
2336 assembleg_dec(temp_var3);
2337 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2341 assembleg_store(temp_var1, ET[below].value);
2342 assembleg_store(temp_var2, ET[ET[below].right].value);
2343 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2344 assembleg_inc(temp_var3);
2345 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2346 if (!void_flag) write_result_g(Result, temp_var3);
2350 assembleg_store(temp_var1, ET[below].value);
2351 assembleg_store(temp_var2, ET[ET[below].right].value);
2352 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2353 assembleg_dec(temp_var3);
2354 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2355 if (!void_flag) write_result_g(Result, temp_var3);
2358 case DARROW_POST_INC_OP:
2359 assembleg_store(temp_var1, ET[below].value);
2360 assembleg_store(temp_var2, ET[ET[below].right].value);
2361 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2362 if (!void_flag) write_result_g(Result, temp_var3);
2363 assembleg_inc(temp_var3);
2364 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2367 case DARROW_POST_DEC_OP:
2368 assembleg_store(temp_var1, ET[below].value);
2369 assembleg_store(temp_var2, ET[ET[below].right].value);
2370 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2371 if (!void_flag) write_result_g(Result, temp_var3);
2372 assembleg_dec(temp_var3);
2373 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2378 AO = veneer_routine(RV__Pr_VR);
2379 goto TwoArgFunctionCall;
2382 AO = veneer_routine(RA__Pr_VR);
2383 goto TwoArgFunctionCall;
2386 AO = veneer_routine(RL__Pr_VR);
2387 goto TwoArgFunctionCall;
2390 case MESSAGE_CALL_OP:
2391 AO2 = veneer_routine(CA__Pr_VR);
2393 goto DoFunctionCall;
2395 case MESSAGE_INC_OP:
2396 case PROPERTY_INC_OP:
2397 AO = veneer_routine(IB__Pr_VR);
2398 goto TwoArgFunctionCall;
2399 case MESSAGE_DEC_OP:
2400 case PROPERTY_DEC_OP:
2401 AO = veneer_routine(DB__Pr_VR);
2402 goto TwoArgFunctionCall;
2403 case MESSAGE_POST_INC_OP:
2404 case PROPERTY_POST_INC_OP:
2405 AO = veneer_routine(IA__Pr_VR);
2406 goto TwoArgFunctionCall;
2407 case MESSAGE_POST_DEC_OP:
2408 case PROPERTY_POST_DEC_OP:
2409 AO = veneer_routine(DA__Pr_VR);
2410 goto TwoArgFunctionCall;
2412 AO = veneer_routine(RA__Sc_VR);
2413 goto TwoArgFunctionCall;
2417 assembly_operand AO2 = ET[below].value;
2418 assembly_operand AO3 = ET[ET[below].right].value;
2420 assembleg_call_2(AO, AO2, AO3, zero_operand);
2422 assembleg_call_2(AO, AO2, AO3, Result);
2426 case PROPERTY_SETEQUALS_OP:
2427 case MESSAGE_SETEQUALS_OP:
2428 if (runtime_error_checking_switch && (!veneer_mode))
2429 AO = veneer_routine(RT__ChPS_VR);
2431 AO = veneer_routine(WV__Pr_VR);
2434 assembly_operand AO2 = ET[below].value;
2435 assembly_operand AO3 = ET[ET[below].right].value;
2436 assembly_operand AO4 = ET[ET[ET[below].right].right].value;
2437 if (AO4.type == LOCALVAR_OT && AO4.value == 0) {
2438 /* Rightmost is on the stack; reduce to previous case. */
2439 if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2440 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2441 /* both already on stack. */
2444 assembleg_store(stack_pointer, AO3);
2445 assembleg_0(stkswap_gc);
2449 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2450 assembleg_store(stack_pointer, AO2);
2453 assembleg_store(stack_pointer, AO3);
2454 assembleg_store(stack_pointer, AO2);
2459 /* We have to get the rightmost on the stack, below the
2461 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2462 if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2463 assembleg_store(stack_pointer, AO4);
2464 assembleg_2(stkroll_gc, three_operand, one_operand);
2467 assembleg_store(stack_pointer, AO4);
2468 assembleg_0(stkswap_gc);
2469 assembleg_store(stack_pointer, AO2);
2473 if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2474 assembleg_store(stack_pointer, AO4);
2475 assembleg_store(stack_pointer, AO3);
2476 assembleg_2(stkroll_gc, three_operand, two_operand);
2479 assembleg_store(stack_pointer, AO4);
2480 assembleg_store(stack_pointer, AO3);
2481 assembleg_store(stack_pointer, AO2);
2486 assembleg_3(call_gc, AO, three_operand, zero_operand);
2488 assembleg_3(call_gc, AO, three_operand, Result);
2495 if (ET[below].value.type == SYSFUN_OT)
2496 { int sf_number = ET[below].value.value;
2498 i = ET[below].right;
2500 { error("Argument to system function missing");
2501 AI.operand[0] = one_operand;
2502 AI.operand_count = 1;
2506 while (i != -1) { j++; i = ET[i].right; }
2508 if (((sf_number != INDIRECT_SYSF) &&
2509 (sf_number != GLK_SYSF) &&
2510 (sf_number != RANDOM_SYSF) && (j > 1)))
2512 error("System function given with too many arguments");
2514 if (sf_number != RANDOM_SYSF)
2516 i = ET[below].right;
2517 for (jcount = 0; jcount < j; jcount++)
2518 { AI.operand[jcount] = ET[i].value;
2521 AI.operand_count = j;
2529 { assembly_operand AO, AO2;
2533 set_constant_ot(&AO);
2534 INITAOTV(&AO2, CONSTANT_OT, begin_word_array());
2535 AO2.marker = ARRAY_MV;
2537 for (arg_c=0, arg_et = ET[below].right;arg_c<j;
2538 arg_c++, arg_et = ET[arg_et].right)
2539 { if (ET[arg_et].value.type == LOCALVAR_OT
2540 || ET[arg_et].value.type == GLOBALVAR_OT)
2541 error("Only constants can be used as possible 'random' results");
2542 array_entry(arg_c, FALSE, ET[arg_et].value);
2544 finish_array(arg_c, FALSE);
2546 assembleg_2(random_gc, AO, stack_pointer);
2547 assembleg_3(aload_gc, AO2, stack_pointer, Result);
2550 assembleg_2(random_gc,
2551 ET[ET[below].right].value, stack_pointer);
2552 assembleg_3(add_gc, stack_pointer, one_operand,
2558 { assembly_operand AO;
2559 AO = ET[ET[below].right].value;
2560 if (runtime_error_checking_switch)
2561 AO = check_nonzero_at_runtime(AO, -1,
2563 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2564 assembleg_3(aload_gc, AO, AO2, Result);
2570 { assembly_operand AO;
2571 AO = ET[ET[below].right].value;
2572 if (runtime_error_checking_switch)
2573 AO = check_nonzero_at_runtime(AO, -1,
2574 (sf_number==CHILD_SYSF)?CHILD_RTE:ELDEST_RTE);
2575 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2576 assembleg_3(aload_gc, AO, AO2, Result);
2582 { assembly_operand AO;
2583 AO = ET[ET[below].right].value;
2584 if (runtime_error_checking_switch)
2585 AO = check_nonzero_at_runtime(AO, -1,
2586 (sf_number==SIBLING_SYSF)
2587 ?SIBLING_RTE:YOUNGER_RTE);
2588 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2589 assembleg_3(aload_gc, AO, AO2, Result);
2594 { assembly_operand AO;
2595 AO = ET[ET[below].right].value;
2596 if (runtime_error_checking_switch)
2597 AO = check_nonzero_at_runtime(AO, -1,
2599 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2600 assembleg_store(temp_var1, zero_operand);
2601 assembleg_3(aload_gc, AO, AO2, temp_var2);
2602 AO2.value = GOBJFIELD_SIBLING();
2603 assemble_label_no(next_label);
2604 assembleg_1_branch(jz_gc, temp_var2, next_label+1);
2605 assembleg_3(add_gc, temp_var1, one_operand,
2607 assembleg_3(aload_gc, temp_var2, AO2, temp_var2);
2608 assembleg_0_branch(jump_gc, next_label);
2609 assemble_label_no(next_label+1);
2612 write_result_g(Result, temp_var1);
2617 i = ET[below].right;
2618 goto IndirectFunctionCallG;
2621 AO2 = veneer_routine(Glk__Wrap_VR);
2622 i = ET[below].right;
2623 goto DoFunctionCall;
2625 case METACLASS_SYSF:
2626 assembleg_call_1(veneer_routine(Metaclass_VR),
2627 ET[ET[below].right].value, Result);
2631 AO = ET[ET[below].right].value;
2632 if (runtime_error_checking_switch)
2633 AO = check_nonzero_at_runtime(AO, -1,
2635 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2636 assembleg_3(aload_gc, AO, AO2, temp_var1);
2637 AO2.value = GOBJFIELD_SIBLING();
2638 assembleg_1_branch(jz_gc, temp_var1, next_label+1);
2639 assemble_label_no(next_label);
2640 assembleg_3(aload_gc, temp_var1, AO2, temp_var2);
2641 assembleg_1_branch(jz_gc, temp_var2, next_label+1);
2642 assembleg_store(temp_var1, temp_var2);
2643 assembleg_0_branch(jump_gc, next_label);
2644 assemble_label_no(next_label+1);
2646 write_result_g(Result, temp_var1);
2651 AO = ET[ET[below].right].value;
2652 if (runtime_error_checking_switch)
2653 AO = check_nonzero_at_runtime(AO, -1,
2655 assembleg_store(temp_var3, AO);
2656 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2657 assembleg_3(aload_gc, temp_var3, AO2, temp_var1);
2658 assembleg_1_branch(jz_gc, temp_var1, next_label+2);
2659 AO2.value = GOBJFIELD_CHILD();
2660 assembleg_3(aload_gc, temp_var1, AO2, temp_var1);
2661 assembleg_1_branch(jz_gc, temp_var1, next_label+2);
2662 assembleg_2_branch(jeq_gc, temp_var3, temp_var1,
2664 assemble_label_no(next_label);
2665 AO2.value = GOBJFIELD_SIBLING();
2666 assembleg_3(aload_gc, temp_var1, AO2, temp_var2);
2667 assembleg_2_branch(jeq_gc, temp_var3, temp_var2,
2669 assembleg_store(temp_var1, temp_var2);
2670 assembleg_0_branch(jump_gc, next_label);
2671 assemble_label_no(next_label+1);
2672 assembleg_store(temp_var1, zero_operand);
2673 assemble_label_no(next_label+2);
2675 write_result_g(Result, temp_var1);
2680 error("*** system function not implemented ***");
2689 IndirectFunctionCallG:
2691 /* Get the function address. */
2698 /* If all the function arguments are in local/global
2699 variables, we have to push them all on the stack.
2700 If all of them are on the stack, we have to do nothing.
2701 If some are and some aren't, we have a hopeless mess,
2702 and we should throw a compiler error.
2708 /* begin part of patch G03701 */
2717 assembleg_2(callf_gc, AO2, void_flag ? zero_operand : Result);
2718 } else if (nargs==1) {
2719 assembleg_call_1(AO2, ET[i].value, void_flag ? zero_operand : Result);
2720 } else if (nargs==2) {
2721 assembly_operand o1 = ET[i].value;
2722 assembly_operand o2 = ET[ET[i].right].value;
2723 assembleg_call_2(AO2, o1, o2, void_flag ? zero_operand : Result);
2724 } else if (nargs==3) {
2725 assembly_operand o1 = ET[i].value;
2726 assembly_operand o2 = ET[ET[i].right].value;
2727 assembly_operand o3 = ET[ET[ET[i].right].right].value;
2728 assembleg_call_3(AO2, o1, o2, o3, void_flag ? zero_operand : Result);
2733 if (ET[i].value.type == LOCALVAR_OT
2734 && ET[i].value.value == 0) {
2738 assembleg_store(stack_pointer, ET[i].value);
2745 if (onstack && offstack)
2746 error("*** Function call cannot be generated with mixed arguments ***");
2748 error("*** Function call cannot be generated with more than one nonstack argument ***");
2752 set_constant_ot(&AO);
2755 assembleg_3(call_gc, AO2, AO, zero_operand);
2757 assembleg_3(call_gc, AO2, AO, Result);
2759 } /* else nargs>=4 */
2760 } /* DoFunctionCall: */
2765 printf("** Trouble op = %d i.e. '%s' **\n",
2766 opnum, operators[opnum].description);
2767 compiler_error("Expr code gen: Can't generate yet");
2771 ET[n].value = Result;
2777 if (ET[n].to_expression)
2780 warning("Logical expression has no side-effects");
2781 if (ET[n].true_label != -1)
2782 assemble_label_no(ET[n].true_label);
2784 assemble_label_no(ET[n].false_label);
2786 else if (ET[n].true_label != -1)
2787 { assemblez_1(push_zc, zero_operand);
2788 assemblez_jump(next_label++);
2789 assemble_label_no(ET[n].true_label);
2790 assemblez_1(push_zc, one_operand);
2791 assemble_label_no(next_label-1);
2794 { assemblez_1(push_zc, one_operand);
2795 assemblez_jump(next_label++);
2796 assemble_label_no(ET[n].false_label);
2797 assemblez_1(push_zc, zero_operand);
2798 assemble_label_no(next_label-1);
2800 ET[n].value = stack_pointer;
2803 if (ET[n].label_after != -1)
2804 assemble_label_no(ET[n].label_after);
2809 if (ET[n].to_expression)
2812 warning("Logical expression has no side-effects");
2813 if (ET[n].true_label != -1)
2814 assemble_label_no(ET[n].true_label);
2816 assemble_label_no(ET[n].false_label);
2818 else if (ET[n].true_label != -1)
2819 { assembleg_store(stack_pointer, zero_operand);
2820 assembleg_jump(next_label++);
2821 assemble_label_no(ET[n].true_label);
2822 assembleg_store(stack_pointer, one_operand);
2823 assemble_label_no(next_label-1);
2826 { assembleg_store(stack_pointer, one_operand);
2827 assembleg_jump(next_label++);
2828 assemble_label_no(ET[n].false_label);
2829 assembleg_store(stack_pointer, zero_operand);
2830 assemble_label_no(next_label-1);
2832 ET[n].value = stack_pointer;
2835 if (ET[n].label_after != -1)
2836 assemble_label_no(ET[n].label_after);
2843 assembly_operand code_generate(assembly_operand AO, int context, int label)
2845 /* Used in three contexts: VOID_CONTEXT, CONDITION_CONTEXT and
2848 If CONDITION_CONTEXT, then compile code branching to label number
2849 "label" if the condition is false: there's no return value.
2850 (Except that if label is -3 or -4 (internal codes for rfalse and
2851 rtrue rather than branch) then this is for branching when the
2852 condition is true. This is used for optimising code generation
2853 for "if" statements.)
2855 Otherwise return the assembly operand containing the result
2856 (probably the stack pointer variable but not necessarily:
2857 e.g. is would be short constant 2 from the expression "j++, 2") */
2861 if (AO.type != EXPRESSION_OT)
2863 { case VOID_CONTEXT:
2864 value_in_void_context(AO);
2865 AO.type = OMITTED_OT;
2868 case CONDITION_CONTEXT:
2870 if (label < -2) assemblez_1_branch(jz_zc, AO, label, FALSE);
2871 else assemblez_1_branch(jz_zc, AO, label, TRUE);
2875 assembleg_1_branch(jnz_gc, AO, label);
2877 assembleg_1_branch(jz_gc, AO, label);
2879 AO.type = OMITTED_OT;
2886 if (expr_trace_level >= 2)
2887 { printf("Raw parse tree:\n"); show_tree(AO, FALSE);
2890 if (context == CONDITION_CONTEXT)
2891 { if (label < -2) annotate_for_conditions(AO.value, label, -1);
2892 else annotate_for_conditions(AO.value, -1, label);
2894 else annotate_for_conditions(AO.value, -1, -1);
2896 if (expr_trace_level >= 1)
2897 { printf("Code generation for expression in ");
2899 { case VOID_CONTEXT: printf("void"); break;
2900 case CONDITION_CONTEXT: printf("condition"); break;
2901 case QUANTITY_CONTEXT: printf("quantity"); break;
2902 case ASSEMBLY_CONTEXT: printf("assembly"); break;
2903 case ARRAY_CONTEXT: printf("array initialisation"); break;
2904 default: printf("* ILLEGAL *"); break;
2906 printf(" context with annotated tree:\n");
2907 show_tree(AO, TRUE);
2910 generate_code_from(AO.value, (context==VOID_CONTEXT));
2911 return ET[AO.value].value;
2914 /* ========================================================================= */
2915 /* Data structure management routines */
2916 /* ------------------------------------------------------------------------- */
2918 extern void init_expressc_vars(void)
2922 extern void expressc_begin_pass(void)
2926 extern void expressc_allocate_arrays(void)
2930 extern void expressc_free_arrays(void)
2934 /* ========================================================================= */