1 /* ------------------------------------------------------------------------- */
2 /* "states" : Statement translator */
4 /* Part of Inform 6.33 */
5 /* copyright (c) Graham Nelson 1993 - 2014 */
7 /* ------------------------------------------------------------------------- */
11 static int match_colon(void)
13 if (token_type
== SEP_TT
)
14 { if (token_value
== SEMICOLON_SEP
)
15 warning("Unlike C, Inform uses ':' to divide parts \
16 of a 'for' loop specification: replacing ';' with ':'");
18 if (token_value
!= COLON_SEP
)
19 { ebf_error("':'", token_text
);
20 panic_mode_error_recovery();
25 { ebf_error("':'", token_text
);
26 panic_mode_error_recovery();
32 static void match_open_bracket(void)
34 if ((token_type
== SEP_TT
) && (token_value
== OPENB_SEP
)) return;
36 ebf_error("'('", token_text
);
39 extern void match_close_bracket(void)
41 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
)) return;
43 ebf_error("')'", token_text
);
46 static void parse_action(void)
47 { int level
= 1, args
= 0, codegen_action
;
48 assembly_operand AO
, AO2
, AO3
, AO4
, AO5
;
50 /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
51 or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
52 to R_Process() with those four arguments. (The latter form,
53 with double brackets, means "return true afterwards".)
55 The R_Process() function should be supplied by the library,
56 although a stub is defined in the veneer.
58 The NOUN, SECOND, and ACTOR arguments are optional. If not
59 supplied, R_Process() will be called with fewer arguments.
60 (But if you supply ACTOR, it must be preceded by a comma.
61 <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
63 To complicate life, the ACTION argument may be a bare action
64 name or a parenthesized expression. (So <Take> is equivalent
65 to <(##Take)>.) We have to peek at the first token, checking
66 whether it's an open-paren, to distinguish these cases.
68 You may ask why the ACTOR argument is last; the "natural"
69 Inform ordering would be "<floyd, take ball>". True! Sadly,
70 Inform's lexer isn't smart enough to parse this consistently,
74 dont_enter_into_symbol_table
= TRUE
;
76 if ((token_type
== SEP_TT
) && (token_value
== LESS_SEP
))
77 { level
= 2; get_next_token();
79 dont_enter_into_symbol_table
= FALSE
;
81 /* Peek at the next token; see if it's an open-paren. */
82 if ((token_type
==SEP_TT
) && (token_value
==OPENB_SEP
))
84 AO2
= parse_expression(ACTION_Q_CONTEXT
);
85 codegen_action
= TRUE
;
88 { codegen_action
= FALSE
;
89 AO2
= action_of_name(token_text
);
96 if (!((token_type
== SEP_TT
) && (token_value
== GREATER_SEP
|| token_value
== COMMA_SEP
)))
99 AO3
= parse_expression(ACTION_Q_CONTEXT
);
103 if (!((token_type
== SEP_TT
) && (token_value
== GREATER_SEP
|| token_value
== COMMA_SEP
)))
106 AO4
= parse_expression(QUANTITY_CONTEXT
);
109 if (!((token_type
== SEP_TT
) && (token_value
== GREATER_SEP
|| token_value
== COMMA_SEP
)))
111 ebf_error("',' or '>'", token_text
);
114 if ((token_type
== SEP_TT
) && (token_value
== COMMA_SEP
))
116 if (!glulx_mode
&& (version_number
< 4))
118 error("<x, y> syntax is not available in Z-code V3 or earlier");
121 AO5
= parse_expression(QUANTITY_CONTEXT
);
123 if (!((token_type
== SEP_TT
) && (token_value
== GREATER_SEP
)))
125 ebf_error("'>'", token_text
);
131 if (!((token_type
== SEP_TT
) && (token_value
== GREATER_SEP
)))
133 ebf_error("'>>'", token_text
);
139 AO
= veneer_routine(R_Process_VR
);
143 if (codegen_action
) AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
144 if (version_number
>=5)
145 assemblez_2(call_2n_zc
, AO
, AO2
);
147 if (version_number
==4)
148 assemblez_2_to(call_vs_zc
, AO
, AO2
, temp_var1
);
150 assemblez_2_to(call_zc
, AO
, AO2
, temp_var1
);
153 AO3
= code_generate(AO3
, QUANTITY_CONTEXT
, -1);
154 if (codegen_action
) AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
155 if (version_number
>=5)
156 assemblez_3(call_vn_zc
, AO
, AO2
, AO3
);
158 if (version_number
==4)
159 assemblez_3_to(call_vs_zc
, AO
, AO2
, AO3
, temp_var1
);
161 assemblez_3_to(call_zc
, AO
, AO2
, AO3
, temp_var1
);
164 AO4
= code_generate(AO4
, QUANTITY_CONTEXT
, -1);
165 AO3
= code_generate(AO3
, QUANTITY_CONTEXT
, -1);
166 if (codegen_action
) AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
167 if (version_number
>=5)
168 assemblez_4(call_vn_zc
, AO
, AO2
, AO3
, AO4
);
170 if (version_number
==4)
171 assemblez_4_to(call_vs_zc
, AO
, AO2
, AO3
, AO4
, temp_var1
);
173 assemblez_4(call_zc
, AO
, AO2
, AO3
, AO4
);
176 AO5
= code_generate(AO5
, QUANTITY_CONTEXT
, -1);
177 AO4
= code_generate(AO4
, QUANTITY_CONTEXT
, -1);
178 AO3
= code_generate(AO3
, QUANTITY_CONTEXT
, -1);
179 if (codegen_action
) AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
180 if (version_number
>=5)
181 assemblez_5(call_vn2_zc
, AO
, AO2
, AO3
, AO4
, AO5
);
183 if (version_number
==4)
184 assemblez_5_to(call_vs2_zc
, AO
, AO2
, AO3
, AO4
, AO5
, temp_var1
);
185 /* if V3 or earlier, we've already displayed an error */
190 if (level
== 2) assemblez_0(rtrue_zc
);
195 AO
= veneer_routine(R_Process_VR
);
201 AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
202 assembleg_call_1(AO
, AO2
, zero_operand
);
206 AO3
= code_generate(AO3
, QUANTITY_CONTEXT
, -1);
208 AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
209 assembleg_call_2(AO
, AO2
, AO3
, zero_operand
);
213 AO4
= code_generate(AO4
, QUANTITY_CONTEXT
, -1);
214 AO3
= code_generate(AO3
, QUANTITY_CONTEXT
, -1);
216 AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
217 assembleg_call_3(AO
, AO2
, AO3
, AO4
, zero_operand
);
221 AO5
= code_generate(AO5
, QUANTITY_CONTEXT
, -1);
222 if (!((AO5
.type
== LOCALVAR_OT
) && (AO5
.value
== 0)))
223 assembleg_store(stack_pointer
, AO5
);
224 AO4
= code_generate(AO4
, QUANTITY_CONTEXT
, -1);
225 if (!((AO4
.type
== LOCALVAR_OT
) && (AO4
.value
== 0)))
226 assembleg_store(stack_pointer
, AO4
);
227 AO3
= code_generate(AO3
, QUANTITY_CONTEXT
, -1);
228 if (!((AO3
.type
== LOCALVAR_OT
) && (AO3
.value
== 0)))
229 assembleg_store(stack_pointer
, AO3
);
231 AO2
= code_generate(AO2
, QUANTITY_CONTEXT
, -1);
232 if (!((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0)))
233 assembleg_store(stack_pointer
, AO2
);
234 assembleg_3(call_gc
, AO
, four_operand
, zero_operand
);
239 assembleg_1(return_gc
, one_operand
);
244 extern int parse_label(void)
248 if ((token_type
== SYMBOL_TT
) &&
249 (stypes
[token_value
] == LABEL_T
))
250 { sflags
[token_value
] |= USED_SFLAG
;
251 return(svals
[token_value
]);
254 if ((token_type
== SYMBOL_TT
) && (sflags
[token_value
] & UNKNOWN_SFLAG
))
255 { assign_symbol(token_value
, next_label
, LABEL_T
);
256 define_symbol_label(token_value
);
258 sflags
[token_value
] |= CHANGE_SFLAG
+ USED_SFLAG
;
259 return(svals
[token_value
]);
262 ebf_error("label name", token_text
);
266 static void parse_print_z(int finally_return
)
267 { int count
= 0; assembly_operand AO
;
269 /* print <printlist> -------------------------------------------------- */
270 /* print_ret <printlist> ---------------------------------------------- */
271 /* <literal-string> --------------------------------------------------- */
273 /* <printlist> is a comma-separated list of items: */
275 /* <literal-string> */
276 /* <other-expression> */
277 /* (char) <expression> */
278 /* (address) <expression> */
279 /* (string) <expression> */
280 /* (a) <expression> */
281 /* (the) <expression> */
282 /* (The) <expression> */
283 /* (name) <expression> */
284 /* (number) <expression> */
285 /* (property) <expression> */
286 /* (<routine>) <expression> */
287 /* (object) <expression> (for use in low-level code only) */
288 /* --------------------------------------------------------------------- */
291 { AI
.text
= token_text
;
292 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) break;
295 if (strlen(token_text
) > 32)
296 { AO
.marker
= STRING_MV
;
297 AO
.type
= LONG_CONSTANT_OT
;
298 AO
.value
= compile_string(token_text
, FALSE
, FALSE
);
299 assemblez_1(print_paddr_zc
, AO
);
302 if ((token_type
== SEP_TT
)
303 && (token_value
== SEMICOLON_SEP
))
304 { assemblez_0(new_line_zc
);
305 assemblez_0(rtrue_zc
);
314 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
))
315 { assemblez_0(print_ret_zc
); return;
319 assemblez_0(print_zc
);
323 if (token_value
== OPENB_SEP
)
324 { misc_keywords
.enabled
= TRUE
;
327 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
))
328 { assembly_operand AO1
;
330 put_token_back(); put_token_back();
331 local_variables
.enabled
= FALSE
;
333 misc_keywords
.enabled
= FALSE
;
334 local_variables
.enabled
= TRUE
;
336 if ((token_type
== STATEMENT_TT
)
337 &&(token_value
== STRING_CODE
))
338 { token_type
= MISC_KEYWORD_TT
;
339 token_value
= STRING_MK
;
344 case MISC_KEYWORD_TT
:
347 if (runtime_error_checking_switch
)
348 { AO
= veneer_routine(RT__ChPrintC_VR
);
353 parse_expression(QUANTITY_CONTEXT
),
354 QUANTITY_CONTEXT
, -1);
355 assemblez_1(print_char_zc
, AO1
);
358 if (runtime_error_checking_switch
)
359 { AO
= veneer_routine(RT__ChPrintA_VR
);
364 parse_expression(QUANTITY_CONTEXT
),
365 QUANTITY_CONTEXT
, -1);
366 assemblez_1(print_addr_zc
, AO1
);
369 if (runtime_error_checking_switch
)
370 { AO
= veneer_routine(RT__ChPrintS_VR
);
375 parse_expression(QUANTITY_CONTEXT
),
376 QUANTITY_CONTEXT
, -1);
377 assemblez_1(print_paddr_zc
, AO1
);
380 if (runtime_error_checking_switch
)
381 { AO
= veneer_routine(RT__ChPrintO_VR
);
386 parse_expression(QUANTITY_CONTEXT
),
387 QUANTITY_CONTEXT
, -1);
388 assemblez_1(print_obj_zc
, AO1
);
391 AO
= veneer_routine(DefArt_VR
);
395 AO
= veneer_routine(InDefArt_VR
);
398 AO
= veneer_routine(CDefArt_VR
);
401 AO
= veneer_routine(CInDefArt_VR
);
404 AO
= veneer_routine(PrintShortName_VR
);
407 AO
= veneer_routine(EnglishNumber_VR
);
410 AO
= veneer_routine(Print__Pname_VR
);
413 error_named("A reserved word was used as a print specification:",
419 if (sflags
[token_value
] & UNKNOWN_SFLAG
)
420 { AO
.type
= LONG_CONSTANT_OT
;
421 AO
.value
= token_value
;
422 AO
.marker
= SYMBOL_MV
;
425 { AO
.type
= LONG_CONSTANT_OT
;
426 AO
.value
= svals
[token_value
];
427 AO
.marker
= IROUTINE_MV
;
428 if (stypes
[token_value
] != ROUTINE_T
)
429 ebf_error("printing routine name", token_text
);
431 sflags
[token_value
] |= USED_SFLAG
;
436 if (version_number
>= 5)
437 assemblez_2(call_2n_zc
, AO
,
438 code_generate(parse_expression(QUANTITY_CONTEXT
),
439 QUANTITY_CONTEXT
, -1));
440 else if (version_number
== 4)
441 assemblez_2_to(call_vs_zc
, AO
,
442 code_generate(parse_expression(QUANTITY_CONTEXT
),
443 QUANTITY_CONTEXT
, -1), temp_var1
);
445 assemblez_2_to(call_zc
, AO
,
446 code_generate(parse_expression(QUANTITY_CONTEXT
),
447 QUANTITY_CONTEXT
, -1), temp_var1
);
450 default: ebf_error("print specification", token_text
);
452 assemblez_1(print_num_zc
,
453 code_generate(parse_expression(QUANTITY_CONTEXT
),
454 QUANTITY_CONTEXT
, -1));
458 put_token_back(); put_token_back(); put_token_back();
459 misc_keywords
.enabled
= FALSE
;
460 assemblez_1(print_num_zc
,
461 code_generate(parse_expression(QUANTITY_CONTEXT
),
462 QUANTITY_CONTEXT
, -1));
467 put_token_back(); misc_keywords
.enabled
= FALSE
;
468 assemblez_1(print_num_zc
,
469 code_generate(parse_expression(QUANTITY_CONTEXT
),
470 QUANTITY_CONTEXT
, -1));
474 PrintTermDone
: misc_keywords
.enabled
= FALSE
;
478 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) break;
479 if ((token_type
!= SEP_TT
) || (token_value
!= COMMA_SEP
))
480 { ebf_error("comma", token_text
);
481 panic_mode_error_recovery(); return;
483 else get_next_token();
486 if (count
== 0) ebf_error("something to print", token_text
);
488 { assemblez_0(new_line_zc
);
489 assemblez_0(rtrue_zc
);
493 static void parse_print_g(int finally_return
)
494 { int count
= 0; assembly_operand AO
, AO2
;
496 /* print <printlist> -------------------------------------------------- */
497 /* print_ret <printlist> ---------------------------------------------- */
498 /* <literal-string> --------------------------------------------------- */
500 /* <printlist> is a comma-separated list of items: */
502 /* <literal-string> */
503 /* <other-expression> */
504 /* (char) <expression> */
505 /* (address) <expression> */
506 /* (string) <expression> */
507 /* (a) <expression> */
508 /* (A) <expression> */
509 /* (the) <expression> */
510 /* (The) <expression> */
511 /* (name) <expression> */
512 /* (number) <expression> */
513 /* (property) <expression> */
514 /* (<routine>) <expression> */
515 /* (object) <expression> (for use in low-level code only) */
516 /* --------------------------------------------------------------------- */
520 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) break;
523 /* We can't compile a string into the instruction,
524 so this always goes into the string area. */
525 { AO
.marker
= STRING_MV
;
526 AO
.type
= CONSTANT_OT
;
527 AO
.value
= compile_string(token_text
, FALSE
, FALSE
);
528 assembleg_1(streamstr_gc
, AO
);
531 if ((token_type
== SEP_TT
)
532 && (token_value
== SEMICOLON_SEP
))
533 { AO
.type
= BYTECONSTANT_OT
;
534 AO
.value
= 0x0A; AO
.marker
= 0;
535 assembleg_1(streamchar_gc
, AO
);
536 AO
.type
= BYTECONSTANT_OT
;
537 AO
.value
= 1; AO
.marker
= 0;
538 assembleg_1(return_gc
, AO
);
548 if (token_value
== OPENB_SEP
)
549 { misc_keywords
.enabled
= TRUE
;
552 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
))
553 { assembly_operand AO1
;
556 put_token_back(); put_token_back();
557 local_variables
.enabled
= FALSE
;
559 misc_keywords
.enabled
= FALSE
;
560 local_variables
.enabled
= TRUE
;
562 if ((token_type
== STATEMENT_TT
)
563 &&(token_value
== STRING_CODE
))
564 { token_type
= MISC_KEYWORD_TT
;
565 token_value
= STRING_MK
;
570 case MISC_KEYWORD_TT
:
573 if (runtime_error_checking_switch
)
574 { AO
= veneer_routine(RT__ChPrintC_VR
);
579 parse_expression(QUANTITY_CONTEXT
),
580 QUANTITY_CONTEXT
, -1);
581 if ((AO1
.type
== LOCALVAR_OT
) && (AO1
.value
== 0))
582 { assembleg_2(stkpeek_gc
, zero_operand
,
585 AO2
.type
= HALFCONSTANT_OT
; AO2
.value
= 0x100; AO2
.marker
= 0;
586 assembleg_2_branch(jgeu_gc
, AO1
, AO2
,
589 assembleg_1(streamchar_gc
, AO1
);
591 assemble_label_no(ln
);
592 assembleg_1(streamunichar_gc
, AO1
);
593 assemble_label_no(ln2
);
596 if (runtime_error_checking_switch
)
597 AO
= veneer_routine(RT__ChPrintA_VR
);
599 AO
= veneer_routine(Print__Addr_VR
);
602 if (runtime_error_checking_switch
)
603 { AO
= veneer_routine(RT__ChPrintS_VR
);
608 parse_expression(QUANTITY_CONTEXT
),
609 QUANTITY_CONTEXT
, -1);
610 assembleg_1(streamstr_gc
, AO1
);
613 if (runtime_error_checking_switch
)
614 { AO
= veneer_routine(RT__ChPrintO_VR
);
619 parse_expression(QUANTITY_CONTEXT
),
620 QUANTITY_CONTEXT
, -1);
621 AO2
.type
= BYTECONSTANT_OT
;
622 AO2
.value
= GOBJFIELD_NAME();
624 assembleg_3(aload_gc
, AO1
, AO2
,
626 assembleg_1(streamstr_gc
, stack_pointer
);
629 AO
= veneer_routine(DefArt_VR
);
633 AO
= veneer_routine(InDefArt_VR
);
636 AO
= veneer_routine(CDefArt_VR
);
639 AO
= veneer_routine(CInDefArt_VR
);
642 AO
= veneer_routine(PrintShortName_VR
);
645 AO
= veneer_routine(EnglishNumber_VR
);
648 AO
= veneer_routine(Print__Pname_VR
);
651 error_named("A reserved word was used as a print specification:",
657 if (sflags
[token_value
] & UNKNOWN_SFLAG
)
658 { AO
.type
= CONSTANT_OT
;
659 AO
.value
= token_value
;
660 AO
.marker
= SYMBOL_MV
;
663 { AO
.type
= CONSTANT_OT
;
664 AO
.value
= svals
[token_value
];
665 AO
.marker
= IROUTINE_MV
;
666 if (stypes
[token_value
] != ROUTINE_T
)
667 ebf_error("printing routine name", token_text
);
669 sflags
[token_value
] |= USED_SFLAG
;
674 AO2
.type
= ZEROCONSTANT_OT
;
675 AO2
.value
= 0; AO2
.marker
= 0;
677 code_generate(parse_expression(QUANTITY_CONTEXT
),
678 QUANTITY_CONTEXT
, -1),
682 default: ebf_error("print specification", token_text
);
684 assembleg_1(streamnum_gc
,
685 code_generate(parse_expression(QUANTITY_CONTEXT
),
686 QUANTITY_CONTEXT
, -1));
690 put_token_back(); put_token_back(); put_token_back();
691 misc_keywords
.enabled
= FALSE
;
692 assembleg_1(streamnum_gc
,
693 code_generate(parse_expression(QUANTITY_CONTEXT
),
694 QUANTITY_CONTEXT
, -1));
699 put_token_back(); misc_keywords
.enabled
= FALSE
;
700 assembleg_1(streamnum_gc
,
701 code_generate(parse_expression(QUANTITY_CONTEXT
),
702 QUANTITY_CONTEXT
, -1));
706 PrintTermDone
: misc_keywords
.enabled
= FALSE
;
710 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) break;
711 if ((token_type
!= SEP_TT
) || (token_value
!= COMMA_SEP
))
712 { ebf_error("comma", token_text
);
713 panic_mode_error_recovery(); return;
715 else get_next_token();
718 if (count
== 0) ebf_error("something to print", token_text
);
721 AO
.type
= BYTECONSTANT_OT
; AO
.value
= 0x0A; AO
.marker
= 0;
722 assembleg_1(streamchar_gc
, AO
);
723 AO
.type
= BYTECONSTANT_OT
; AO
.value
= 1; AO
.marker
= 0;
724 assembleg_1(return_gc
, AO
);
728 static void parse_statement_z(int break_label
, int continue_label
)
729 { int ln
, ln2
, ln3
, ln4
, flag
;
730 assembly_operand AO
, AO2
, AO3
, AO4
;
731 debug_location spare_debug_location1
, spare_debug_location2
;
735 if ((token_type
== SEP_TT
) && (token_value
== PROPERTY_SEP
))
736 { /* That is, a full stop, signifying a label */
739 if (token_type
== SYMBOL_TT
)
741 if (sflags
[token_value
] & UNKNOWN_SFLAG
)
742 { assign_symbol(token_value
, next_label
, LABEL_T
);
743 sflags
[token_value
] |= USED_SFLAG
;
744 assemble_label_no(next_label
);
745 define_symbol_label(token_value
);
749 { if (stypes
[token_value
] != LABEL_T
) goto LabelError
;
750 if (sflags
[token_value
] & CHANGE_SFLAG
)
751 { sflags
[token_value
] &= (~(CHANGE_SFLAG
));
752 assemble_label_no(svals
[token_value
]);
753 define_symbol_label(token_value
);
755 else error_named("Duplicate definition of label:", token_text
);
759 if ((token_type
!= SEP_TT
) || (token_value
!= SEMICOLON_SEP
))
760 { ebf_error("';'", token_text
);
761 put_token_back(); return;
764 /* Interesting point of Inform grammar: a statement can only
765 consist solely of a label when it is immediately followed
769 if ((token_type
== SEP_TT
) && (token_value
== CLOSE_BRACE_SEP
))
770 { put_token_back(); return;
772 statement_debug_location
= get_token_location();
773 parse_statement(break_label
, continue_label
);
776 LabelError
: ebf_error("label name", token_text
);
779 if ((token_type
== SEP_TT
) && (token_value
== HASH_SEP
))
780 { parse_directive(TRUE
);
781 parse_statement(break_label
, continue_label
); return;
784 if ((token_type
== SEP_TT
) && (token_value
== AT_SEP
))
785 { parse_assembly(); return;
788 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) return;
790 if (token_type
== DQ_TT
)
791 { parse_print_z(TRUE
); return;
794 if ((token_type
== SEP_TT
) && (token_value
== LESS_SEP
))
795 { parse_action(); goto StatementTerminator
; }
797 if (token_type
== EOF_TT
)
798 { ebf_error("statement", token_text
); return; }
800 if (token_type
!= STATEMENT_TT
)
802 AO
= parse_expression(VOID_CONTEXT
);
803 code_generate(AO
, VOID_CONTEXT
, -1);
804 if (vivc_flag
) { panic_mode_error_recovery(); return; }
805 goto StatementTerminator
;
808 statements
.enabled
= FALSE
;
812 /* -------------------------------------------------------------------- */
813 /* box <string-1> ... <string-n> -------------------------------------- */
814 /* -------------------------------------------------------------------- */
817 if (version_number
== 3)
818 warning("The 'box' statement has no effect in a version 3 game");
819 AO3
.type
= LONG_CONSTANT_OT
;
820 AO3
.value
= begin_table_array();
821 AO3
.marker
= ARRAY_MV
;
825 if ((token_type
==SEP_TT
)&&(token_value
==SEMICOLON_SEP
))
827 if (token_type
!= DQ_TT
)
828 ebf_error("text of box line in double-quotes",
831 for (i
=0, j
=0; token_text
[i
] != 0; j
++)
832 if (token_text
[i
] == '@')
833 { if (token_text
[i
+1] == '@')
835 while (isdigit(token_text
[i
])) i
++;
839 if (token_text
[i
] != 0) i
++;
840 if (token_text
[i
] != 0) i
++;
844 if (j
> ln2
) ln2
= j
;
847 array_entry(ln
++,parse_expression(CONSTANT_CONTEXT
));
851 error("No lines of text given for 'box' display");
853 if (version_number
== 3) return;
855 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= ln2
; AO2
.marker
= 0;
856 AO4
.type
= VARIABLE_OT
; AO4
.value
= 255; AO4
.marker
= 0;
857 assemblez_3_to(call_vs_zc
, veneer_routine(Box__Routine_VR
),
861 /* -------------------------------------------------------------------- */
862 /* break -------------------------------------------------------------- */
863 /* -------------------------------------------------------------------- */
866 if (break_label
== -1)
867 error("'break' can only be used in a loop or 'switch' block");
869 assemblez_jump(break_label
);
872 /* -------------------------------------------------------------------- */
873 /* continue ----------------------------------------------------------- */
874 /* -------------------------------------------------------------------- */
877 if (continue_label
== -1)
878 error("'continue' can only be used in a loop block");
880 assemblez_jump(continue_label
);
883 /* -------------------------------------------------------------------- */
884 /* do <codeblock> until (<condition>) --------------------------------- */
885 /* -------------------------------------------------------------------- */
888 assemble_label_no(ln
= next_label
++);
889 ln2
= next_label
++; ln3
= next_label
++;
890 parse_code_block(ln3
, ln2
, 0);
891 statements
.enabled
= TRUE
;
893 if ((token_type
== STATEMENT_TT
)
894 && (token_value
== UNTIL_CODE
))
895 { assemble_label_no(ln2
);
896 match_open_bracket();
897 AO
= parse_expression(CONDITION_CONTEXT
);
898 match_close_bracket();
899 code_generate(AO
, CONDITION_CONTEXT
, ln
);
901 else error("'do' without matching 'until'");
903 assemble_label_no(ln3
);
906 /* -------------------------------------------------------------------- */
907 /* font on/off -------------------------------------------------------- */
908 /* -------------------------------------------------------------------- */
911 misc_keywords
.enabled
= TRUE
;
913 misc_keywords
.enabled
= FALSE
;
914 if ((token_type
!= MISC_KEYWORD_TT
)
915 || ((token_value
!= ON_MK
)
916 && (token_value
!= OFF_MK
)))
917 { ebf_error("'on' or 'off'", token_text
);
918 panic_mode_error_recovery();
922 if (version_number
>= 5)
923 { /* Use the V5 @set_font opcode, setting font 4
924 (for font off) or 1 (for font on). */
925 AO
.type
= SHORT_CONSTANT_OT
; AO
.marker
= 0;
926 if (token_value
== ON_MK
)
930 assemblez_1_to(set_font_zc
, AO
, temp_var1
);
934 /* Set the fixed-pitch header bit. */
935 AO
.type
= SHORT_CONSTANT_OT
;
938 AO2
.type
= SHORT_CONSTANT_OT
;
941 AO3
.type
= VARIABLE_OT
;
944 assemblez_2_to(loadw_zc
, AO
, AO2
, AO3
);
946 if (token_value
== ON_MK
)
947 { AO4
.type
= LONG_CONSTANT_OT
;
950 assemblez_2_to(and_zc
, AO4
, AO3
, AO3
);
953 { AO4
.type
= SHORT_CONSTANT_OT
;
956 assemblez_2_to(or_zc
, AO4
, AO3
, AO3
);
959 assemblez_3(storew_zc
, AO
, AO2
, AO3
);
962 /* -------------------------------------------------------------------- */
963 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
964 /* -------------------------------------------------------------------- */
966 /* Note that it's legal for any or all of the three sections of a
967 'for' specification to be empty. This 'for' implementation
968 often wastes 3 bytes with a redundant branch rather than keep
969 expression parse trees for long periods (as previous versions
970 of Inform did, somewhat crudely by simply storing the textual
971 form of a 'for' loop). It is adequate for now. */
974 match_open_bracket();
977 /* Initialisation code */
979 if (!((token_type
==SEP_TT
)&&(token_value
==COLON_SEP
)))
981 if (!((token_type
==SEP_TT
)&&(token_value
==SUPERCLASS_SEP
)))
982 { sequence_point_follows
= TRUE
;
983 statement_debug_location
= get_token_location();
984 code_generate(parse_expression(FORINIT_CONTEXT
),
988 if ((token_type
==SEP_TT
)&&(token_value
== SUPERCLASS_SEP
))
990 if ((token_type
==SEP_TT
)&&(token_value
== CLOSEB_SEP
))
991 { assemble_label_no(ln
= next_label
++);
993 parse_code_block(ln2
, ln
, 0);
994 sequence_point_follows
= FALSE
;
995 if (!execution_never_reaches_here
)
997 assemble_label_no(ln2
);
1000 AO
.type
= OMITTED_OT
;
1004 if (!match_colon()) break;
1008 AO
.type
= OMITTED_OT
;
1009 if (!((token_type
==SEP_TT
)&&(token_value
==COLON_SEP
)))
1011 spare_debug_location1
= get_token_location();
1012 AO
= parse_expression(CONDITION_CONTEXT
);
1013 if (!match_colon()) break;
1018 AO2
.type
= OMITTED_OT
; flag
= 0;
1019 if (!((token_type
==SEP_TT
)&&(token_value
==CLOSEB_SEP
)))
1021 spare_debug_location2
= get_token_location();
1022 AO2
= parse_expression(VOID_CONTEXT
);
1023 match_close_bracket();
1024 flag
= test_for_incdec(AO2
);
1031 if ((AO2
.type
== OMITTED_OT
) || (flag
!= 0))
1033 assemble_label_no(ln
);
1034 if (flag
==0) assemble_label_no(ln2
);
1036 /* The "finished yet?" condition */
1038 if (AO
.type
!= OMITTED_OT
)
1039 { sequence_point_follows
= TRUE
;
1040 statement_debug_location
= spare_debug_location1
;
1041 code_generate(AO
, CONDITION_CONTEXT
, ln3
);
1047 /* This is the jump which could be avoided with the aid
1048 of long-term expression storage */
1050 sequence_point_follows
= FALSE
;
1051 assemblez_jump(ln2
);
1053 /* The "update" part */
1055 assemble_label_no(ln
);
1056 sequence_point_follows
= TRUE
;
1057 statement_debug_location
= spare_debug_location2
;
1058 code_generate(AO2
, VOID_CONTEXT
, -1);
1060 assemble_label_no(ln2
);
1062 /* The "finished yet?" condition */
1064 if (AO
.type
!= OMITTED_OT
)
1065 { sequence_point_follows
= TRUE
;
1066 statement_debug_location
= spare_debug_location1
;
1067 code_generate(AO
, CONDITION_CONTEXT
, ln3
);
1073 /* In this optimised case, update code is at the end
1074 of the loop block, so "continue" goes there */
1076 parse_code_block(ln3
, ln2
, 0);
1077 assemble_label_no(ln2
);
1079 sequence_point_follows
= TRUE
;
1080 statement_debug_location
= spare_debug_location2
;
1082 { AO3
.type
= SHORT_CONSTANT_OT
;
1085 && (flag
>=MAX_LOCAL_VARIABLES
) && (flag
<LOWEST_SYSTEM_VAR_NUMBER
))
1086 AO3
.marker
= VARIABLE_MV
;
1087 else AO3
.marker
= 0;
1088 assemblez_1(inc_zc
, AO3
);
1091 { AO3
.type
= SHORT_CONSTANT_OT
;
1093 if ((module_switch
) && (flag
>=MAX_LOCAL_VARIABLES
)
1094 && (flag
<LOWEST_SYSTEM_VAR_NUMBER
))
1095 AO3
.marker
= VARIABLE_MV
;
1096 else AO3
.marker
= 0;
1097 assemblez_1(dec_zc
, AO3
);
1103 /* In the unoptimised case, update code is at the
1104 start of the loop block, so "continue" goes there */
1106 parse_code_block(ln3
, ln
, 0);
1107 if (!execution_never_reaches_here
)
1108 { sequence_point_follows
= FALSE
;
1113 assemble_label_no(ln3
);
1116 /* -------------------------------------------------------------------- */
1117 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
1118 /* -------------------------------------------------------------------- */
1121 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1122 QUANTITY_CONTEXT
, -1);
1123 if ((AO
.type
== VARIABLE_OT
) && (AO
.value
== 0))
1126 AO
.type
= SHORT_CONSTANT_OT
;
1127 if (version_number
!= 6) assemblez_1(pull_zc
, AO
);
1128 else assemblez_0_to(pull_zc
, AO
);
1129 AO
.type
= VARIABLE_OT
;
1134 if ((token_type
== SEP_TT
)&&(token_value
== SEMICOLON_SEP
))
1136 if ((token_type
== SEP_TT
)&&(token_value
== ARTNOT_SEP
))
1139 { if ((token_type
== SYMBOL_TT
)
1140 && (stypes
[token_value
] != ATTRIBUTE_T
))
1141 warning_named("This is not a declared Attribute:",
1146 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1147 QUANTITY_CONTEXT
, -1);
1148 if (runtime_error_checking_switch
)
1149 { ln2
= (ln
==set_attr_zc
)?RT__ChG_VR
:RT__ChGt_VR
;
1150 if (version_number
>= 5)
1151 assemblez_3(call_vn_zc
, veneer_routine(ln2
),
1155 assemblez_3_to(call_zc
, veneer_routine(ln2
),
1156 AO
, AO2
, temp_var1
);
1160 assemblez_2(ln
, AO
, AO2
);
1163 /* -------------------------------------------------------------------- */
1164 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
1165 /* -------------------------------------------------------------------- */
1170 match_open_bracket();
1171 AO
= parse_expression(CONDITION_CONTEXT
);
1172 match_close_bracket();
1174 statements
.enabled
= TRUE
;
1176 if ((token_type
== STATEMENT_TT
)&&(token_value
== RTRUE_CODE
))
1179 if ((token_type
== STATEMENT_TT
)&&(token_value
== RFALSE_CODE
))
1186 code_generate(AO
, CONDITION_CONTEXT
, ln
);
1188 if (ln
>= 0) parse_code_block(break_label
, continue_label
, 0);
1191 if ((token_type
!= SEP_TT
)
1192 || (token_value
!= SEMICOLON_SEP
))
1193 { ebf_error("';'", token_text
);
1198 statements
.enabled
= TRUE
;
1200 if ((token_type
== STATEMENT_TT
) && (token_value
== ELSE_CODE
))
1203 { ln2
= next_label
++;
1204 if (!execution_never_reaches_here
)
1205 { sequence_point_follows
= FALSE
;
1206 assemblez_jump(ln2
);
1210 else put_token_back();
1212 if (ln
>= 0) assemble_label_no(ln
);
1215 { parse_code_block(break_label
, continue_label
, 0);
1216 if (ln
>= 0) assemble_label_no(ln2
);
1221 /* -------------------------------------------------------------------- */
1222 /* inversion ---------------------------------------------------------- */
1223 /* -------------------------------------------------------------------- */
1225 case INVERSION_CODE
:
1227 AO
.type
= SHORT_CONSTANT_OT
;
1231 AO2
.type
= SHORT_CONSTANT_OT
;
1234 assemblez_2_to(loadb_zc
, AO
, AO2
, temp_var1
);
1235 assemblez_1(print_char_zc
, temp_var1
);
1237 assemblez_2_to(loadb_zc
, AO
, AO2
, temp_var1
);
1238 assemblez_1(print_char_zc
, temp_var1
);
1240 assemblez_2_to(loadb_zc
, AO
, AO2
, temp_var1
);
1241 assemblez_1(print_char_zc
, temp_var1
);
1243 assemblez_2_to(loadb_zc
, AO
, AO2
, temp_var1
);
1244 assemblez_1(print_char_zc
, temp_var1
);
1247 /* -------------------------------------------------------------------- */
1248 /* jump <label> ------------------------------------------------------- */
1249 /* -------------------------------------------------------------------- */
1252 assemblez_jump(parse_label());
1255 /* -------------------------------------------------------------------- */
1256 /* move <expression> to <expression> ---------------------------------- */
1257 /* -------------------------------------------------------------------- */
1260 misc_keywords
.enabled
= TRUE
;
1261 AO
= parse_expression(QUANTITY_CONTEXT
);
1264 misc_keywords
.enabled
= FALSE
;
1265 if ((token_type
!= MISC_KEYWORD_TT
)
1266 || (token_value
!= TO_MK
))
1267 { ebf_error("'to'", token_text
);
1268 panic_mode_error_recovery();
1272 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1273 QUANTITY_CONTEXT
, -1);
1274 AO
= code_generate(AO
, QUANTITY_CONTEXT
, -1);
1275 if ((runtime_error_checking_switch
) && (veneer_mode
== FALSE
))
1276 { if (version_number
>= 5)
1277 assemblez_3(call_vn_zc
, veneer_routine(RT__ChT_VR
),
1280 { assemblez_3_to(call_zc
, veneer_routine(RT__ChT_VR
),
1281 AO
, AO2
, temp_var1
);
1285 assemblez_2(insert_obj_zc
, AO
, AO2
);
1288 /* -------------------------------------------------------------------- */
1289 /* new_line ----------------------------------------------------------- */
1290 /* -------------------------------------------------------------------- */
1292 case NEW_LINE_CODE
: assemblez_0(new_line_zc
); break;
1294 /* -------------------------------------------------------------------- */
1295 /* objectloop (<initialisation>) <codeblock> -------------------------- */
1296 /* -------------------------------------------------------------------- */
1298 case OBJECTLOOP_CODE
:
1300 match_open_bracket();
1302 if (token_type
== LOCAL_VARIABLE_TT
)
1303 AO
.value
= token_value
;
1305 if ((token_type
== SYMBOL_TT
) &&
1306 (stypes
[token_value
] == GLOBAL_VARIABLE_T
))
1307 AO
.value
= svals
[token_value
];
1309 { ebf_error("'objectloop' variable", token_text
);
1310 panic_mode_error_recovery(); break;
1312 AO
.type
= VARIABLE_OT
;
1313 if ((module_switch
) && (AO
.value
>= MAX_LOCAL_VARIABLES
)
1314 && (AO
.value
< LOWEST_SYSTEM_VAR_NUMBER
))
1315 AO
.marker
= VARIABLE_MV
;
1317 misc_keywords
.enabled
= TRUE
;
1318 get_next_token(); flag
= TRUE
;
1319 misc_keywords
.enabled
= FALSE
;
1320 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
))
1324 if ((token_type
== MISC_KEYWORD_TT
)
1325 && (token_value
== NEAR_MK
)) ln
= 1;
1326 if ((token_type
== MISC_KEYWORD_TT
)
1327 && (token_value
== FROM_MK
)) ln
= 2;
1328 if ((token_type
== CND_TT
) && (token_value
== IN_COND
))
1331 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
))
1338 { /* Old style (Inform 5) objectloops: note that we
1339 implement objectloop (a in b) in the old way since
1340 this runs through objects in a different order from
1341 the new way, and there may be existing Inform code
1343 assembly_operand AO4
;
1345 sequence_point_follows
= TRUE
;
1346 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1347 QUANTITY_CONTEXT
, -1);
1348 match_close_bracket();
1350 { AO3
.type
= VARIABLE_OT
; AO3
.value
= 0; AO3
.marker
= 0;
1351 if (runtime_error_checking_switch
)
1352 AO2
= check_nonzero_at_runtime(AO2
, -1,
1354 assemblez_1_to(get_parent_zc
, AO2
, AO3
);
1355 assemblez_objcode(get_child_zc
, AO3
, AO3
, -2, TRUE
);
1359 { AO3
.type
= VARIABLE_OT
; AO3
.value
= 0; AO3
.marker
= 0;
1360 if (runtime_error_checking_switch
)
1362 AO2
= check_nonzero_at_runtime(AO2
, -1,
1365 assemblez_objcode(get_child_zc
, AO2
, AO3
, -2, TRUE
);
1368 assemblez_store(AO
, AO2
);
1369 assemblez_1_branch(jz_zc
, AO
, ln2
= next_label
++, TRUE
);
1370 assemble_label_no(ln4
= next_label
++);
1371 parse_code_block(ln2
, ln3
= next_label
++, 0);
1372 sequence_point_follows
= FALSE
;
1373 assemble_label_no(ln3
);
1374 if (runtime_error_checking_switch
)
1375 { AO2
= check_nonzero_at_runtime(AO
, ln2
,
1378 && ((AO4
.type
!= VARIABLE_OT
)||(AO4
.value
!= 0))
1379 && ((AO4
.type
!= VARIABLE_OT
)
1380 ||(AO4
.value
!= AO
.value
)))
1381 { assembly_operand en_ao
;
1382 en_ao
.value
= OBJECTLOOP_BROKEN_RTE
;
1384 en_ao
.type
= SHORT_CONSTANT_OT
;
1385 assemblez_2_branch(jin_zc
, AO
, AO4
,
1387 assemblez_3(call_vn_zc
, veneer_routine(RT__Err_VR
),
1389 assemblez_jump(ln2
);
1390 assemble_label_no(next_label
++);
1394 assemblez_objcode(get_sibling_zc
, AO2
, AO
, ln4
, TRUE
);
1395 assemble_label_no(ln2
);
1399 sequence_point_follows
= TRUE
;
1400 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= 1; AO2
.marker
= 0;
1401 assemblez_store(AO
, AO2
);
1403 assemble_label_no(ln
= next_label
++);
1409 sequence_point_follows
= TRUE
;
1410 code_generate(parse_expression(CONDITION_CONTEXT
),
1411 CONDITION_CONTEXT
, ln3
);
1412 match_close_bracket();
1414 parse_code_block(ln2
, ln3
, 0);
1416 sequence_point_follows
= FALSE
;
1417 assemble_label_no(ln3
);
1419 AO2
.type
= LONG_CONSTANT_OT
; AO2
.value
= no_objects
;
1420 AO2
.marker
= NO_OBJS_MV
;
1421 assemblez_2_branch(jg_zc
, AO
, AO2
, ln2
, TRUE
);
1423 assemble_label_no(ln2
);
1426 /* -------------------------------------------------------------------- */
1427 /* (see routine above) ------------------------------------------------ */
1428 /* -------------------------------------------------------------------- */
1432 parse_print_z(FALSE
); return;
1433 case PRINT_RET_CODE
:
1435 parse_print_z(TRUE
); return;
1437 /* -------------------------------------------------------------------- */
1438 /* quit --------------------------------------------------------------- */
1439 /* -------------------------------------------------------------------- */
1441 case QUIT_CODE
: assemblez_0(quit_zc
); break;
1443 /* -------------------------------------------------------------------- */
1444 /* read <expression> <expression> [<Routine>] ------------------------- */
1445 /* -------------------------------------------------------------------- */
1448 AO
.type
= VARIABLE_OT
; AO
.value
= 252; AO
.marker
= 0;
1450 code_generate(parse_expression(QUANTITY_CONTEXT
),
1451 QUANTITY_CONTEXT
, -1));
1452 if (version_number
> 3)
1453 { AO3
.type
= SHORT_CONSTANT_OT
; AO3
.value
= 1;AO3
.marker
= 0;
1454 AO4
.type
= SHORT_CONSTANT_OT
; AO4
.value
= 0;AO4
.marker
= 0;
1455 assemblez_3(storeb_zc
, AO
, AO3
, AO4
);
1457 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1458 QUANTITY_CONTEXT
, -1);
1461 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
))
1464 { if (version_number
== 3)
1466 "In Version 3 no status-line drawing routine can be given");
1468 { assembly_operand AO5
;
1469 /* Move the temp4 (buffer) value to the stack,
1470 since the routine might alter temp4. */
1471 assemblez_store(stack_pointer
, AO
);
1474 AO5
= parse_expression(CONSTANT_CONTEXT
);
1476 if (version_number
>= 5)
1477 assemblez_1(call_1n_zc
, AO5
);
1479 assemblez_1_to(call_zc
, AO5
, temp_var1
);
1483 if (version_number
> 4)
1484 { assemblez_2_to(aread_zc
, AO
, AO2
, temp_var1
);
1486 else assemblez_2(sread_zc
, AO
, AO2
);
1489 /* -------------------------------------------------------------------- */
1490 /* remove <expression> ------------------------------------------------ */
1491 /* -------------------------------------------------------------------- */
1494 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1495 QUANTITY_CONTEXT
, -1);
1496 if ((runtime_error_checking_switch
) && (veneer_mode
== FALSE
))
1497 { if (version_number
>= 5)
1498 assemblez_2(call_2n_zc
, veneer_routine(RT__ChR_VR
),
1501 { assemblez_2_to(call_zc
, veneer_routine(RT__ChR_VR
),
1506 assemblez_1(remove_obj_zc
, AO
);
1509 /* -------------------------------------------------------------------- */
1510 /* restore <label> ---------------------------------------------------- */
1511 /* -------------------------------------------------------------------- */
1514 if (version_number
< 5)
1515 assemblez_0_branch(restore_zc
, parse_label(), TRUE
);
1517 { AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= 2;
1519 assemblez_0_to(restore_zc
, temp_var1
);
1520 assemblez_2_branch(je_zc
, temp_var1
, AO2
, parse_label(), TRUE
);
1524 /* -------------------------------------------------------------------- */
1525 /* return [<expression>] ---------------------------------------------- */
1526 /* -------------------------------------------------------------------- */
1530 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
))
1531 { assemblez_0(rtrue_zc
); return; }
1533 AO
= code_generate(parse_expression(RETURN_Q_CONTEXT
),
1534 QUANTITY_CONTEXT
, -1);
1535 if ((AO
.type
== SHORT_CONSTANT_OT
) && (AO
.value
== 0)
1536 && (AO
.marker
== 0))
1537 { assemblez_0(rfalse_zc
); break; }
1538 if ((AO
.type
== SHORT_CONSTANT_OT
) && (AO
.value
== 1)
1539 && (AO
.marker
== 0))
1540 { assemblez_0(rtrue_zc
); break; }
1541 if ((AO
.type
== VARIABLE_OT
) && (AO
.value
== 0))
1542 { assemblez_0(ret_popped_zc
); break; }
1543 assemblez_1(ret_zc
, AO
);
1546 /* -------------------------------------------------------------------- */
1547 /* rfalse ------------------------------------------------------------- */
1548 /* -------------------------------------------------------------------- */
1550 case RFALSE_CODE
: assemblez_0(rfalse_zc
); break;
1552 /* -------------------------------------------------------------------- */
1553 /* rtrue -------------------------------------------------------------- */
1554 /* -------------------------------------------------------------------- */
1556 case RTRUE_CODE
: assemblez_0(rtrue_zc
); break;
1558 /* -------------------------------------------------------------------- */
1559 /* save <label> ------------------------------------------------------- */
1560 /* -------------------------------------------------------------------- */
1563 if (version_number
< 5)
1564 assemblez_0_branch(save_zc
, parse_label(), TRUE
);
1566 { AO
.type
= VARIABLE_OT
; AO
.value
= 255; AO
.marker
= 0;
1567 assemblez_0_to(save_zc
, AO
);
1568 assemblez_1_branch(jz_zc
, AO
, parse_label(), FALSE
);
1572 /* -------------------------------------------------------------------- */
1573 /* spaces <expression> ------------------------------------------------ */
1574 /* -------------------------------------------------------------------- */
1577 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1578 QUANTITY_CONTEXT
, -1);
1579 AO2
.type
= VARIABLE_OT
; AO2
.value
= 255; AO2
.marker
= 0;
1581 assemblez_store(AO2
, AO
);
1583 AO
.type
= SHORT_CONSTANT_OT
; AO
.value
= 32; AO
.marker
= 0;
1584 AO3
.type
= SHORT_CONSTANT_OT
; AO3
.value
= 1; AO3
.marker
= 0;
1586 assemblez_2_branch(jl_zc
, AO2
, AO3
, ln
= next_label
++, TRUE
);
1587 assemble_label_no(ln2
= next_label
++);
1588 assemblez_1(print_char_zc
, AO
);
1590 assemblez_1_branch(jz_zc
, AO2
, ln2
, FALSE
);
1591 assemble_label_no(ln
);
1594 /* -------------------------------------------------------------------- */
1595 /* string <expression> <literal-string> ------------------------------- */
1596 /* -------------------------------------------------------------------- */
1599 AO
.type
= SHORT_CONSTANT_OT
; AO
.value
= 0; AO
.marker
= 0;
1600 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.value
= 12; AO2
.marker
= 0;
1601 AO3
.type
= VARIABLE_OT
; AO3
.value
= 252; AO3
.marker
= 0;
1602 assemblez_2_to(loadw_zc
, AO
, AO2
, AO3
);
1603 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1604 QUANTITY_CONTEXT
, -1);
1606 if (token_type
== DQ_TT
)
1607 { AO4
.value
= compile_string(token_text
, TRUE
, TRUE
);
1609 AO4
.type
= LONG_CONSTANT_OT
;
1613 AO4
= parse_expression(CONSTANT_CONTEXT
);
1615 assemblez_3(storew_zc
, AO3
, AO2
, AO4
);
1618 /* -------------------------------------------------------------------- */
1619 /* style roman/reverse/bold/underline/fixed --------------------------- */
1620 /* -------------------------------------------------------------------- */
1623 if (version_number
==3)
1625 "The 'style' statement cannot be used for Version 3 games");
1626 panic_mode_error_recovery();
1630 misc_keywords
.enabled
= TRUE
;
1632 misc_keywords
.enabled
= FALSE
;
1633 if ((token_type
!= MISC_KEYWORD_TT
)
1634 || ((token_value
!= ROMAN_MK
)
1635 && (token_value
!= REVERSE_MK
)
1636 && (token_value
!= BOLD_MK
)
1637 && (token_value
!= UNDERLINE_MK
)
1638 && (token_value
!= FIXED_MK
)))
1640 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1642 panic_mode_error_recovery();
1646 AO
.type
= SHORT_CONSTANT_OT
; AO
.marker
= 0;
1648 { case ROMAN_MK
: AO
.value
= 0; break;
1649 case REVERSE_MK
: AO
.value
= 1; break;
1650 case BOLD_MK
: AO
.value
= 2; break;
1651 case UNDERLINE_MK
: AO
.value
= 4; break;
1652 case FIXED_MK
: AO
.value
= 8; break;
1654 assemblez_1(set_text_style_zc
, AO
); break;
1656 /* -------------------------------------------------------------------- */
1657 /* switch (<expression>) <codeblock> ---------------------------------- */
1658 /* -------------------------------------------------------------------- */
1661 match_open_bracket();
1662 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
1663 QUANTITY_CONTEXT
, -1);
1664 match_close_bracket();
1666 AO2
.type
= VARIABLE_OT
; AO2
.value
= 255; AO2
.marker
= 0;
1667 assemblez_store(AO2
, AO
);
1669 parse_code_block(ln
= next_label
++, continue_label
, 1);
1670 assemble_label_no(ln
);
1673 /* -------------------------------------------------------------------- */
1674 /* while (<condition>) <codeblock> ------------------------------------ */
1675 /* -------------------------------------------------------------------- */
1678 assemble_label_no(ln
= next_label
++);
1679 match_open_bracket();
1681 code_generate(parse_expression(CONDITION_CONTEXT
),
1682 CONDITION_CONTEXT
, ln2
= next_label
++);
1683 match_close_bracket();
1685 parse_code_block(ln2
, ln
, 0);
1686 sequence_point_follows
= FALSE
;
1688 assemble_label_no(ln2
);
1691 /* -------------------------------------------------------------------- */
1694 error("'default' without matching 'switch'"); break;
1696 error("'else' without matching 'if'"); break;
1698 error("'until' without matching 'do'");
1699 panic_mode_error_recovery(); return;
1702 StatementTerminator
:
1705 if ((token_type
!= SEP_TT
) || (token_value
!= SEMICOLON_SEP
))
1706 { ebf_error("';'", token_text
);
1711 static void parse_statement_g(int break_label
, int continue_label
)
1712 { int ln
, ln2
, ln3
, ln4
, flag
, onstack
;
1713 assembly_operand AO
, AO2
, AO3
, AO4
;
1714 debug_location spare_debug_location1
, spare_debug_location2
;
1718 if ((token_type
== SEP_TT
) && (token_value
== PROPERTY_SEP
))
1719 { /* That is, a full stop, signifying a label */
1722 if (token_type
== SYMBOL_TT
)
1724 if (sflags
[token_value
] & UNKNOWN_SFLAG
)
1725 { assign_symbol(token_value
, next_label
, LABEL_T
);
1726 sflags
[token_value
] |= USED_SFLAG
;
1727 assemble_label_no(next_label
);
1728 define_symbol_label(token_value
);
1732 { if (stypes
[token_value
] != LABEL_T
) goto LabelError
;
1733 if (sflags
[token_value
] & CHANGE_SFLAG
)
1734 { sflags
[token_value
] &= (~(CHANGE_SFLAG
));
1735 assemble_label_no(svals
[token_value
]);
1736 define_symbol_label(token_value
);
1738 else error_named("Duplicate definition of label:", token_text
);
1742 if ((token_type
!= SEP_TT
) || (token_value
!= SEMICOLON_SEP
))
1743 { ebf_error("';'", token_text
);
1744 put_token_back(); return;
1747 /* Interesting point of Inform grammar: a statement can only
1748 consist solely of a label when it is immediately followed
1752 if ((token_type
== SEP_TT
) && (token_value
== CLOSE_BRACE_SEP
))
1753 { put_token_back(); return;
1755 /* The following line prevents labels from influencing the positions
1756 of sequence points. */
1757 statement_debug_location
= get_token_location();
1758 parse_statement(break_label
, continue_label
);
1761 LabelError
: ebf_error("label name", token_text
);
1764 if ((token_type
== SEP_TT
) && (token_value
== HASH_SEP
))
1765 { parse_directive(TRUE
);
1766 parse_statement(break_label
, continue_label
); return;
1769 if ((token_type
== SEP_TT
) && (token_value
== AT_SEP
))
1770 { parse_assembly(); return;
1773 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) return;
1775 if (token_type
== DQ_TT
)
1776 { parse_print_g(TRUE
); return;
1779 if ((token_type
== SEP_TT
) && (token_value
== LESS_SEP
))
1780 { parse_action(); goto StatementTerminator
; }
1782 if (token_type
== EOF_TT
)
1783 { ebf_error("statement", token_text
); return; }
1785 if (token_type
!= STATEMENT_TT
)
1787 AO
= parse_expression(VOID_CONTEXT
);
1788 code_generate(AO
, VOID_CONTEXT
, -1);
1789 if (vivc_flag
) { panic_mode_error_recovery(); return; }
1790 goto StatementTerminator
;
1793 statements
.enabled
= FALSE
;
1798 /* -------------------------------------------------------------------- */
1799 /* box <string-1> ... <string-n> -------------------------------------- */
1800 /* -------------------------------------------------------------------- */
1803 AO3
.type
= CONSTANT_OT
;
1804 AO3
.value
= begin_table_array();
1805 AO3
.marker
= ARRAY_MV
;
1809 if ((token_type
==SEP_TT
)&&(token_value
==SEMICOLON_SEP
))
1811 if (token_type
!= DQ_TT
)
1812 ebf_error("text of box line in double-quotes",
1815 for (i
=0, j
=0; token_text
[i
] != 0; j
++)
1816 if (token_text
[i
] == '@')
1817 { if (token_text
[i
+1] == '@')
1819 while (isdigit(token_text
[i
])) i
++;
1823 if (token_text
[i
] != 0) i
++;
1824 if (token_text
[i
] != 0) i
++;
1828 if (j
> ln2
) ln2
= j
;
1831 array_entry(ln
++,parse_expression(CONSTANT_CONTEXT
));
1835 error("No lines of text given for 'box' display");
1837 AO2
.value
= ln2
; AO2
.marker
= 0; set_constant_ot(&AO2
);
1838 assembleg_call_2(veneer_routine(Box__Routine_VR
),
1839 AO2
, AO3
, zero_operand
);
1842 /* -------------------------------------------------------------------- */
1843 /* break -------------------------------------------------------------- */
1844 /* -------------------------------------------------------------------- */
1847 if (break_label
== -1)
1848 error("'break' can only be used in a loop or 'switch' block");
1850 assembleg_jump(break_label
);
1853 /* -------------------------------------------------------------------- */
1854 /* continue ----------------------------------------------------------- */
1855 /* -------------------------------------------------------------------- */
1858 if (continue_label
== -1)
1859 error("'continue' can only be used in a loop block");
1861 assembleg_jump(continue_label
);
1864 /* -------------------------------------------------------------------- */
1865 /* do <codeblock> until (<condition>) --------------------------------- */
1866 /* -------------------------------------------------------------------- */
1869 assemble_label_no(ln
= next_label
++);
1870 ln2
= next_label
++; ln3
= next_label
++;
1871 parse_code_block(ln3
, ln2
, 0);
1872 statements
.enabled
= TRUE
;
1874 if ((token_type
== STATEMENT_TT
)
1875 && (token_value
== UNTIL_CODE
))
1876 { assemble_label_no(ln2
);
1877 match_open_bracket();
1878 AO
= parse_expression(CONDITION_CONTEXT
);
1879 match_close_bracket();
1880 code_generate(AO
, CONDITION_CONTEXT
, ln
);
1882 else error("'do' without matching 'until'");
1884 assemble_label_no(ln3
);
1887 /* -------------------------------------------------------------------- */
1888 /* font on/off -------------------------------------------------------- */
1889 /* -------------------------------------------------------------------- */
1892 misc_keywords
.enabled
= TRUE
;
1894 misc_keywords
.enabled
= FALSE
;
1895 if ((token_type
!= MISC_KEYWORD_TT
)
1896 || ((token_value
!= ON_MK
)
1897 && (token_value
!= OFF_MK
)))
1898 { ebf_error("'on' or 'off'", token_text
);
1899 panic_mode_error_recovery();
1903 /* Call glk_set_style(normal or preformatted) */
1906 set_constant_ot(&AO
);
1907 if (token_value
== ON_MK
)
1911 assembleg_call_2(veneer_routine(Glk__Wrap_VR
),
1912 AO
, AO2
, zero_operand
);
1915 /* -------------------------------------------------------------------- */
1916 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
1917 /* -------------------------------------------------------------------- */
1919 /* Note that it's legal for any or all of the three sections of a
1920 'for' specification to be empty. This 'for' implementation
1921 often wastes 3 bytes with a redundant branch rather than keep
1922 expression parse trees for long periods (as previous versions
1923 of Inform did, somewhat crudely by simply storing the textual
1924 form of a 'for' loop). It is adequate for now. */
1927 match_open_bracket();
1930 /* Initialisation code */
1932 if (!((token_type
==SEP_TT
)&&(token_value
==COLON_SEP
)))
1934 if (!((token_type
==SEP_TT
)&&(token_value
==SUPERCLASS_SEP
)))
1935 { sequence_point_follows
= TRUE
;
1936 statement_debug_location
= get_token_location();
1937 code_generate(parse_expression(FORINIT_CONTEXT
),
1941 if ((token_type
==SEP_TT
)&&(token_value
== SUPERCLASS_SEP
))
1943 if ((token_type
==SEP_TT
)&&(token_value
== CLOSEB_SEP
))
1944 { assemble_label_no(ln
= next_label
++);
1946 parse_code_block(ln2
, ln
, 0);
1947 sequence_point_follows
= FALSE
;
1948 if (!execution_never_reaches_here
)
1950 assemble_label_no(ln2
);
1953 AO
.type
= OMITTED_OT
;
1957 if (!match_colon()) break;
1961 AO
.type
= OMITTED_OT
;
1962 if (!((token_type
==SEP_TT
)&&(token_value
==COLON_SEP
)))
1964 spare_debug_location1
= get_token_location();
1965 AO
= parse_expression(CONDITION_CONTEXT
);
1966 if (!match_colon()) break;
1971 AO2
.type
= OMITTED_OT
; flag
= 0;
1972 if (!((token_type
==SEP_TT
)&&(token_value
==CLOSEB_SEP
)))
1974 spare_debug_location2
= get_token_location();
1975 AO2
= parse_expression(VOID_CONTEXT
);
1976 match_close_bracket();
1977 flag
= test_for_incdec(AO2
);
1984 if ((AO2
.type
== OMITTED_OT
) || (flag
!= 0))
1986 assemble_label_no(ln
);
1987 if (flag
==0) assemble_label_no(ln2
);
1989 /* The "finished yet?" condition */
1991 if (AO
.type
!= OMITTED_OT
)
1992 { sequence_point_follows
= TRUE
;
1993 statement_debug_location
= spare_debug_location1
;
1994 code_generate(AO
, CONDITION_CONTEXT
, ln3
);
2000 /* This is the jump which could be avoided with the aid
2001 of long-term expression storage */
2003 sequence_point_follows
= FALSE
;
2004 assembleg_jump(ln2
);
2006 /* The "update" part */
2008 assemble_label_no(ln
);
2009 sequence_point_follows
= TRUE
;
2010 statement_debug_location
= spare_debug_location2
;
2011 code_generate(AO2
, VOID_CONTEXT
, -1);
2013 assemble_label_no(ln2
);
2015 /* The "finished yet?" condition */
2017 if (AO
.type
!= OMITTED_OT
)
2018 { sequence_point_follows
= TRUE
;
2019 statement_debug_location
= spare_debug_location1
;
2020 code_generate(AO
, CONDITION_CONTEXT
, ln3
);
2026 /* In this optimised case, update code is at the end
2027 of the loop block, so "continue" goes there */
2029 parse_code_block(ln3
, ln2
, 0);
2030 assemble_label_no(ln2
);
2032 sequence_point_follows
= TRUE
;
2033 statement_debug_location
= spare_debug_location2
;
2036 if (AO3
.value
>= MAX_LOCAL_VARIABLES
)
2037 AO3
.type
= GLOBALVAR_OT
;
2039 AO3
.type
= LOCALVAR_OT
;
2041 assembleg_3(add_gc
, AO3
, one_operand
, AO3
);
2044 { AO3
.value
= -flag
;
2045 if (AO3
.value
>= MAX_LOCAL_VARIABLES
)
2046 AO3
.type
= GLOBALVAR_OT
;
2048 AO3
.type
= LOCALVAR_OT
;
2050 assembleg_3(sub_gc
, AO3
, one_operand
, AO3
);
2056 /* In the unoptimised case, update code is at the
2057 start of the loop block, so "continue" goes there */
2059 parse_code_block(ln3
, ln
, 0);
2060 if (!execution_never_reaches_here
)
2061 { sequence_point_follows
= FALSE
;
2066 assemble_label_no(ln3
);
2069 /* -------------------------------------------------------------------- */
2070 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2071 /* -------------------------------------------------------------------- */
2074 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2075 QUANTITY_CONTEXT
, -1);
2076 if ((AO
.type
== LOCALVAR_OT
) && (AO
.value
== 0))
2083 if ((token_type
== SEP_TT
)
2084 && (token_value
== SEMICOLON_SEP
)) {
2086 assembleg_2(copy_gc
, stack_pointer
, zero_operand
);
2090 if ((token_type
== SEP_TT
)&&(token_value
== ARTNOT_SEP
))
2093 { if ((token_type
== SYMBOL_TT
)
2094 && (stypes
[token_value
] != ATTRIBUTE_T
))
2095 warning_named("This is not a declared Attribute:",
2100 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2101 QUANTITY_CONTEXT
, -1);
2102 if (runtime_error_checking_switch
&& (!veneer_mode
))
2103 { ln2
= (ln
? RT__ChG_VR
: RT__ChGt_VR
);
2104 if ((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0)) {
2105 /* already on stack */
2108 assembleg_store(stack_pointer
, AO2
);
2111 assembleg_2(stkpeek_gc
, one_operand
, stack_pointer
);
2113 assembleg_store(stack_pointer
, AO
);
2114 assembleg_3(call_gc
, veneer_routine(ln2
), two_operand
,
2118 if (is_constant_ot(AO2
.type
) && AO2
.marker
== 0) {
2120 set_constant_ot(&AO2
);
2125 AO3
.type
= BYTECONSTANT_OT
;
2126 assembleg_3(add_gc
, AO2
, AO3
, stack_pointer
);
2127 AO2
= stack_pointer
;
2130 if ((AO2
.type
== LOCALVAR_OT
) && (AO2
.value
== 0))
2131 assembleg_2(stkpeek_gc
, one_operand
,
2134 assembleg_2(stkpeek_gc
, zero_operand
,
2141 assembleg_3(astorebit_gc
, AO
, AO2
, AO3
);
2145 /* -------------------------------------------------------------------- */
2146 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2147 /* -------------------------------------------------------------------- */
2152 match_open_bracket();
2153 AO
= parse_expression(CONDITION_CONTEXT
);
2154 match_close_bracket();
2156 statements
.enabled
= TRUE
;
2158 if ((token_type
== STATEMENT_TT
)&&(token_value
== RTRUE_CODE
))
2161 if ((token_type
== STATEMENT_TT
)&&(token_value
== RFALSE_CODE
))
2168 code_generate(AO
, CONDITION_CONTEXT
, ln
);
2170 if (ln
>= 0) parse_code_block(break_label
, continue_label
, 0);
2173 if ((token_type
!= SEP_TT
)
2174 || (token_value
!= SEMICOLON_SEP
))
2175 { ebf_error("';'", token_text
);
2180 statements
.enabled
= TRUE
;
2182 if ((token_type
== STATEMENT_TT
) && (token_value
== ELSE_CODE
))
2185 { ln2
= next_label
++;
2186 if (!execution_never_reaches_here
)
2187 { sequence_point_follows
= FALSE
;
2188 assembleg_jump(ln2
);
2192 else put_token_back();
2194 if (ln
>= 0) assemble_label_no(ln
);
2197 { parse_code_block(break_label
, continue_label
, 0);
2198 if (ln
>= 0) assemble_label_no(ln2
);
2203 /* -------------------------------------------------------------------- */
2204 /* inversion ---------------------------------------------------------- */
2205 /* -------------------------------------------------------------------- */
2207 case INVERSION_CODE
:
2209 AO2
.type
= DEREFERENCE_OT
;
2210 AO2
.value
= GLULX_HEADER_SIZE
+8;
2211 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2212 assembleg_1(streamchar_gc
, stack_pointer
);
2213 AO2
.value
= GLULX_HEADER_SIZE
+9;
2214 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2215 assembleg_1(streamchar_gc
, stack_pointer
);
2216 AO2
.value
= GLULX_HEADER_SIZE
+10;
2217 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2218 assembleg_1(streamchar_gc
, stack_pointer
);
2219 AO2
.value
= GLULX_HEADER_SIZE
+11;
2220 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2221 assembleg_1(streamchar_gc
, stack_pointer
);
2226 set_constant_ot(&AO
);
2227 assembleg_1(streamchar_gc
, AO
);
2229 set_constant_ot(&AO
);
2230 assembleg_1(streamchar_gc
, AO
);
2232 AO2
.value
= GLULX_HEADER_SIZE
+12;
2233 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2234 assembleg_1(streamchar_gc
, stack_pointer
);
2235 AO2
.value
= GLULX_HEADER_SIZE
+13;
2236 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2237 assembleg_1(streamchar_gc
, stack_pointer
);
2238 AO2
.value
= GLULX_HEADER_SIZE
+14;
2239 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2240 assembleg_1(streamchar_gc
, stack_pointer
);
2241 AO2
.value
= GLULX_HEADER_SIZE
+15;
2242 assembleg_2(copyb_gc
, AO2
, stack_pointer
);
2243 assembleg_1(streamchar_gc
, stack_pointer
);
2247 set_constant_ot(&AO
);
2248 assembleg_1(streamchar_gc
, AO
);
2253 /* -------------------------------------------------------------------- */
2254 /* jump <label> ------------------------------------------------------- */
2255 /* -------------------------------------------------------------------- */
2258 assembleg_jump(parse_label());
2261 /* -------------------------------------------------------------------- */
2262 /* move <expression> to <expression> ---------------------------------- */
2263 /* -------------------------------------------------------------------- */
2266 misc_keywords
.enabled
= TRUE
;
2267 AO
= parse_expression(QUANTITY_CONTEXT
);
2270 misc_keywords
.enabled
= FALSE
;
2271 if ((token_type
!= MISC_KEYWORD_TT
)
2272 || (token_value
!= TO_MK
))
2273 { ebf_error("'to'", token_text
);
2274 panic_mode_error_recovery();
2278 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2279 QUANTITY_CONTEXT
, -1);
2280 AO
= code_generate(AO
, QUANTITY_CONTEXT
, -1);
2281 if ((runtime_error_checking_switch
) && (veneer_mode
== FALSE
))
2282 assembleg_call_2(veneer_routine(RT__ChT_VR
), AO
, AO2
,
2285 assembleg_call_2(veneer_routine(OB__Move_VR
), AO
, AO2
,
2289 /* -------------------------------------------------------------------- */
2290 /* new_line ----------------------------------------------------------- */
2291 /* -------------------------------------------------------------------- */
2294 AO
.type
= BYTECONSTANT_OT
; AO
.value
= 0x0A; AO
.marker
= 0;
2295 assembleg_1(streamchar_gc
, AO
);
2298 /* -------------------------------------------------------------------- */
2299 /* objectloop (<initialisation>) <codeblock> -------------------------- */
2300 /* -------------------------------------------------------------------- */
2302 case OBJECTLOOP_CODE
:
2304 match_open_bracket();
2306 if (token_type
== LOCAL_VARIABLE_TT
) {
2307 AO
.value
= token_value
;
2308 AO
.type
= LOCALVAR_OT
;
2311 else if ((token_type
== SYMBOL_TT
) &&
2312 (stypes
[token_value
] == GLOBAL_VARIABLE_T
)) {
2313 AO
.value
= svals
[token_value
];
2314 AO
.type
= GLOBALVAR_OT
;
2318 ebf_error("'objectloop' variable", token_text
);
2319 panic_mode_error_recovery();
2322 misc_keywords
.enabled
= TRUE
;
2323 get_next_token(); flag
= TRUE
;
2324 misc_keywords
.enabled
= FALSE
;
2325 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
))
2329 if ((token_type
== MISC_KEYWORD_TT
)
2330 && (token_value
== NEAR_MK
)) ln
= 1;
2331 if ((token_type
== MISC_KEYWORD_TT
)
2332 && (token_value
== FROM_MK
)) ln
= 2;
2333 if ((token_type
== CND_TT
) && (token_value
== IN_COND
))
2336 if ((token_type
== SEP_TT
) && (token_value
== CLOSEB_SEP
))
2343 /* Old style (Inform 5) objectloops: note that we
2344 implement objectloop (a in b) in the old way since
2345 this runs through objects in a different order from
2346 the new way, and there may be existing Inform code
2348 assembly_operand AO4
, AO5
;
2350 sequence_point_follows
= TRUE
;
2351 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2352 QUANTITY_CONTEXT
, -1);
2353 match_close_bracket();
2355 if (runtime_error_checking_switch
)
2356 AO2
= check_nonzero_at_runtime(AO2
, -1,
2358 AO4
.type
= BYTECONSTANT_OT
;
2359 AO4
.value
= GOBJFIELD_PARENT();
2361 assembleg_3(aload_gc
, AO2
, AO4
, stack_pointer
);
2362 AO4
.type
= BYTECONSTANT_OT
;
2363 AO4
.value
= GOBJFIELD_CHILD();
2365 assembleg_3(aload_gc
, stack_pointer
, AO4
, stack_pointer
);
2366 AO2
= stack_pointer
;
2369 if (runtime_error_checking_switch
) {
2371 AO2
= check_nonzero_at_runtime(AO2
, -1,
2374 AO4
.type
= BYTECONSTANT_OT
;
2375 AO4
.value
= GOBJFIELD_CHILD();
2377 assembleg_3(aload_gc
, AO2
, AO4
, stack_pointer
);
2378 AO2
= stack_pointer
;
2383 assembleg_store(AO
, AO2
);
2384 assembleg_1_branch(jz_gc
, AO
, ln2
= next_label
++);
2385 assemble_label_no(ln4
= next_label
++);
2386 parse_code_block(ln2
, ln3
= next_label
++, 0);
2387 sequence_point_follows
= FALSE
;
2388 assemble_label_no(ln3
);
2389 if (runtime_error_checking_switch
) {
2390 AO2
= check_nonzero_at_runtime(AO
, ln2
,
2393 && ((AO5
.type
!= LOCALVAR_OT
)||(AO5
.value
!= 0))
2394 && ((AO5
.type
!= LOCALVAR_OT
)||(AO5
.value
!= AO
.value
)))
2395 { assembly_operand en_ao
;
2396 en_ao
.value
= OBJECTLOOP_BROKEN_RTE
;
2398 set_constant_ot(&en_ao
);
2399 AO4
.type
= BYTECONSTANT_OT
;
2400 AO4
.value
= GOBJFIELD_PARENT();
2402 assembleg_3(aload_gc
, AO
, AO4
, stack_pointer
);
2403 assembleg_2_branch(jeq_gc
, stack_pointer
, AO5
,
2405 assembleg_call_2(veneer_routine(RT__Err_VR
),
2406 en_ao
, AO
, zero_operand
);
2407 assembleg_jump(ln2
);
2408 assemble_label_no(next_label
++);
2414 AO4
.type
= BYTECONSTANT_OT
;
2415 AO4
.value
= GOBJFIELD_SIBLING();
2417 assembleg_3(aload_gc
, AO2
, AO4
, AO
);
2418 assembleg_1_branch(jnz_gc
, AO
, ln4
);
2419 assemble_label_no(ln2
);
2423 sequence_point_follows
= TRUE
;
2424 ln
= symbol_index("Class", -1);
2425 AO2
.value
= svals
[ln
];
2426 AO2
.marker
= OBJECT_MV
;
2427 AO2
.type
= CONSTANT_OT
;
2428 assembleg_store(AO
, AO2
);
2430 assemble_label_no(ln
= next_label
++);
2436 sequence_point_follows
= TRUE
;
2437 code_generate(parse_expression(CONDITION_CONTEXT
),
2438 CONDITION_CONTEXT
, ln3
);
2439 match_close_bracket();
2441 parse_code_block(ln2
, ln3
, 0);
2443 sequence_point_follows
= FALSE
;
2444 assemble_label_no(ln3
);
2445 AO4
.type
= BYTECONSTANT_OT
;
2446 AO4
.value
= GOBJFIELD_CHAIN();
2448 assembleg_3(aload_gc
, AO
, AO4
, AO
);
2449 assembleg_1_branch(jnz_gc
, AO
, ln
);
2450 assemble_label_no(ln2
);
2453 /* -------------------------------------------------------------------- */
2454 /* (see routine above) ------------------------------------------------ */
2455 /* -------------------------------------------------------------------- */
2459 parse_print_g(FALSE
); return;
2460 case PRINT_RET_CODE
:
2462 parse_print_g(TRUE
); return;
2464 /* -------------------------------------------------------------------- */
2465 /* quit --------------------------------------------------------------- */
2466 /* -------------------------------------------------------------------- */
2469 assembleg_0(quit_gc
); break;
2471 /* -------------------------------------------------------------------- */
2472 /* remove <expression> ------------------------------------------------ */
2473 /* -------------------------------------------------------------------- */
2476 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2477 QUANTITY_CONTEXT
, -1);
2478 if ((runtime_error_checking_switch
) && (veneer_mode
== FALSE
))
2479 assembleg_call_1(veneer_routine(RT__ChR_VR
), AO
,
2482 assembleg_call_1(veneer_routine(OB__Remove_VR
), AO
,
2486 /* -------------------------------------------------------------------- */
2487 /* return [<expression>] ---------------------------------------------- */
2488 /* -------------------------------------------------------------------- */
2492 if ((token_type
== SEP_TT
) && (token_value
== SEMICOLON_SEP
)) {
2493 AO
.type
= BYTECONSTANT_OT
; AO
.value
= 1; AO
.marker
= 0;
2494 assembleg_1(return_gc
, AO
);
2498 AO
= code_generate(parse_expression(RETURN_Q_CONTEXT
),
2499 QUANTITY_CONTEXT
, -1);
2500 assembleg_1(return_gc
, AO
);
2503 /* -------------------------------------------------------------------- */
2504 /* rfalse ------------------------------------------------------------- */
2505 /* -------------------------------------------------------------------- */
2508 assembleg_1(return_gc
, zero_operand
);
2511 /* -------------------------------------------------------------------- */
2512 /* rtrue -------------------------------------------------------------- */
2513 /* -------------------------------------------------------------------- */
2516 assembleg_1(return_gc
, one_operand
);
2519 /* -------------------------------------------------------------------- */
2520 /* spaces <expression> ------------------------------------------------ */
2521 /* -------------------------------------------------------------------- */
2524 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2525 QUANTITY_CONTEXT
, -1);
2527 assembleg_store(temp_var1
, AO
);
2529 AO
.value
= 32; AO
.marker
= 0; set_constant_ot(&AO
);
2531 assembleg_2_branch(jlt_gc
, temp_var1
, one_operand
,
2533 assemble_label_no(ln2
= next_label
++);
2534 assembleg_1(streamchar_gc
, AO
);
2535 assembleg_dec(temp_var1
);
2536 assembleg_1_branch(jnz_gc
, temp_var1
, ln2
);
2537 assemble_label_no(ln
);
2540 /* -------------------------------------------------------------------- */
2541 /* string <expression> <literal-string> ------------------------------- */
2542 /* -------------------------------------------------------------------- */
2545 AO2
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2546 QUANTITY_CONTEXT
, -1);
2548 if (token_type
== DQ_TT
)
2549 { AO4
.value
= compile_string(token_text
, TRUE
, TRUE
);
2550 AO4
.marker
= STRING_MV
;
2551 AO4
.type
= CONSTANT_OT
;
2555 AO4
= parse_expression(CONSTANT_CONTEXT
);
2557 assembleg_call_2(veneer_routine(Dynam__String_VR
),
2558 AO2
, AO4
, zero_operand
);
2561 /* -------------------------------------------------------------------- */
2562 /* style roman/reverse/bold/underline/fixed --------------------------- */
2563 /* -------------------------------------------------------------------- */
2566 misc_keywords
.enabled
= TRUE
;
2568 misc_keywords
.enabled
= FALSE
;
2569 if ((token_type
!= MISC_KEYWORD_TT
)
2570 || ((token_value
!= ROMAN_MK
)
2571 && (token_value
!= REVERSE_MK
)
2572 && (token_value
!= BOLD_MK
)
2573 && (token_value
!= UNDERLINE_MK
)
2574 && (token_value
!= FIXED_MK
)))
2576 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2578 panic_mode_error_recovery();
2582 /* Call glk_set_style() */
2586 set_constant_ot(&AO
);
2589 AO2
= zero_operand
; /* normal */
2592 AO2
.value
= 5; /* alert */
2594 set_constant_ot(&AO2
);
2597 AO2
.value
= 4; /* subheader */
2599 set_constant_ot(&AO2
);
2602 AO2
= one_operand
; /* emphasized */
2605 AO2
= two_operand
; /* preformatted */
2608 assembleg_call_2(veneer_routine(Glk__Wrap_VR
),
2609 AO
, AO2
, zero_operand
);
2612 /* -------------------------------------------------------------------- */
2613 /* switch (<expression>) <codeblock> ---------------------------------- */
2614 /* -------------------------------------------------------------------- */
2617 match_open_bracket();
2618 AO
= code_generate(parse_expression(QUANTITY_CONTEXT
),
2619 QUANTITY_CONTEXT
, -1);
2620 match_close_bracket();
2622 assembleg_store(temp_var1
, AO
);
2624 parse_code_block(ln
= next_label
++, continue_label
, 1);
2625 assemble_label_no(ln
);
2628 /* -------------------------------------------------------------------- */
2629 /* while (<condition>) <codeblock> ------------------------------------ */
2630 /* -------------------------------------------------------------------- */
2633 assemble_label_no(ln
= next_label
++);
2634 match_open_bracket();
2636 code_generate(parse_expression(CONDITION_CONTEXT
),
2637 CONDITION_CONTEXT
, ln2
= next_label
++);
2638 match_close_bracket();
2640 parse_code_block(ln2
, ln
, 0);
2641 sequence_point_follows
= FALSE
;
2643 assemble_label_no(ln2
);
2646 /* -------------------------------------------------------------------- */
2649 error("'default' without matching 'switch'"); break;
2651 error("'else' without matching 'if'"); break;
2653 error("'until' without matching 'do'");
2654 panic_mode_error_recovery(); return;
2656 /* -------------------------------------------------------------------- */
2658 /* And a useful default, which will never be triggered in a complete
2659 Inform compiler, but which is important in development. */
2662 error("*** Statement code gen: Can't generate yet ***\n");
2663 panic_mode_error_recovery(); return;
2666 StatementTerminator
:
2669 if ((token_type
!= SEP_TT
) || (token_value
!= SEMICOLON_SEP
))
2670 { ebf_error("';'", token_text
);
2675 extern void parse_statement(int break_label
, int continue_label
)
2678 parse_statement_z(break_label
, continue_label
);
2680 parse_statement_g(break_label
, continue_label
);
2683 /* ========================================================================= */
2684 /* Data structure management routines */
2685 /* ------------------------------------------------------------------------- */
2687 extern void init_states_vars(void)
2691 extern void states_begin_pass(void)
2695 extern void states_allocate_arrays(void)
2699 extern void states_free_arrays(void)
2703 /* ========================================================================= */