1 /* ------------------------------------------------------------------------- */
2 /* "expressc" : The expression code generator */
4 /* Part of Inform 6.33 */
5 /* copyright (c) Graham Nelson 1993 - 2014 */
7 /* ------------------------------------------------------------------------- */
11 int vivc_flag
; /* TRUE if the last code-generated
12 expression produced a "value in void
13 context" error: used to help the syntax
14 analyser recover from unknown-keyword
15 errors, since unknown keywords are
16 treated as yet-to-be-defined constants
17 and thus as values in void context */
19 /* These data structures are global, because they're too useful to be
21 assembly_operand stack_pointer
, temp_var1
, temp_var2
, temp_var3
,
22 temp_var4
, zero_operand
, one_operand
, two_operand
, three_operand
,
23 four_operand
, valueless_operand
;
25 static void make_operands(void)
28 stack_pointer
.type
= VARIABLE_OT
;
29 stack_pointer
.value
= 0;
30 stack_pointer
.marker
= 0;
31 temp_var1
.type
= VARIABLE_OT
;
32 temp_var1
.value
= 255;
34 temp_var2
.type
= VARIABLE_OT
;
35 temp_var2
.value
= 254;
37 temp_var3
.type
= VARIABLE_OT
;
38 temp_var3
.value
= 253;
40 temp_var4
.type
= VARIABLE_OT
;
41 temp_var4
.value
= 252;
43 zero_operand
.type
= SHORT_CONSTANT_OT
;
44 zero_operand
.value
= 0;
45 zero_operand
.marker
= 0;
46 one_operand
.type
= SHORT_CONSTANT_OT
;
47 one_operand
.value
= 1;
48 one_operand
.marker
= 0;
49 two_operand
.type
= SHORT_CONSTANT_OT
;
50 two_operand
.value
= 2;
51 two_operand
.marker
= 0;
52 three_operand
.type
= SHORT_CONSTANT_OT
;
53 three_operand
.value
= 3;
54 three_operand
.marker
= 0;
55 four_operand
.type
= SHORT_CONSTANT_OT
;
56 four_operand
.value
= 4;
57 four_operand
.marker
= 0;
58 valueless_operand
.type
= OMITTED_OT
;
59 valueless_operand
.value
= 0;
60 valueless_operand
.marker
= 0;
63 stack_pointer
.type
= LOCALVAR_OT
;
64 stack_pointer
.value
= 0;
65 stack_pointer
.marker
= 0;
66 temp_var1
.type
= GLOBALVAR_OT
;
67 temp_var1
.value
= MAX_LOCAL_VARIABLES
+0;
69 temp_var2
.type
= GLOBALVAR_OT
;
70 temp_var2
.value
= MAX_LOCAL_VARIABLES
+1;
72 temp_var3
.type
= GLOBALVAR_OT
;
73 temp_var3
.value
= MAX_LOCAL_VARIABLES
+2;
75 temp_var4
.type
= GLOBALVAR_OT
;
76 temp_var4
.value
= MAX_LOCAL_VARIABLES
+3;
78 zero_operand
.type
= ZEROCONSTANT_OT
;
79 zero_operand
.value
= 0;
80 zero_operand
.marker
= 0;
81 one_operand
.type
= BYTECONSTANT_OT
;
82 one_operand
.value
= 1;
83 one_operand
.marker
= 0;
84 two_operand
.type
= BYTECONSTANT_OT
;
85 two_operand
.value
= 2;
86 two_operand
.marker
= 0;
87 three_operand
.type
= BYTECONSTANT_OT
;
88 three_operand
.value
= 3;
89 three_operand
.marker
= 0;
90 four_operand
.type
= BYTECONSTANT_OT
;
91 four_operand
.value
= 4;
92 four_operand
.marker
= 0;
93 valueless_operand
.type
= OMITTED_OT
;
94 valueless_operand
.value
= 0;
95 valueless_operand
.marker
= 0;
99 /* ------------------------------------------------------------------------- */
100 /* The table of conditionals. (Only used in Glulx) */
102 #define ZERO_CC (500)
103 #define EQUAL_CC (502)
108 #define OFCLASS_CC (512)
109 #define PROVIDES_CC (514)
111 #define FIRST_CC (500)
112 #define LAST_CC (515)
114 typedef struct condclass_s
{
115 int32 posform
; /* Opcode for the conditional in its positive form. */
116 int32 negform
; /* Opcode for the conditional in its negated form. */
119 condclass condclasses
[] = {
130 /* ------------------------------------------------------------------------- */
131 /* The table of operators.
133 The ordering in this table is not significant except that it must match
134 the #define's in "header.h" */
136 operator operators
[NUM_OPERATORS
] =
138 /* ------------------------ */
140 /* ------------------------ */
142 { 0, SEP_TT
, COMMA_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0, "comma" },
144 /* ------------------------ */
146 /* ------------------------ */
148 { 1, SEP_TT
, SETEQUALS_SEP
, IN_U
, R_A
, 1, -1, -1, 1, 0,
149 "assignment operator '='" },
151 /* ------------------------ */
152 /* Level 2: ~~ && || */
153 /* ------------------------ */
155 { 2, SEP_TT
, LOGAND_SEP
, IN_U
, L_A
, 0, -1, -1, 0, LOGOR_OP
,
156 "logical conjunction '&&'" },
157 { 2, SEP_TT
, LOGOR_SEP
, IN_U
, L_A
, 0, -1, -1, 0, LOGAND_OP
,
158 "logical disjunction '||'" },
159 { 2, SEP_TT
, LOGNOT_SEP
, PRE_U
, R_A
, 0, -1, -1, 0, LOGNOT_OP
,
160 "logical negation '~~'" },
162 /* ------------------------ */
169 /* ------------------------ */
171 { 3, -1, -1, -1, 0, 0, 400 + jz_zc
, ZERO_CC
+0, 0, NONZERO_OP
,
172 "expression used as condition then negated" },
173 { 3, -1, -1, -1, 0, 0, 800 + jz_zc
, ZERO_CC
+1, 0, ZERO_OP
,
174 "expression used as condition" },
175 { 3, SEP_TT
, CONDEQUALS_SEP
, IN_U
, 0, 0, 400 + je_zc
, EQUAL_CC
+0, 0, NOTEQUAL_OP
,
177 { 3, SEP_TT
, NOTEQUAL_SEP
, IN_U
, 0, 0, 800 + je_zc
, EQUAL_CC
+1, 0, CONDEQUALS_OP
,
179 { 3, SEP_TT
, GE_SEP
, IN_U
, 0, 0, 800 + jl_zc
, LT_CC
+1, 0, LESS_OP
,
181 { 3, SEP_TT
, GREATER_SEP
, IN_U
, 0, 0, 400 + jg_zc
, GT_CC
+0, 0, LE_OP
,
183 { 3, SEP_TT
, LE_SEP
, IN_U
, 0, 0, 800 + jg_zc
, GT_CC
+1, 0, GREATER_OP
,
185 { 3, SEP_TT
, LESS_SEP
, IN_U
, 0, 0, 400 + jl_zc
, LT_CC
+0, 0, GE_OP
,
187 { 3, CND_TT
, HAS_COND
, IN_U
, 0, 0, 400 + test_attr_zc
, HAS_CC
+0, 0, HASNT_OP
,
189 { 3, CND_TT
, HASNT_COND
, IN_U
, 0, 0, 800 + test_attr_zc
, HAS_CC
+1, 0, HAS_OP
,
190 "'hasnt' condition" },
191 { 3, CND_TT
, IN_COND
, IN_U
, 0, 0, 400 + jin_zc
, IN_CC
+0, 0, NOTIN_OP
,
193 { 3, CND_TT
, NOTIN_COND
, IN_U
, 0, 0, 800 + jin_zc
, IN_CC
+1, 0, IN_OP
,
194 "'notin' condition" },
195 { 3, CND_TT
, OFCLASS_COND
, IN_U
, 0, 0, 600, OFCLASS_CC
+0, 0, NOTOFCLASS_OP
,
196 "'ofclass' condition" },
197 { 3, CND_TT
, PROVIDES_COND
, IN_U
, 0, 0, 601, PROVIDES_CC
+0, 0, NOTPROVIDES_OP
,
198 "'provides' condition" },
199 { 3, -1, -1, -1, 0, 0, 1000, OFCLASS_CC
+1, 0, OFCLASS_OP
,
200 "negated 'ofclass' condition" },
201 { 3, -1, -1, -1, 0, 0, 1001, PROVIDES_CC
+1, 0, PROVIDES_OP
,
202 "negated 'provides' condition" },
204 /* ------------------------ */
206 /* ------------------------ */
208 { 4, CND_TT
, OR_COND
, IN_U
, L_A
, 0, -1, -1, 0, 0, "'or'" },
210 /* ------------------------ */
211 /* Level 5: + binary - */
212 /* ------------------------ */
214 { 5, SEP_TT
, PLUS_SEP
, IN_U
, L_A
, 0, add_zc
, add_gc
, 0, 0, "'+'" },
215 { 5, SEP_TT
, MINUS_SEP
, IN_U
, L_A
, 0, sub_zc
, sub_gc
, 0, 0, "'-'" },
217 /* ------------------------ */
220 /* ------------------------ */
222 { 6, SEP_TT
, TIMES_SEP
, IN_U
, L_A
, 0, mul_zc
, mul_gc
, 0, 0, "'*'" },
223 { 6, SEP_TT
, DIVIDE_SEP
, IN_U
, L_A
, 0, div_zc
, div_gc
, 0, 0, "'/'" },
224 { 6, SEP_TT
, REMAINDER_SEP
, IN_U
, L_A
, 0, mod_zc
, mod_gc
, 0, 0,
225 "remainder after division '%'" },
226 { 6, SEP_TT
, ARTAND_SEP
, IN_U
, L_A
, 0, and_zc
, bitand_gc
, 0, 0,
228 { 6, SEP_TT
, ARTOR_SEP
, IN_U
, L_A
, 0, or_zc
, bitor_gc
, 0, 0,
230 { 6, SEP_TT
, ARTNOT_SEP
, PRE_U
, R_A
, 0, -1, bitnot_gc
, 0, 0,
233 /* ------------------------ */
234 /* Level 7: -> --> */
235 /* ------------------------ */
237 { 7, SEP_TT
, ARROW_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
238 "byte array operator '->'" },
239 { 7, SEP_TT
, DARROW_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
240 "word array operator '-->'" },
242 /* ------------------------ */
243 /* Level 8: unary - */
244 /* ------------------------ */
246 { 8, SEP_TT
, UNARY_MINUS_SEP
, PRE_U
, R_A
, 0, -1, neg_gc
, 0, 0,
249 /* ------------------------ */
251 /* (prefix or postfix) */
252 /* ------------------------ */
254 { 9, SEP_TT
, INC_SEP
, PRE_U
, R_A
, 2, -1, -1, 1, 0,
255 "pre-increment operator '++'" },
256 { 9, SEP_TT
, POST_INC_SEP
, POST_U
, R_A
, 3, -1, -1, 1, 0,
257 "post-increment operator '++'" },
258 { 9, SEP_TT
, DEC_SEP
, PRE_U
, R_A
, 4, -1, -1, 1, 0,
259 "pre-decrement operator '--'" },
260 { 9, SEP_TT
, POST_DEC_SEP
, POST_U
, R_A
, 5, -1, -1, 1, 0,
261 "post-decrement operator '--'" },
263 /* ------------------------ */
264 /* Level 10: .& .# */
266 /* ------------------------ */
268 {10, SEP_TT
, PROPADD_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
269 "property address operator '.&'" },
270 {10, SEP_TT
, PROPNUM_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
271 "property length operator '.#'" },
272 {10, SEP_TT
, MPROPADD_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
273 "individual property address operator '..&'" },
274 {10, SEP_TT
, MPROPNUM_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
275 "individual property length operator '..#'" },
277 /* ------------------------ */
278 /* Level 11: function ( */
279 /* ------------------------ */
281 {11, SEP_TT
, OPENB_SEP
, IN_U
, L_A
, 0, -1, -1, 1, 0,
284 /* ------------------------ */
286 /* ------------------------ */
288 {12, SEP_TT
, MESSAGE_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
289 "individual property selector '..'" },
290 {12, SEP_TT
, PROPERTY_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
291 "property selector '.'" },
293 /* ------------------------ */
295 /* ------------------------ */
297 {13, SEP_TT
, SUPERCLASS_SEP
, IN_U
, L_A
, 0, -1, -1, 0, 0,
298 "superclass operator '::'" },
300 /* ------------------------ */
301 /* Miscellaneous operators */
302 /* generated at lvalue */
304 /* ------------------------ */
306 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -> = */
307 "byte array entry assignment" },
308 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* --> = */
309 "word array entry assignment" },
310 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* .. = */
311 "individual property assignment" },
312 { 1, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* . = */
313 "common property assignment" },
315 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ -> */
316 "byte array entry preincrement" },
317 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ --> */
318 "word array entry preincrement" },
319 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ .. */
320 "individual property preincrement" },
321 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* ++ . */
322 "common property preincrement" },
324 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- -> */
325 "byte array entry predecrement" },
326 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- --> */
327 "word array entry predecrement" },
328 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- .. */
329 "individual property predecrement" },
330 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -- . */
331 "common property predecrement" },
333 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -> ++ */
334 "byte array entry postincrement" },
335 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* --> ++ */
336 "word array entry postincrement" },
337 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* .. ++ */
338 "individual property postincrement" },
339 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* . ++ */
340 "common property postincrement" },
342 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* -> -- */
343 "byte array entry postdecrement" },
344 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* --> -- */
345 "word array entry postdecrement" },
346 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* .. -- */
347 "individual property postdecrement" },
348 { 9, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* . -- */
349 "common property postdecrement" },
351 {11, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* x.y(args) */
352 "call to common property" },
353 {11, -1, -1, -1, -1, 0, -1, -1, 1, 0, /* x..y(args) */
354 "call to individual property" },
356 /* ------------------------ */
357 /* And one Glulx-only op */
358 /* which just pushes its */
359 /* argument on the stack, */
361 /* ------------------------ */
363 {14, -1, -1, -1, -1, 0, -1, -1, 1, 0,
367 /* --- Condition annotater ------------------------------------------------- */
369 static void annotate_for_conditions(int n
, int a
, int b
)
370 { int i
, opnum
= ET
[n
].operator_number
;
372 ET
[n
].label_after
= -1;
373 ET
[n
].to_expression
= FALSE
;
374 ET
[n
].true_label
= a
;
375 ET
[n
].false_label
= b
;
377 if (ET
[n
].down
== -1) return;
379 if ((operators
[opnum
].precedence
== 2)
380 || (operators
[opnum
].precedence
== 3))
381 { if ((a
== -1) && (b
== -1))
382 { if (opnum
== LOGAND_OP
)
384 ET
[n
].false_label
= b
;
385 ET
[n
].to_expression
= TRUE
;
389 ET
[n
].true_label
= a
;
390 ET
[n
].to_expression
= TRUE
;
399 ET
[n
].false_label
= b
;
400 ET
[n
].label_after
= b
;
402 annotate_for_conditions(ET
[n
].down
, -1, b
);
403 if (b
== ET
[n
].label_after
)
404 annotate_for_conditions(ET
[ET
[n
].down
].right
, a
, -1);
405 else annotate_for_conditions(ET
[ET
[n
].down
].right
, a
, b
);
410 ET
[n
].true_label
= a
;
411 ET
[n
].label_after
= a
;
413 annotate_for_conditions(ET
[n
].down
, a
, -1);
414 if (a
== ET
[n
].label_after
)
415 annotate_for_conditions(ET
[ET
[n
].down
].right
, -1, b
);
416 else annotate_for_conditions(ET
[ET
[n
].down
].right
, a
, b
);
422 { annotate_for_conditions(i
, -1, -1); i
= ET
[i
].right
; }
425 /* --- Code generator ------------------------------------------------------ */
427 static void value_in_void_context_z(assembly_operand AO
)
433 { case LONG_CONSTANT_OT
:
434 case SHORT_CONSTANT_OT
:
436 if (AO
.marker
== SYMBOL_MV
)
437 t
= (char *) (symbs
[AO
.value
]);
440 t
= variable_name(AO
.value
);
443 compiler_error("Unable to print value in void context");
449 if (strcmp(t
, "print_paddr") == 0)
450 obsolete_warning("ignoring 'print_paddr': use 'print (string)' instead");
452 if (strcmp(t
, "print_addr") == 0)
453 obsolete_warning("ignoring 'print_addr': use 'print (address)' instead");
455 if (strcmp(t
, "print_char") == 0)
456 obsolete_warning("ignoring 'print_char': use 'print (char)' instead");
458 ebf_error("expression with side-effects", t
);
461 static void write_result_z(assembly_operand to
, assembly_operand from
)
462 { if (to
.value
== from
.value
) return;
463 if (to
.value
== 0) assemblez_1(push_zc
, from
);
464 else assemblez_store(to
, from
);
467 static void pop_zm_stack(void)
468 { assembly_operand st
;
469 if (version_number
< 5) assemblez_0(pop_zc
);
471 { st
.marker
= 0; st
.type
= VARIABLE_OT
; st
.value
= 0;
472 assemblez_1_branch(jz_zc
, st
, -2, TRUE
);
476 static void access_memory_z(int oc
, assembly_operand AO1
, assembly_operand AO2
,
477 assembly_operand AO3
)
480 assembly_operand zero_ao
, max_ao
, size_ao
, en_ao
, type_ao
, an_ao
,
482 int x
, y
, byte_flag
, read_flag
, from_module
;
484 if (AO1
.marker
== ARRAY_MV
)
486 if ((oc
== loadb_zc
) || (oc
== storeb_zc
)) byte_flag
=TRUE
;
487 else byte_flag
= FALSE
;
488 if ((oc
== loadb_zc
) || (oc
== loadw_zc
)) read_flag
=TRUE
;
489 else read_flag
= FALSE
;
491 zero_ao
.type
= SHORT_CONSTANT_OT
;
492 zero_ao
.value
= 0; zero_ao
.marker
= 0;
494 size_ao
= zero_ao
; size_ao
.value
= -1;
495 for (x
=0; x
<no_arrays
; x
++)
496 { if (AO1
.value
== svals
[array_symbols
[x
]])
497 { size_ao
.value
= array_sizes
[x
]; y
=x
;
500 if (size_ao
.value
==-1)
504 type_ao
= zero_ao
; type_ao
.value
= array_types
[y
];
506 if ((!is_systemfile()))
509 if ((array_types
[y
] == WORD_ARRAY
)
510 || (array_types
[y
] == TABLE_ARRAY
))
511 warning("Using '->' to access a --> or table array");
515 if ((array_types
[y
] == BYTE_ARRAY
)
516 || (array_types
[y
] == STRING_ARRAY
))
517 warning("Using '-->' to access a -> or string array");
524 if ((!runtime_error_checking_switch
) || (veneer_mode
))
525 { if ((oc
== loadb_zc
) || (oc
== loadw_zc
))
526 assemblez_2_to(oc
, AO1
, AO2
, AO3
);
528 assemblez_3(oc
, AO1
, AO2
, AO3
);
532 /* If we recognise AO1 as arising textually from a declared
533 array, we can check bounds explicitly. */
535 if ((AO1
.marker
== ARRAY_MV
) && (!from_module
))
537 int passed_label
= next_label
++, failed_label
= next_label
++,
538 final_label
= next_label
++;
539 /* Calculate the largest permitted array entry + 1
540 Here "size_ao.value" = largest permitted entry of its own kind */
544 && ((array_types
[y
] == WORD_ARRAY
)
545 || (array_types
[y
] == TABLE_ARRAY
)))
546 { max_ao
.value
= size_ao
.value
*2 + 1;
550 && ((array_types
[y
] == BYTE_ARRAY
)
551 || (array_types
[y
] == STRING_ARRAY
)
552 || (array_types
[y
] == BUFFER_ARRAY
)))
553 { if ((size_ao
.value
% 2) == 0)
554 max_ao
.value
= size_ao
.value
/2 - 1;
555 else max_ao
.value
= (size_ao
.value
-1)/2;
560 if (size_ao
.value
>= 256) size_ao
.type
= LONG_CONSTANT_OT
;
561 if (max_ao
.value
>= 256) max_ao
.type
= LONG_CONSTANT_OT
;
563 /* Can't write to the size entry in a string or table */
564 if (((array_types
[y
] == STRING_ARRAY
)
565 || (array_types
[y
] == TABLE_ARRAY
))
567 { if ((array_types
[y
] == TABLE_ARRAY
) && byte_flag
)
569 else zero_ao
.value
= 1;
572 en_ao
= zero_ao
; en_ao
.value
= ABOUNDS_RTE
;
573 switch(oc
) { case loadb_zc
: en_ao
.value
= ABOUNDS_RTE
; break;
574 case loadw_zc
: en_ao
.value
= ABOUNDS_RTE
+1; break;
575 case storeb_zc
: en_ao
.value
= ABOUNDS_RTE
+2; break;
576 case storew_zc
: en_ao
.value
= ABOUNDS_RTE
+3; break; }
579 if ((AO2
.type
== VARIABLE_OT
)&&(AO2
.value
== 0))
580 { assemblez_store(temp_var2
, AO2
);
581 assemblez_store(AO2
, temp_var2
);
582 index_ao
= temp_var2
;
584 assemblez_2_branch(jl_zc
, index_ao
, zero_ao
, failed_label
, TRUE
);
585 assemblez_2_branch(jl_zc
, index_ao
, max_ao
, passed_label
, TRUE
);
586 assemble_label_no(failed_label
);
587 an_ao
= zero_ao
; an_ao
.value
= y
;
588 assemblez_6(call_vn2_zc
, veneer_routine(RT__Err_VR
), en_ao
,
589 index_ao
, size_ao
, type_ao
, an_ao
);
591 /* We have to clear any of AO1, AO2, AO3 off the stack if
592 present, so that we can achieve the same effect on the stack
593 that executing the opcode would have had */
595 if ((AO1
.type
== VARIABLE_OT
) && (AO1
.value
== 0)) pop_zm_stack();
596 if ((AO2
.type
== VARIABLE_OT
) && (AO2
.value
== 0)) pop_zm_stack();
597 if ((AO3
.type
== VARIABLE_OT
) && (AO3
.value
== 0))
598 { if ((oc
== loadb_zc
) || (oc
== loadw_zc
))
599 { assemblez_store(AO3
, zero_ao
);
603 assemblez_jump(final_label
);
605 assemble_label_no(passed_label
);
606 if ((oc
== loadb_zc
) || (oc
== loadw_zc
))
607 assemblez_2_to(oc
, AO1
, AO2
, AO3
);
609 assemblez_3(oc
, AO1
, AO2
, AO3
);
610 assemble_label_no(final_label
);
614 /* Otherwise, compile a call to the veneer which verifies that
615 the proposed read/write is within dynamic Z-machine memory. */
617 switch(oc
) { case loadb_zc
: vr
= RT__ChLDB_VR
; break;
618 case loadw_zc
: vr
= RT__ChLDW_VR
; break;
619 case storeb_zc
: vr
= RT__ChSTB_VR
; break;
620 case storew_zc
: vr
= RT__ChSTW_VR
; break; }
622 if ((oc
== loadb_zc
) || (oc
== loadw_zc
))
623 assemblez_3_to(call_vs_zc
, veneer_routine(vr
), AO1
, AO2
, AO3
);
625 assemblez_4(call_vn_zc
, veneer_routine(vr
), AO1
, AO2
, AO3
);
628 static assembly_operand
check_nonzero_at_runtime_z(assembly_operand AO1
,
629 int error_label
, int rte_number
)
630 { assembly_operand AO2
, AO3
;
631 int check_sp
= FALSE
, passed_label
, failed_label
, last_label
;
632 if (veneer_mode
) return AO1
;
634 /* Assemble to code to check that the operand AO1 is ofclass Object:
635 if it is, execution should continue and the stack should be
636 unchanged. Otherwise, call the veneer's run-time-error routine
637 with the given error number, and then: if the label isn't -1,
638 switch execution to this label, with the value popped from
639 the stack if it was on the stack in the first place;
640 if the label is -1, either replace the top of the stack with
641 the constant 2, or return the operand (short constant) 2.
643 The point of 2 is that object 2 is the class-object Object
644 and therefore has no parent, child or sibling, so that the
645 built-in tree functions will safely return 0 on this object. */
647 /* Sometimes we can already see that the object number is valid. */
648 if (((AO1
.type
== LONG_CONSTANT_OT
) || (AO1
.type
== SHORT_CONSTANT_OT
))
649 && (AO1
.marker
== 0) && (AO1
.value
>= 1) && (AO1
.value
< no_objects
))
652 passed_label
= next_label
++;
653 failed_label
= next_label
++;
654 AO2
.type
= LONG_CONSTANT_OT
;
655 AO2
.value
= actual_largest_object_SC
;
656 AO2
.marker
= INCON_MV
;
657 AO3
.value
= 5; AO3
.type
= SHORT_CONSTANT_OT
; AO3
.marker
= 0;
659 if ((rte_number
== IN_RTE
) || (rte_number
== HAS_RTE
)
660 || (rte_number
== PROPERTY_RTE
) || (rte_number
== PROP_NUM_RTE
)
661 || (rte_number
== PROP_ADD_RTE
))
662 { /* Allow classes */
664 if ((AO1
.type
== VARIABLE_OT
) && (AO1
.value
== 0))
665 { /* That is, if AO1 is the stack pointer */
667 assemblez_store(temp_var2
, AO1
);
668 assemblez_store(AO1
, temp_var2
);
669 assemblez_2_branch(jg_zc
, AO3
, temp_var2
, failed_label
, TRUE
);
670 assemblez_2_branch(jg_zc
, temp_var2
, AO2
, passed_label
, FALSE
);
673 { assemblez_2_branch(jg_zc
, AO3
, AO1
, failed_label
, TRUE
);
674 assemblez_2_branch(jg_zc
, AO1
, AO2
, passed_label
, FALSE
);
678 { if ((AO1
.type
== VARIABLE_OT
) && (AO1
.value
== 0))
679 { /* That is, if AO1 is the stack pointer */
681 assemblez_store(temp_var2
, AO1
);
682 assemblez_store(AO1
, temp_var2
);
683 assemblez_2_branch(jg_zc
, AO3
, temp_var2
, failed_label
, TRUE
);
684 assemblez_2_branch(jg_zc
, temp_var2
, AO2
, failed_label
, TRUE
);
686 assemblez_2_branch(jin_zc
, temp_var2
, AO3
, passed_label
, FALSE
);
689 { assemblez_2_branch(jg_zc
, AO3
, AO1
, failed_label
, TRUE
);
690 assemblez_2_branch(jg_zc
, AO1
, AO2
, failed_label
, TRUE
);
692 assemblez_2_branch(jin_zc
, AO1
, AO3
, passed_label
, FALSE
);
696 assemble_label_no(failed_label
);
697 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= rte_number
; AO2
.marker
= 0;
698 if (version_number
>= 5)
699 assemblez_3(call_vn_zc
, veneer_routine(RT__Err_VR
), AO2
, AO1
);
701 assemblez_3_to(call_zc
, veneer_routine(RT__Err_VR
), AO2
, AO1
, temp_var2
);
703 if (error_label
!= -1)
704 { /* Jump to the error label */
705 if (error_label
== -3) assemblez_0(rfalse_zc
);
706 else if (error_label
== -4) assemblez_0(rtrue_zc
);
707 else assemblez_jump(error_label
);
711 { /* Push the short constant 2 */
712 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= 2; AO2
.marker
= 0;
713 assemblez_store(AO1
, AO2
);
716 { /* Store either short constant 2 or the operand's value in
717 the temporary variable */
718 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= 2; AO2
.marker
= 0;
719 AO3
= temp_var2
; assemblez_store(AO3
, AO2
);
720 last_label
= next_label
++;
721 assemblez_jump(last_label
);
722 assemble_label_no(passed_label
);
723 assemblez_store(AO3
, AO1
);
724 assemble_label_no(last_label
);
728 assemble_label_no(passed_label
);
732 static void compile_conditional_z(int oc
,
733 assembly_operand AO1
, assembly_operand AO2
, int label
, int flag
)
734 { assembly_operand AO3
; int the_zc
, error_label
= label
,
735 va_flag
= FALSE
, va_label
;
740 { if ((runtime_error_checking_switch
) && (oc
== jin_zc
))
741 { if (flag
) error_label
= next_label
++;
742 AO1
= check_nonzero_at_runtime(AO1
, error_label
, IN_RTE
);
744 if ((runtime_error_checking_switch
) && (oc
== test_attr_zc
))
745 { if (flag
) error_label
= next_label
++;
746 AO1
= check_nonzero_at_runtime(AO1
, error_label
, HAS_RTE
);
748 { case SHORT_CONSTANT_OT
:
749 case LONG_CONSTANT_OT
:
751 { if ((AO2
.value
< 0) || (AO2
.value
> 47))
752 error("'has'/'hasnt' applied to illegal attribute number");
756 { int pa_label
= next_label
++, fa_label
= next_label
++;
757 assembly_operand en_ao
, zero_ao
, max_ao
;
758 assemblez_store(temp_var1
, AO1
);
759 if ((AO1
.type
== VARIABLE_OT
)&&(AO1
.value
== 0))
760 assemblez_store(AO1
, temp_var1
);
761 assemblez_store(temp_var2
, AO2
);
762 if ((AO2
.type
== VARIABLE_OT
)&&(AO2
.value
== 0))
763 assemblez_store(AO2
, temp_var2
);
764 zero_ao
.type
= SHORT_CONSTANT_OT
; zero_ao
.marker
= 0;
765 zero_ao
.value
= 0; max_ao
= zero_ao
; max_ao
.value
= 48;
766 assemblez_2_branch(jl_zc
,temp_var2
,zero_ao
,fa_label
,TRUE
);
767 assemblez_2_branch(jl_zc
,temp_var2
,max_ao
,pa_label
,TRUE
);
768 assemble_label_no(fa_label
);
769 en_ao
= zero_ao
; en_ao
.value
= 19;
770 assemblez_4(call_vn_zc
, veneer_routine(RT__Err_VR
),
771 en_ao
, temp_var1
, temp_var2
);
772 va_flag
= TRUE
; va_label
= next_label
++;
773 assemblez_jump(va_label
);
774 assemble_label_no(pa_label
);
778 assemblez_2_branch(oc
, AO1
, AO2
, label
, flag
);
779 if (error_label
!= label
) assemble_label_no(error_label
);
780 if (va_flag
) assemble_label_no(va_label
);
784 AO3
.type
= VARIABLE_OT
; AO3
.value
= 0; AO3
.marker
= 0;
786 the_zc
= (version_number
== 3)?call_zc
:call_vs_zc
;
788 assemblez_3_to(the_zc
, veneer_routine(OP__Pr_VR
), AO1
, AO2
, AO3
);
790 assemblez_3_to(the_zc
, veneer_routine(OC__Cl_VR
), AO1
, AO2
, AO3
);
792 assemblez_1_branch(jz_zc
, AO3
, label
, !flag
);
795 static void value_in_void_context_g(assembly_operand AO
)
802 case HALFCONSTANT_OT
:
803 case BYTECONSTANT_OT
:
804 case ZEROCONSTANT_OT
:
806 if (AO
.marker
== SYMBOL_MV
)
807 t
= (char *) (symbs
[AO
.value
]);
811 t
= variable_name(AO
.value
);
814 compiler_error("Unable to print value in void context");
820 ebf_error("expression with side-effects", t
);
823 static void write_result_g(assembly_operand to
, assembly_operand from
)
824 { if (to
.value
== from
.value
&& to
.type
== from
.type
) return;
825 assembleg_store(to
, from
);
828 static void access_memory_g(int oc
, assembly_operand AO1
, assembly_operand AO2
,
829 assembly_operand AO3
)
831 int data_len
, read_flag
;
832 assembly_operand zero_ao
, max_ao
, size_ao
, en_ao
, type_ao
, an_ao
,
834 int passed_label
, failed_label
, final_label
, x
, y
;
836 if ((oc
== aloadb_gc
) || (oc
== astoreb_gc
)) data_len
= 1;
837 else if ((oc
== aloads_gc
) || (oc
== astores_gc
)) data_len
= 2;
840 if ((oc
== aloadb_gc
) || (oc
== aloads_gc
) || (oc
== aload_gc
))
845 if (AO1
.marker
== ARRAY_MV
)
847 zero_ao
.value
= 0; zero_ao
.marker
= 0;
849 size_ao
= zero_ao
; size_ao
.value
= -1;
850 for (x
=0; x
<no_arrays
; x
++)
851 { if (AO1
.value
== svals
[array_symbols
[x
]])
852 { size_ao
.value
= array_sizes
[x
]; y
=x
;
855 if (size_ao
.value
==-1) compiler_error("Array size can't be found");
857 type_ao
= zero_ao
; type_ao
.value
= array_types
[y
];
859 if ((!is_systemfile()))
862 if ((array_types
[y
] == WORD_ARRAY
)
863 || (array_types
[y
] == TABLE_ARRAY
))
864 warning("Using '->' to access a --> or table array");
868 if ((array_types
[y
] == BYTE_ARRAY
)
869 || (array_types
[y
] == STRING_ARRAY
))
870 warning("Using '-->' to access a -> or string array");
876 if ((!runtime_error_checking_switch
) || (veneer_mode
))
878 assembleg_3(oc
, AO1
, AO2
, AO3
);
882 /* If we recognise AO1 as arising textually from a declared
883 array, we can check bounds explicitly. */
885 if (AO1
.marker
== ARRAY_MV
)
887 /* Calculate the largest permitted array entry + 1
888 Here "size_ao.value" = largest permitted entry of its own kind */
891 && ((array_types
[y
] == WORD_ARRAY
)
892 || (array_types
[y
] == TABLE_ARRAY
)))
893 { max_ao
.value
= size_ao
.value
*4 + 3;
897 && ((array_types
[y
] == BYTE_ARRAY
)
898 || (array_types
[y
] == STRING_ARRAY
)
899 || (array_types
[y
] == BUFFER_ARRAY
)))
900 { max_ao
.value
= (size_ao
.value
-3)/4;
905 /* Can't write to the size entry in a string or table */
906 if (((array_types
[y
] == STRING_ARRAY
)
907 || (array_types
[y
] == TABLE_ARRAY
))
909 { if ((array_types
[y
] == TABLE_ARRAY
) && data_len
== 1)
911 else zero_ao
.value
= 1;
914 en_ao
= zero_ao
; en_ao
.value
= ABOUNDS_RTE
;
916 switch(oc
) { case aloadb_gc
: en_ao
.value
= ABOUNDS_RTE
; break;
917 case aload_gc
: en_ao
.value
= ABOUNDS_RTE
+1; break;
918 case astoreb_gc
: en_ao
.value
= ABOUNDS_RTE
+2; break;
919 case astore_gc
: en_ao
.value
= ABOUNDS_RTE
+3; break; }
921 set_constant_ot(&zero_ao
);
922 set_constant_ot(&size_ao
);
923 set_constant_ot(&max_ao
);
924 set_constant_ot(&type_ao
);
925 set_constant_ot(&en_ao
);
927 /* If we recognize A02 as a constant, we can do the test right
929 if (is_constant_ot(AO2
.type
) && AO2
.marker
== 0) {
930 if (AO2
.value
< zero_ao
.value
|| AO2
.value
>= max_ao
.value
) {
931 error("Array reference is out-of-bounds");
933 assembleg_3(oc
, AO1
, AO2
, AO3
);
937 passed_label
= next_label
++;
938 failed_label
= next_label
++;
939 final_label
= next_label
++;
942 if ((AO2
.type
== LOCALVAR_OT
)&&(AO2
.value
== 0))
943 { assembleg_store(temp_var2
, AO2
); /* ### could peek */
944 assembleg_store(AO2
, temp_var2
);
945 index_ao
= temp_var2
;
947 assembleg_2_branch(jlt_gc
, index_ao
, zero_ao
, failed_label
);
948 assembleg_2_branch(jlt_gc
, index_ao
, max_ao
, passed_label
);
949 assemble_label_no(failed_label
);
951 an_ao
= zero_ao
; an_ao
.value
= y
;
952 set_constant_ot(&an_ao
);
953 five_ao
= zero_ao
; five_ao
.value
= 5;
954 set_constant_ot(&five_ao
);
956 /* Call the error veneer routine. */
957 assembleg_store(stack_pointer
, an_ao
);
958 assembleg_store(stack_pointer
, type_ao
);
959 assembleg_store(stack_pointer
, size_ao
);
960 assembleg_store(stack_pointer
, index_ao
);
961 assembleg_store(stack_pointer
, en_ao
);
962 assembleg_3(call_gc
, veneer_routine(RT__Err_VR
),
963 five_ao
, zero_operand
);
965 /* We have to clear any of AO1, AO2, AO3 off the stack if
966 present, so that we can achieve the same effect on the stack
967 that executing the opcode would have had */
969 if ((AO1
.type
== LOCALVAR_OT
) && (AO1
.value
== 0))
970 assembleg_2(copy_gc
, stack_pointer
, zero_operand
);
971 if ((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0))
972 assembleg_2(copy_gc
, stack_pointer
, zero_operand
);
973 if ((AO3
.type
== LOCALVAR_OT
) && (AO3
.value
== 0))
974 { if ((oc
== aloadb_gc
) || (oc
== aload_gc
))
975 { assembleg_store(AO3
, zero_ao
);
977 else assembleg_2(copy_gc
, stack_pointer
, zero_operand
);
979 assembleg_jump(final_label
);
981 assemble_label_no(passed_label
);
982 assembleg_3(oc
, AO1
, AO2
, AO3
);
983 assemble_label_no(final_label
);
987 /* Otherwise, compile a call to the veneer which verifies that
988 the proposed read/write is within dynamic Z-machine memory. */
991 case aloadb_gc
: vr
= RT__ChLDB_VR
; break;
992 case aload_gc
: vr
= RT__ChLDW_VR
; break;
993 case astoreb_gc
: vr
= RT__ChSTB_VR
; break;
994 case astore_gc
: vr
= RT__ChSTW_VR
; break;
997 if ((oc
== aloadb_gc
) || (oc
== aload_gc
))
998 assembleg_call_2(veneer_routine(vr
), AO1
, AO2
, AO3
);
1000 assembleg_call_3(veneer_routine(vr
), AO1
, AO2
, AO3
, zero_operand
);
1003 static assembly_operand
check_nonzero_at_runtime_g(assembly_operand AO1
,
1004 int error_label
, int rte_number
)
1006 assembly_operand AO
, AO2
, AO3
;
1008 int check_sp
= FALSE
, passed_label
, failed_label
, last_label
;
1013 /* Assemble to code to check that the operand AO1 is ofclass Object:
1014 if it is, execution should continue and the stack should be
1015 unchanged. Otherwise, call the veneer's run-time-error routine
1016 with the given error number, and then: if the label isn't -1,
1017 switch execution to this label, with the value popped from
1018 the stack if it was on the stack in the first place;
1019 if the label is -1, either replace the top of the stack with
1020 the constant symbol (class-object) Object.
1022 The Object has no parent, child or sibling, so that the
1023 built-in tree functions will safely return 0 on this object. */
1025 /* Sometimes we can already see that the object number is valid. */
1026 if (AO1
.marker
== OBJECT_MV
&&
1027 ((AO1
.value
>= 1) && (AO1
.value
<= no_objects
))) {
1031 passed_label
= next_label
++;
1032 failed_label
= next_label
++;
1034 if ((AO1
.type
== LOCALVAR_OT
) && (AO1
.value
== 0) && (AO1
.marker
== 0)) {
1035 /* That is, if AO1 is the stack pointer */
1037 assembleg_store(temp_var2
, stack_pointer
);
1038 assembleg_store(stack_pointer
, temp_var2
);
1045 if ((rte_number
== IN_RTE
) || (rte_number
== HAS_RTE
)
1046 || (rte_number
== PROPERTY_RTE
) || (rte_number
== PROP_NUM_RTE
)
1047 || (rte_number
== PROP_ADD_RTE
)) {
1049 /* Test if zero... */
1050 assembleg_1_branch(jz_gc
, AO
, failed_label
);
1051 /* Test if first byte is 0x70... */
1052 assembleg_3(aloadb_gc
, AO
, zero_operand
, stack_pointer
);
1054 AO3
.value
= 0x70; /* type byte -- object */
1055 set_constant_ot(&AO3
);
1056 assembleg_2_branch(jeq_gc
, stack_pointer
, AO3
, passed_label
);
1059 /* Test if zero... */
1060 assembleg_1_branch(jz_gc
, AO
, failed_label
);
1061 /* Test if first byte is 0x70... */
1062 assembleg_3(aloadb_gc
, AO
, zero_operand
, stack_pointer
);
1064 AO3
.value
= 0x70; /* type byte -- object */
1065 set_constant_ot(&AO3
);
1066 assembleg_2_branch(jne_gc
, stack_pointer
, AO3
, failed_label
);
1067 /* Test if inside the "Class" object... */
1068 AO3
.type
= BYTECONSTANT_OT
;
1069 AO3
.value
= GOBJFIELD_PARENT();
1071 assembleg_3(aload_gc
, AO
, AO3
, stack_pointer
);
1072 ln
= symbol_index("Class", -1);
1073 AO3
.value
= svals
[ln
];
1074 AO3
.marker
= OBJECT_MV
;
1075 AO3
.type
= CONSTANT_OT
;
1076 assembleg_2_branch(jne_gc
, stack_pointer
, AO3
, passed_label
);
1079 assemble_label_no(failed_label
);
1081 AO2
.value
= rte_number
;
1082 set_constant_ot(&AO2
);
1083 assembleg_call_2(veneer_routine(RT__Err_VR
), AO2
, AO1
, zero_operand
);
1085 if (error_label
!= -1) {
1086 /* Jump to the error label */
1087 if (error_label
== -3) assembleg_1(return_gc
, zero_operand
);
1088 else if (error_label
== -4) assembleg_1(return_gc
, one_operand
);
1089 else assembleg_jump(error_label
);
1092 /* Build the symbol for "Object" */
1093 ln
= symbol_index("Object", -1);
1094 AO2
.value
= svals
[ln
];
1095 AO2
.marker
= OBJECT_MV
;
1096 AO2
.type
= CONSTANT_OT
;
1099 assembleg_store(AO1
, AO2
);
1102 /* Store either "Object" or the operand's value in the temporary
1104 assembleg_store(temp_var2
, AO2
);
1105 last_label
= next_label
++;
1106 assembleg_jump(last_label
);
1107 assemble_label_no(passed_label
);
1108 assembleg_store(temp_var2
, AO1
);
1109 assemble_label_no(last_label
);
1114 assemble_label_no(passed_label
);
1118 static void compile_conditional_g(condclass
*cc
,
1119 assembly_operand AO1
, assembly_operand AO2
, int label
, int flag
)
1120 { assembly_operand AO4
;
1121 int the_zc
, error_label
= label
,
1122 va_flag
= FALSE
, va_label
;
1126 the_zc
= (flag
? cc
->posform
: cc
->negform
);
1129 switch ((cc
-condclasses
)*2 + 500) {
1132 if (runtime_error_checking_switch
) {
1134 error_label
= next_label
++;
1135 AO1
= check_nonzero_at_runtime(AO1
, error_label
, HAS_RTE
);
1136 if (is_constant_ot(AO2
.type
) && AO2
.marker
== 0) {
1137 if ((AO2
.value
< 0) || (AO2
.value
>= NUM_ATTR_BYTES
*8)) {
1138 error("'has'/'hasnt' applied to illegal attribute number");
1142 int pa_label
= next_label
++, fa_label
= next_label
++;
1143 assembly_operand en_ao
, max_ao
;
1145 if ((AO1
.type
== LOCALVAR_OT
) && (AO1
.value
== 0)) {
1146 if ((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0)) {
1147 assembleg_2(stkpeek_gc
, zero_operand
, temp_var1
);
1148 assembleg_2(stkpeek_gc
, one_operand
, temp_var2
);
1151 assembleg_2(stkpeek_gc
, zero_operand
, temp_var1
);
1152 assembleg_store(temp_var2
, AO2
);
1156 assembleg_store(temp_var1
, AO1
);
1157 if ((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0)) {
1158 assembleg_2(stkpeek_gc
, zero_operand
, temp_var2
);
1161 assembleg_store(temp_var2
, AO2
);
1166 max_ao
.value
= NUM_ATTR_BYTES
*8;
1167 set_constant_ot(&max_ao
);
1168 assembleg_2_branch(jlt_gc
, temp_var2
, zero_operand
, fa_label
);
1169 assembleg_2_branch(jlt_gc
, temp_var2
, max_ao
, pa_label
);
1170 assemble_label_no(fa_label
);
1172 en_ao
.value
= 19; /* INVALIDATTR_RTE */
1173 set_constant_ot(&en_ao
);
1174 assembleg_store(stack_pointer
, temp_var2
);
1175 assembleg_store(stack_pointer
, temp_var1
);
1176 assembleg_store(stack_pointer
, en_ao
);
1177 assembleg_3(call_gc
, veneer_routine(RT__Err_VR
),
1178 three_operand
, zero_operand
);
1180 va_label
= next_label
++;
1181 assembleg_jump(va_label
);
1182 assemble_label_no(pa_label
);
1185 if (is_constant_ot(AO2
.type
) && AO2
.marker
== 0) {
1187 set_constant_ot(&AO2
);
1192 AO4
.type
= BYTECONSTANT_OT
;
1193 if ((AO1
.type
== LOCALVAR_OT
) && (AO1
.value
== 0)) {
1194 if ((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0))
1195 assembleg_0(stkswap_gc
);
1196 assembleg_3(add_gc
, AO2
, AO4
, stack_pointer
);
1197 assembleg_0(stkswap_gc
);
1200 assembleg_3(add_gc
, AO2
, AO4
, stack_pointer
);
1202 AO2
= stack_pointer
;
1204 assembleg_3(aloadbit_gc
, AO1
, AO2
, stack_pointer
);
1205 the_zc
= (flag
? jnz_gc
: jz_gc
);
1206 AO1
= stack_pointer
;
1210 if (runtime_error_checking_switch
) {
1212 error_label
= next_label
++;
1213 AO1
= check_nonzero_at_runtime(AO1
, error_label
, IN_RTE
);
1215 AO4
.value
= GOBJFIELD_PARENT();
1217 AO4
.type
= BYTECONSTANT_OT
;
1218 assembleg_3(aload_gc
, AO1
, AO4
, stack_pointer
);
1219 AO1
= stack_pointer
;
1220 the_zc
= (flag
? jeq_gc
: jne_gc
);
1224 assembleg_call_2(veneer_routine(OC__Cl_VR
), AO1
, AO2
, stack_pointer
);
1225 the_zc
= (flag
? jnz_gc
: jz_gc
);
1226 AO1
= stack_pointer
;
1230 assembleg_call_2(veneer_routine(OP__Pr_VR
), AO1
, AO2
, stack_pointer
);
1231 the_zc
= (flag
? jnz_gc
: jz_gc
);
1232 AO1
= stack_pointer
;
1236 error("condition not yet supported in Glulx");
1241 if (the_zc
== jnz_gc
|| the_zc
== jz_gc
)
1242 assembleg_1_branch(the_zc
, AO1
, label
);
1244 assembleg_2_branch(the_zc
, AO1
, AO2
, label
);
1245 if (error_label
!= label
) assemble_label_no(error_label
);
1246 if (va_flag
) assemble_label_no(va_label
);
1249 static void value_in_void_context(assembly_operand AO
)
1252 value_in_void_context_z(AO
);
1254 value_in_void_context_g(AO
);
1258 extern assembly_operand
check_nonzero_at_runtime(assembly_operand AO1
,
1259 int error_label
, int rte_number
)
1262 return check_nonzero_at_runtime_z(AO1
, error_label
, rte_number
);
1264 return check_nonzero_at_runtime_g(AO1
, error_label
, rte_number
);
1267 static void generate_code_from(int n
, int void_flag
)
1269 /* When void, this must not leave anything on the stack. */
1271 int i
, j
, below
, above
, opnum
, arity
; assembly_operand Result
;
1273 below
= ET
[n
].down
; above
= ET
[n
].up
;
1275 { if ((void_flag
) && (ET
[n
].value
.type
!= OMITTED_OT
))
1276 value_in_void_context(ET
[n
].value
);
1280 opnum
= ET
[n
].operator_number
;
1282 if (opnum
== COMMA_OP
)
1283 { generate_code_from(below
, TRUE
);
1284 generate_code_from(ET
[below
].right
, void_flag
);
1285 ET
[n
].value
= ET
[ET
[below
].right
].value
;
1286 goto OperatorGenerated
;
1289 if ((opnum
== LOGAND_OP
) || (opnum
== LOGOR_OP
))
1290 { generate_code_from(below
, FALSE
);
1291 generate_code_from(ET
[below
].right
, FALSE
);
1292 goto OperatorGenerated
;
1297 /* Signifies a SETEQUALS_OP which has already been done */
1299 ET
[n
].down
= -1; return;
1302 /* Note that (except in the cases of comma and logical and/or) it
1303 is essential to code generate the operands right to left, because
1304 of the peculiar way the Z-machine's stack works:
1308 (for instance) pulls to the first operand, then the second. So
1314 calculates (b+7)-(a*2), not the other way around (as would be more
1315 usual in stack machines evaluating expressions written in reverse
1316 Polish notation). (Basically this is because the Z-machine was
1317 designed to implement a LISP-like language naturally expressed
1318 in forward Polish notation: (PLUS 3 4), for instance.) */
1320 /* And the Glulx machine follows the Z-machine in this respect. */
1324 { i
= ET
[i
].right
; arity
++;
1326 for (j
=arity
;j
>0;j
--)
1330 { k
++; i
= ET
[i
].right
;
1332 generate_code_from(i
, FALSE
);
1336 /* Check this again, because code generation lower down may have
1337 stubbed it into -1 */
1339 if (ET
[n
].operator_number
== -1)
1340 { ET
[n
].down
= -1; return;
1345 if (operators
[opnum
].opcode_number_z
>= 400)
1347 /* Conditional terms such as '==': */
1349 int a
= ET
[n
].true_label
, b
= ET
[n
].false_label
,
1350 branch_away
, branch_other
,
1351 make_jump_away
= FALSE
, make_branch_label
= FALSE
;
1352 int oc
= operators
[opnum
].opcode_number_z
-400, flag
= TRUE
;
1354 if (oc
>= 400) { oc
= oc
- 400; flag
= FALSE
; }
1356 if ((oc
== je_zc
) && (arity
== 2))
1357 { i
= ET
[ET
[n
].down
].right
;
1358 if ((ET
[i
].value
.value
== zero_operand
.value
)
1359 && (ET
[i
].value
.type
== zero_operand
.type
))
1363 /* If the condition has truth state flag, branch to
1364 label a, and if not, to label b. Possibly one of a, b
1365 equals -1, meaning "continue from this instruction".
1367 branch_away is the label which is a branch away (the one
1368 which isn't immediately after) and flag is the truth
1369 state to branch there.
1371 Note that when multiple instructions are needed (because
1372 of the use of the 'or' operator) the branch_other label
1373 is created if need be.
1376 /* Reduce to the case where the branch_away label does exist: */
1378 if (a
== -1) { a
= b
; b
= -1; flag
= !flag
; }
1380 branch_away
= a
; branch_other
= b
;
1381 if (branch_other
!= -1) make_jump_away
= TRUE
;
1383 if ((((oc
!= je_zc
)&&(arity
> 2)) || (arity
> 4)) && (flag
== FALSE
))
1385 /* In this case, we have an 'or' situation where multiple
1386 instructions are needed and where the overall condition
1387 is negated. That is, we have, e.g.
1389 if not (A cond B or C or D) then branch_away
1391 which we transform into
1393 if (A cond B) then branch_other
1394 if (A cond C) then branch_other
1395 if not (A cond D) then branch_away
1398 if (branch_other
== -1)
1399 { branch_other
= next_label
++; make_branch_label
= TRUE
;
1404 assemblez_1_branch(jz_zc
, ET
[below
].value
, branch_away
, flag
);
1406 { assembly_operand left_operand
;
1409 compile_conditional_z(oc
, ET
[below
].value
,
1410 ET
[ET
[below
].right
].value
, branch_away
, flag
);
1412 { /* The case of a condition using "or".
1413 First: if the condition tests the stack pointer,
1414 and it can't always be done in a single test, move
1415 the value off the stack and into temporary variable
1418 if (((ET
[below
].value
.type
== VARIABLE_OT
)
1419 && (ET
[below
].value
.value
== 0))
1420 && ((oc
!= je_zc
) || (arity
>4)) )
1421 { left_operand
.type
= VARIABLE_OT
;
1422 left_operand
.value
= 255;
1423 left_operand
.marker
= 0;
1424 assemblez_store(left_operand
, ET
[below
].value
);
1426 else left_operand
= ET
[below
].value
;
1427 i
= ET
[below
].right
; arity
--;
1429 /* "left_operand" now holds the quantity to be tested;
1430 "i" holds the right operand reached so far;
1431 "arity" the number of right operands. */
1434 { if ((oc
== je_zc
) && (arity
>1))
1436 /* je_zc is an especially good case since the
1437 Z-machine implements "or" for up to three
1438 right operands automatically, though it's an
1439 especially bad case to generate code for! */
1442 { assemblez_3_branch(je_zc
,
1443 left_operand
, ET
[i
].value
,
1444 ET
[ET
[i
].right
].value
, branch_away
, flag
);
1445 i
= ET
[i
].right
; arity
--;
1448 { if ((arity
== 3) || flag
)
1449 assemblez_4_branch(je_zc
, left_operand
,
1451 ET
[ET
[i
].right
].value
,
1452 ET
[ET
[ET
[i
].right
].right
].value
,
1455 assemblez_4_branch(je_zc
, left_operand
,
1457 ET
[ET
[i
].right
].value
,
1458 ET
[ET
[ET
[i
].right
].right
].value
,
1459 branch_other
, !flag
);
1460 i
= ET
[ET
[i
].right
].right
; arity
-= 2;
1464 { /* Otherwise we can compare the left_operand with
1465 only one right operand at the time. There are
1466 two cases: it's the last right operand, or it
1469 if ((arity
== 1) || flag
)
1470 compile_conditional_z(oc
, left_operand
,
1471 ET
[i
].value
, branch_away
, flag
);
1473 compile_conditional_z(oc
, left_operand
,
1474 ET
[i
].value
, branch_other
, !flag
);
1476 i
= ET
[i
].right
; arity
--;
1482 /* NB: These two conditions cannot both occur, fortunately! */
1484 if (make_branch_label
) assemble_label_no(branch_other
);
1485 if (make_jump_away
) assemblez_jump(branch_other
);
1487 goto OperatorGenerated
;
1492 if (operators
[opnum
].opcode_number_g
>= FIRST_CC
1493 && operators
[opnum
].opcode_number_g
<= LAST_CC
) {
1494 /* Conditional terms such as '==': */
1496 int a
= ET
[n
].true_label
, b
= ET
[n
].false_label
;
1497 int branch_away
, branch_other
, flag
,
1498 make_jump_away
= FALSE
, make_branch_label
= FALSE
;
1499 int ccode
= operators
[opnum
].opcode_number_g
;
1500 condclass
*cc
= &condclasses
[(ccode
-FIRST_CC
) / 2];
1501 flag
= (ccode
& 1) ? 0 : 1;
1503 /* If the comparison is "equal to (constant) 0", change it
1504 to the simple "zero" test. Unfortunately, this doesn't
1505 work for the commutative form "(constant) 0 is equal to".
1506 At least I don't think it does. */
1508 if ((cc
== &condclasses
[1]) && (arity
== 2)) {
1509 i
= ET
[ET
[n
].down
].right
;
1510 if ((ET
[i
].value
.value
== 0)
1511 && (ET
[i
].value
.marker
== 0)
1512 && is_constant_ot(ET
[i
].value
.type
)) {
1513 cc
= &condclasses
[0];
1517 /* If the condition has truth state flag, branch to
1518 label a, and if not, to label b. Possibly one of a, b
1519 equals -1, meaning "continue from this instruction".
1521 branch_away is the label which is a branch away (the one
1522 which isn't immediately after) and flag is the truth
1523 state to branch there.
1525 Note that when multiple instructions are needed (because
1526 of the use of the 'or' operator) the branch_other label
1527 is created if need be.
1530 /* Reduce to the case where the branch_away label does exist: */
1532 if (a
== -1) { a
= b
; b
= -1; flag
= !flag
; }
1534 branch_away
= a
; branch_other
= b
;
1535 if (branch_other
!= -1) make_jump_away
= TRUE
;
1537 if ((arity
> 2) && (flag
== FALSE
)) {
1538 /* In this case, we have an 'or' situation where multiple
1539 instructions are needed and where the overall condition
1540 is negated. That is, we have, e.g.
1542 if not (A cond B or C or D) then branch_away
1544 which we transform into
1546 if (A cond B) then branch_other
1547 if (A cond C) then branch_other
1548 if not (A cond D) then branch_away
1551 if (branch_other
== -1) {
1552 branch_other
= next_label
++; make_branch_label
= TRUE
;
1556 if (cc
== &condclasses
[0]) {
1557 assembleg_1_branch((flag
? cc
->posform
: cc
->negform
),
1558 ET
[below
].value
, branch_away
);
1562 compile_conditional_g(cc
, ET
[below
].value
,
1563 ET
[ET
[below
].right
].value
, branch_away
, flag
);
1566 /* The case of a condition using "or".
1567 First: if the condition tests the stack pointer,
1568 and it can't always be done in a single test, move
1569 the value off the stack and into temporary variable
1572 assembly_operand left_operand
;
1573 if (((ET
[below
].value
.type
== LOCALVAR_OT
)
1574 && (ET
[below
].value
.value
== 0))) {
1575 assembleg_store(temp_var1
, ET
[below
].value
);
1576 left_operand
= temp_var1
;
1579 left_operand
= ET
[below
].value
;
1581 i
= ET
[below
].right
;
1584 /* "left_operand" now holds the quantity to be tested;
1585 "i" holds the right operand reached so far;
1586 "arity" the number of right operands. */
1589 /* We can compare the left_operand with
1590 only one right operand at the time. There are
1591 two cases: it's the last right operand, or it
1594 if ((arity
== 1) || flag
)
1595 compile_conditional_g(cc
, left_operand
,
1596 ET
[i
].value
, branch_away
, flag
);
1598 compile_conditional_g(cc
, left_operand
,
1599 ET
[i
].value
, branch_other
, !flag
);
1607 /* NB: These two conditions cannot both occur, fortunately! */
1609 if (make_branch_label
) assemble_label_no(branch_other
);
1610 if (make_jump_away
) assembleg_jump(branch_other
);
1612 goto OperatorGenerated
;
1617 /* The operator is now definitely one which produces a value */
1619 if (void_flag
&& (!(operators
[opnum
].side_effect
)))
1620 error_named("Evaluating this has no effect:",
1621 operators
[opnum
].description
);
1623 /* Where shall we put the resulting value? (In Glulx, this could
1624 be smarter, and peg the result into ZEROCONSTANT.) */
1626 if (void_flag
) Result
= temp_var1
; /* Throw it away */
1628 { if ((above
!= -1) && (ET
[above
].operator_number
== SETEQUALS_OP
))
1630 /* If the node above is "set variable equal to", then
1631 make that variable the place to put the result, and
1632 delete the SETEQUALS_OP node since its effect has already
1633 been accomplished. */
1635 ET
[above
].operator_number
= -1;
1636 Result
= ET
[ET
[above
].down
].value
;
1637 ET
[above
].value
= Result
;
1639 else Result
= stack_pointer
; /* Otherwise, put it on the stack */
1644 if (operators
[opnum
].opcode_number_z
!= -1)
1646 /* Operators directly translatable into Z-code opcodes: infix ops
1647 take two operands whereas pre/postfix operators take only one */
1649 if (operators
[opnum
].usage
== IN_U
)
1650 { int o_n
= operators
[opnum
].opcode_number_z
;
1651 if (runtime_error_checking_switch
&& (!veneer_mode
)
1652 && ((o_n
== div_zc
) || (o_n
== mod_zc
)))
1653 { assembly_operand by_ao
, error_ao
; int ln
;
1654 by_ao
= ET
[ET
[below
].right
].value
;
1655 if ((by_ao
.value
!= 0) && (by_ao
.marker
== 0)
1656 && ((by_ao
.type
== SHORT_CONSTANT_OT
)
1657 || (by_ao
.type
== LONG_CONSTANT_OT
)))
1658 assemblez_2_to(o_n
, ET
[below
].value
,
1662 assemblez_store(temp_var1
, ET
[below
].value
);
1663 assemblez_store(temp_var2
, by_ao
);
1665 assemblez_1_branch(jz_zc
, temp_var2
, ln
, FALSE
);
1666 error_ao
.type
= SHORT_CONSTANT_OT
; error_ao
.marker
= 0;
1667 error_ao
.value
= DBYZERO_RTE
;
1668 assemblez_2(call_vn_zc
, veneer_routine(RT__Err_VR
),
1670 assemblez_inc(temp_var2
);
1671 assemble_label_no(ln
);
1672 assemblez_2_to(o_n
, temp_var1
, temp_var2
, Result
);
1676 assemblez_2_to(o_n
, ET
[below
].value
,
1677 ET
[ET
[below
].right
].value
, Result
);
1681 assemblez_1_to(operators
[opnum
].opcode_number_z
, ET
[below
].value
,
1687 access_memory_z(loadb_zc
, ET
[below
].value
,
1688 ET
[ET
[below
].right
].value
, Result
);
1691 access_memory_z(loadw_zc
, ET
[below
].value
,
1692 ET
[ET
[below
].right
].value
, Result
);
1694 case UNARY_MINUS_OP
:
1695 assemblez_2_to(sub_zc
, zero_operand
, ET
[below
].value
, Result
);
1698 assemblez_1_to(not_zc
, ET
[below
].value
, Result
);
1702 { assembly_operand AO
= ET
[below
].value
;
1703 if (runtime_error_checking_switch
&& (!veneer_mode
))
1704 AO
= check_nonzero_at_runtime(AO
, -1, PROP_ADD_RTE
);
1705 assemblez_2_to(get_prop_addr_zc
, AO
,
1706 ET
[ET
[below
].right
].value
, temp_var1
);
1707 if (!void_flag
) write_result_z(Result
, temp_var1
);
1712 { assembly_operand AO
= ET
[below
].value
;
1713 if (runtime_error_checking_switch
&& (!veneer_mode
))
1714 AO
= check_nonzero_at_runtime(AO
, -1, PROP_NUM_RTE
);
1715 assemblez_2_to(get_prop_addr_zc
, AO
,
1716 ET
[ET
[below
].right
].value
, temp_var1
);
1717 assemblez_1_branch(jz_zc
, temp_var1
, next_label
++, TRUE
);
1718 assemblez_1_to(get_prop_len_zc
, temp_var1
, temp_var1
);
1719 assemble_label_no(next_label
-1);
1720 if (!void_flag
) write_result_z(Result
, temp_var1
);
1725 { assembly_operand AO
= ET
[below
].value
;
1727 if (runtime_error_checking_switch
&& (!veneer_mode
))
1728 assemblez_3_to(call_vs_zc
, veneer_routine(RT__ChPR_VR
),
1729 AO
, ET
[ET
[below
].right
].value
, temp_var1
);
1731 assemblez_2_to(get_prop_zc
, AO
,
1732 ET
[ET
[below
].right
].value
, temp_var1
);
1733 if (!void_flag
) write_result_z(Result
, temp_var1
);
1738 j
=1; AI
.operand
[0] = veneer_routine(RV__Pr_VR
);
1739 goto GenFunctionCallZ
;
1741 j
=1; AI
.operand
[0] = veneer_routine(RA__Pr_VR
);
1742 goto GenFunctionCallZ
;
1744 j
=1; AI
.operand
[0] = veneer_routine(RL__Pr_VR
);
1745 goto GenFunctionCallZ
;
1746 case MESSAGE_SETEQUALS_OP
:
1747 j
=1; AI
.operand
[0] = veneer_routine(WV__Pr_VR
);
1748 goto GenFunctionCallZ
;
1749 case MESSAGE_INC_OP
:
1750 j
=1; AI
.operand
[0] = veneer_routine(IB__Pr_VR
);
1751 goto GenFunctionCallZ
;
1752 case MESSAGE_DEC_OP
:
1753 j
=1; AI
.operand
[0] = veneer_routine(DB__Pr_VR
);
1754 goto GenFunctionCallZ
;
1755 case MESSAGE_POST_INC_OP
:
1756 j
=1; AI
.operand
[0] = veneer_routine(IA__Pr_VR
);
1757 goto GenFunctionCallZ
;
1758 case MESSAGE_POST_DEC_OP
:
1759 j
=1; AI
.operand
[0] = veneer_routine(DA__Pr_VR
);
1760 goto GenFunctionCallZ
;
1762 j
=1; AI
.operand
[0] = veneer_routine(RA__Sc_VR
);
1763 goto GenFunctionCallZ
;
1765 j
=1; AI
.operand
[0] = veneer_routine(CA__Pr_VR
);
1766 goto GenFunctionCallZ
;
1767 case MESSAGE_CALL_OP
:
1768 j
=1; AI
.operand
[0] = veneer_routine(CA__Pr_VR
);
1769 goto GenFunctionCallZ
;
1775 if ((ET
[below
].value
.type
== VARIABLE_OT
)
1776 && (ET
[below
].value
.value
>= 256))
1777 { int sf_number
= ET
[below
].value
.value
- 256;
1779 i
= ET
[below
].right
;
1781 { error("Argument to system function missing");
1782 AI
.operand
[0] = one_operand
;
1783 AI
.operand_count
= 1;
1787 while (i
!= -1) { j
++; i
= ET
[i
].right
; }
1789 if (((sf_number
!= INDIRECT_SYSF
) &&
1790 (sf_number
!= RANDOM_SYSF
) && (j
> 1))
1791 || ((sf_number
== INDIRECT_SYSF
) && (j
>7)))
1793 error("System function given with too many arguments");
1795 if (sf_number
!= RANDOM_SYSF
)
1797 i
= ET
[below
].right
;
1798 for (jcount
= 0; jcount
< j
; jcount
++)
1799 { AI
.operand
[jcount
] = ET
[i
].value
;
1802 AI
.operand_count
= j
;
1805 AI
.store_variable_number
= Result
.value
;
1806 AI
.branch_label_number
= -1;
1811 { assembly_operand AO
, AO2
; int arg_c
, arg_et
;
1812 AO
.value
= j
; AO
.marker
= 0;
1813 AO
.type
= SHORT_CONSTANT_OT
;
1814 AO2
.type
= LONG_CONSTANT_OT
;
1815 AO2
.value
= begin_word_array();
1816 AO2
.marker
= ARRAY_MV
;
1818 for (arg_c
=0, arg_et
= ET
[below
].right
;arg_c
<j
;
1819 arg_c
++, arg_et
= ET
[arg_et
].right
)
1820 { if (ET
[arg_et
].value
.type
== VARIABLE_OT
)
1821 error("Only constants can be used as possible 'random' results");
1822 array_entry(arg_c
, ET
[arg_et
].value
);
1824 finish_array(arg_c
);
1826 assemblez_1_to(random_zc
, AO
, temp_var1
);
1827 assemblez_dec(temp_var1
);
1828 assemblez_2_to(loadw_zc
, AO2
, temp_var1
, Result
);
1831 assemblez_1_to(random_zc
,
1832 ET
[ET
[below
].right
].value
, Result
);
1836 { assembly_operand AO
;
1837 AO
= ET
[ET
[below
].right
].value
;
1838 if (runtime_error_checking_switch
)
1839 AO
= check_nonzero_at_runtime(AO
, -1,
1841 assemblez_1_to(get_parent_zc
, AO
, Result
);
1847 { assembly_operand AO
;
1848 AO
= ET
[ET
[below
].right
].value
;
1849 if (runtime_error_checking_switch
)
1850 AO
= check_nonzero_at_runtime(AO
, -1,
1851 (sf_number
==CHILD_SYSF
)?CHILD_RTE
:ELDEST_RTE
);
1852 assemblez_objcode(get_child_zc
,
1853 AO
, Result
, -2, TRUE
);
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,
1863 (sf_number
==SIBLING_SYSF
)
1864 ?SIBLING_RTE
:YOUNGER_RTE
);
1865 assemblez_objcode(get_sibling_zc
,
1866 AO
, Result
, -2, TRUE
);
1871 j
=0; i
= ET
[below
].right
;
1872 goto IndirectFunctionCallZ
;
1875 { assembly_operand AO
;
1876 AO
= ET
[ET
[below
].right
].value
;
1877 if (runtime_error_checking_switch
)
1878 AO
= check_nonzero_at_runtime(AO
, -1,
1880 assemblez_store(temp_var1
, zero_operand
);
1881 assemblez_objcode(get_child_zc
,
1882 AO
, stack_pointer
, next_label
+1, FALSE
);
1883 assemble_label_no(next_label
);
1884 assemblez_inc(temp_var1
);
1885 assemblez_objcode(get_sibling_zc
,
1886 stack_pointer
, stack_pointer
,
1888 assemble_label_no(next_label
+1);
1889 assemblez_store(temp_var2
, stack_pointer
);
1890 if (!void_flag
) write_result_z(Result
, temp_var1
);
1896 { assembly_operand AO
;
1897 AO
= ET
[ET
[below
].right
].value
;
1898 if (runtime_error_checking_switch
)
1899 AO
= check_nonzero_at_runtime(AO
, -1,
1901 assemblez_objcode(get_child_zc
,
1902 AO
, temp_var1
, next_label
+1, FALSE
);
1903 assemblez_1(push_zc
, temp_var1
);
1904 assemble_label_no(next_label
);
1905 assemblez_store(temp_var1
, stack_pointer
);
1906 assemblez_objcode(get_sibling_zc
,
1907 temp_var1
, stack_pointer
, next_label
, TRUE
);
1908 assemble_label_no(next_label
+1);
1909 if (!void_flag
) write_result_z(Result
, temp_var1
);
1915 assemblez_store(temp_var1
, ET
[ET
[below
].right
].value
);
1916 if (runtime_error_checking_switch
)
1917 check_nonzero_at_runtime(temp_var1
, -1,
1919 assemblez_1_to(get_parent_zc
, temp_var1
, temp_var3
);
1920 assemblez_1_branch(jz_zc
, temp_var3
,next_label
+1,TRUE
);
1921 assemblez_store(temp_var2
, temp_var3
);
1922 assemblez_store(temp_var3
, zero_operand
);
1923 assemblez_objcode(get_child_zc
,
1924 temp_var2
, temp_var2
, next_label
, TRUE
);
1925 assemble_label_no(next_label
++);
1926 assemblez_2_branch(je_zc
, temp_var1
, temp_var2
,
1928 assemblez_store(temp_var3
, temp_var2
);
1929 assemblez_objcode(get_sibling_zc
,
1930 temp_var2
, temp_var2
, next_label
- 1, TRUE
);
1931 assemble_label_no(next_label
++);
1932 if (!void_flag
) write_result_z(Result
, temp_var3
);
1935 case METACLASS_SYSF
:
1936 assemblez_2_to((version_number
==3)?call_zc
:call_vs_zc
,
1937 veneer_routine(Metaclass_VR
),
1938 ET
[ET
[below
].right
].value
, Result
);
1942 error("The glk() system function does not exist in Z-code");
1952 IndirectFunctionCallZ
:
1954 while ((i
!= -1) && (j
<8))
1955 { AI
.operand
[j
++] = ET
[i
].value
;
1959 if ((j
> 4) && (version_number
== 3))
1960 { error("A function may be called with at most 3 arguments");
1963 if ((j
==8) && (i
!= -1))
1964 { error("A function may be called with at most 7 arguments");
1967 AI
.operand_count
= j
;
1969 if ((void_flag
) && (version_number
>= 5))
1970 { AI
.store_variable_number
= -1;
1972 { case 1: AI
.internal_number
= call_1n_zc
; break;
1973 case 2: AI
.internal_number
= call_2n_zc
; break;
1974 case 3: case 4: AI
.internal_number
= call_vn_zc
; break;
1975 case 5: case 6: case 7: case 8:
1976 AI
.internal_number
= call_vn2_zc
; break;
1980 { AI
.store_variable_number
= Result
.value
;
1981 if (version_number
== 3)
1982 AI
.internal_number
= call_zc
;
1985 { case 1: AI
.internal_number
= call_1s_zc
; break;
1986 case 2: AI
.internal_number
= call_2s_zc
; break;
1987 case 3: case 4: AI
.internal_number
= call_vs_zc
; break;
1988 case 5: case 6: case 7: case 8:
1989 AI
.internal_number
= call_vs2_zc
; break;
1993 AI
.branch_label_number
= -1;
1994 assemblez_instruction(&AI
);
1998 assemblez_store(ET
[below
].value
,
1999 ET
[ET
[below
].right
].value
);
2000 if (!void_flag
) write_result_z(Result
, ET
[below
].value
);
2003 case PROPERTY_SETEQUALS_OP
:
2005 { if (runtime_error_checking_switch
)
2006 assemblez_4_to(call_zc
, veneer_routine(RT__ChPS_VR
),
2007 ET
[below
].value
, ET
[ET
[below
].right
].value
,
2008 ET
[ET
[ET
[below
].right
].right
].value
, Result
);
2010 { assemblez_store(temp_var1
,
2011 ET
[ET
[ET
[below
].right
].right
].value
);
2012 assemblez_3(put_prop_zc
, ET
[below
].value
,
2013 ET
[ET
[below
].right
].value
,
2015 write_result_z(Result
, temp_var1
);
2019 { if (runtime_error_checking_switch
&& (!veneer_mode
))
2020 assemblez_4(call_vn_zc
, veneer_routine(RT__ChPS_VR
),
2021 ET
[below
].value
, ET
[ET
[below
].right
].value
,
2022 ET
[ET
[ET
[below
].right
].right
].value
);
2023 else assemblez_3(put_prop_zc
, ET
[below
].value
,
2024 ET
[ET
[below
].right
].value
,
2025 ET
[ET
[ET
[below
].right
].right
].value
);
2028 case ARROW_SETEQUALS_OP
:
2030 { assemblez_store(temp_var1
,
2031 ET
[ET
[ET
[below
].right
].right
].value
);
2032 access_memory_z(storeb_zc
, ET
[below
].value
,
2033 ET
[ET
[below
].right
].value
,
2035 write_result_z(Result
, temp_var1
);
2037 else access_memory_z(storeb_zc
, ET
[below
].value
,
2038 ET
[ET
[below
].right
].value
,
2039 ET
[ET
[ET
[below
].right
].right
].value
);
2042 case DARROW_SETEQUALS_OP
:
2044 { assemblez_store(temp_var1
,
2045 ET
[ET
[ET
[below
].right
].right
].value
);
2046 access_memory_z(storew_zc
, ET
[below
].value
,
2047 ET
[ET
[below
].right
].value
,
2049 write_result_z(Result
, temp_var1
);
2052 access_memory_z(storew_zc
, ET
[below
].value
,
2053 ET
[ET
[below
].right
].value
,
2054 ET
[ET
[ET
[below
].right
].right
].value
);
2058 assemblez_inc(ET
[below
].value
);
2059 if (!void_flag
) write_result_z(Result
, ET
[below
].value
);
2062 assemblez_dec(ET
[below
].value
);
2063 if (!void_flag
) write_result_z(Result
, ET
[below
].value
);
2066 if (!void_flag
) write_result_z(Result
, ET
[below
].value
);
2067 assemblez_inc(ET
[below
].value
);
2070 if (!void_flag
) write_result_z(Result
, ET
[below
].value
);
2071 assemblez_dec(ET
[below
].value
);
2075 assemblez_store(temp_var1
, ET
[below
].value
);
2076 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2077 access_memory_z(loadb_zc
, temp_var1
, temp_var2
, temp_var3
);
2078 assemblez_inc(temp_var3
);
2079 access_memory_z(storeb_zc
, temp_var1
, temp_var2
, temp_var3
);
2080 if (!void_flag
) write_result_z(Result
, temp_var3
);
2084 assemblez_store(temp_var1
, ET
[below
].value
);
2085 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2086 access_memory_z(loadb_zc
, temp_var1
, temp_var2
, temp_var3
);
2087 assemblez_dec(temp_var3
);
2088 access_memory_z(storeb_zc
, temp_var1
, temp_var2
, temp_var3
);
2089 if (!void_flag
) write_result_z(Result
, temp_var3
);
2092 case ARROW_POST_INC_OP
:
2093 assemblez_store(temp_var1
, ET
[below
].value
);
2094 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2095 access_memory_z(loadb_zc
, temp_var1
, temp_var2
, temp_var3
);
2096 if (!void_flag
) write_result_z(Result
, temp_var3
);
2097 assemblez_inc(temp_var3
);
2098 access_memory_z(storeb_zc
, temp_var1
, temp_var2
, temp_var3
);
2101 case ARROW_POST_DEC_OP
:
2102 assemblez_store(temp_var1
, ET
[below
].value
);
2103 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2104 access_memory_z(loadb_zc
, temp_var1
, temp_var2
, temp_var3
);
2105 if (!void_flag
) write_result_z(Result
, temp_var3
);
2106 assemblez_dec(temp_var3
);
2107 access_memory_z(storeb_zc
, temp_var1
, temp_var2
, temp_var3
);
2111 assemblez_store(temp_var1
, ET
[below
].value
);
2112 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2113 access_memory_z(loadw_zc
, temp_var1
, temp_var2
, temp_var3
);
2114 assemblez_inc(temp_var3
);
2115 access_memory_z(storew_zc
, temp_var1
, temp_var2
, temp_var3
);
2116 if (!void_flag
) write_result_z(Result
, temp_var3
);
2120 assemblez_store(temp_var1
, ET
[below
].value
);
2121 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2122 access_memory_z(loadw_zc
, temp_var1
, temp_var2
, temp_var3
);
2123 assemblez_dec(temp_var3
);
2124 access_memory_z(storew_zc
, temp_var1
, temp_var2
, temp_var3
);
2125 if (!void_flag
) write_result_z(Result
, temp_var3
);
2128 case DARROW_POST_INC_OP
:
2129 assemblez_store(temp_var1
, ET
[below
].value
);
2130 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2131 access_memory_z(loadw_zc
, temp_var1
, temp_var2
, temp_var3
);
2132 if (!void_flag
) write_result_z(Result
, temp_var3
);
2133 assemblez_inc(temp_var3
);
2134 access_memory_z(storew_zc
, temp_var1
, temp_var2
, temp_var3
);
2137 case DARROW_POST_DEC_OP
:
2138 assemblez_store(temp_var1
, ET
[below
].value
);
2139 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2140 access_memory_z(loadw_zc
, temp_var1
, temp_var2
, temp_var3
);
2141 if (!void_flag
) write_result_z(Result
, temp_var3
);
2142 assemblez_dec(temp_var3
);
2143 access_memory_z(storew_zc
, temp_var1
, temp_var2
, temp_var3
);
2146 case PROPERTY_INC_OP
:
2147 assemblez_store(temp_var1
, ET
[below
].value
);
2148 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2149 assemblez_2_to(get_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2150 assemblez_inc(temp_var3
);
2151 if (runtime_error_checking_switch
&& (!veneer_mode
))
2152 assemblez_4(call_vn_zc
, veneer_routine(RT__ChPS_VR
),
2153 temp_var1
, temp_var2
, temp_var3
);
2154 else assemblez_3(put_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2155 if (!void_flag
) write_result_z(Result
, temp_var3
);
2158 case PROPERTY_DEC_OP
:
2159 assemblez_store(temp_var1
, ET
[below
].value
);
2160 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2161 assemblez_2_to(get_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2162 assemblez_dec(temp_var3
);
2163 if (runtime_error_checking_switch
&& (!veneer_mode
))
2164 assemblez_4(call_vn_zc
, veneer_routine(RT__ChPS_VR
),
2165 temp_var1
, temp_var2
, temp_var3
);
2166 else assemblez_3(put_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2167 if (!void_flag
) write_result_z(Result
, temp_var3
);
2170 case PROPERTY_POST_INC_OP
:
2171 assemblez_store(temp_var1
, ET
[below
].value
);
2172 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2173 assemblez_2_to(get_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2174 if (!void_flag
) write_result_z(Result
, temp_var3
);
2175 assemblez_inc(temp_var3
);
2176 if (runtime_error_checking_switch
&& (!veneer_mode
))
2177 assemblez_4(call_vn_zc
, veneer_routine(RT__ChPS_VR
),
2178 temp_var1
, temp_var2
, temp_var3
);
2179 else assemblez_3(put_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2182 case PROPERTY_POST_DEC_OP
:
2183 assemblez_store(temp_var1
, ET
[below
].value
);
2184 assemblez_store(temp_var2
, ET
[ET
[below
].right
].value
);
2185 assemblez_2_to(get_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2186 if (!void_flag
) write_result_z(Result
, temp_var3
);
2187 assemblez_dec(temp_var3
);
2188 if (runtime_error_checking_switch
&& (!veneer_mode
))
2189 assemblez_4(call_vn_zc
, veneer_routine(RT__ChPS_VR
),
2190 temp_var1
, temp_var2
, temp_var3
);
2191 else assemblez_3(put_prop_zc
, temp_var1
, temp_var2
, temp_var3
);
2195 printf("** Trouble op = %d i.e. '%s' **\n",
2196 opnum
, operators
[opnum
].description
);
2197 compiler_error("Expr code gen: Can't generate yet");
2201 assembly_operand AO
, AO2
;
2202 if (operators
[opnum
].opcode_number_g
!= -1)
2204 /* Operators directly translatable into opcodes: infix ops
2205 take two operands whereas pre/postfix operators take only one */
2207 if (operators
[opnum
].usage
== IN_U
)
2208 { int o_n
= operators
[opnum
].opcode_number_g
;
2209 if (runtime_error_checking_switch
&& (!veneer_mode
)
2210 && ((o_n
== div_gc
) || (o_n
== mod_gc
)))
2211 { assembly_operand by_ao
, error_ao
; int ln
;
2212 by_ao
= ET
[ET
[below
].right
].value
;
2213 if ((by_ao
.value
!= 0) && (by_ao
.marker
== 0)
2214 && is_constant_ot(by_ao
.type
))
2215 assembleg_3(o_n
, ET
[below
].value
,
2218 { assembleg_store(temp_var1
, ET
[below
].value
);
2219 assembleg_store(temp_var2
, by_ao
);
2221 assembleg_1_branch(jnz_gc
, temp_var2
, ln
);
2222 error_ao
.marker
= 0;
2223 error_ao
.value
= DBYZERO_RTE
;
2224 set_constant_ot(&error_ao
);
2225 assembleg_call_1(veneer_routine(RT__Err_VR
),
2226 error_ao
, zero_operand
);
2227 assembleg_store(temp_var2
, one_operand
);
2228 assemble_label_no(ln
);
2229 assembleg_3(o_n
, temp_var1
, temp_var2
, Result
);
2233 assembleg_3(o_n
, ET
[below
].value
,
2234 ET
[ET
[below
].right
].value
, Result
);
2237 assembleg_2(operators
[opnum
].opcode_number_g
, ET
[below
].value
,
2245 if (ET
[below
].value
.type
== Result
.type
2246 && ET
[below
].value
.value
== Result
.value
2247 && ET
[below
].value
.marker
== Result
.marker
)
2249 assembleg_2(copy_gc
, ET
[below
].value
, Result
);
2252 case UNARY_MINUS_OP
:
2253 assembleg_2(neg_gc
, ET
[below
].value
, Result
);
2256 assembleg_2(bitnot_gc
, ET
[below
].value
, Result
);
2260 access_memory_g(aloadb_gc
, ET
[below
].value
,
2261 ET
[ET
[below
].right
].value
, Result
);
2264 access_memory_g(aload_gc
, ET
[below
].value
,
2265 ET
[ET
[below
].right
].value
, Result
);
2269 assembleg_store(ET
[below
].value
,
2270 ET
[ET
[below
].right
].value
);
2271 if (!void_flag
) write_result_g(Result
, ET
[below
].value
);
2274 case ARROW_SETEQUALS_OP
:
2276 { assembleg_store(temp_var1
,
2277 ET
[ET
[ET
[below
].right
].right
].value
);
2278 access_memory_g(astoreb_gc
, ET
[below
].value
,
2279 ET
[ET
[below
].right
].value
,
2281 write_result_g(Result
, temp_var1
);
2283 else access_memory_g(astoreb_gc
, ET
[below
].value
,
2284 ET
[ET
[below
].right
].value
,
2285 ET
[ET
[ET
[below
].right
].right
].value
);
2288 case DARROW_SETEQUALS_OP
:
2290 { assembleg_store(temp_var1
,
2291 ET
[ET
[ET
[below
].right
].right
].value
);
2292 access_memory_g(astore_gc
, ET
[below
].value
,
2293 ET
[ET
[below
].right
].value
,
2295 write_result_g(Result
, temp_var1
);
2298 access_memory_g(astore_gc
, ET
[below
].value
,
2299 ET
[ET
[below
].right
].value
,
2300 ET
[ET
[ET
[below
].right
].right
].value
);
2304 assembleg_inc(ET
[below
].value
);
2305 if (!void_flag
) write_result_g(Result
, ET
[below
].value
);
2308 assembleg_dec(ET
[below
].value
);
2309 if (!void_flag
) write_result_g(Result
, ET
[below
].value
);
2312 if (!void_flag
) write_result_g(Result
, ET
[below
].value
);
2313 assembleg_inc(ET
[below
].value
);
2316 if (!void_flag
) write_result_g(Result
, ET
[below
].value
);
2317 assembleg_dec(ET
[below
].value
);
2321 assembleg_store(temp_var1
, ET
[below
].value
);
2322 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2323 access_memory_g(aloadb_gc
, temp_var1
, temp_var2
, temp_var3
);
2324 assembleg_inc(temp_var3
);
2325 access_memory_g(astoreb_gc
, temp_var1
, temp_var2
, temp_var3
);
2326 if (!void_flag
) write_result_g(Result
, temp_var3
);
2330 assembleg_store(temp_var1
, ET
[below
].value
);
2331 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2332 access_memory_g(aloadb_gc
, temp_var1
, temp_var2
, temp_var3
);
2333 assembleg_dec(temp_var3
);
2334 access_memory_g(astoreb_gc
, temp_var1
, temp_var2
, temp_var3
);
2335 if (!void_flag
) write_result_g(Result
, temp_var3
);
2338 case ARROW_POST_INC_OP
:
2339 assembleg_store(temp_var1
, ET
[below
].value
);
2340 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2341 access_memory_g(aloadb_gc
, temp_var1
, temp_var2
, temp_var3
);
2342 if (!void_flag
) write_result_g(Result
, temp_var3
);
2343 assembleg_inc(temp_var3
);
2344 access_memory_g(astoreb_gc
, temp_var1
, temp_var2
, temp_var3
);
2347 case ARROW_POST_DEC_OP
:
2348 assembleg_store(temp_var1
, ET
[below
].value
);
2349 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2350 access_memory_g(aloadb_gc
, temp_var1
, temp_var2
, temp_var3
);
2351 if (!void_flag
) write_result_g(Result
, temp_var3
);
2352 assembleg_dec(temp_var3
);
2353 access_memory_g(astoreb_gc
, temp_var1
, temp_var2
, temp_var3
);
2357 assembleg_store(temp_var1
, ET
[below
].value
);
2358 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2359 access_memory_g(aload_gc
, temp_var1
, temp_var2
, temp_var3
);
2360 assembleg_inc(temp_var3
);
2361 access_memory_g(astore_gc
, temp_var1
, temp_var2
, temp_var3
);
2362 if (!void_flag
) write_result_g(Result
, temp_var3
);
2366 assembleg_store(temp_var1
, ET
[below
].value
);
2367 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2368 access_memory_g(aload_gc
, temp_var1
, temp_var2
, temp_var3
);
2369 assembleg_dec(temp_var3
);
2370 access_memory_g(astore_gc
, temp_var1
, temp_var2
, temp_var3
);
2371 if (!void_flag
) write_result_g(Result
, temp_var3
);
2374 case DARROW_POST_INC_OP
:
2375 assembleg_store(temp_var1
, ET
[below
].value
);
2376 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2377 access_memory_g(aload_gc
, temp_var1
, temp_var2
, temp_var3
);
2378 if (!void_flag
) write_result_g(Result
, temp_var3
);
2379 assembleg_inc(temp_var3
);
2380 access_memory_g(astore_gc
, temp_var1
, temp_var2
, temp_var3
);
2383 case DARROW_POST_DEC_OP
:
2384 assembleg_store(temp_var1
, ET
[below
].value
);
2385 assembleg_store(temp_var2
, ET
[ET
[below
].right
].value
);
2386 access_memory_g(aload_gc
, temp_var1
, temp_var2
, temp_var3
);
2387 if (!void_flag
) write_result_g(Result
, temp_var3
);
2388 assembleg_dec(temp_var3
);
2389 access_memory_g(astore_gc
, temp_var1
, temp_var2
, temp_var3
);
2394 AO
= veneer_routine(RV__Pr_VR
);
2395 goto TwoArgFunctionCall
;
2398 AO
= veneer_routine(RA__Pr_VR
);
2399 goto TwoArgFunctionCall
;
2402 AO
= veneer_routine(RL__Pr_VR
);
2403 goto TwoArgFunctionCall
;
2406 case MESSAGE_CALL_OP
:
2407 AO2
= veneer_routine(CA__Pr_VR
);
2409 goto DoFunctionCall
;
2411 case MESSAGE_INC_OP
:
2412 case PROPERTY_INC_OP
:
2413 AO
= veneer_routine(IB__Pr_VR
);
2414 goto TwoArgFunctionCall
;
2415 case MESSAGE_DEC_OP
:
2416 case PROPERTY_DEC_OP
:
2417 AO
= veneer_routine(DB__Pr_VR
);
2418 goto TwoArgFunctionCall
;
2419 case MESSAGE_POST_INC_OP
:
2420 case PROPERTY_POST_INC_OP
:
2421 AO
= veneer_routine(IA__Pr_VR
);
2422 goto TwoArgFunctionCall
;
2423 case MESSAGE_POST_DEC_OP
:
2424 case PROPERTY_POST_DEC_OP
:
2425 AO
= veneer_routine(DA__Pr_VR
);
2426 goto TwoArgFunctionCall
;
2428 AO
= veneer_routine(RA__Sc_VR
);
2429 goto TwoArgFunctionCall
;
2433 assembly_operand AO2
= ET
[below
].value
;
2434 assembly_operand AO3
= ET
[ET
[below
].right
].value
;
2436 assembleg_call_2(AO
, AO2
, AO3
, zero_operand
);
2438 assembleg_call_2(AO
, AO2
, AO3
, Result
);
2442 case PROPERTY_SETEQUALS_OP
:
2443 case MESSAGE_SETEQUALS_OP
:
2444 if (runtime_error_checking_switch
&& (!veneer_mode
))
2445 AO
= veneer_routine(RT__ChPS_VR
);
2447 AO
= veneer_routine(WV__Pr_VR
);
2450 assembly_operand AO2
= ET
[below
].value
;
2451 assembly_operand AO3
= ET
[ET
[below
].right
].value
;
2452 assembly_operand AO4
= ET
[ET
[ET
[below
].right
].right
].value
;
2453 if (AO4
.type
== LOCALVAR_OT
&& AO4
.value
== 0) {
2454 /* Rightmost is on the stack; reduce to previous case. */
2455 if (AO2
.type
== LOCALVAR_OT
&& AO2
.value
== 0) {
2456 if (AO3
.type
== LOCALVAR_OT
&& AO3
.value
== 0) {
2457 /* both already on stack. */
2460 assembleg_store(stack_pointer
, AO3
);
2461 assembleg_0(stkswap_gc
);
2465 if (AO3
.type
== LOCALVAR_OT
&& AO3
.value
== 0) {
2466 assembleg_store(stack_pointer
, AO2
);
2469 assembleg_store(stack_pointer
, AO3
);
2470 assembleg_store(stack_pointer
, AO2
);
2475 /* We have to get the rightmost on the stack, below the
2477 if (AO3
.type
== LOCALVAR_OT
&& AO3
.value
== 0) {
2478 if (AO2
.type
== LOCALVAR_OT
&& AO2
.value
== 0) {
2479 assembleg_store(stack_pointer
, AO4
);
2480 assembleg_2(stkroll_gc
, three_operand
, one_operand
);
2483 assembleg_store(stack_pointer
, AO4
);
2484 assembleg_0(stkswap_gc
);
2485 assembleg_store(stack_pointer
, AO2
);
2489 if (AO2
.type
== LOCALVAR_OT
&& AO2
.value
== 0) {
2490 assembleg_store(stack_pointer
, AO4
);
2491 assembleg_store(stack_pointer
, AO3
);
2492 assembleg_2(stkroll_gc
, three_operand
, two_operand
);
2495 assembleg_store(stack_pointer
, AO4
);
2496 assembleg_store(stack_pointer
, AO3
);
2497 assembleg_store(stack_pointer
, AO2
);
2502 assembleg_3(call_gc
, AO
, three_operand
, zero_operand
);
2504 assembleg_3(call_gc
, AO
, three_operand
, Result
);
2511 if (ET
[below
].value
.type
== SYSFUN_OT
)
2512 { int sf_number
= ET
[below
].value
.value
;
2514 i
= ET
[below
].right
;
2516 { error("Argument to system function missing");
2517 AI
.operand
[0] = one_operand
;
2518 AI
.operand_count
= 1;
2522 while (i
!= -1) { j
++; i
= ET
[i
].right
; }
2524 if (((sf_number
!= INDIRECT_SYSF
) &&
2525 (sf_number
!= GLK_SYSF
) &&
2526 (sf_number
!= RANDOM_SYSF
) && (j
> 1)))
2528 error("System function given with too many arguments");
2530 if (sf_number
!= RANDOM_SYSF
)
2532 i
= ET
[below
].right
;
2533 for (jcount
= 0; jcount
< j
; jcount
++)
2534 { AI
.operand
[jcount
] = ET
[i
].value
;
2537 AI
.operand_count
= j
;
2545 { assembly_operand AO
, AO2
;
2549 set_constant_ot(&AO
);
2550 AO2
.type
= CONSTANT_OT
;
2551 AO2
.value
= begin_word_array();
2552 AO2
.marker
= ARRAY_MV
;
2554 for (arg_c
=0, arg_et
= ET
[below
].right
;arg_c
<j
;
2555 arg_c
++, arg_et
= ET
[arg_et
].right
)
2556 { if (ET
[arg_et
].value
.type
== LOCALVAR_OT
2557 || ET
[arg_et
].value
.type
== GLOBALVAR_OT
)
2558 error("Only constants can be used as possible 'random' results");
2559 array_entry(arg_c
, ET
[arg_et
].value
);
2561 finish_array(arg_c
);
2563 assembleg_2(random_gc
, AO
, stack_pointer
);
2564 assembleg_3(aload_gc
, AO2
, stack_pointer
, Result
);
2567 assembleg_2(random_gc
,
2568 ET
[ET
[below
].right
].value
, stack_pointer
);
2569 assembleg_3(add_gc
, stack_pointer
, one_operand
,
2575 { assembly_operand AO
;
2576 AO
= ET
[ET
[below
].right
].value
;
2577 if (runtime_error_checking_switch
)
2578 AO
= check_nonzero_at_runtime(AO
, -1,
2580 AO2
.type
= BYTECONSTANT_OT
;
2581 AO2
.value
= GOBJFIELD_PARENT();
2583 assembleg_3(aload_gc
, AO
, AO2
, Result
);
2589 { assembly_operand AO
;
2590 AO
= ET
[ET
[below
].right
].value
;
2591 if (runtime_error_checking_switch
)
2592 AO
= check_nonzero_at_runtime(AO
, -1,
2593 (sf_number
==CHILD_SYSF
)?CHILD_RTE
:ELDEST_RTE
);
2594 AO2
.type
= BYTECONSTANT_OT
;
2595 AO2
.value
= GOBJFIELD_CHILD();
2597 assembleg_3(aload_gc
, AO
, AO2
, Result
);
2603 { assembly_operand AO
;
2604 AO
= ET
[ET
[below
].right
].value
;
2605 if (runtime_error_checking_switch
)
2606 AO
= check_nonzero_at_runtime(AO
, -1,
2607 (sf_number
==SIBLING_SYSF
)
2608 ?SIBLING_RTE
:YOUNGER_RTE
);
2609 AO2
.type
= BYTECONSTANT_OT
;
2610 AO2
.value
= GOBJFIELD_SIBLING();
2612 assembleg_3(aload_gc
, AO
, AO2
, Result
);
2617 { assembly_operand AO
;
2618 AO
= ET
[ET
[below
].right
].value
;
2619 if (runtime_error_checking_switch
)
2620 AO
= check_nonzero_at_runtime(AO
, -1,
2622 AO2
.type
= BYTECONSTANT_OT
;
2623 AO2
.value
= GOBJFIELD_CHILD();
2625 assembleg_store(temp_var1
, zero_operand
);
2626 assembleg_3(aload_gc
, AO
, AO2
, temp_var2
);
2627 AO2
.value
= GOBJFIELD_SIBLING();
2628 assemble_label_no(next_label
);
2629 assembleg_1_branch(jz_gc
, temp_var2
, next_label
+1);
2630 assembleg_3(add_gc
, temp_var1
, one_operand
,
2632 assembleg_3(aload_gc
, temp_var2
, AO2
, temp_var2
);
2633 assembleg_0_branch(jump_gc
, next_label
);
2634 assemble_label_no(next_label
+1);
2637 write_result_g(Result
, temp_var1
);
2642 i
= ET
[below
].right
;
2643 goto IndirectFunctionCallG
;
2646 AO2
= veneer_routine(Glk__Wrap_VR
);
2647 i
= ET
[below
].right
;
2648 goto DoFunctionCall
;
2650 case METACLASS_SYSF
:
2651 assembleg_call_1(veneer_routine(Metaclass_VR
),
2652 ET
[ET
[below
].right
].value
, Result
);
2656 AO
= ET
[ET
[below
].right
].value
;
2657 if (runtime_error_checking_switch
)
2658 AO
= check_nonzero_at_runtime(AO
, -1,
2661 AO2
.value
= GOBJFIELD_CHILD();
2662 AO2
.type
= BYTECONSTANT_OT
;
2663 assembleg_3(aload_gc
, AO
, AO2
, temp_var1
);
2664 AO2
.value
= GOBJFIELD_SIBLING();
2665 assembleg_1_branch(jz_gc
, temp_var1
, next_label
+1);
2666 assemble_label_no(next_label
);
2667 assembleg_3(aload_gc
, temp_var1
, AO2
, temp_var2
);
2668 assembleg_1_branch(jz_gc
, temp_var2
, next_label
+1);
2669 assembleg_store(temp_var1
, temp_var2
);
2670 assembleg_0_branch(jump_gc
, next_label
);
2671 assemble_label_no(next_label
+1);
2673 write_result_g(Result
, temp_var1
);
2678 AO
= ET
[ET
[below
].right
].value
;
2679 if (runtime_error_checking_switch
)
2680 AO
= check_nonzero_at_runtime(AO
, -1,
2682 assembleg_store(temp_var3
, AO
);
2684 AO2
.value
= GOBJFIELD_PARENT();
2685 AO2
.type
= BYTECONSTANT_OT
;
2686 assembleg_3(aload_gc
, temp_var3
, AO2
, temp_var1
);
2687 assembleg_1_branch(jz_gc
, temp_var1
, next_label
+2);
2688 AO2
.value
= GOBJFIELD_CHILD();
2689 assembleg_3(aload_gc
, temp_var1
, AO2
, temp_var1
);
2690 assembleg_1_branch(jz_gc
, temp_var1
, next_label
+2);
2691 assembleg_2_branch(jeq_gc
, temp_var3
, temp_var1
,
2693 assemble_label_no(next_label
);
2694 AO2
.value
= GOBJFIELD_SIBLING();
2695 assembleg_3(aload_gc
, temp_var1
, AO2
, temp_var2
);
2696 assembleg_2_branch(jeq_gc
, temp_var3
, temp_var2
,
2698 assembleg_store(temp_var1
, temp_var2
);
2699 assembleg_0_branch(jump_gc
, next_label
);
2700 assemble_label_no(next_label
+1);
2701 assembleg_store(temp_var1
, zero_operand
);
2702 assemble_label_no(next_label
+2);
2704 write_result_g(Result
, temp_var1
);
2709 error("*** system function not implemented ***");
2718 IndirectFunctionCallG
:
2720 /* Get the function address. */
2727 /* If all the function arguments are in local/global
2728 variables, we have to push them all on the stack.
2729 If all of them are on the stack, we have to do nothing.
2730 If some are and some aren't, we have a hopeless mess,
2731 and we should throw a compiler error.
2737 /* begin part of patch G03701 */
2746 assembleg_2(callf_gc
, AO2
, void_flag
? zero_operand
: Result
);
2747 } else if (nargs
==1) {
2748 assembleg_call_1(AO2
, ET
[i
].value
, void_flag
? zero_operand
: Result
);
2749 } else if (nargs
==2) {
2750 assembly_operand o1
= ET
[i
].value
;
2751 assembly_operand o2
= ET
[ET
[i
].right
].value
;
2752 assembleg_call_2(AO2
, o1
, o2
, void_flag
? zero_operand
: Result
);
2753 } else if (nargs
==3) {
2754 assembly_operand o1
= ET
[i
].value
;
2755 assembly_operand o2
= ET
[ET
[i
].right
].value
;
2756 assembly_operand o3
= ET
[ET
[ET
[i
].right
].right
].value
;
2757 assembleg_call_3(AO2
, o1
, o2
, o3
, void_flag
? zero_operand
: Result
);
2762 if (ET
[i
].value
.type
== LOCALVAR_OT
2763 && ET
[i
].value
.value
== 0) {
2767 assembleg_store(stack_pointer
, ET
[i
].value
);
2774 if (onstack
&& offstack
)
2775 error("*** Function call cannot be generated with mixed arguments ***");
2777 error("*** Function call cannot be generated with more than one nonstack argument ***");
2781 set_constant_ot(&AO
);
2784 assembleg_3(call_gc
, AO2
, AO
, zero_operand
);
2786 assembleg_3(call_gc
, AO2
, AO
, Result
);
2788 } /* else nargs>=4 */
2789 } /* DoFunctionCall: */
2794 printf("** Trouble op = %d i.e. '%s' **\n",
2795 opnum
, operators
[opnum
].description
);
2796 compiler_error("Expr code gen: Can't generate yet");
2800 ET
[n
].value
= Result
;
2806 if (ET
[n
].to_expression
)
2807 { if (ET
[n
].true_label
!= -1)
2808 { assemblez_1(push_zc
, zero_operand
);
2809 assemblez_jump(next_label
++);
2810 assemble_label_no(ET
[n
].true_label
);
2811 assemblez_1(push_zc
, one_operand
);
2812 assemble_label_no(next_label
-1);
2815 { assemblez_1(push_zc
, one_operand
);
2816 assemblez_jump(next_label
++);
2817 assemble_label_no(ET
[n
].false_label
);
2818 assemblez_1(push_zc
, zero_operand
);
2819 assemble_label_no(next_label
-1);
2821 ET
[n
].value
= stack_pointer
;
2824 if (ET
[n
].label_after
!= -1)
2825 assemble_label_no(ET
[n
].label_after
);
2830 if (ET
[n
].to_expression
)
2831 { if (ET
[n
].true_label
!= -1)
2832 { assembleg_store(stack_pointer
, zero_operand
);
2833 assembleg_jump(next_label
++);
2834 assemble_label_no(ET
[n
].true_label
);
2835 assembleg_store(stack_pointer
, one_operand
);
2836 assemble_label_no(next_label
-1);
2839 { assembleg_store(stack_pointer
, one_operand
);
2840 assembleg_jump(next_label
++);
2841 assemble_label_no(ET
[n
].false_label
);
2842 assembleg_store(stack_pointer
, zero_operand
);
2843 assemble_label_no(next_label
-1);
2845 ET
[n
].value
= stack_pointer
;
2848 if (ET
[n
].label_after
!= -1)
2849 assemble_label_no(ET
[n
].label_after
);
2856 assembly_operand
code_generate(assembly_operand AO
, int context
, int label
)
2858 /* Used in three contexts: VOID_CONTEXT, CONDITION_CONTEXT and
2861 If CONDITION_CONTEXT, then compile code branching to label number
2862 "label" if the condition is false: there's no return value.
2863 (Except that if label is -3 or -4 (internal codes for rfalse and
2864 rtrue rather than branch) then this is for branching when the
2865 condition is true. This is used for optimising code generation
2866 for "if" statements.)
2868 Otherwise return the assembly operand containing the result
2869 (probably the stack pointer variable but not necessarily:
2870 e.g. is would be short constant 2 from the expression "j++, 2") */
2874 if (AO
.type
!= EXPRESSION_OT
)
2876 { case VOID_CONTEXT
:
2877 value_in_void_context(AO
);
2878 AO
.type
= OMITTED_OT
;
2881 case CONDITION_CONTEXT
:
2883 if (label
< -2) assemblez_1_branch(jz_zc
, AO
, label
, FALSE
);
2884 else assemblez_1_branch(jz_zc
, AO
, label
, TRUE
);
2888 assembleg_1_branch(jnz_gc
, AO
, label
);
2890 assembleg_1_branch(jz_gc
, AO
, label
);
2892 AO
.type
= OMITTED_OT
;
2899 if (expr_trace_level
>= 2)
2900 { printf("Raw parse tree:\n"); show_tree(AO
, FALSE
);
2903 if (context
== CONDITION_CONTEXT
)
2904 { if (label
< -2) annotate_for_conditions(AO
.value
, label
, -1);
2905 else annotate_for_conditions(AO
.value
, -1, label
);
2907 else annotate_for_conditions(AO
.value
, -1, -1);
2909 if (expr_trace_level
>= 1)
2910 { printf("Code generation for expression in ");
2912 { case VOID_CONTEXT
: printf("void"); break;
2913 case CONDITION_CONTEXT
: printf("condition"); break;
2914 case QUANTITY_CONTEXT
: printf("quantity"); break;
2915 case ASSEMBLY_CONTEXT
: printf("assembly"); break;
2916 case ARRAY_CONTEXT
: printf("array initialisation"); break;
2917 default: printf("* ILLEGAL *"); break;
2919 printf(" context with annotated tree:\n");
2920 show_tree(AO
, TRUE
);
2923 generate_code_from(AO
.value
, (context
==VOID_CONTEXT
));
2924 return ET
[AO
.value
].value
;
2927 /* ========================================================================= */
2928 /* Data structure management routines */
2929 /* ------------------------------------------------------------------------- */
2931 extern void init_expressc_vars(void)
2935 extern void expressc_begin_pass(void)
2939 extern void expressc_allocate_arrays(void)
2943 extern void expressc_free_arrays(void)
2947 /* ========================================================================= */