1 /* ------------------------------------------------------------------------- */
2 /* "expressc" : The expression code generator */
4 /* Copyright (c) Graham Nelson 1993 - 2020 */
6 /* This file is part of Inform. */
8 /* Inform is free software: you can redistribute it and/or modify */
9 /* it under the terms of the GNU General Public License as published by */
10 /* the Free Software Foundation, either version 3 of the License, or */
11 /* (at your option) any later version. */
13 /* Inform is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16 /* GNU General Public License for more details. */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with Inform. If not, see https://gnu.org/licenses/ */
21 /* ------------------------------------------------------------------------- */
25 int vivc_flag; /* TRUE if the last code-generated
26 expression produced a "value in void
27 context" error: used to help the syntax
28 analyser recover from unknown-keyword
29 errors, since unknown keywords are
30 treated as yet-to-be-defined constants
31 and thus as values in void context */
33 /* These data structures are global, because they're too useful to be
35 assembly_operand stack_pointer, temp_var1, temp_var2, temp_var3,
36 temp_var4, zero_operand, one_operand, two_operand, three_operand,
37 four_operand, valueless_operand;
39 static void make_operands(void)
42 INITAOTV(&stack_pointer, VARIABLE_OT, 0);
43 INITAOTV(&temp_var1, VARIABLE_OT, 255);
44 INITAOTV(&temp_var2, VARIABLE_OT, 254);
45 INITAOTV(&temp_var3, VARIABLE_OT, 253);
46 INITAOTV(&temp_var4, VARIABLE_OT, 252);
47 INITAOTV(&zero_operand, SHORT_CONSTANT_OT, 0);
48 INITAOTV(&one_operand, SHORT_CONSTANT_OT, 1);
49 INITAOTV(&two_operand, SHORT_CONSTANT_OT, 2);
50 INITAOTV(&three_operand, SHORT_CONSTANT_OT, 3);
51 INITAOTV(&four_operand, SHORT_CONSTANT_OT, 4);
52 INITAOTV(&valueless_operand, OMITTED_OT, 0);
55 INITAOTV(&stack_pointer, LOCALVAR_OT, 0);
56 INITAOTV(&temp_var1, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+0);
57 INITAOTV(&temp_var2, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+1);
58 INITAOTV(&temp_var3, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+2);
59 INITAOTV(&temp_var4, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+3);
60 INITAOTV(&zero_operand, ZEROCONSTANT_OT, 0);
61 INITAOTV(&one_operand, BYTECONSTANT_OT, 1);
62 INITAOTV(&two_operand, BYTECONSTANT_OT, 2);
63 INITAOTV(&three_operand, BYTECONSTANT_OT, 3);
64 INITAOTV(&four_operand, BYTECONSTANT_OT, 4);
65 INITAOTV(&valueless_operand, OMITTED_OT, 0);
69 /* ------------------------------------------------------------------------- */
70 /* The table of conditionals. (Only used in Glulx) */
73 #define EQUAL_CC (502)
78 #define OFCLASS_CC (512)
79 #define PROVIDES_CC (514)
81 #define FIRST_CC (500)
84 typedef struct condclass_s {
85 int32 posform; /* Opcode for the conditional in its positive form. */
86 int32 negform; /* Opcode for the conditional in its negated form. */
89 condclass condclasses[] = {
100 /* ------------------------------------------------------------------------- */
101 /* The table of operators.
103 The ordering in this table is not significant except that it must match
104 the #define's in "header.h" */
106 operator operators[NUM_OPERATORS] =
108 /* ------------------------ */
110 /* ------------------------ */
112 { 0, SEP_TT, COMMA_SEP, IN_U, L_A, 0, -1, -1, 0, 0, "comma" },
114 /* ------------------------ */
116 /* ------------------------ */
118 { 1, SEP_TT, SETEQUALS_SEP, IN_U, R_A, 1, -1, -1, 1, 0,
119 "assignment operator '='" },
121 /* ------------------------ */
122 /* Level 2: ~~ && || */
123 /* ------------------------ */
125 { 2, SEP_TT, LOGAND_SEP, IN_U, L_A, 0, -1, -1, 0, LOGOR_OP,
126 "logical conjunction '&&'" },
127 { 2, SEP_TT, LOGOR_SEP, IN_U, L_A, 0, -1, -1, 0, LOGAND_OP,
128 "logical disjunction '||'" },
129 { 2, SEP_TT, LOGNOT_SEP, PRE_U, R_A, 0, -1, -1, 0, LOGNOT_OP,
130 "logical negation '~~'" },
132 /* ------------------------ */
139 /* ------------------------ */
141 { 3, -1, -1, -1, 0, 0, 400 + jz_zc, ZERO_CC+0, 0, NONZERO_OP,
142 "expression used as condition then negated" },
143 { 3, -1, -1, -1, 0, 0, 800 + jz_zc, ZERO_CC+1, 0, ZERO_OP,
144 "expression used as condition" },
145 { 3, SEP_TT, CONDEQUALS_SEP, IN_U, 0, 0, 400 + je_zc, EQUAL_CC+0, 0, NOTEQUAL_OP,
147 { 3, SEP_TT, NOTEQUAL_SEP, IN_U, 0, 0, 800 + je_zc, EQUAL_CC+1, 0, CONDEQUALS_OP,
149 { 3, SEP_TT, GE_SEP, IN_U, 0, 0, 800 + jl_zc, LT_CC+1, 0, LESS_OP,
151 { 3, SEP_TT, GREATER_SEP, IN_U, 0, 0, 400 + jg_zc, GT_CC+0, 0, LE_OP,
153 { 3, SEP_TT, LE_SEP, IN_U, 0, 0, 800 + jg_zc, GT_CC+1, 0, GREATER_OP,
155 { 3, SEP_TT, LESS_SEP, IN_U, 0, 0, 400 + jl_zc, LT_CC+0, 0, GE_OP,
157 { 3, CND_TT, HAS_COND, IN_U, 0, 0, 400 + test_attr_zc, HAS_CC+0, 0, HASNT_OP,
159 { 3, CND_TT, HASNT_COND, IN_U, 0, 0, 800 + test_attr_zc, HAS_CC+1, 0, HAS_OP,
160 "'hasnt' condition" },
161 { 3, CND_TT, IN_COND, IN_U, 0, 0, 400 + jin_zc, IN_CC+0, 0, NOTIN_OP,
163 { 3, CND_TT, NOTIN_COND, IN_U, 0, 0, 800 + jin_zc, IN_CC+1, 0, IN_OP,
164 "'notin' condition" },
165 { 3, CND_TT, OFCLASS_COND, IN_U, 0, 0, 600, OFCLASS_CC+0, 0, NOTOFCLASS_OP,
166 "'ofclass' condition" },
167 { 3, CND_TT, PROVIDES_COND, IN_U, 0, 0, 601, PROVIDES_CC+0, 0, NOTPROVIDES_OP,
168 "'provides' condition" },
169 { 3, -1, -1, -1, 0, 0, 1000, OFCLASS_CC+1, 0, OFCLASS_OP,
170 "negated 'ofclass' condition" },
171 { 3, -1, -1, -1, 0, 0, 1001, PROVIDES_CC+1, 0, PROVIDES_OP,
172 "negated 'provides' condition" },
174 /* ------------------------ */
176 /* ------------------------ */
178 { 4, CND_TT, OR_COND, IN_U, L_A, 0, -1, -1, 0, 0, "'or'" },
180 /* ------------------------ */
181 /* Level 5: + binary - */
182 /* ------------------------ */
184 { 5, SEP_TT, PLUS_SEP, IN_U, L_A, 0, add_zc, add_gc, 0, 0, "'+'" },
185 { 5, SEP_TT, MINUS_SEP, IN_U, L_A, 0, sub_zc, sub_gc, 0, 0, "'-'" },
187 /* ------------------------ */
190 /* ------------------------ */
192 { 6, SEP_TT, TIMES_SEP, IN_U, L_A, 0, mul_zc, mul_gc, 0, 0, "'*'" },
193 { 6, SEP_TT, DIVIDE_SEP, IN_U, L_A, 0, div_zc, div_gc, 0, 0, "'/'" },
194 { 6, SEP_TT, REMAINDER_SEP, IN_U, L_A, 0, mod_zc, mod_gc, 0, 0,
195 "remainder after division '%'" },
196 { 6, SEP_TT, ARTAND_SEP, IN_U, L_A, 0, and_zc, bitand_gc, 0, 0,
198 { 6, SEP_TT, ARTOR_SEP, IN_U, L_A, 0, or_zc, bitor_gc, 0, 0,
200 { 6, SEP_TT, ARTNOT_SEP, PRE_U, R_A, 0, -1, bitnot_gc, 0, 0,
203 /* ------------------------ */
204 /* Level 7: -> --> */
205 /* ------------------------ */
207 { 7, SEP_TT, ARROW_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
208 "byte array operator '->'" },
209 { 7, SEP_TT, DARROW_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
210 "word array operator '-->'" },
212 /* ------------------------ */
213 /* Level 8: unary - */
214 /* ------------------------ */
216 { 8, SEP_TT, UNARY_MINUS_SEP, PRE_U, R_A, 0, -1, neg_gc, 0, 0,
219 /* ------------------------ */
221 /* (prefix or postfix) */
222 /* ------------------------ */
224 { 9, SEP_TT, INC_SEP, PRE_U, R_A, 2, -1, -1, 1, 0,
225 "pre-increment operator '++'" },
226 { 9, SEP_TT, POST_INC_SEP, POST_U, R_A, 3, -1, -1, 1, 0,
227 "post-increment operator '++'" },
228 { 9, SEP_TT, DEC_SEP, PRE_U, R_A, 4, -1, -1, 1, 0,
229 "pre-decrement operator '--'" },
230 { 9, SEP_TT, POST_DEC_SEP, POST_U, R_A, 5, -1, -1, 1, 0,
231 "post-decrement operator '--'" },
233 /* ------------------------ */
234 /* Level 10: .& .# */
236 /* ------------------------ */
238 {10, SEP_TT, PROPADD_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
239 "property address operator '.&'" },
240 {10, SEP_TT, PROPNUM_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
241 "property length operator '.#'" },
242 {10, SEP_TT, MPROPADD_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
243 "individual property address operator '..&'" },
244 {10, SEP_TT, MPROPNUM_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
245 "individual property length operator '..#'" },
247 /* ------------------------ */
248 /* Level 11: function ( */
249 /* ------------------------ */
251 {11, SEP_TT, OPENB_SEP, IN_U, L_A, 0, -1, -1, 1, 0,
254 /* ------------------------ */
256 /* ------------------------ */
258 {12, SEP_TT, MESSAGE_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
259 "individual property selector '..'" },
260 {12, SEP_TT, PROPERTY_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
261 "property selector '.'" },
263 /* ------------------------ */
265 /* ------------------------ */
267 {13, SEP_TT, SUPERCLASS_SEP, IN_U, L_A, 0, -1, -1, 0, 0,
268 "superclass operator '::'" },
270 /* ------------------------ */
271 /* Miscellaneous operators */
272 /* generated at lvalue */
274 /* ------------------------ */
276 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -> = */
277 "byte array entry assignment" },
278 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* --> = */
279 "word array entry assignment" },
280 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* .. = */
281 "individual property assignment" },
282 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* . = */
283 "common property assignment" },
285 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ -> */
286 "byte array entry preincrement" },
287 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ --> */
288 "word array entry preincrement" },
289 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ .. */
290 "individual property preincrement" },
291 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ . */
292 "common property preincrement" },
294 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- -> */
295 "byte array entry predecrement" },
296 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- --> */
297 "word array entry predecrement" },
298 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- .. */
299 "individual property predecrement" },
300 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- . */
301 "common property predecrement" },
303 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -> ++ */
304 "byte array entry postincrement" },
305 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* --> ++ */
306 "word array entry postincrement" },
307 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* .. ++ */
308 "individual property postincrement" },
309 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* . ++ */
310 "common property postincrement" },
312 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -> -- */
313 "byte array entry postdecrement" },
314 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* --> -- */
315 "word array entry postdecrement" },
316 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* .. -- */
317 "individual property postdecrement" },
318 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* . -- */
319 "common property postdecrement" },
321 {11, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* x.y(args) */
322 "call to common property" },
323 {11, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* x..y(args) */
324 "call to individual property" },
326 /* ------------------------ */
327 /* And one Glulx-only op */
328 /* which just pushes its */
329 /* argument on the stack, */
331 /* ------------------------ */
333 {14, -1, -1, -1, -1, 0, -1, -1, 1, 0,
337 /* --- Condition annotater ------------------------------------------------- */
339 static void annotate_for_conditions(int n, int a, int b)
340 { int i, opnum = ET[n].operator_number;
342 ET[n].label_after = -1;
343 ET[n].to_expression = FALSE;
344 ET[n].true_label = a;
345 ET[n].false_label = b;
347 if (ET[n].down == -1) return;
349 if ((operators[opnum].precedence == 2)
350 || (operators[opnum].precedence == 3))
351 { if ((a == -1) && (b == -1))
352 { if (opnum == LOGAND_OP)
354 ET[n].false_label = b;
355 ET[n].to_expression = TRUE;
359 ET[n].true_label = a;
360 ET[n].to_expression = TRUE;
369 ET[n].false_label = b;
370 ET[n].label_after = b;
372 annotate_for_conditions(ET[n].down, -1, b);
373 if (b == ET[n].label_after)
374 annotate_for_conditions(ET[ET[n].down].right, a, -1);
375 else annotate_for_conditions(ET[ET[n].down].right, a, b);
380 ET[n].true_label = a;
381 ET[n].label_after = a;
383 annotate_for_conditions(ET[n].down, a, -1);
384 if (a == ET[n].label_after)
385 annotate_for_conditions(ET[ET[n].down].right, -1, b);
386 else annotate_for_conditions(ET[ET[n].down].right, a, b);
392 { annotate_for_conditions(i, -1, -1); i = ET[i].right; }
395 /* --- Code generator ------------------------------------------------------ */
397 static void value_in_void_context_z(assembly_operand AO)
403 { case LONG_CONSTANT_OT:
404 case SHORT_CONSTANT_OT:
406 if (AO.marker == SYMBOL_MV)
407 t = (char *) (symbs[AO.value]);
410 t = variable_name(AO.value);
413 compiler_error("Unable to print value in void context");
419 if (strcmp(t, "print_paddr") == 0)
420 obsolete_warning("ignoring 'print_paddr': use 'print (string)' instead");
422 if (strcmp(t, "print_addr") == 0)
423 obsolete_warning("ignoring 'print_addr': use 'print (address)' instead");
425 if (strcmp(t, "print_char") == 0)
426 obsolete_warning("ignoring 'print_char': use 'print (char)' instead");
428 ebf_error("expression with side-effects", t);
431 static void write_result_z(assembly_operand to, assembly_operand from)
432 { if (to.value == from.value) return;
433 if (to.value == 0) assemblez_1(push_zc, from);
434 else assemblez_store(to, from);
437 static void pop_zm_stack(void)
438 { assembly_operand st;
439 if (version_number < 5) assemblez_0(pop_zc);
441 { INITAOTV(&st, VARIABLE_OT, 0);
442 assemblez_1_branch(jz_zc, st, -2, TRUE);
446 static void access_memory_z(int oc, assembly_operand AO1, assembly_operand AO2,
447 assembly_operand AO3)
450 assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
452 int x = 0, y = 0, byte_flag = FALSE, read_flag = FALSE, from_module = FALSE;
454 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
458 if ((oc == loadb_zc) || (oc == storeb_zc)) byte_flag=TRUE;
459 else byte_flag = FALSE;
460 if ((oc == loadb_zc) || (oc == loadw_zc)) read_flag=TRUE;
461 else read_flag = FALSE;
463 zero_ao.type = SHORT_CONSTANT_OT;
466 size_ao = zero_ao; size_ao.value = -1;
467 for (x=0; x<no_arrays; x++)
468 { if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
469 && (AO1.value == svals[array_symbols[x]]))
470 { size_ao.value = array_sizes[x]; y=x;
474 if (array_locs[y] && !read_flag) {
475 error("Cannot write to a static array");
478 if (size_ao.value==-1)
482 type_ao = zero_ao; type_ao.value = array_types[y];
484 if ((!is_systemfile()))
487 if ((array_types[y] == WORD_ARRAY)
488 || (array_types[y] == TABLE_ARRAY))
489 warning("Using '->' to access a --> or table array");
493 if ((array_types[y] == BYTE_ARRAY)
494 || (array_types[y] == STRING_ARRAY))
495 warning("Using '-->' to access a -> or string array");
502 if ((!runtime_error_checking_switch) || (veneer_mode))
503 { if ((oc == loadb_zc) || (oc == loadw_zc))
504 assemblez_2_to(oc, AO1, AO2, AO3);
506 assemblez_3(oc, AO1, AO2, AO3);
510 /* If we recognise AO1 as arising textually from a declared
511 array, we can check bounds explicitly. */
513 if ((AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV) && (!from_module))
515 int passed_label = next_label++, failed_label = next_label++,
516 final_label = next_label++;
517 /* Calculate the largest permitted array entry + 1
518 Here "size_ao.value" = largest permitted entry of its own kind */
522 && ((array_types[y] == WORD_ARRAY)
523 || (array_types[y] == TABLE_ARRAY)))
524 { max_ao.value = size_ao.value*2 + 1;
528 && ((array_types[y] == BYTE_ARRAY)
529 || (array_types[y] == STRING_ARRAY)
530 || (array_types[y] == BUFFER_ARRAY)))
531 { if ((size_ao.value % 2) == 0)
532 max_ao.value = size_ao.value/2 - 1;
533 else max_ao.value = (size_ao.value-1)/2;
538 if (size_ao.value >= 256) size_ao.type = LONG_CONSTANT_OT;
539 if (max_ao.value >= 256) max_ao.type = LONG_CONSTANT_OT;
541 /* Can't write to the size entry in a string or table */
542 if (((array_types[y] == STRING_ARRAY)
543 || (array_types[y] == TABLE_ARRAY))
545 { if ((array_types[y] == TABLE_ARRAY) && byte_flag)
547 else zero_ao.value = 1;
550 en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
551 switch(oc) { case loadb_zc: en_ao.value = ABOUNDS_RTE; break;
552 case loadw_zc: en_ao.value = ABOUNDS_RTE+1; break;
553 case storeb_zc: en_ao.value = ABOUNDS_RTE+2; break;
554 case storew_zc: en_ao.value = ABOUNDS_RTE+3; break; }
557 if ((AO2.type == VARIABLE_OT)&&(AO2.value == 0))
558 { assemblez_store(temp_var2, AO2);
559 assemblez_store(AO2, temp_var2);
560 index_ao = temp_var2;
562 assemblez_2_branch(jl_zc, index_ao, zero_ao, failed_label, TRUE);
563 assemblez_2_branch(jl_zc, index_ao, max_ao, passed_label, TRUE);
564 assemble_label_no(failed_label);
565 an_ao = zero_ao; an_ao.value = y;
566 assemblez_6(call_vn2_zc, veneer_routine(RT__Err_VR), en_ao,
567 index_ao, size_ao, type_ao, an_ao);
569 /* We have to clear any of AO1, AO2, AO3 off the stack if
570 present, so that we can achieve the same effect on the stack
571 that executing the opcode would have had */
573 if ((AO1.type == VARIABLE_OT) && (AO1.value == 0)) pop_zm_stack();
574 if ((AO2.type == VARIABLE_OT) && (AO2.value == 0)) pop_zm_stack();
575 if ((AO3.type == VARIABLE_OT) && (AO3.value == 0))
576 { if ((oc == loadb_zc) || (oc == loadw_zc))
577 { assemblez_store(AO3, zero_ao);
581 assemblez_jump(final_label);
583 assemble_label_no(passed_label);
584 if ((oc == loadb_zc) || (oc == loadw_zc))
585 assemblez_2_to(oc, AO1, AO2, AO3);
587 assemblez_3(oc, AO1, AO2, AO3);
588 assemble_label_no(final_label);
592 /* Otherwise, compile a call to the veneer which verifies that
593 the proposed read/write is within dynamic Z-machine memory. */
595 switch(oc) { case loadb_zc: vr = RT__ChLDB_VR; break;
596 case loadw_zc: vr = RT__ChLDW_VR; break;
597 case storeb_zc: vr = RT__ChSTB_VR; break;
598 case storew_zc: vr = RT__ChSTW_VR; break;
599 default: compiler_error("unknown array opcode");
602 if ((oc == loadb_zc) || (oc == loadw_zc))
603 assemblez_3_to(call_vs_zc, veneer_routine(vr), AO1, AO2, AO3);
605 assemblez_4(call_vn_zc, veneer_routine(vr), AO1, AO2, AO3);
608 static assembly_operand check_nonzero_at_runtime_z(assembly_operand AO1,
609 int error_label, int rte_number)
610 { assembly_operand AO2, AO3;
611 int check_sp = FALSE, passed_label, failed_label, last_label;
612 if (veneer_mode) return AO1;
614 /* Assemble to code to check that the operand AO1 is ofclass Object:
615 if it is, execution should continue and the stack should be
616 unchanged. Otherwise, call the veneer's run-time-error routine
617 with the given error number, and then: if the label isn't -1,
618 switch execution to this label, with the value popped from
619 the stack if it was on the stack in the first place;
620 if the label is -1, either replace the top of the stack with
621 the constant 2, or return the operand (short constant) 2.
623 The point of 2 is that object 2 is the class-object Object
624 and therefore has no parent, child or sibling, so that the
625 built-in tree functions will safely return 0 on this object. */
627 /* Sometimes we can already see that the object number is valid. */
628 if (((AO1.type == LONG_CONSTANT_OT) || (AO1.type == SHORT_CONSTANT_OT))
629 && (AO1.marker == 0) && (AO1.value >= 1) && (AO1.value < no_objects))
632 passed_label = next_label++;
633 failed_label = next_label++;
634 INITAOTV(&AO2, LONG_CONSTANT_OT, actual_largest_object_SC);
635 AO2.marker = INCON_MV;
636 INITAOTV(&AO3, SHORT_CONSTANT_OT, 5);
638 if ((rte_number == IN_RTE) || (rte_number == HAS_RTE)
639 || (rte_number == PROPERTY_RTE) || (rte_number == PROP_NUM_RTE)
640 || (rte_number == PROP_ADD_RTE))
641 { /* Allow classes */
643 if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
644 { /* That is, if AO1 is the stack pointer */
646 assemblez_store(temp_var2, AO1);
647 assemblez_store(AO1, temp_var2);
648 assemblez_2_branch(jg_zc, AO3, temp_var2, failed_label, TRUE);
649 assemblez_2_branch(jg_zc, temp_var2, AO2, passed_label, FALSE);
652 { assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
653 assemblez_2_branch(jg_zc, AO1, AO2, passed_label, FALSE);
657 { if ((AO1.type == VARIABLE_OT) && (AO1.value == 0))
658 { /* That is, if AO1 is the stack pointer */
660 assemblez_store(temp_var2, AO1);
661 assemblez_store(AO1, temp_var2);
662 assemblez_2_branch(jg_zc, AO3, temp_var2, failed_label, TRUE);
663 assemblez_2_branch(jg_zc, temp_var2, AO2, failed_label, TRUE);
665 assemblez_2_branch(jin_zc, temp_var2, AO3, passed_label, FALSE);
668 { assemblez_2_branch(jg_zc, AO3, AO1, failed_label, TRUE);
669 assemblez_2_branch(jg_zc, AO1, AO2, failed_label, TRUE);
671 assemblez_2_branch(jin_zc, AO1, AO3, passed_label, FALSE);
675 assemble_label_no(failed_label);
676 INITAOTV(&AO2, SHORT_CONSTANT_OT, rte_number);
677 if (version_number >= 5)
678 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR), AO2, AO1);
680 assemblez_3_to(call_zc, veneer_routine(RT__Err_VR), AO2, AO1, temp_var2);
682 if (error_label != -1)
683 { /* Jump to the error label */
684 if (error_label == -3) assemblez_0(rfalse_zc);
685 else if (error_label == -4) assemblez_0(rtrue_zc);
686 else assemblez_jump(error_label);
690 { /* Push the short constant 2 */
691 INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
692 assemblez_store(AO1, AO2);
695 { /* Store either short constant 2 or the operand's value in
696 the temporary variable */
697 INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
698 AO3 = temp_var2; assemblez_store(AO3, AO2);
699 last_label = next_label++;
700 assemblez_jump(last_label);
701 assemble_label_no(passed_label);
702 assemblez_store(AO3, AO1);
703 assemble_label_no(last_label);
707 assemble_label_no(passed_label);
711 static void compile_conditional_z(int oc,
712 assembly_operand AO1, assembly_operand AO2, int label, int flag)
713 { assembly_operand AO3; int the_zc, error_label = label,
714 va_flag = FALSE, va_label = 0;
719 { if ((runtime_error_checking_switch) && (oc == jin_zc))
720 { if (flag) error_label = next_label++;
721 AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
723 if ((runtime_error_checking_switch) && (oc == test_attr_zc))
724 { if (flag) error_label = next_label++;
725 AO1 = check_nonzero_at_runtime(AO1, error_label, HAS_RTE);
727 { case SHORT_CONSTANT_OT:
728 case LONG_CONSTANT_OT:
730 { if ((AO2.value < 0) || (AO2.value > 47))
731 error("'has'/'hasnt' applied to illegal attribute number");
735 { int pa_label = next_label++, fa_label = next_label++;
736 assembly_operand en_ao, zero_ao, max_ao;
737 assemblez_store(temp_var1, AO1);
738 if ((AO1.type == VARIABLE_OT)&&(AO1.value == 0))
739 assemblez_store(AO1, temp_var1);
740 assemblez_store(temp_var2, AO2);
741 if ((AO2.type == VARIABLE_OT)&&(AO2.value == 0))
742 assemblez_store(AO2, temp_var2);
743 INITAOT(&zero_ao, SHORT_CONSTANT_OT);
745 max_ao = zero_ao; max_ao.value = 48;
746 assemblez_2_branch(jl_zc,temp_var2,zero_ao,fa_label,TRUE);
747 assemblez_2_branch(jl_zc,temp_var2,max_ao,pa_label,TRUE);
748 assemble_label_no(fa_label);
749 en_ao = zero_ao; en_ao.value = 19;
750 assemblez_4(call_vn_zc, veneer_routine(RT__Err_VR),
751 en_ao, temp_var1, temp_var2);
752 va_flag = TRUE; va_label = next_label++;
753 assemblez_jump(va_label);
754 assemble_label_no(pa_label);
758 assemblez_2_branch(oc, AO1, AO2, label, flag);
759 if (error_label != label) assemble_label_no(error_label);
760 if (va_flag) assemble_label_no(va_label);
764 INITAOTV(&AO3, VARIABLE_OT, 0);
766 the_zc = (version_number == 3)?call_zc:call_vs_zc;
768 assemblez_3_to(the_zc, veneer_routine(OP__Pr_VR), AO1, AO2, AO3);
770 assemblez_3_to(the_zc, veneer_routine(OC__Cl_VR), AO1, AO2, AO3);
772 assemblez_1_branch(jz_zc, AO3, label, !flag);
775 static void value_in_void_context_g(assembly_operand AO)
782 case HALFCONSTANT_OT:
783 case BYTECONSTANT_OT:
784 case ZEROCONSTANT_OT:
786 if (AO.marker == SYMBOL_MV)
787 t = (char *) (symbs[AO.value]);
791 t = variable_name(AO.value);
794 compiler_error("Unable to print value in void context");
800 ebf_error("expression with side-effects", t);
803 static void write_result_g(assembly_operand to, assembly_operand from)
804 { if (to.value == from.value && to.type == from.type) return;
805 assembleg_store(to, from);
808 static void access_memory_g(int oc, assembly_operand AO1, assembly_operand AO2,
809 assembly_operand AO3)
811 int data_len, read_flag;
812 assembly_operand zero_ao, max_ao, size_ao, en_ao, type_ao, an_ao,
814 int passed_label, failed_label, final_label, x = 0, y = 0;
816 if ((oc == aloadb_gc) || (oc == astoreb_gc)) data_len = 1;
817 else if ((oc == aloads_gc) || (oc == astores_gc)) data_len = 2;
820 if ((oc == aloadb_gc) || (oc == aloads_gc) || (oc == aload_gc))
825 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
829 size_ao = zero_ao; size_ao.value = -1;
830 for (x=0; x<no_arrays; x++)
831 { if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
832 && (AO1.value == svals[array_symbols[x]]))
833 { size_ao.value = array_sizes[x]; y=x;
836 if (size_ao.value==-1) compiler_error("Array size can't be found");
838 type_ao = zero_ao; type_ao.value = array_types[y];
840 if (array_locs[y] && !read_flag) {
841 error("Cannot write to a static array");
844 if ((!is_systemfile()))
847 if ((array_types[y] == WORD_ARRAY)
848 || (array_types[y] == TABLE_ARRAY))
849 warning("Using '->' to access a --> or table array");
853 if ((array_types[y] == BYTE_ARRAY)
854 || (array_types[y] == STRING_ARRAY))
855 warning("Using '-->' to access a -> or string array");
861 if ((!runtime_error_checking_switch) || (veneer_mode))
863 assembleg_3(oc, AO1, AO2, AO3);
867 /* If we recognise AO1 as arising textually from a declared
868 array, we can check bounds explicitly. */
870 if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV)
872 /* Calculate the largest permitted array entry + 1
873 Here "size_ao.value" = largest permitted entry of its own kind */
876 && ((array_types[y] == WORD_ARRAY)
877 || (array_types[y] == TABLE_ARRAY)))
878 { max_ao.value = size_ao.value*4 + 3;
882 && ((array_types[y] == BYTE_ARRAY)
883 || (array_types[y] == STRING_ARRAY)
884 || (array_types[y] == BUFFER_ARRAY)))
885 { max_ao.value = (size_ao.value-3)/4;
890 /* Can't write to the size entry in a string or table */
891 if (((array_types[y] == STRING_ARRAY)
892 || (array_types[y] == TABLE_ARRAY))
894 { if ((array_types[y] == TABLE_ARRAY) && data_len == 1)
896 else zero_ao.value = 1;
899 en_ao = zero_ao; en_ao.value = ABOUNDS_RTE;
901 switch(oc) { case aloadb_gc: en_ao.value = ABOUNDS_RTE; break;
902 case aload_gc: en_ao.value = ABOUNDS_RTE+1; break;
903 case astoreb_gc: en_ao.value = ABOUNDS_RTE+2; break;
904 case astore_gc: en_ao.value = ABOUNDS_RTE+3; break; }
906 set_constant_ot(&zero_ao);
907 set_constant_ot(&size_ao);
908 set_constant_ot(&max_ao);
909 set_constant_ot(&type_ao);
910 set_constant_ot(&en_ao);
912 /* If we recognize A02 as a constant, we can do the test right
914 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
915 if (AO2.value < zero_ao.value || AO2.value >= max_ao.value) {
916 error("Array reference is out-of-bounds");
918 assembleg_3(oc, AO1, AO2, AO3);
922 passed_label = next_label++;
923 failed_label = next_label++;
924 final_label = next_label++;
927 if ((AO2.type == LOCALVAR_OT)&&(AO2.value == 0))
928 { assembleg_store(temp_var2, AO2); /* ### could peek */
929 assembleg_store(AO2, temp_var2);
930 index_ao = temp_var2;
932 assembleg_2_branch(jlt_gc, index_ao, zero_ao, failed_label);
933 assembleg_2_branch(jlt_gc, index_ao, max_ao, passed_label);
934 assemble_label_no(failed_label);
936 an_ao = zero_ao; an_ao.value = y;
937 set_constant_ot(&an_ao);
938 five_ao = zero_ao; five_ao.value = 5;
939 set_constant_ot(&five_ao);
941 /* Call the error veneer routine. */
942 assembleg_store(stack_pointer, an_ao);
943 assembleg_store(stack_pointer, type_ao);
944 assembleg_store(stack_pointer, size_ao);
945 assembleg_store(stack_pointer, index_ao);
946 assembleg_store(stack_pointer, en_ao);
947 assembleg_3(call_gc, veneer_routine(RT__Err_VR),
948 five_ao, zero_operand);
950 /* We have to clear any of AO1, AO2, AO3 off the stack if
951 present, so that we can achieve the same effect on the stack
952 that executing the opcode would have had */
954 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
955 assembleg_2(copy_gc, stack_pointer, zero_operand);
956 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
957 assembleg_2(copy_gc, stack_pointer, zero_operand);
958 if ((AO3.type == LOCALVAR_OT) && (AO3.value == 0))
959 { if ((oc == aloadb_gc) || (oc == aload_gc))
960 { assembleg_store(AO3, zero_ao);
962 else assembleg_2(copy_gc, stack_pointer, zero_operand);
964 assembleg_jump(final_label);
966 assemble_label_no(passed_label);
967 assembleg_3(oc, AO1, AO2, AO3);
968 assemble_label_no(final_label);
972 /* Otherwise, compile a call to the veneer which verifies that
973 the proposed read/write is within dynamic Z-machine memory. */
976 case aloadb_gc: vr = RT__ChLDB_VR; break;
977 case aload_gc: vr = RT__ChLDW_VR; break;
978 case astoreb_gc: vr = RT__ChSTB_VR; break;
979 case astore_gc: vr = RT__ChSTW_VR; break;
980 default: compiler_error("unknown array opcode");
983 if ((oc == aloadb_gc) || (oc == aload_gc))
984 assembleg_call_2(veneer_routine(vr), AO1, AO2, AO3);
986 assembleg_call_3(veneer_routine(vr), AO1, AO2, AO3, zero_operand);
989 static assembly_operand check_nonzero_at_runtime_g(assembly_operand AO1,
990 int error_label, int rte_number)
992 assembly_operand AO, AO2, AO3;
994 int check_sp = FALSE, passed_label, failed_label, last_label;
999 /* Assemble to code to check that the operand AO1 is ofclass Object:
1000 if it is, execution should continue and the stack should be
1001 unchanged. Otherwise, call the veneer's run-time-error routine
1002 with the given error number, and then: if the label isn't -1,
1003 switch execution to this label, with the value popped from
1004 the stack if it was on the stack in the first place;
1005 if the label is -1, either replace the top of the stack with
1006 the constant symbol (class-object) Object.
1008 The Object has no parent, child or sibling, so that the
1009 built-in tree functions will safely return 0 on this object. */
1011 /* Sometimes we can already see that the object number is valid. */
1012 if (AO1.marker == OBJECT_MV &&
1013 ((AO1.value >= 1) && (AO1.value <= no_objects))) {
1017 passed_label = next_label++;
1018 failed_label = next_label++;
1020 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0) && (AO1.marker == 0)) {
1021 /* That is, if AO1 is the stack pointer */
1023 assembleg_store(temp_var2, stack_pointer);
1024 assembleg_store(stack_pointer, temp_var2);
1031 if ((rte_number == IN_RTE) || (rte_number == HAS_RTE)
1032 || (rte_number == PROPERTY_RTE) || (rte_number == PROP_NUM_RTE)
1033 || (rte_number == PROP_ADD_RTE)) {
1035 /* Test if zero... */
1036 assembleg_1_branch(jz_gc, AO, failed_label);
1037 /* Test if first byte is 0x70... */
1038 assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
1040 AO3.value = 0x70; /* type byte -- object */
1041 set_constant_ot(&AO3);
1042 assembleg_2_branch(jeq_gc, stack_pointer, AO3, passed_label);
1045 /* Test if zero... */
1046 assembleg_1_branch(jz_gc, AO, failed_label);
1047 /* Test if first byte is 0x70... */
1048 assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
1050 AO3.value = 0x70; /* type byte -- object */
1051 set_constant_ot(&AO3);
1052 assembleg_2_branch(jne_gc, stack_pointer, AO3, failed_label);
1053 /* Test if inside the "Class" object... */
1054 INITAOTV(&AO3, BYTECONSTANT_OT, GOBJFIELD_PARENT());
1055 assembleg_3(aload_gc, AO, AO3, stack_pointer);
1056 ln = symbol_index("Class", -1);
1057 AO3.value = svals[ln];
1058 AO3.marker = OBJECT_MV;
1059 AO3.type = CONSTANT_OT;
1060 assembleg_2_branch(jne_gc, stack_pointer, AO3, passed_label);
1063 assemble_label_no(failed_label);
1065 AO2.value = rte_number;
1066 set_constant_ot(&AO2);
1067 assembleg_call_2(veneer_routine(RT__Err_VR), AO2, AO1, zero_operand);
1069 if (error_label != -1) {
1070 /* Jump to the error label */
1071 if (error_label == -3) assembleg_1(return_gc, zero_operand);
1072 else if (error_label == -4) assembleg_1(return_gc, one_operand);
1073 else assembleg_jump(error_label);
1076 /* Build the symbol for "Object" */
1077 ln = symbol_index("Object", -1);
1078 AO2.value = svals[ln];
1079 AO2.marker = OBJECT_MV;
1080 AO2.type = CONSTANT_OT;
1083 assembleg_store(AO1, AO2);
1086 /* Store either "Object" or the operand's value in the temporary
1088 assembleg_store(temp_var2, AO2);
1089 last_label = next_label++;
1090 assembleg_jump(last_label);
1091 assemble_label_no(passed_label);
1092 assembleg_store(temp_var2, AO1);
1093 assemble_label_no(last_label);
1098 assemble_label_no(passed_label);
1102 static void compile_conditional_g(condclass *cc,
1103 assembly_operand AO1, assembly_operand AO2, int label, int flag)
1104 { assembly_operand AO4;
1105 int the_zc, error_label = label,
1106 va_flag = FALSE, va_label = 0;
1110 the_zc = (flag ? cc->posform : cc->negform);
1113 switch ((cc-condclasses)*2 + 500) {
1116 if (runtime_error_checking_switch) {
1118 error_label = next_label++;
1119 AO1 = check_nonzero_at_runtime(AO1, error_label, HAS_RTE);
1120 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1121 if ((AO2.value < 0) || (AO2.value >= NUM_ATTR_BYTES*8)) {
1122 error("'has'/'hasnt' applied to illegal attribute number");
1126 int pa_label = next_label++, fa_label = next_label++;
1127 assembly_operand en_ao, max_ao;
1129 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) {
1130 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1131 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1132 assembleg_2(stkpeek_gc, one_operand, temp_var2);
1135 assembleg_2(stkpeek_gc, zero_operand, temp_var1);
1136 assembleg_store(temp_var2, AO2);
1140 assembleg_store(temp_var1, AO1);
1141 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
1142 assembleg_2(stkpeek_gc, zero_operand, temp_var2);
1145 assembleg_store(temp_var2, AO2);
1150 max_ao.value = NUM_ATTR_BYTES*8;
1151 set_constant_ot(&max_ao);
1152 assembleg_2_branch(jlt_gc, temp_var2, zero_operand, fa_label);
1153 assembleg_2_branch(jlt_gc, temp_var2, max_ao, pa_label);
1154 assemble_label_no(fa_label);
1156 en_ao.value = 19; /* INVALIDATTR_RTE */
1157 set_constant_ot(&en_ao);
1158 assembleg_store(stack_pointer, temp_var2);
1159 assembleg_store(stack_pointer, temp_var1);
1160 assembleg_store(stack_pointer, en_ao);
1161 assembleg_3(call_gc, veneer_routine(RT__Err_VR),
1162 three_operand, zero_operand);
1164 va_label = next_label++;
1165 assembleg_jump(va_label);
1166 assemble_label_no(pa_label);
1169 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1171 set_constant_ot(&AO2);
1176 AO4.type = BYTECONSTANT_OT;
1177 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0)) {
1178 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
1179 assembleg_0(stkswap_gc);
1180 assembleg_3(add_gc, AO2, AO4, stack_pointer);
1181 assembleg_0(stkswap_gc);
1184 assembleg_3(add_gc, AO2, AO4, stack_pointer);
1186 AO2 = stack_pointer;
1188 assembleg_3(aloadbit_gc, AO1, AO2, stack_pointer);
1189 the_zc = (flag ? jnz_gc : jz_gc);
1190 AO1 = stack_pointer;
1194 if (runtime_error_checking_switch) {
1196 error_label = next_label++;
1197 AO1 = check_nonzero_at_runtime(AO1, error_label, IN_RTE);
1200 AO4.value = GOBJFIELD_PARENT();
1201 AO4.type = BYTECONSTANT_OT;
1202 assembleg_3(aload_gc, AO1, AO4, stack_pointer);
1203 AO1 = stack_pointer;
1204 the_zc = (flag ? jeq_gc : jne_gc);
1208 assembleg_call_2(veneer_routine(OC__Cl_VR), AO1, AO2, stack_pointer);
1209 the_zc = (flag ? jnz_gc : jz_gc);
1210 AO1 = stack_pointer;
1214 assembleg_call_2(veneer_routine(OP__Pr_VR), AO1, AO2, stack_pointer);
1215 the_zc = (flag ? jnz_gc : jz_gc);
1216 AO1 = stack_pointer;
1220 error("condition not yet supported in Glulx");
1225 if (the_zc == jnz_gc || the_zc == jz_gc)
1226 assembleg_1_branch(the_zc, AO1, label);
1228 assembleg_2_branch(the_zc, AO1, AO2, label);
1229 if (error_label != label) assemble_label_no(error_label);
1230 if (va_flag) assemble_label_no(va_label);
1233 static void value_in_void_context(assembly_operand AO)
1236 value_in_void_context_z(AO);
1238 value_in_void_context_g(AO);
1242 extern assembly_operand check_nonzero_at_runtime(assembly_operand AO1,
1243 int error_label, int rte_number)
1246 return check_nonzero_at_runtime_z(AO1, error_label, rte_number);
1248 return check_nonzero_at_runtime_g(AO1, error_label, rte_number);
1251 static void generate_code_from(int n, int void_flag)
1253 /* When void, this must not leave anything on the stack. */
1255 int i, j, below, above, opnum, arity; assembly_operand Result;
1257 below = ET[n].down; above = ET[n].up;
1259 { if ((void_flag) && (ET[n].value.type != OMITTED_OT))
1260 value_in_void_context(ET[n].value);
1264 opnum = ET[n].operator_number;
1266 if (opnum == COMMA_OP)
1267 { generate_code_from(below, TRUE);
1268 generate_code_from(ET[below].right, void_flag);
1269 ET[n].value = ET[ET[below].right].value;
1270 goto OperatorGenerated;
1273 if ((opnum == LOGAND_OP) || (opnum == LOGOR_OP))
1274 { generate_code_from(below, FALSE);
1275 generate_code_from(ET[below].right, FALSE);
1276 goto OperatorGenerated;
1281 /* Signifies a SETEQUALS_OP which has already been done */
1283 ET[n].down = -1; return;
1286 /* Note that (except in the cases of comma and logical and/or) it
1287 is essential to code generate the operands right to left, because
1288 of the peculiar way the Z-machine's stack works:
1292 (for instance) pulls to the first operand, then the second. So
1298 calculates (b+7)-(a*2), not the other way around (as would be more
1299 usual in stack machines evaluating expressions written in reverse
1300 Polish notation). (Basically this is because the Z-machine was
1301 designed to implement a LISP-like language naturally expressed
1302 in forward Polish notation: (PLUS 3 4), for instance.) */
1304 /* And the Glulx machine follows the Z-machine in this respect. */
1308 { i = ET[i].right; arity++;
1310 for (j=arity;j>0;j--)
1314 { k++; i = ET[i].right;
1316 generate_code_from(i, FALSE);
1320 /* Check this again, because code generation lower down may have
1321 stubbed it into -1 */
1323 if (ET[n].operator_number == -1)
1324 { ET[n].down = -1; return;
1329 if (operators[opnum].opcode_number_z >= 400)
1331 /* Conditional terms such as '==': */
1333 int a = ET[n].true_label, b = ET[n].false_label,
1334 branch_away, branch_other,
1335 make_jump_away = FALSE, make_branch_label = FALSE;
1336 int oc = operators[opnum].opcode_number_z-400, flag = TRUE;
1338 if (oc >= 400) { oc = oc - 400; flag = FALSE; }
1340 if ((oc == je_zc) && (arity == 2))
1341 { i = ET[ET[n].down].right;
1342 if ((ET[i].value.value == zero_operand.value)
1343 && (ET[i].value.type == zero_operand.type))
1347 /* If the condition has truth state flag, branch to
1348 label a, and if not, to label b. Possibly one of a, b
1349 equals -1, meaning "continue from this instruction".
1351 branch_away is the label which is a branch away (the one
1352 which isn't immediately after) and flag is the truth
1353 state to branch there.
1355 Note that when multiple instructions are needed (because
1356 of the use of the 'or' operator) the branch_other label
1357 is created if need be.
1360 /* Reduce to the case where the branch_away label does exist: */
1362 if (a == -1) { a = b; b = -1; flag = !flag; }
1364 branch_away = a; branch_other = b;
1365 if (branch_other != -1) make_jump_away = TRUE;
1367 if ((((oc != je_zc)&&(arity > 2)) || (arity > 4)) && (flag == FALSE))
1369 /* In this case, we have an 'or' situation where multiple
1370 instructions are needed and where the overall condition
1371 is negated. That is, we have, e.g.
1373 if not (A cond B or C or D) then branch_away
1375 which we transform into
1377 if (A cond B) then branch_other
1378 if (A cond C) then branch_other
1379 if not (A cond D) then branch_away
1382 if (branch_other == -1)
1383 { branch_other = next_label++; make_branch_label = TRUE;
1388 assemblez_1_branch(jz_zc, ET[below].value, branch_away, flag);
1390 { assembly_operand left_operand;
1393 compile_conditional_z(oc, ET[below].value,
1394 ET[ET[below].right].value, branch_away, flag);
1396 { /* The case of a condition using "or".
1397 First: if the condition tests the stack pointer,
1398 and it can't always be done in a single test, move
1399 the value off the stack and into temporary variable
1402 if (((ET[below].value.type == VARIABLE_OT)
1403 && (ET[below].value.value == 0))
1404 && ((oc != je_zc) || (arity>4)) )
1405 { INITAOTV(&left_operand, VARIABLE_OT, 255);
1406 assemblez_store(left_operand, ET[below].value);
1408 else left_operand = ET[below].value;
1409 i = ET[below].right; arity--;
1411 /* "left_operand" now holds the quantity to be tested;
1412 "i" holds the right operand reached so far;
1413 "arity" the number of right operands. */
1416 { if ((oc == je_zc) && (arity>1))
1418 /* je_zc is an especially good case since the
1419 Z-machine implements "or" for up to three
1420 right operands automatically, though it's an
1421 especially bad case to generate code for! */
1424 { assemblez_3_branch(je_zc,
1425 left_operand, ET[i].value,
1426 ET[ET[i].right].value, branch_away, flag);
1427 i = ET[i].right; arity--;
1430 { if ((arity == 3) || flag)
1431 assemblez_4_branch(je_zc, left_operand,
1433 ET[ET[i].right].value,
1434 ET[ET[ET[i].right].right].value,
1437 assemblez_4_branch(je_zc, left_operand,
1439 ET[ET[i].right].value,
1440 ET[ET[ET[i].right].right].value,
1441 branch_other, !flag);
1442 i = ET[ET[i].right].right; arity -= 2;
1446 { /* Otherwise we can compare the left_operand with
1447 only one right operand at the time. There are
1448 two cases: it's the last right operand, or it
1451 if ((arity == 1) || flag)
1452 compile_conditional_z(oc, left_operand,
1453 ET[i].value, branch_away, flag);
1455 compile_conditional_z(oc, left_operand,
1456 ET[i].value, branch_other, !flag);
1458 i = ET[i].right; arity--;
1464 /* NB: These two conditions cannot both occur, fortunately! */
1466 if (make_branch_label) assemble_label_no(branch_other);
1467 if (make_jump_away) assemblez_jump(branch_other);
1469 goto OperatorGenerated;
1474 if (operators[opnum].opcode_number_g >= FIRST_CC
1475 && operators[opnum].opcode_number_g <= LAST_CC) {
1476 /* Conditional terms such as '==': */
1478 int a = ET[n].true_label, b = ET[n].false_label;
1479 int branch_away, branch_other, flag,
1480 make_jump_away = FALSE, make_branch_label = FALSE;
1481 int ccode = operators[opnum].opcode_number_g;
1482 condclass *cc = &condclasses[(ccode-FIRST_CC) / 2];
1483 flag = (ccode & 1) ? 0 : 1;
1485 /* If the comparison is "equal to (constant) 0", change it
1486 to the simple "zero" test. Unfortunately, this doesn't
1487 work for the commutative form "(constant) 0 is equal to".
1488 At least I don't think it does. */
1490 if ((cc == &condclasses[1]) && (arity == 2)) {
1491 i = ET[ET[n].down].right;
1492 if ((ET[i].value.value == 0)
1493 && (ET[i].value.marker == 0)
1494 && is_constant_ot(ET[i].value.type)) {
1495 cc = &condclasses[0];
1499 /* If the condition has truth state flag, branch to
1500 label a, and if not, to label b. Possibly one of a, b
1501 equals -1, meaning "continue from this instruction".
1503 branch_away is the label which is a branch away (the one
1504 which isn't immediately after) and flag is the truth
1505 state to branch there.
1507 Note that when multiple instructions are needed (because
1508 of the use of the 'or' operator) the branch_other label
1509 is created if need be.
1512 /* Reduce to the case where the branch_away label does exist: */
1514 if (a == -1) { a = b; b = -1; flag = !flag; }
1516 branch_away = a; branch_other = b;
1517 if (branch_other != -1) make_jump_away = TRUE;
1519 if ((arity > 2) && (flag == FALSE)) {
1520 /* In this case, we have an 'or' situation where multiple
1521 instructions are needed and where the overall condition
1522 is negated. That is, we have, e.g.
1524 if not (A cond B or C or D) then branch_away
1526 which we transform into
1528 if (A cond B) then branch_other
1529 if (A cond C) then branch_other
1530 if not (A cond D) then branch_away
1533 if (branch_other == -1) {
1534 branch_other = next_label++; make_branch_label = TRUE;
1538 if (cc == &condclasses[0]) {
1539 assembleg_1_branch((flag ? cc->posform : cc->negform),
1540 ET[below].value, branch_away);
1544 compile_conditional_g(cc, ET[below].value,
1545 ET[ET[below].right].value, branch_away, flag);
1548 /* The case of a condition using "or".
1549 First: if the condition tests the stack pointer,
1550 and it can't always be done in a single test, move
1551 the value off the stack and into temporary variable
1554 assembly_operand left_operand;
1555 if (((ET[below].value.type == LOCALVAR_OT)
1556 && (ET[below].value.value == 0))) {
1557 assembleg_store(temp_var1, ET[below].value);
1558 left_operand = temp_var1;
1561 left_operand = ET[below].value;
1563 i = ET[below].right;
1566 /* "left_operand" now holds the quantity to be tested;
1567 "i" holds the right operand reached so far;
1568 "arity" the number of right operands. */
1571 /* We can compare the left_operand with
1572 only one right operand at the time. There are
1573 two cases: it's the last right operand, or it
1576 if ((arity == 1) || flag)
1577 compile_conditional_g(cc, left_operand,
1578 ET[i].value, branch_away, flag);
1580 compile_conditional_g(cc, left_operand,
1581 ET[i].value, branch_other, !flag);
1589 /* NB: These two conditions cannot both occur, fortunately! */
1591 if (make_branch_label) assemble_label_no(branch_other);
1592 if (make_jump_away) assembleg_jump(branch_other);
1594 goto OperatorGenerated;
1599 /* The operator is now definitely one which produces a value */
1601 if (void_flag && (!(operators[opnum].side_effect)))
1602 error_named("Evaluating this has no effect:",
1603 operators[opnum].description);
1605 /* Where shall we put the resulting value? (In Glulx, this could
1606 be smarter, and peg the result into ZEROCONSTANT.) */
1608 if (void_flag) Result = temp_var1; /* Throw it away */
1610 { if ((above != -1) && (ET[above].operator_number == SETEQUALS_OP))
1612 /* If the node above is "set variable equal to", then
1613 make that variable the place to put the result, and
1614 delete the SETEQUALS_OP node since its effect has already
1615 been accomplished. */
1617 ET[above].operator_number = -1;
1618 Result = ET[ET[above].down].value;
1619 ET[above].value = Result;
1621 else Result = stack_pointer; /* Otherwise, put it on the stack */
1626 if (operators[opnum].opcode_number_z != -1)
1628 /* Operators directly translatable into Z-code opcodes: infix ops
1629 take two operands whereas pre/postfix operators take only one */
1631 if (operators[opnum].usage == IN_U)
1632 { int o_n = operators[opnum].opcode_number_z;
1633 if (runtime_error_checking_switch && (!veneer_mode)
1634 && ((o_n == div_zc) || (o_n == mod_zc)))
1635 { assembly_operand by_ao, error_ao; int ln;
1636 by_ao = ET[ET[below].right].value;
1637 if ((by_ao.value != 0) && (by_ao.marker == 0)
1638 && ((by_ao.type == SHORT_CONSTANT_OT)
1639 || (by_ao.type == LONG_CONSTANT_OT)))
1640 assemblez_2_to(o_n, ET[below].value,
1644 assemblez_store(temp_var1, ET[below].value);
1645 assemblez_store(temp_var2, by_ao);
1647 assemblez_1_branch(jz_zc, temp_var2, ln, FALSE);
1648 INITAOT(&error_ao, SHORT_CONSTANT_OT);
1649 error_ao.value = DBYZERO_RTE;
1650 assemblez_2(call_vn_zc, veneer_routine(RT__Err_VR),
1652 assemblez_inc(temp_var2);
1653 assemble_label_no(ln);
1654 assemblez_2_to(o_n, temp_var1, temp_var2, Result);
1658 assemblez_2_to(o_n, ET[below].value,
1659 ET[ET[below].right].value, Result);
1663 assemblez_1_to(operators[opnum].opcode_number_z, ET[below].value,
1669 access_memory_z(loadb_zc, ET[below].value,
1670 ET[ET[below].right].value, Result);
1673 access_memory_z(loadw_zc, ET[below].value,
1674 ET[ET[below].right].value, Result);
1676 case UNARY_MINUS_OP:
1677 assemblez_2_to(sub_zc, zero_operand, ET[below].value, Result);
1680 assemblez_1_to(not_zc, ET[below].value, Result);
1684 { assembly_operand AO = ET[below].value;
1685 if (runtime_error_checking_switch && (!veneer_mode))
1686 AO = check_nonzero_at_runtime(AO, -1, PROP_ADD_RTE);
1687 assemblez_2_to(get_prop_addr_zc, AO,
1688 ET[ET[below].right].value, temp_var1);
1689 if (!void_flag) write_result_z(Result, temp_var1);
1694 { assembly_operand AO = ET[below].value;
1695 if (runtime_error_checking_switch && (!veneer_mode))
1696 AO = check_nonzero_at_runtime(AO, -1, PROP_NUM_RTE);
1697 assemblez_2_to(get_prop_addr_zc, AO,
1698 ET[ET[below].right].value, temp_var1);
1699 assemblez_1_branch(jz_zc, temp_var1, next_label++, TRUE);
1700 assemblez_1_to(get_prop_len_zc, temp_var1, temp_var1);
1701 assemble_label_no(next_label-1);
1702 if (!void_flag) write_result_z(Result, temp_var1);
1707 { assembly_operand AO = ET[below].value;
1709 if (runtime_error_checking_switch && (!veneer_mode))
1710 assemblez_3_to(call_vs_zc, veneer_routine(RT__ChPR_VR),
1711 AO, ET[ET[below].right].value, temp_var1);
1713 assemblez_2_to(get_prop_zc, AO,
1714 ET[ET[below].right].value, temp_var1);
1715 if (!void_flag) write_result_z(Result, temp_var1);
1720 j=1; AI.operand[0] = veneer_routine(RV__Pr_VR);
1721 goto GenFunctionCallZ;
1723 j=1; AI.operand[0] = veneer_routine(RA__Pr_VR);
1724 goto GenFunctionCallZ;
1726 j=1; AI.operand[0] = veneer_routine(RL__Pr_VR);
1727 goto GenFunctionCallZ;
1728 case MESSAGE_SETEQUALS_OP:
1729 j=1; AI.operand[0] = veneer_routine(WV__Pr_VR);
1730 goto GenFunctionCallZ;
1731 case MESSAGE_INC_OP:
1732 j=1; AI.operand[0] = veneer_routine(IB__Pr_VR);
1733 goto GenFunctionCallZ;
1734 case MESSAGE_DEC_OP:
1735 j=1; AI.operand[0] = veneer_routine(DB__Pr_VR);
1736 goto GenFunctionCallZ;
1737 case MESSAGE_POST_INC_OP:
1738 j=1; AI.operand[0] = veneer_routine(IA__Pr_VR);
1739 goto GenFunctionCallZ;
1740 case MESSAGE_POST_DEC_OP:
1741 j=1; AI.operand[0] = veneer_routine(DA__Pr_VR);
1742 goto GenFunctionCallZ;
1744 j=1; AI.operand[0] = veneer_routine(RA__Sc_VR);
1745 goto GenFunctionCallZ;
1747 j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
1748 goto GenFunctionCallZ;
1749 case MESSAGE_CALL_OP:
1750 j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
1751 goto GenFunctionCallZ;
1757 if ((ET[below].value.type == VARIABLE_OT)
1758 && (ET[below].value.value >= 256))
1759 { int sf_number = ET[below].value.value - 256;
1761 i = ET[below].right;
1763 { error("Argument to system function missing");
1764 AI.operand[0] = one_operand;
1765 AI.operand_count = 1;
1769 while (i != -1) { j++; i = ET[i].right; }
1771 if (((sf_number != INDIRECT_SYSF) &&
1772 (sf_number != RANDOM_SYSF) && (j > 1))
1773 || ((sf_number == INDIRECT_SYSF) && (j>7)))
1775 error("System function given with too many arguments");
1777 if (sf_number != RANDOM_SYSF)
1779 i = ET[below].right;
1780 for (jcount = 0; jcount < j; jcount++)
1781 { AI.operand[jcount] = ET[i].value;
1784 AI.operand_count = j;
1787 AI.store_variable_number = Result.value;
1788 AI.branch_label_number = -1;
1793 { assembly_operand AO, AO2; int arg_c, arg_et;
1794 INITAOTV(&AO, SHORT_CONSTANT_OT, j);
1795 INITAOT(&AO2, LONG_CONSTANT_OT);
1796 AO2.value = begin_word_array();
1797 AO2.marker = ARRAY_MV;
1799 for (arg_c=0, arg_et = ET[below].right;arg_c<j;
1800 arg_c++, arg_et = ET[arg_et].right)
1801 { if (ET[arg_et].value.type == VARIABLE_OT)
1802 error("Only constants can be used as possible 'random' results");
1803 array_entry(arg_c, FALSE, ET[arg_et].value);
1805 finish_array(arg_c, FALSE);
1807 assemblez_1_to(random_zc, AO, temp_var1);
1808 assemblez_dec(temp_var1);
1809 assemblez_2_to(loadw_zc, AO2, temp_var1, Result);
1812 assemblez_1_to(random_zc,
1813 ET[ET[below].right].value, Result);
1817 { assembly_operand AO;
1818 AO = ET[ET[below].right].value;
1819 if (runtime_error_checking_switch)
1820 AO = check_nonzero_at_runtime(AO, -1,
1822 assemblez_1_to(get_parent_zc, AO, Result);
1828 { assembly_operand AO;
1829 AO = ET[ET[below].right].value;
1830 if (runtime_error_checking_switch)
1831 AO = check_nonzero_at_runtime(AO, -1,
1832 (sf_number==CHILD_SYSF)?CHILD_RTE:ELDEST_RTE);
1833 assemblez_objcode(get_child_zc,
1834 AO, Result, -2, TRUE);
1840 { assembly_operand AO;
1841 AO = ET[ET[below].right].value;
1842 if (runtime_error_checking_switch)
1843 AO = check_nonzero_at_runtime(AO, -1,
1844 (sf_number==SIBLING_SYSF)
1845 ?SIBLING_RTE:YOUNGER_RTE);
1846 assemblez_objcode(get_sibling_zc,
1847 AO, Result, -2, TRUE);
1852 j=0; i = ET[below].right;
1853 goto IndirectFunctionCallZ;
1856 { assembly_operand AO;
1857 AO = ET[ET[below].right].value;
1858 if (runtime_error_checking_switch)
1859 AO = check_nonzero_at_runtime(AO, -1,
1861 assemblez_store(temp_var1, zero_operand);
1862 assemblez_objcode(get_child_zc,
1863 AO, stack_pointer, next_label+1, FALSE);
1864 assemble_label_no(next_label);
1865 assemblez_inc(temp_var1);
1866 assemblez_objcode(get_sibling_zc,
1867 stack_pointer, stack_pointer,
1869 assemble_label_no(next_label+1);
1870 assemblez_store(temp_var2, stack_pointer);
1871 if (!void_flag) write_result_z(Result, temp_var1);
1877 { assembly_operand AO;
1878 AO = ET[ET[below].right].value;
1879 if (runtime_error_checking_switch)
1880 AO = check_nonzero_at_runtime(AO, -1,
1882 assemblez_objcode(get_child_zc,
1883 AO, temp_var1, next_label+1, FALSE);
1884 assemblez_1(push_zc, temp_var1);
1885 assemble_label_no(next_label);
1886 assemblez_store(temp_var1, stack_pointer);
1887 assemblez_objcode(get_sibling_zc,
1888 temp_var1, stack_pointer, next_label, TRUE);
1889 assemble_label_no(next_label+1);
1890 if (!void_flag) write_result_z(Result, temp_var1);
1896 assemblez_store(temp_var1, ET[ET[below].right].value);
1897 if (runtime_error_checking_switch)
1898 check_nonzero_at_runtime(temp_var1, -1,
1900 assemblez_1_to(get_parent_zc, temp_var1, temp_var3);
1901 assemblez_1_branch(jz_zc, temp_var3,next_label+1,TRUE);
1902 assemblez_store(temp_var2, temp_var3);
1903 assemblez_store(temp_var3, zero_operand);
1904 assemblez_objcode(get_child_zc,
1905 temp_var2, temp_var2, next_label, TRUE);
1906 assemble_label_no(next_label++);
1907 assemblez_2_branch(je_zc, temp_var1, temp_var2,
1909 assemblez_store(temp_var3, temp_var2);
1910 assemblez_objcode(get_sibling_zc,
1911 temp_var2, temp_var2, next_label - 1, TRUE);
1912 assemble_label_no(next_label++);
1913 if (!void_flag) write_result_z(Result, temp_var3);
1916 case METACLASS_SYSF:
1917 assemblez_2_to((version_number==3)?call_zc:call_vs_zc,
1918 veneer_routine(Metaclass_VR),
1919 ET[ET[below].right].value, Result);
1923 error("The glk() system function does not exist in Z-code");
1933 IndirectFunctionCallZ:
1935 while ((i != -1) && (j<8))
1936 { AI.operand[j++] = ET[i].value;
1940 if ((j > 4) && (version_number == 3))
1941 { error("A function may be called with at most 3 arguments");
1944 if ((j==8) && (i != -1))
1945 { error("A function may be called with at most 7 arguments");
1948 AI.operand_count = j;
1950 if ((void_flag) && (version_number >= 5))
1951 { AI.store_variable_number = -1;
1953 { case 1: AI.internal_number = call_1n_zc; break;
1954 case 2: AI.internal_number = call_2n_zc; break;
1955 case 3: case 4: AI.internal_number = call_vn_zc; break;
1956 case 5: case 6: case 7: case 8:
1957 AI.internal_number = call_vn2_zc; break;
1961 { AI.store_variable_number = Result.value;
1962 if (version_number == 3)
1963 AI.internal_number = call_zc;
1966 { case 1: AI.internal_number = call_1s_zc; break;
1967 case 2: AI.internal_number = call_2s_zc; break;
1968 case 3: case 4: AI.internal_number = call_vs_zc; break;
1969 case 5: case 6: case 7: case 8:
1970 AI.internal_number = call_vs2_zc; break;
1974 AI.branch_label_number = -1;
1975 assemblez_instruction(&AI);
1979 assemblez_store(ET[below].value,
1980 ET[ET[below].right].value);
1981 if (!void_flag) write_result_z(Result, ET[below].value);
1984 case PROPERTY_SETEQUALS_OP:
1986 { if (runtime_error_checking_switch)
1987 assemblez_4_to(call_zc, veneer_routine(RT__ChPS_VR),
1988 ET[below].value, ET[ET[below].right].value,
1989 ET[ET[ET[below].right].right].value, Result);
1991 { assemblez_store(temp_var1,
1992 ET[ET[ET[below].right].right].value);
1993 assemblez_3(put_prop_zc, ET[below].value,
1994 ET[ET[below].right].value,
1996 write_result_z(Result, temp_var1);
2000 { if (runtime_error_checking_switch && (!veneer_mode))
2001 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2002 ET[below].value, ET[ET[below].right].value,
2003 ET[ET[ET[below].right].right].value);
2004 else assemblez_3(put_prop_zc, ET[below].value,
2005 ET[ET[below].right].value,
2006 ET[ET[ET[below].right].right].value);
2009 case ARROW_SETEQUALS_OP:
2011 { assemblez_store(temp_var1,
2012 ET[ET[ET[below].right].right].value);
2013 access_memory_z(storeb_zc, ET[below].value,
2014 ET[ET[below].right].value,
2016 write_result_z(Result, temp_var1);
2018 else access_memory_z(storeb_zc, ET[below].value,
2019 ET[ET[below].right].value,
2020 ET[ET[ET[below].right].right].value);
2023 case DARROW_SETEQUALS_OP:
2025 { assemblez_store(temp_var1,
2026 ET[ET[ET[below].right].right].value);
2027 access_memory_z(storew_zc, ET[below].value,
2028 ET[ET[below].right].value,
2030 write_result_z(Result, temp_var1);
2033 access_memory_z(storew_zc, ET[below].value,
2034 ET[ET[below].right].value,
2035 ET[ET[ET[below].right].right].value);
2039 assemblez_inc(ET[below].value);
2040 if (!void_flag) write_result_z(Result, ET[below].value);
2043 assemblez_dec(ET[below].value);
2044 if (!void_flag) write_result_z(Result, ET[below].value);
2047 if (!void_flag) write_result_z(Result, ET[below].value);
2048 assemblez_inc(ET[below].value);
2051 if (!void_flag) write_result_z(Result, ET[below].value);
2052 assemblez_dec(ET[below].value);
2056 assemblez_store(temp_var1, ET[below].value);
2057 assemblez_store(temp_var2, ET[ET[below].right].value);
2058 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2059 assemblez_inc(temp_var3);
2060 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2061 if (!void_flag) write_result_z(Result, temp_var3);
2065 assemblez_store(temp_var1, ET[below].value);
2066 assemblez_store(temp_var2, ET[ET[below].right].value);
2067 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2068 assemblez_dec(temp_var3);
2069 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2070 if (!void_flag) write_result_z(Result, temp_var3);
2073 case ARROW_POST_INC_OP:
2074 assemblez_store(temp_var1, ET[below].value);
2075 assemblez_store(temp_var2, ET[ET[below].right].value);
2076 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2077 if (!void_flag) write_result_z(Result, temp_var3);
2078 assemblez_inc(temp_var3);
2079 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2082 case ARROW_POST_DEC_OP:
2083 assemblez_store(temp_var1, ET[below].value);
2084 assemblez_store(temp_var2, ET[ET[below].right].value);
2085 access_memory_z(loadb_zc, temp_var1, temp_var2, temp_var3);
2086 if (!void_flag) write_result_z(Result, temp_var3);
2087 assemblez_dec(temp_var3);
2088 access_memory_z(storeb_zc, temp_var1, temp_var2, temp_var3);
2092 assemblez_store(temp_var1, ET[below].value);
2093 assemblez_store(temp_var2, ET[ET[below].right].value);
2094 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2095 assemblez_inc(temp_var3);
2096 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2097 if (!void_flag) write_result_z(Result, temp_var3);
2101 assemblez_store(temp_var1, ET[below].value);
2102 assemblez_store(temp_var2, ET[ET[below].right].value);
2103 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2104 assemblez_dec(temp_var3);
2105 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2106 if (!void_flag) write_result_z(Result, temp_var3);
2109 case DARROW_POST_INC_OP:
2110 assemblez_store(temp_var1, ET[below].value);
2111 assemblez_store(temp_var2, ET[ET[below].right].value);
2112 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2113 if (!void_flag) write_result_z(Result, temp_var3);
2114 assemblez_inc(temp_var3);
2115 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2118 case DARROW_POST_DEC_OP:
2119 assemblez_store(temp_var1, ET[below].value);
2120 assemblez_store(temp_var2, ET[ET[below].right].value);
2121 access_memory_z(loadw_zc, temp_var1, temp_var2, temp_var3);
2122 if (!void_flag) write_result_z(Result, temp_var3);
2123 assemblez_dec(temp_var3);
2124 access_memory_z(storew_zc, temp_var1, temp_var2, temp_var3);
2127 case PROPERTY_INC_OP:
2128 assemblez_store(temp_var1, ET[below].value);
2129 assemblez_store(temp_var2, ET[ET[below].right].value);
2130 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2131 assemblez_inc(temp_var3);
2132 if (runtime_error_checking_switch && (!veneer_mode))
2133 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2134 temp_var1, temp_var2, temp_var3);
2135 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2136 if (!void_flag) write_result_z(Result, temp_var3);
2139 case PROPERTY_DEC_OP:
2140 assemblez_store(temp_var1, ET[below].value);
2141 assemblez_store(temp_var2, ET[ET[below].right].value);
2142 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2143 assemblez_dec(temp_var3);
2144 if (runtime_error_checking_switch && (!veneer_mode))
2145 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2146 temp_var1, temp_var2, temp_var3);
2147 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2148 if (!void_flag) write_result_z(Result, temp_var3);
2151 case PROPERTY_POST_INC_OP:
2152 assemblez_store(temp_var1, ET[below].value);
2153 assemblez_store(temp_var2, ET[ET[below].right].value);
2154 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2155 if (!void_flag) write_result_z(Result, temp_var3);
2156 assemblez_inc(temp_var3);
2157 if (runtime_error_checking_switch && (!veneer_mode))
2158 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2159 temp_var1, temp_var2, temp_var3);
2160 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2163 case PROPERTY_POST_DEC_OP:
2164 assemblez_store(temp_var1, ET[below].value);
2165 assemblez_store(temp_var2, ET[ET[below].right].value);
2166 assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
2167 if (!void_flag) write_result_z(Result, temp_var3);
2168 assemblez_dec(temp_var3);
2169 if (runtime_error_checking_switch && (!veneer_mode))
2170 assemblez_4(call_vn_zc, veneer_routine(RT__ChPS_VR),
2171 temp_var1, temp_var2, temp_var3);
2172 else assemblez_3(put_prop_zc, temp_var1, temp_var2, temp_var3);
2176 printf("** Trouble op = %d i.e. '%s' **\n",
2177 opnum, operators[opnum].description);
2178 compiler_error("Expr code gen: Can't generate yet");
2182 assembly_operand AO, AO2;
2183 if (operators[opnum].opcode_number_g != -1)
2185 /* Operators directly translatable into opcodes: infix ops
2186 take two operands whereas pre/postfix operators take only one */
2188 if (operators[opnum].usage == IN_U)
2189 { int o_n = operators[opnum].opcode_number_g;
2190 if (runtime_error_checking_switch && (!veneer_mode)
2191 && ((o_n == div_gc) || (o_n == mod_gc)))
2192 { assembly_operand by_ao, error_ao; int ln;
2193 by_ao = ET[ET[below].right].value;
2194 if ((by_ao.value != 0) && (by_ao.marker == 0)
2195 && is_constant_ot(by_ao.type))
2196 assembleg_3(o_n, ET[below].value,
2199 { assembleg_store(temp_var1, ET[below].value);
2200 assembleg_store(temp_var2, by_ao);
2202 assembleg_1_branch(jnz_gc, temp_var2, ln);
2204 error_ao.value = DBYZERO_RTE;
2205 set_constant_ot(&error_ao);
2206 assembleg_call_1(veneer_routine(RT__Err_VR),
2207 error_ao, zero_operand);
2208 assembleg_store(temp_var2, one_operand);
2209 assemble_label_no(ln);
2210 assembleg_3(o_n, temp_var1, temp_var2, Result);
2214 assembleg_3(o_n, ET[below].value,
2215 ET[ET[below].right].value, Result);
2218 assembleg_2(operators[opnum].opcode_number_g, ET[below].value,
2226 if (ET[below].value.type == Result.type
2227 && ET[below].value.value == Result.value
2228 && ET[below].value.marker == Result.marker)
2230 assembleg_2(copy_gc, ET[below].value, Result);
2233 case UNARY_MINUS_OP:
2234 assembleg_2(neg_gc, ET[below].value, Result);
2237 assembleg_2(bitnot_gc, ET[below].value, Result);
2241 access_memory_g(aloadb_gc, ET[below].value,
2242 ET[ET[below].right].value, Result);
2245 access_memory_g(aload_gc, ET[below].value,
2246 ET[ET[below].right].value, Result);
2250 assembleg_store(ET[below].value,
2251 ET[ET[below].right].value);
2252 if (!void_flag) write_result_g(Result, ET[below].value);
2255 case ARROW_SETEQUALS_OP:
2257 { assembleg_store(temp_var1,
2258 ET[ET[ET[below].right].right].value);
2259 access_memory_g(astoreb_gc, ET[below].value,
2260 ET[ET[below].right].value,
2262 write_result_g(Result, temp_var1);
2264 else access_memory_g(astoreb_gc, ET[below].value,
2265 ET[ET[below].right].value,
2266 ET[ET[ET[below].right].right].value);
2269 case DARROW_SETEQUALS_OP:
2271 { assembleg_store(temp_var1,
2272 ET[ET[ET[below].right].right].value);
2273 access_memory_g(astore_gc, ET[below].value,
2274 ET[ET[below].right].value,
2276 write_result_g(Result, temp_var1);
2279 access_memory_g(astore_gc, ET[below].value,
2280 ET[ET[below].right].value,
2281 ET[ET[ET[below].right].right].value);
2285 assembleg_inc(ET[below].value);
2286 if (!void_flag) write_result_g(Result, ET[below].value);
2289 assembleg_dec(ET[below].value);
2290 if (!void_flag) write_result_g(Result, ET[below].value);
2293 if (!void_flag) write_result_g(Result, ET[below].value);
2294 assembleg_inc(ET[below].value);
2297 if (!void_flag) write_result_g(Result, ET[below].value);
2298 assembleg_dec(ET[below].value);
2302 assembleg_store(temp_var1, ET[below].value);
2303 assembleg_store(temp_var2, ET[ET[below].right].value);
2304 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2305 assembleg_inc(temp_var3);
2306 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2307 if (!void_flag) write_result_g(Result, temp_var3);
2311 assembleg_store(temp_var1, ET[below].value);
2312 assembleg_store(temp_var2, ET[ET[below].right].value);
2313 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2314 assembleg_dec(temp_var3);
2315 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2316 if (!void_flag) write_result_g(Result, temp_var3);
2319 case ARROW_POST_INC_OP:
2320 assembleg_store(temp_var1, ET[below].value);
2321 assembleg_store(temp_var2, ET[ET[below].right].value);
2322 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2323 if (!void_flag) write_result_g(Result, temp_var3);
2324 assembleg_inc(temp_var3);
2325 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2328 case ARROW_POST_DEC_OP:
2329 assembleg_store(temp_var1, ET[below].value);
2330 assembleg_store(temp_var2, ET[ET[below].right].value);
2331 access_memory_g(aloadb_gc, temp_var1, temp_var2, temp_var3);
2332 if (!void_flag) write_result_g(Result, temp_var3);
2333 assembleg_dec(temp_var3);
2334 access_memory_g(astoreb_gc, temp_var1, temp_var2, temp_var3);
2338 assembleg_store(temp_var1, ET[below].value);
2339 assembleg_store(temp_var2, ET[ET[below].right].value);
2340 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2341 assembleg_inc(temp_var3);
2342 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2343 if (!void_flag) write_result_g(Result, temp_var3);
2347 assembleg_store(temp_var1, ET[below].value);
2348 assembleg_store(temp_var2, ET[ET[below].right].value);
2349 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2350 assembleg_dec(temp_var3);
2351 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2352 if (!void_flag) write_result_g(Result, temp_var3);
2355 case DARROW_POST_INC_OP:
2356 assembleg_store(temp_var1, ET[below].value);
2357 assembleg_store(temp_var2, ET[ET[below].right].value);
2358 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2359 if (!void_flag) write_result_g(Result, temp_var3);
2360 assembleg_inc(temp_var3);
2361 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2364 case DARROW_POST_DEC_OP:
2365 assembleg_store(temp_var1, ET[below].value);
2366 assembleg_store(temp_var2, ET[ET[below].right].value);
2367 access_memory_g(aload_gc, temp_var1, temp_var2, temp_var3);
2368 if (!void_flag) write_result_g(Result, temp_var3);
2369 assembleg_dec(temp_var3);
2370 access_memory_g(astore_gc, temp_var1, temp_var2, temp_var3);
2375 AO = veneer_routine(RV__Pr_VR);
2376 goto TwoArgFunctionCall;
2379 AO = veneer_routine(RA__Pr_VR);
2380 goto TwoArgFunctionCall;
2383 AO = veneer_routine(RL__Pr_VR);
2384 goto TwoArgFunctionCall;
2387 case MESSAGE_CALL_OP:
2388 AO2 = veneer_routine(CA__Pr_VR);
2390 goto DoFunctionCall;
2392 case MESSAGE_INC_OP:
2393 case PROPERTY_INC_OP:
2394 AO = veneer_routine(IB__Pr_VR);
2395 goto TwoArgFunctionCall;
2396 case MESSAGE_DEC_OP:
2397 case PROPERTY_DEC_OP:
2398 AO = veneer_routine(DB__Pr_VR);
2399 goto TwoArgFunctionCall;
2400 case MESSAGE_POST_INC_OP:
2401 case PROPERTY_POST_INC_OP:
2402 AO = veneer_routine(IA__Pr_VR);
2403 goto TwoArgFunctionCall;
2404 case MESSAGE_POST_DEC_OP:
2405 case PROPERTY_POST_DEC_OP:
2406 AO = veneer_routine(DA__Pr_VR);
2407 goto TwoArgFunctionCall;
2409 AO = veneer_routine(RA__Sc_VR);
2410 goto TwoArgFunctionCall;
2414 assembly_operand AO2 = ET[below].value;
2415 assembly_operand AO3 = ET[ET[below].right].value;
2417 assembleg_call_2(AO, AO2, AO3, zero_operand);
2419 assembleg_call_2(AO, AO2, AO3, Result);
2423 case PROPERTY_SETEQUALS_OP:
2424 case MESSAGE_SETEQUALS_OP:
2425 if (runtime_error_checking_switch && (!veneer_mode))
2426 AO = veneer_routine(RT__ChPS_VR);
2428 AO = veneer_routine(WV__Pr_VR);
2431 assembly_operand AO2 = ET[below].value;
2432 assembly_operand AO3 = ET[ET[below].right].value;
2433 assembly_operand AO4 = ET[ET[ET[below].right].right].value;
2434 if (AO4.type == LOCALVAR_OT && AO4.value == 0) {
2435 /* Rightmost is on the stack; reduce to previous case. */
2436 if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2437 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2438 /* both already on stack. */
2441 assembleg_store(stack_pointer, AO3);
2442 assembleg_0(stkswap_gc);
2446 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2447 assembleg_store(stack_pointer, AO2);
2450 assembleg_store(stack_pointer, AO3);
2451 assembleg_store(stack_pointer, AO2);
2456 /* We have to get the rightmost on the stack, below the
2458 if (AO3.type == LOCALVAR_OT && AO3.value == 0) {
2459 if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2460 assembleg_store(stack_pointer, AO4);
2461 assembleg_2(stkroll_gc, three_operand, one_operand);
2464 assembleg_store(stack_pointer, AO4);
2465 assembleg_0(stkswap_gc);
2466 assembleg_store(stack_pointer, AO2);
2470 if (AO2.type == LOCALVAR_OT && AO2.value == 0) {
2471 assembleg_store(stack_pointer, AO4);
2472 assembleg_store(stack_pointer, AO3);
2473 assembleg_2(stkroll_gc, three_operand, two_operand);
2476 assembleg_store(stack_pointer, AO4);
2477 assembleg_store(stack_pointer, AO3);
2478 assembleg_store(stack_pointer, AO2);
2483 assembleg_3(call_gc, AO, three_operand, zero_operand);
2485 assembleg_3(call_gc, AO, three_operand, Result);
2492 if (ET[below].value.type == SYSFUN_OT)
2493 { int sf_number = ET[below].value.value;
2495 i = ET[below].right;
2497 { error("Argument to system function missing");
2498 AI.operand[0] = one_operand;
2499 AI.operand_count = 1;
2503 while (i != -1) { j++; i = ET[i].right; }
2505 if (((sf_number != INDIRECT_SYSF) &&
2506 (sf_number != GLK_SYSF) &&
2507 (sf_number != RANDOM_SYSF) && (j > 1)))
2509 error("System function given with too many arguments");
2511 if (sf_number != RANDOM_SYSF)
2513 i = ET[below].right;
2514 for (jcount = 0; jcount < j; jcount++)
2515 { AI.operand[jcount] = ET[i].value;
2518 AI.operand_count = j;
2526 { assembly_operand AO, AO2;
2530 set_constant_ot(&AO);
2531 INITAOTV(&AO2, CONSTANT_OT, begin_word_array());
2532 AO2.marker = ARRAY_MV;
2534 for (arg_c=0, arg_et = ET[below].right;arg_c<j;
2535 arg_c++, arg_et = ET[arg_et].right)
2536 { if (ET[arg_et].value.type == LOCALVAR_OT
2537 || ET[arg_et].value.type == GLOBALVAR_OT)
2538 error("Only constants can be used as possible 'random' results");
2539 array_entry(arg_c, FALSE, ET[arg_et].value);
2541 finish_array(arg_c, FALSE);
2543 assembleg_2(random_gc, AO, stack_pointer);
2544 assembleg_3(aload_gc, AO2, stack_pointer, Result);
2547 assembleg_2(random_gc,
2548 ET[ET[below].right].value, stack_pointer);
2549 assembleg_3(add_gc, stack_pointer, one_operand,
2555 { assembly_operand AO;
2556 AO = ET[ET[below].right].value;
2557 if (runtime_error_checking_switch)
2558 AO = check_nonzero_at_runtime(AO, -1,
2560 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2561 assembleg_3(aload_gc, AO, AO2, Result);
2567 { assembly_operand AO;
2568 AO = ET[ET[below].right].value;
2569 if (runtime_error_checking_switch)
2570 AO = check_nonzero_at_runtime(AO, -1,
2571 (sf_number==CHILD_SYSF)?CHILD_RTE:ELDEST_RTE);
2572 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2573 assembleg_3(aload_gc, AO, AO2, Result);
2579 { assembly_operand AO;
2580 AO = ET[ET[below].right].value;
2581 if (runtime_error_checking_switch)
2582 AO = check_nonzero_at_runtime(AO, -1,
2583 (sf_number==SIBLING_SYSF)
2584 ?SIBLING_RTE:YOUNGER_RTE);
2585 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2586 assembleg_3(aload_gc, AO, AO2, Result);
2591 { assembly_operand AO;
2592 AO = ET[ET[below].right].value;
2593 if (runtime_error_checking_switch)
2594 AO = check_nonzero_at_runtime(AO, -1,
2596 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2597 assembleg_store(temp_var1, zero_operand);
2598 assembleg_3(aload_gc, AO, AO2, temp_var2);
2599 AO2.value = GOBJFIELD_SIBLING();
2600 assemble_label_no(next_label);
2601 assembleg_1_branch(jz_gc, temp_var2, next_label+1);
2602 assembleg_3(add_gc, temp_var1, one_operand,
2604 assembleg_3(aload_gc, temp_var2, AO2, temp_var2);
2605 assembleg_0_branch(jump_gc, next_label);
2606 assemble_label_no(next_label+1);
2609 write_result_g(Result, temp_var1);
2614 i = ET[below].right;
2615 goto IndirectFunctionCallG;
2618 AO2 = veneer_routine(Glk__Wrap_VR);
2619 i = ET[below].right;
2620 goto DoFunctionCall;
2622 case METACLASS_SYSF:
2623 assembleg_call_1(veneer_routine(Metaclass_VR),
2624 ET[ET[below].right].value, Result);
2628 AO = ET[ET[below].right].value;
2629 if (runtime_error_checking_switch)
2630 AO = check_nonzero_at_runtime(AO, -1,
2632 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2633 assembleg_3(aload_gc, AO, AO2, temp_var1);
2634 AO2.value = GOBJFIELD_SIBLING();
2635 assembleg_1_branch(jz_gc, temp_var1, next_label+1);
2636 assemble_label_no(next_label);
2637 assembleg_3(aload_gc, temp_var1, AO2, temp_var2);
2638 assembleg_1_branch(jz_gc, temp_var2, next_label+1);
2639 assembleg_store(temp_var1, temp_var2);
2640 assembleg_0_branch(jump_gc, next_label);
2641 assemble_label_no(next_label+1);
2643 write_result_g(Result, temp_var1);
2648 AO = ET[ET[below].right].value;
2649 if (runtime_error_checking_switch)
2650 AO = check_nonzero_at_runtime(AO, -1,
2652 assembleg_store(temp_var3, AO);
2653 INITAOTV(&AO2, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2654 assembleg_3(aload_gc, temp_var3, AO2, temp_var1);
2655 assembleg_1_branch(jz_gc, temp_var1, next_label+2);
2656 AO2.value = GOBJFIELD_CHILD();
2657 assembleg_3(aload_gc, temp_var1, AO2, temp_var1);
2658 assembleg_1_branch(jz_gc, temp_var1, next_label+2);
2659 assembleg_2_branch(jeq_gc, temp_var3, temp_var1,
2661 assemble_label_no(next_label);
2662 AO2.value = GOBJFIELD_SIBLING();
2663 assembleg_3(aload_gc, temp_var1, AO2, temp_var2);
2664 assembleg_2_branch(jeq_gc, temp_var3, temp_var2,
2666 assembleg_store(temp_var1, temp_var2);
2667 assembleg_0_branch(jump_gc, next_label);
2668 assemble_label_no(next_label+1);
2669 assembleg_store(temp_var1, zero_operand);
2670 assemble_label_no(next_label+2);
2672 write_result_g(Result, temp_var1);
2677 error("*** system function not implemented ***");
2686 IndirectFunctionCallG:
2688 /* Get the function address. */
2695 /* If all the function arguments are in local/global
2696 variables, we have to push them all on the stack.
2697 If all of them are on the stack, we have to do nothing.
2698 If some are and some aren't, we have a hopeless mess,
2699 and we should throw a compiler error.
2705 /* begin part of patch G03701 */
2714 assembleg_2(callf_gc, AO2, void_flag ? zero_operand : Result);
2715 } else if (nargs==1) {
2716 assembleg_call_1(AO2, ET[i].value, void_flag ? zero_operand : Result);
2717 } else if (nargs==2) {
2718 assembly_operand o1 = ET[i].value;
2719 assembly_operand o2 = ET[ET[i].right].value;
2720 assembleg_call_2(AO2, o1, o2, void_flag ? zero_operand : Result);
2721 } else if (nargs==3) {
2722 assembly_operand o1 = ET[i].value;
2723 assembly_operand o2 = ET[ET[i].right].value;
2724 assembly_operand o3 = ET[ET[ET[i].right].right].value;
2725 assembleg_call_3(AO2, o1, o2, o3, void_flag ? zero_operand : Result);
2730 if (ET[i].value.type == LOCALVAR_OT
2731 && ET[i].value.value == 0) {
2735 assembleg_store(stack_pointer, ET[i].value);
2742 if (onstack && offstack)
2743 error("*** Function call cannot be generated with mixed arguments ***");
2745 error("*** Function call cannot be generated with more than one nonstack argument ***");
2749 set_constant_ot(&AO);
2752 assembleg_3(call_gc, AO2, AO, zero_operand);
2754 assembleg_3(call_gc, AO2, AO, Result);
2756 } /* else nargs>=4 */
2757 } /* DoFunctionCall: */
2762 printf("** Trouble op = %d i.e. '%s' **\n",
2763 opnum, operators[opnum].description);
2764 compiler_error("Expr code gen: Can't generate yet");
2768 ET[n].value = Result;
2774 if (ET[n].to_expression)
2777 warning("Logical expression has no side-effects");
2778 if (ET[n].true_label != -1)
2779 assemble_label_no(ET[n].true_label);
2781 assemble_label_no(ET[n].false_label);
2783 else if (ET[n].true_label != -1)
2784 { assemblez_1(push_zc, zero_operand);
2785 assemblez_jump(next_label++);
2786 assemble_label_no(ET[n].true_label);
2787 assemblez_1(push_zc, one_operand);
2788 assemble_label_no(next_label-1);
2791 { assemblez_1(push_zc, one_operand);
2792 assemblez_jump(next_label++);
2793 assemble_label_no(ET[n].false_label);
2794 assemblez_1(push_zc, zero_operand);
2795 assemble_label_no(next_label-1);
2797 ET[n].value = stack_pointer;
2800 if (ET[n].label_after != -1)
2801 assemble_label_no(ET[n].label_after);
2806 if (ET[n].to_expression)
2809 warning("Logical expression has no side-effects");
2810 if (ET[n].true_label != -1)
2811 assemble_label_no(ET[n].true_label);
2813 assemble_label_no(ET[n].false_label);
2815 else if (ET[n].true_label != -1)
2816 { assembleg_store(stack_pointer, zero_operand);
2817 assembleg_jump(next_label++);
2818 assemble_label_no(ET[n].true_label);
2819 assembleg_store(stack_pointer, one_operand);
2820 assemble_label_no(next_label-1);
2823 { assembleg_store(stack_pointer, one_operand);
2824 assembleg_jump(next_label++);
2825 assemble_label_no(ET[n].false_label);
2826 assembleg_store(stack_pointer, zero_operand);
2827 assemble_label_no(next_label-1);
2829 ET[n].value = stack_pointer;
2832 if (ET[n].label_after != -1)
2833 assemble_label_no(ET[n].label_after);
2840 assembly_operand code_generate(assembly_operand AO, int context, int label)
2842 /* Used in three contexts: VOID_CONTEXT, CONDITION_CONTEXT and
2845 If CONDITION_CONTEXT, then compile code branching to label number
2846 "label" if the condition is false: there's no return value.
2847 (Except that if label is -3 or -4 (internal codes for rfalse and
2848 rtrue rather than branch) then this is for branching when the
2849 condition is true. This is used for optimising code generation
2850 for "if" statements.)
2852 Otherwise return the assembly operand containing the result
2853 (probably the stack pointer variable but not necessarily:
2854 e.g. is would be short constant 2 from the expression "j++, 2") */
2858 if (AO.type != EXPRESSION_OT)
2860 { case VOID_CONTEXT:
2861 value_in_void_context(AO);
2862 AO.type = OMITTED_OT;
2865 case CONDITION_CONTEXT:
2867 if (label < -2) assemblez_1_branch(jz_zc, AO, label, FALSE);
2868 else assemblez_1_branch(jz_zc, AO, label, TRUE);
2872 assembleg_1_branch(jnz_gc, AO, label);
2874 assembleg_1_branch(jz_gc, AO, label);
2876 AO.type = OMITTED_OT;
2883 if (expr_trace_level >= 2)
2884 { printf("Raw parse tree:\n"); show_tree(AO, FALSE);
2887 if (context == CONDITION_CONTEXT)
2888 { if (label < -2) annotate_for_conditions(AO.value, label, -1);
2889 else annotate_for_conditions(AO.value, -1, label);
2891 else annotate_for_conditions(AO.value, -1, -1);
2893 if (expr_trace_level >= 1)
2894 { printf("Code generation for expression in ");
2896 { case VOID_CONTEXT: printf("void"); break;
2897 case CONDITION_CONTEXT: printf("condition"); break;
2898 case QUANTITY_CONTEXT: printf("quantity"); break;
2899 case ASSEMBLY_CONTEXT: printf("assembly"); break;
2900 case ARRAY_CONTEXT: printf("array initialisation"); break;
2901 default: printf("* ILLEGAL *"); break;
2903 printf(" context with annotated tree:\n");
2904 show_tree(AO, TRUE);
2907 generate_code_from(AO.value, (context==VOID_CONTEXT));
2908 return ET[AO.value].value;
2911 /* ========================================================================= */
2912 /* Data structure management routines */
2913 /* ------------------------------------------------------------------------- */
2915 extern void init_expressc_vars(void)
2919 extern void expressc_begin_pass(void)
2923 extern void expressc_allocate_arrays(void)
2927 extern void expressc_free_arrays(void)
2931 /* ========================================================================= */