1 /* ------------------------------------------------------------------------- */
2 /* "states" : Statement translator */
4 /* Part of Inform 6.35 */
5 /* copyright (c) Graham Nelson 1993 - 2021 */
7 /* Inform is free software: you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation, either version 3 of the License, or */
10 /* (at your option) any later version. */
12 /* Inform is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with Inform. If not, see https://gnu.org/licenses/ *
20 /* ------------------------------------------------------------------------- */
24 static int match_colon(void)
26 if (token_type == SEP_TT)
27 { if (token_value == SEMICOLON_SEP)
28 warning("Unlike C, Inform uses ':' to divide parts \
29 of a 'for' loop specification: replacing ';' with ':'");
31 if (token_value != COLON_SEP)
32 { ebf_error("':'", token_text);
33 panic_mode_error_recovery();
38 { ebf_error("':'", token_text);
39 panic_mode_error_recovery();
45 static void match_open_bracket(void)
47 if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
49 ebf_error("'('", token_text);
52 extern void match_close_bracket(void)
54 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
56 ebf_error("')'", token_text);
59 static void parse_action(void)
60 { int level = 1, args = 0, codegen_action;
61 assembly_operand AO, AO2, AO3, AO4, AO5;
63 /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
64 or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
65 to R_Process() with those four arguments. (The latter form,
66 with double brackets, means "return true afterwards".)
68 The R_Process() function should be supplied by the library,
69 although a stub is defined in the veneer.
71 The NOUN, SECOND, and ACTOR arguments are optional. If not
72 supplied, R_Process() will be called with fewer arguments.
73 (But if you supply ACTOR, it must be preceded by a comma.
74 <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
76 To complicate life, the ACTION argument may be a bare action
77 name or a parenthesized expression. (So <Take> is equivalent
78 to <(##Take)>.) We have to peek at the first token, checking
79 whether it's an open-paren, to distinguish these cases.
81 You may ask why the ACTOR argument is last; the "natural"
82 Inform ordering would be "<floyd, take ball>". True! Sadly,
83 Inform's lexer isn't smart enough to parse this consistently,
87 dont_enter_into_symbol_table = TRUE;
89 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
90 { level = 2; get_next_token();
92 dont_enter_into_symbol_table = FALSE;
94 /* Peek at the next token; see if it's an open-paren. */
95 if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
97 AO2 = parse_expression(ACTION_Q_CONTEXT);
98 codegen_action = TRUE;
101 { codegen_action = FALSE;
102 AO2 = action_of_name(token_text);
109 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
112 AO3 = parse_expression(ACTION_Q_CONTEXT);
116 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
119 AO4 = parse_expression(QUANTITY_CONTEXT);
122 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
124 ebf_error("',' or '>'", token_text);
127 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
129 if (!glulx_mode && (version_number < 4))
131 error("<x, y> syntax is not available in Z-code V3 or earlier");
134 AO5 = parse_expression(QUANTITY_CONTEXT);
136 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
138 ebf_error("'>'", token_text);
144 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
146 ebf_error("'>>'", token_text);
152 AO = veneer_routine(R_Process_VR);
156 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
157 if (version_number>=5)
158 assemblez_2(call_2n_zc, AO, AO2);
160 if (version_number==4)
161 assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
163 assemblez_2_to(call_zc, AO, AO2, temp_var1);
166 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
167 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
168 if (version_number>=5)
169 assemblez_3(call_vn_zc, AO, AO2, AO3);
171 if (version_number==4)
172 assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
174 assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
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_4(call_vn_zc, AO, AO2, AO3, AO4);
183 if (version_number==4)
184 assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
186 assemblez_4_to(call_zc, AO, AO2, AO3, AO4, temp_var1);
189 AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
190 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
191 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
192 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
193 if (version_number>=5)
194 assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
196 if (version_number==4)
197 assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
198 /* if V3 or earlier, we've already displayed an error */
203 if (level == 2) assemblez_0(rtrue_zc);
208 AO = veneer_routine(R_Process_VR);
214 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
215 assembleg_call_1(AO, AO2, zero_operand);
219 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
221 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
222 assembleg_call_2(AO, AO2, AO3, zero_operand);
226 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
227 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
229 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
230 assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
234 AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
235 if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
236 assembleg_store(stack_pointer, AO5);
237 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
238 if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
239 assembleg_store(stack_pointer, AO4);
240 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
241 if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
242 assembleg_store(stack_pointer, AO3);
244 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
245 if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
246 assembleg_store(stack_pointer, AO2);
247 assembleg_3(call_gc, AO, four_operand, zero_operand);
252 assembleg_1(return_gc, one_operand);
257 extern int parse_label(void)
261 if ((token_type == SYMBOL_TT) &&
262 (stypes[token_value] == LABEL_T))
263 { sflags[token_value] |= USED_SFLAG;
264 return(svals[token_value]);
267 if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
268 { assign_symbol(token_value, next_label, LABEL_T);
269 define_symbol_label(token_value);
271 sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
272 return(svals[token_value]);
275 ebf_error("label name", token_text);
279 static void parse_print_z(int finally_return)
280 { int count = 0; assembly_operand AO;
282 /* print <printlist> -------------------------------------------------- */
283 /* print_ret <printlist> ---------------------------------------------- */
284 /* <literal-string> --------------------------------------------------- */
286 /* <printlist> is a comma-separated list of items: */
288 /* <literal-string> */
289 /* <other-expression> */
290 /* (char) <expression> */
291 /* (address) <expression> */
292 /* (string) <expression> */
293 /* (a) <expression> */
294 /* (the) <expression> */
295 /* (The) <expression> */
296 /* (name) <expression> */
297 /* (number) <expression> */
298 /* (property) <expression> */
299 /* (<routine>) <expression> */
300 /* (object) <expression> (for use in low-level code only) */
301 /* --------------------------------------------------------------------- */
304 { AI.text = token_text;
305 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
308 if (strlen(token_text) > 32)
309 { INITAOT(&AO, LONG_CONSTANT_OT);
310 AO.marker = STRING_MV;
311 AO.value = compile_string(token_text, STRCTX_GAME);
312 assemblez_1(print_paddr_zc, AO);
315 if ((token_type == SEP_TT)
316 && (token_value == SEMICOLON_SEP))
317 { assemblez_0(new_line_zc);
318 assemblez_0(rtrue_zc);
327 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
328 { assemblez_0(print_ret_zc); return;
332 assemblez_0(print_zc);
336 if (token_value == OPENB_SEP)
337 { misc_keywords.enabled = TRUE;
340 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
341 { assembly_operand AO1;
343 put_token_back(); put_token_back();
344 local_variables.enabled = FALSE;
346 misc_keywords.enabled = FALSE;
347 local_variables.enabled = TRUE;
349 if ((token_type == STATEMENT_TT)
350 &&(token_value == STRING_CODE))
351 { token_type = MISC_KEYWORD_TT;
352 token_value = STRING_MK;
357 case MISC_KEYWORD_TT:
360 if (runtime_error_checking_switch)
361 { AO = veneer_routine(RT__ChPrintC_VR);
366 parse_expression(QUANTITY_CONTEXT),
367 QUANTITY_CONTEXT, -1);
368 assemblez_1(print_char_zc, AO1);
371 if (runtime_error_checking_switch)
372 { AO = veneer_routine(RT__ChPrintA_VR);
377 parse_expression(QUANTITY_CONTEXT),
378 QUANTITY_CONTEXT, -1);
379 assemblez_1(print_addr_zc, AO1);
382 if (runtime_error_checking_switch)
383 { AO = veneer_routine(RT__ChPrintS_VR);
388 parse_expression(QUANTITY_CONTEXT),
389 QUANTITY_CONTEXT, -1);
390 assemblez_1(print_paddr_zc, AO1);
393 if (runtime_error_checking_switch)
394 { AO = veneer_routine(RT__ChPrintO_VR);
399 parse_expression(QUANTITY_CONTEXT),
400 QUANTITY_CONTEXT, -1);
401 assemblez_1(print_obj_zc, AO1);
404 AO = veneer_routine(DefArt_VR);
408 AO = veneer_routine(InDefArt_VR);
411 AO = veneer_routine(CDefArt_VR);
414 AO = veneer_routine(CInDefArt_VR);
417 AO = veneer_routine(PrintShortName_VR);
420 AO = veneer_routine(EnglishNumber_VR);
423 AO = veneer_routine(Print__Pname_VR);
426 error_named("A reserved word was used as a print specification:",
432 if (sflags[token_value] & UNKNOWN_SFLAG)
433 { INITAOT(&AO, LONG_CONSTANT_OT);
434 AO.value = token_value;
435 AO.marker = SYMBOL_MV;
438 { INITAOT(&AO, LONG_CONSTANT_OT);
439 AO.value = svals[token_value];
440 AO.marker = IROUTINE_MV;
441 if (stypes[token_value] != ROUTINE_T)
442 ebf_error("printing routine name", token_text);
444 sflags[token_value] |= USED_SFLAG;
449 if (version_number >= 5)
450 assemblez_2(call_2n_zc, AO,
451 code_generate(parse_expression(QUANTITY_CONTEXT),
452 QUANTITY_CONTEXT, -1));
453 else if (version_number == 4)
454 assemblez_2_to(call_vs_zc, AO,
455 code_generate(parse_expression(QUANTITY_CONTEXT),
456 QUANTITY_CONTEXT, -1), temp_var1);
458 assemblez_2_to(call_zc, AO,
459 code_generate(parse_expression(QUANTITY_CONTEXT),
460 QUANTITY_CONTEXT, -1), temp_var1);
463 default: ebf_error("print specification", token_text);
465 assemblez_1(print_num_zc,
466 code_generate(parse_expression(QUANTITY_CONTEXT),
467 QUANTITY_CONTEXT, -1));
471 put_token_back(); put_token_back(); put_token_back();
472 misc_keywords.enabled = FALSE;
473 assemblez_1(print_num_zc,
474 code_generate(parse_expression(QUANTITY_CONTEXT),
475 QUANTITY_CONTEXT, -1));
480 put_token_back(); misc_keywords.enabled = FALSE;
481 assemblez_1(print_num_zc,
482 code_generate(parse_expression(QUANTITY_CONTEXT),
483 QUANTITY_CONTEXT, -1));
487 PrintTermDone: misc_keywords.enabled = FALSE;
491 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
492 if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
493 { ebf_error("comma", token_text);
494 panic_mode_error_recovery(); return;
496 else get_next_token();
499 if (count == 0) ebf_error("something to print", token_text);
501 { assemblez_0(new_line_zc);
502 assemblez_0(rtrue_zc);
506 static void parse_print_g(int finally_return)
507 { int count = 0; assembly_operand AO, AO2;
509 /* print <printlist> -------------------------------------------------- */
510 /* print_ret <printlist> ---------------------------------------------- */
511 /* <literal-string> --------------------------------------------------- */
513 /* <printlist> is a comma-separated list of items: */
515 /* <literal-string> */
516 /* <other-expression> */
517 /* (char) <expression> */
518 /* (address) <expression> */
519 /* (string) <expression> */
520 /* (a) <expression> */
521 /* (A) <expression> */
522 /* (the) <expression> */
523 /* (The) <expression> */
524 /* (name) <expression> */
525 /* (number) <expression> */
526 /* (property) <expression> */
527 /* (<routine>) <expression> */
528 /* (object) <expression> (for use in low-level code only) */
529 /* --------------------------------------------------------------------- */
533 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
536 /* We can't compile a string into the instruction,
537 so this always goes into the string area. */
538 { INITAOT(&AO, CONSTANT_OT);
539 AO.marker = STRING_MV;
540 AO.value = compile_string(token_text, STRCTX_GAME);
541 assembleg_1(streamstr_gc, AO);
544 if ((token_type == SEP_TT)
545 && (token_value == SEMICOLON_SEP))
546 { INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
547 assembleg_1(streamchar_gc, AO);
548 INITAOTV(&AO, BYTECONSTANT_OT, 1);
549 assembleg_1(return_gc, AO);
559 if (token_value == OPENB_SEP)
560 { misc_keywords.enabled = TRUE;
563 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
564 { assembly_operand AO1;
567 put_token_back(); put_token_back();
568 local_variables.enabled = FALSE;
570 misc_keywords.enabled = FALSE;
571 local_variables.enabled = TRUE;
573 if ((token_type == STATEMENT_TT)
574 &&(token_value == STRING_CODE))
575 { token_type = MISC_KEYWORD_TT;
576 token_value = STRING_MK;
581 case MISC_KEYWORD_TT:
584 if (runtime_error_checking_switch)
585 { AO = veneer_routine(RT__ChPrintC_VR);
590 parse_expression(QUANTITY_CONTEXT),
591 QUANTITY_CONTEXT, -1);
592 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
593 { assembleg_2(stkpeek_gc, zero_operand,
596 INITAOTV(&AO2, HALFCONSTANT_OT, 0x100);
597 assembleg_2_branch(jgeu_gc, AO1, AO2,
600 assembleg_1(streamchar_gc, AO1);
602 assemble_label_no(ln);
603 assembleg_1(streamunichar_gc, AO1);
604 assemble_label_no(ln2);
607 if (runtime_error_checking_switch)
608 AO = veneer_routine(RT__ChPrintA_VR);
610 AO = veneer_routine(Print__Addr_VR);
613 if (runtime_error_checking_switch)
614 { AO = veneer_routine(RT__ChPrintS_VR);
619 parse_expression(QUANTITY_CONTEXT),
620 QUANTITY_CONTEXT, -1);
621 assembleg_1(streamstr_gc, AO1);
624 if (runtime_error_checking_switch)
625 { AO = veneer_routine(RT__ChPrintO_VR);
630 parse_expression(QUANTITY_CONTEXT),
631 QUANTITY_CONTEXT, -1);
632 INITAOT(&AO2, BYTECONSTANT_OT);
633 AO2.value = GOBJFIELD_NAME();
634 assembleg_3(aload_gc, AO1, AO2,
636 assembleg_1(streamstr_gc, stack_pointer);
639 AO = veneer_routine(DefArt_VR);
643 AO = veneer_routine(InDefArt_VR);
646 AO = veneer_routine(CDefArt_VR);
649 AO = veneer_routine(CInDefArt_VR);
652 AO = veneer_routine(PrintShortName_VR);
655 AO = veneer_routine(EnglishNumber_VR);
658 AO = veneer_routine(Print__Pname_VR);
661 error_named("A reserved word was used as a print specification:",
667 if (sflags[token_value] & UNKNOWN_SFLAG)
668 { INITAOT(&AO, CONSTANT_OT);
669 AO.value = token_value;
670 AO.marker = SYMBOL_MV;
673 { INITAOT(&AO, CONSTANT_OT);
674 AO.value = svals[token_value];
675 AO.marker = IROUTINE_MV;
676 if (stypes[token_value] != ROUTINE_T)
677 ebf_error("printing routine name", token_text);
679 sflags[token_value] |= USED_SFLAG;
684 INITAOT(&AO2, ZEROCONSTANT_OT);
686 code_generate(parse_expression(QUANTITY_CONTEXT),
687 QUANTITY_CONTEXT, -1),
691 default: ebf_error("print specification", token_text);
693 assembleg_1(streamnum_gc,
694 code_generate(parse_expression(QUANTITY_CONTEXT),
695 QUANTITY_CONTEXT, -1));
699 put_token_back(); put_token_back(); put_token_back();
700 misc_keywords.enabled = FALSE;
701 assembleg_1(streamnum_gc,
702 code_generate(parse_expression(QUANTITY_CONTEXT),
703 QUANTITY_CONTEXT, -1));
708 put_token_back(); misc_keywords.enabled = FALSE;
709 assembleg_1(streamnum_gc,
710 code_generate(parse_expression(QUANTITY_CONTEXT),
711 QUANTITY_CONTEXT, -1));
715 PrintTermDone: misc_keywords.enabled = FALSE;
719 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
720 if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
721 { ebf_error("comma", token_text);
722 panic_mode_error_recovery(); return;
724 else get_next_token();
727 if (count == 0) ebf_error("something to print", token_text);
730 INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
731 assembleg_1(streamchar_gc, AO);
732 INITAOTV(&AO, BYTECONSTANT_OT, 1);
733 assembleg_1(return_gc, AO);
737 static void parse_statement_z(int break_label, int continue_label)
738 { int ln, ln2, ln3, ln4, flag;
739 assembly_operand AO, AO2, AO3, AO4;
740 debug_location spare_debug_location1, spare_debug_location2;
744 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
745 { /* That is, a full stop, signifying a label */
748 if (token_type == SYMBOL_TT)
750 if (sflags[token_value] & UNKNOWN_SFLAG)
751 { assign_symbol(token_value, next_label, LABEL_T);
752 sflags[token_value] |= USED_SFLAG;
753 assemble_label_no(next_label);
754 define_symbol_label(token_value);
758 { if (stypes[token_value] != LABEL_T) goto LabelError;
759 if (sflags[token_value] & CHANGE_SFLAG)
760 { sflags[token_value] &= (~(CHANGE_SFLAG));
761 assemble_label_no(svals[token_value]);
762 define_symbol_label(token_value);
764 else error_named("Duplicate definition of label:", token_text);
768 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
769 { ebf_error("';'", token_text);
770 put_token_back(); return;
773 /* Interesting point of Inform grammar: a statement can only
774 consist solely of a label when it is immediately followed
778 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
779 { put_token_back(); return;
781 statement_debug_location = get_token_location();
782 parse_statement(break_label, continue_label);
785 LabelError: ebf_error("label name", token_text);
788 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
789 { parse_directive(TRUE);
790 parse_statement(break_label, continue_label); return;
793 if ((token_type == SEP_TT) && (token_value == AT_SEP))
794 { parse_assembly(); return;
797 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
799 if (token_type == DQ_TT)
800 { parse_print_z(TRUE); return;
803 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
804 { parse_action(); goto StatementTerminator; }
806 if (token_type == EOF_TT)
807 { ebf_error("statement", token_text); return; }
809 if (token_type != STATEMENT_TT)
811 AO = parse_expression(VOID_CONTEXT);
812 code_generate(AO, VOID_CONTEXT, -1);
813 if (vivc_flag) { panic_mode_error_recovery(); return; }
814 goto StatementTerminator;
817 statements.enabled = FALSE;
821 /* -------------------------------------------------------------------- */
822 /* box <string-1> ... <string-n> -------------------------------------- */
823 /* -------------------------------------------------------------------- */
826 if (version_number == 3)
827 warning("The 'box' statement has no effect in a version 3 game");
828 INITAOT(&AO3, LONG_CONSTANT_OT);
829 AO3.value = begin_table_array();
830 AO3.marker = ARRAY_MV;
834 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
836 if (token_type != DQ_TT)
837 ebf_error("text of box line in double-quotes",
840 for (i=0, j=0; token_text[i] != 0; j++)
841 if (token_text[i] == '@')
842 { if (token_text[i+1] == '@')
844 while (isdigit(token_text[i])) i++;
848 if (token_text[i] != 0) i++;
849 if (token_text[i] != 0) i++;
853 if (j > ln2) ln2 = j;
856 array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
858 finish_array(ln, FALSE);
860 error("No lines of text given for 'box' display");
862 if (version_number == 3) return;
864 INITAOTV(&AO2, SHORT_CONSTANT_OT, ln2);
865 INITAOTV(&AO4, VARIABLE_OT, 255);
866 assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
870 /* -------------------------------------------------------------------- */
871 /* break -------------------------------------------------------------- */
872 /* -------------------------------------------------------------------- */
875 if (break_label == -1)
876 error("'break' can only be used in a loop or 'switch' block");
878 assemblez_jump(break_label);
881 /* -------------------------------------------------------------------- */
882 /* continue ----------------------------------------------------------- */
883 /* -------------------------------------------------------------------- */
886 if (continue_label == -1)
887 error("'continue' can only be used in a loop block");
889 assemblez_jump(continue_label);
892 /* -------------------------------------------------------------------- */
893 /* do <codeblock> until (<condition>) --------------------------------- */
894 /* -------------------------------------------------------------------- */
897 assemble_label_no(ln = next_label++);
898 ln2 = next_label++; ln3 = next_label++;
899 parse_code_block(ln3, ln2, 0);
900 statements.enabled = TRUE;
902 if ((token_type == STATEMENT_TT)
903 && (token_value == UNTIL_CODE))
904 { assemble_label_no(ln2);
905 match_open_bracket();
906 AO = parse_expression(CONDITION_CONTEXT);
907 match_close_bracket();
908 code_generate(AO, CONDITION_CONTEXT, ln);
910 else error("'do' without matching 'until'");
912 assemble_label_no(ln3);
915 /* -------------------------------------------------------------------- */
916 /* font on/off -------------------------------------------------------- */
917 /* -------------------------------------------------------------------- */
920 misc_keywords.enabled = TRUE;
922 misc_keywords.enabled = FALSE;
923 if ((token_type != MISC_KEYWORD_TT)
924 || ((token_value != ON_MK)
925 && (token_value != OFF_MK)))
926 { ebf_error("'on' or 'off'", token_text);
927 panic_mode_error_recovery();
931 if (version_number >= 5)
932 { /* Use the V5 @set_font opcode, setting font 4
933 (for font off) or 1 (for font on). */
934 INITAOT(&AO, SHORT_CONSTANT_OT);
935 if (token_value == ON_MK)
939 assemblez_1_to(set_font_zc, AO, temp_var1);
943 /* Set the fixed-pitch header bit. */
944 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
945 INITAOTV(&AO2, SHORT_CONSTANT_OT, 8);
946 INITAOTV(&AO3, VARIABLE_OT, 255);
947 assemblez_2_to(loadw_zc, AO, AO2, AO3);
949 if (token_value == ON_MK)
950 { INITAOTV(&AO4, LONG_CONSTANT_OT, 0xfffd);
951 assemblez_2_to(and_zc, AO4, AO3, AO3);
954 { INITAOTV(&AO4, SHORT_CONSTANT_OT, 2);
955 assemblez_2_to(or_zc, AO4, AO3, AO3);
958 assemblez_3(storew_zc, AO, AO2, AO3);
961 /* -------------------------------------------------------------------- */
962 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
963 /* -------------------------------------------------------------------- */
965 /* Note that it's legal for any or all of the three sections of a
966 'for' specification to be empty. This 'for' implementation
967 often wastes 3 bytes with a redundant branch rather than keep
968 expression parse trees for long periods (as previous versions
969 of Inform did, somewhat crudely by simply storing the textual
970 form of a 'for' loop). It is adequate for now. */
973 match_open_bracket();
976 /* Initialisation code */
977 AO.type = OMITTED_OT;
978 spare_debug_location1 = statement_debug_location;
979 AO2.type = OMITTED_OT; flag = 0;
980 spare_debug_location2 = statement_debug_location;
982 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
984 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
985 { sequence_point_follows = TRUE;
986 statement_debug_location = get_token_location();
987 code_generate(parse_expression(FORINIT_CONTEXT),
991 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
993 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
994 { assemble_label_no(ln = next_label++);
996 parse_code_block(ln2, ln, 0);
997 sequence_point_follows = FALSE;
998 if (!execution_never_reaches_here)
1000 assemble_label_no(ln2);
1006 if (!match_colon()) break;
1010 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1012 spare_debug_location1 = get_token_location();
1013 AO = parse_expression(CONDITION_CONTEXT);
1014 if (!match_colon()) break;
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 { INITAOTV(&AO3, SHORT_CONSTANT_OT, flag);
1084 && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1085 AO3.marker = VARIABLE_MV;
1086 assemblez_1(inc_zc, AO3);
1089 { INITAOTV(&AO3, SHORT_CONSTANT_OT, -flag);
1090 if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
1091 && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1092 AO3.marker = VARIABLE_MV;
1093 assemblez_1(dec_zc, AO3);
1099 /* In the unoptimised case, update code is at the
1100 start of the loop block, so "continue" goes there */
1102 parse_code_block(ln3, ln, 0);
1103 if (!execution_never_reaches_here)
1104 { sequence_point_follows = FALSE;
1109 assemble_label_no(ln3);
1112 /* -------------------------------------------------------------------- */
1113 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
1114 /* -------------------------------------------------------------------- */
1117 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1118 QUANTITY_CONTEXT, -1);
1119 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1120 { INITAOTV(&AO, SHORT_CONSTANT_OT, 252);
1121 if (version_number != 6) assemblez_1(pull_zc, AO);
1122 else assemblez_0_to(pull_zc, AO);
1123 AO.type = VARIABLE_OT;
1128 if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
1130 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
1133 { if ((token_type == SYMBOL_TT)
1134 && (stypes[token_value] != ATTRIBUTE_T))
1135 warning_named("This is not a declared Attribute:",
1140 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1141 QUANTITY_CONTEXT, -1);
1142 if (runtime_error_checking_switch)
1143 { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
1144 if (version_number >= 5)
1145 assemblez_3(call_vn_zc, veneer_routine(ln2),
1149 assemblez_3_to(call_zc, veneer_routine(ln2),
1150 AO, AO2, temp_var1);
1154 assemblez_2(ln, AO, AO2);
1157 /* -------------------------------------------------------------------- */
1158 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
1159 /* -------------------------------------------------------------------- */
1165 match_open_bracket();
1166 AO = parse_expression(CONDITION_CONTEXT);
1167 match_close_bracket();
1169 statements.enabled = TRUE;
1171 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
1174 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
1181 code_generate(AO, CONDITION_CONTEXT, ln);
1183 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
1186 if ((token_type != SEP_TT)
1187 || (token_value != SEMICOLON_SEP))
1188 { ebf_error("';'", token_text);
1193 statements.enabled = TRUE;
1196 /* An #if directive around the ELSE clause is legal. */
1197 while ((token_type == SEP_TT) && (token_value == HASH_SEP))
1198 { parse_directive(TRUE);
1199 statements.enabled = TRUE;
1203 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
1206 { ln2 = next_label++;
1207 if (!execution_never_reaches_here)
1208 { sequence_point_follows = FALSE;
1209 assemblez_jump(ln2);
1213 else put_token_back();
1215 if (ln >= 0) assemble_label_no(ln);
1218 { parse_code_block(break_label, continue_label, 0);
1219 if (ln >= 0) assemble_label_no(ln2);
1224 /* -------------------------------------------------------------------- */
1225 /* inversion ---------------------------------------------------------- */
1226 /* -------------------------------------------------------------------- */
1228 case INVERSION_CODE:
1229 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1230 INITAOT(&AO2, SHORT_CONSTANT_OT);
1233 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1234 assemblez_1(print_char_zc, temp_var1);
1236 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1237 assemblez_1(print_char_zc, temp_var1);
1239 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1240 assemblez_1(print_char_zc, temp_var1);
1242 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1243 assemblez_1(print_char_zc, temp_var1);
1246 /* -------------------------------------------------------------------- */
1247 /* jump <label> ------------------------------------------------------- */
1248 /* -------------------------------------------------------------------- */
1251 assemblez_jump(parse_label());
1254 /* -------------------------------------------------------------------- */
1255 /* move <expression> to <expression> ---------------------------------- */
1256 /* -------------------------------------------------------------------- */
1259 misc_keywords.enabled = TRUE;
1260 AO = parse_expression(QUANTITY_CONTEXT);
1263 misc_keywords.enabled = FALSE;
1264 if ((token_type != MISC_KEYWORD_TT)
1265 || (token_value != TO_MK))
1266 { ebf_error("'to'", token_text);
1267 panic_mode_error_recovery();
1271 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1272 QUANTITY_CONTEXT, -1);
1273 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
1274 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1275 { if (version_number >= 5)
1276 assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
1279 { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
1280 AO, AO2, temp_var1);
1284 assemblez_2(insert_obj_zc, AO, AO2);
1287 /* -------------------------------------------------------------------- */
1288 /* new_line ----------------------------------------------------------- */
1289 /* -------------------------------------------------------------------- */
1291 case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
1293 /* -------------------------------------------------------------------- */
1294 /* objectloop (<initialisation>) <codeblock> -------------------------- */
1295 /* -------------------------------------------------------------------- */
1297 case OBJECTLOOP_CODE:
1299 match_open_bracket();
1301 INITAOT(&AO, VARIABLE_OT);
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 if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
1313 && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
1314 AO.marker = VARIABLE_MV;
1315 misc_keywords.enabled = TRUE;
1316 get_next_token(); flag = TRUE;
1317 misc_keywords.enabled = FALSE;
1318 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1322 if ((token_type == MISC_KEYWORD_TT)
1323 && (token_value == NEAR_MK)) ln = 1;
1324 if ((token_type == MISC_KEYWORD_TT)
1325 && (token_value == FROM_MK)) ln = 2;
1326 if ((token_type == CND_TT) && (token_value == IN_COND))
1329 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1336 { /* Old style (Inform 5) objectloops: note that we
1337 implement objectloop (a in b) in the old way since
1338 this runs through objects in a different order from
1339 the new way, and there may be existing Inform code
1341 assembly_operand AO4;
1344 sequence_point_follows = TRUE;
1345 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1346 QUANTITY_CONTEXT, -1);
1347 match_close_bracket();
1349 { INITAOTV(&AO3, VARIABLE_OT, 0);
1350 if (runtime_error_checking_switch)
1351 AO2 = check_nonzero_at_runtime(AO2, -1,
1353 assemblez_1_to(get_parent_zc, AO2, AO3);
1354 assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
1358 { INITAOTV(&AO3, VARIABLE_OT, 0);
1359 if (runtime_error_checking_switch)
1361 AO2 = check_nonzero_at_runtime(AO2, -1,
1364 assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
1367 assemblez_store(AO, AO2);
1368 assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
1369 assemble_label_no(ln4 = next_label++);
1370 parse_code_block(ln2, ln3 = next_label++, 0);
1371 sequence_point_follows = FALSE;
1372 assemble_label_no(ln3);
1373 if (runtime_error_checking_switch)
1374 { AO2 = check_nonzero_at_runtime(AO, ln2,
1377 && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
1378 && ((AO4.type != VARIABLE_OT)
1379 ||(AO4.value != AO.value)))
1380 { assembly_operand en_ao;
1381 INITAOTV(&en_ao, SHORT_CONSTANT_OT, OBJECTLOOP_BROKEN_RTE);
1382 assemblez_2_branch(jin_zc, AO, AO4,
1384 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
1386 assemblez_jump(ln2);
1387 assemble_label_no(next_label++);
1391 assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
1392 assemble_label_no(ln2);
1396 sequence_point_follows = TRUE;
1397 INITAOTV(&AO2, SHORT_CONSTANT_OT, 1);
1398 assemblez_store(AO, AO2);
1400 assemble_label_no(ln = next_label++);
1406 sequence_point_follows = TRUE;
1407 code_generate(parse_expression(CONDITION_CONTEXT),
1408 CONDITION_CONTEXT, ln3);
1409 match_close_bracket();
1411 parse_code_block(ln2, ln3, 0);
1413 sequence_point_follows = FALSE;
1414 assemble_label_no(ln3);
1416 INITAOTV(&AO2, LONG_CONSTANT_OT, no_objects);
1417 AO2.marker = NO_OBJS_MV;
1418 assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
1420 assemble_label_no(ln2);
1423 /* -------------------------------------------------------------------- */
1424 /* (see routine above) ------------------------------------------------ */
1425 /* -------------------------------------------------------------------- */
1429 parse_print_z(FALSE); return;
1430 case PRINT_RET_CODE:
1432 parse_print_z(TRUE); return;
1434 /* -------------------------------------------------------------------- */
1435 /* quit --------------------------------------------------------------- */
1436 /* -------------------------------------------------------------------- */
1438 case QUIT_CODE: assemblez_0(quit_zc); break;
1440 /* -------------------------------------------------------------------- */
1441 /* read <expression> <expression> [<Routine>] ------------------------- */
1442 /* -------------------------------------------------------------------- */
1445 INITAOTV(&AO, VARIABLE_OT, 252);
1447 code_generate(parse_expression(QUANTITY_CONTEXT),
1448 QUANTITY_CONTEXT, -1));
1449 if (version_number > 3)
1450 { INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1451 INITAOTV(&AO4, SHORT_CONSTANT_OT, 0);
1452 assemblez_3(storeb_zc, AO, AO3, AO4);
1454 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1455 QUANTITY_CONTEXT, -1);
1458 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1461 { if (version_number == 3)
1463 "In Version 3 no status-line drawing routine can be given");
1465 { assembly_operand AO5;
1466 /* Move the temp4 (buffer) value to the stack,
1467 since the routine might alter temp4. */
1468 assemblez_store(stack_pointer, AO);
1471 AO5 = parse_expression(CONSTANT_CONTEXT);
1473 if (version_number >= 5)
1474 assemblez_1(call_1n_zc, AO5);
1476 assemblez_1_to(call_zc, AO5, temp_var1);
1480 if (version_number > 4)
1481 { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
1483 else assemblez_2(sread_zc, AO, AO2);
1486 /* -------------------------------------------------------------------- */
1487 /* remove <expression> ------------------------------------------------ */
1488 /* -------------------------------------------------------------------- */
1491 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1492 QUANTITY_CONTEXT, -1);
1493 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1494 { if (version_number >= 5)
1495 assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
1498 { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
1503 assemblez_1(remove_obj_zc, AO);
1506 /* -------------------------------------------------------------------- */
1507 /* restore <label> ---------------------------------------------------- */
1508 /* -------------------------------------------------------------------- */
1511 if (version_number < 5)
1512 assemblez_0_branch(restore_zc, parse_label(), TRUE);
1514 { INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
1515 assemblez_0_to(restore_zc, temp_var1);
1516 assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
1520 /* -------------------------------------------------------------------- */
1521 /* return [<expression>] ---------------------------------------------- */
1522 /* -------------------------------------------------------------------- */
1526 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1527 { assemblez_0(rtrue_zc); return; }
1529 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
1530 QUANTITY_CONTEXT, -1);
1531 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
1532 && (AO.marker == 0))
1533 { assemblez_0(rfalse_zc); break; }
1534 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
1535 && (AO.marker == 0))
1536 { assemblez_0(rtrue_zc); break; }
1537 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1538 { assemblez_0(ret_popped_zc); break; }
1539 assemblez_1(ret_zc, AO);
1542 /* -------------------------------------------------------------------- */
1543 /* rfalse ------------------------------------------------------------- */
1544 /* -------------------------------------------------------------------- */
1546 case RFALSE_CODE: assemblez_0(rfalse_zc); break;
1548 /* -------------------------------------------------------------------- */
1549 /* rtrue -------------------------------------------------------------- */
1550 /* -------------------------------------------------------------------- */
1552 case RTRUE_CODE: assemblez_0(rtrue_zc); break;
1554 /* -------------------------------------------------------------------- */
1555 /* save <label> ------------------------------------------------------- */
1556 /* -------------------------------------------------------------------- */
1559 if (version_number < 5)
1560 assemblez_0_branch(save_zc, parse_label(), TRUE);
1562 { INITAOTV(&AO, VARIABLE_OT, 255);
1563 assemblez_0_to(save_zc, AO);
1564 assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
1568 /* -------------------------------------------------------------------- */
1569 /* spaces <expression> ------------------------------------------------ */
1570 /* -------------------------------------------------------------------- */
1573 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1574 QUANTITY_CONTEXT, -1);
1575 INITAOTV(&AO2, VARIABLE_OT, 255);
1577 assemblez_store(AO2, AO);
1579 INITAOTV(&AO, SHORT_CONSTANT_OT, 32);
1580 INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1582 assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
1583 assemble_label_no(ln2 = next_label++);
1584 assemblez_1(print_char_zc, AO);
1586 assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
1587 assemble_label_no(ln);
1590 /* -------------------------------------------------------------------- */
1591 /* string <expression> <literal-string> ------------------------------- */
1592 /* -------------------------------------------------------------------- */
1595 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1596 INITAOTV(&AO2, SHORT_CONSTANT_OT, 12);
1597 INITAOTV(&AO3, VARIABLE_OT, 252);
1598 assemblez_2_to(loadw_zc, AO, AO2, AO3);
1599 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1600 QUANTITY_CONTEXT, -1);
1601 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1602 if (AO2.value >= 96)
1603 { error("Z-machine dynamic strings are limited to 96");
1606 if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) {
1607 memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
1611 if (token_type == DQ_TT)
1612 { INITAOT(&AO4, LONG_CONSTANT_OT);
1613 /* This string must be in low memory so that the
1614 dynamic string table can refer to it. */
1615 AO4.value = compile_string(token_text, STRCTX_LOWSTRING);
1619 AO4 = parse_expression(CONSTANT_CONTEXT);
1621 assemblez_3(storew_zc, AO3, AO2, AO4);
1624 /* -------------------------------------------------------------------- */
1625 /* style roman/reverse/bold/underline/fixed --------------------------- */
1626 /* -------------------------------------------------------------------- */
1629 if (version_number==3)
1631 "The 'style' statement cannot be used for Version 3 games");
1632 panic_mode_error_recovery();
1636 misc_keywords.enabled = TRUE;
1638 misc_keywords.enabled = FALSE;
1639 if ((token_type != MISC_KEYWORD_TT)
1640 || ((token_value != ROMAN_MK)
1641 && (token_value != REVERSE_MK)
1642 && (token_value != BOLD_MK)
1643 && (token_value != UNDERLINE_MK)
1644 && (token_value != FIXED_MK)))
1646 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1648 panic_mode_error_recovery();
1652 INITAOT(&AO, SHORT_CONSTANT_OT);
1654 { case ROMAN_MK: AO.value = 0; break;
1655 case REVERSE_MK: AO.value = 1; break;
1656 case BOLD_MK: AO.value = 2; break;
1657 case UNDERLINE_MK: AO.value = 4; break;
1658 case FIXED_MK: AO.value = 8; break;
1660 assemblez_1(set_text_style_zc, AO); break;
1662 /* -------------------------------------------------------------------- */
1663 /* switch (<expression>) <codeblock> ---------------------------------- */
1664 /* -------------------------------------------------------------------- */
1667 match_open_bracket();
1668 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1669 QUANTITY_CONTEXT, -1);
1670 match_close_bracket();
1672 INITAOTV(&AO2, VARIABLE_OT, 255);
1673 assemblez_store(AO2, AO);
1675 parse_code_block(ln = next_label++, continue_label, 1);
1676 assemble_label_no(ln);
1679 /* -------------------------------------------------------------------- */
1680 /* while (<condition>) <codeblock> ------------------------------------ */
1681 /* -------------------------------------------------------------------- */
1684 assemble_label_no(ln = next_label++);
1685 match_open_bracket();
1687 code_generate(parse_expression(CONDITION_CONTEXT),
1688 CONDITION_CONTEXT, ln2 = next_label++);
1689 match_close_bracket();
1691 parse_code_block(ln2, ln, 0);
1692 sequence_point_follows = FALSE;
1694 assemble_label_no(ln2);
1697 /* -------------------------------------------------------------------- */
1700 error("'default' without matching 'switch'"); break;
1702 error("'else' without matching 'if'"); break;
1704 error("'until' without matching 'do'");
1705 panic_mode_error_recovery(); return;
1708 StatementTerminator:
1711 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1712 { ebf_error("';'", token_text);
1717 static void parse_statement_g(int break_label, int continue_label)
1718 { int ln, ln2, ln3, ln4, flag, onstack;
1719 assembly_operand AO, AO2, AO3, AO4;
1720 debug_location spare_debug_location1, spare_debug_location2;
1724 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
1725 { /* That is, a full stop, signifying a label */
1728 if (token_type == SYMBOL_TT)
1730 if (sflags[token_value] & UNKNOWN_SFLAG)
1731 { assign_symbol(token_value, next_label, LABEL_T);
1732 sflags[token_value] |= USED_SFLAG;
1733 assemble_label_no(next_label);
1734 define_symbol_label(token_value);
1738 { if (stypes[token_value] != LABEL_T) goto LabelError;
1739 if (sflags[token_value] & CHANGE_SFLAG)
1740 { sflags[token_value] &= (~(CHANGE_SFLAG));
1741 assemble_label_no(svals[token_value]);
1742 define_symbol_label(token_value);
1744 else error_named("Duplicate definition of label:", token_text);
1748 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1749 { ebf_error("';'", token_text);
1750 put_token_back(); return;
1753 /* Interesting point of Inform grammar: a statement can only
1754 consist solely of a label when it is immediately followed
1758 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
1759 { put_token_back(); return;
1761 /* The following line prevents labels from influencing the positions
1762 of sequence points. */
1763 statement_debug_location = get_token_location();
1764 parse_statement(break_label, continue_label);
1767 LabelError: ebf_error("label name", token_text);
1770 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
1771 { parse_directive(TRUE);
1772 parse_statement(break_label, continue_label); return;
1775 if ((token_type == SEP_TT) && (token_value == AT_SEP))
1776 { parse_assembly(); return;
1779 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
1781 if (token_type == DQ_TT)
1782 { parse_print_g(TRUE); return;
1785 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
1786 { parse_action(); goto StatementTerminator; }
1788 if (token_type == EOF_TT)
1789 { ebf_error("statement", token_text); return; }
1791 if (token_type != STATEMENT_TT)
1793 AO = parse_expression(VOID_CONTEXT);
1794 code_generate(AO, VOID_CONTEXT, -1);
1795 if (vivc_flag) { panic_mode_error_recovery(); return; }
1796 goto StatementTerminator;
1799 statements.enabled = FALSE;
1804 /* -------------------------------------------------------------------- */
1805 /* box <string-1> ... <string-n> -------------------------------------- */
1806 /* -------------------------------------------------------------------- */
1809 INITAOT(&AO3, CONSTANT_OT);
1810 AO3.value = begin_table_array();
1811 AO3.marker = ARRAY_MV;
1815 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
1817 if (token_type != DQ_TT)
1818 ebf_error("text of box line in double-quotes",
1821 for (i=0, j=0; token_text[i] != 0; j++)
1822 if (token_text[i] == '@')
1823 { if (token_text[i+1] == '@')
1825 while (isdigit(token_text[i])) i++;
1829 if (token_text[i] != 0) i++;
1830 if (token_text[i] != 0) i++;
1834 if (j > ln2) ln2 = j;
1837 array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
1839 finish_array(ln, FALSE);
1841 error("No lines of text given for 'box' display");
1844 AO2.value = ln2; set_constant_ot(&AO2);
1845 assembleg_call_2(veneer_routine(Box__Routine_VR),
1846 AO2, AO3, zero_operand);
1849 /* -------------------------------------------------------------------- */
1850 /* break -------------------------------------------------------------- */
1851 /* -------------------------------------------------------------------- */
1854 if (break_label == -1)
1855 error("'break' can only be used in a loop or 'switch' block");
1857 assembleg_jump(break_label);
1860 /* -------------------------------------------------------------------- */
1861 /* continue ----------------------------------------------------------- */
1862 /* -------------------------------------------------------------------- */
1865 if (continue_label == -1)
1866 error("'continue' can only be used in a loop block");
1868 assembleg_jump(continue_label);
1871 /* -------------------------------------------------------------------- */
1872 /* do <codeblock> until (<condition>) --------------------------------- */
1873 /* -------------------------------------------------------------------- */
1876 assemble_label_no(ln = next_label++);
1877 ln2 = next_label++; ln3 = next_label++;
1878 parse_code_block(ln3, ln2, 0);
1879 statements.enabled = TRUE;
1881 if ((token_type == STATEMENT_TT)
1882 && (token_value == UNTIL_CODE))
1883 { assemble_label_no(ln2);
1884 match_open_bracket();
1885 AO = parse_expression(CONDITION_CONTEXT);
1886 match_close_bracket();
1887 code_generate(AO, CONDITION_CONTEXT, ln);
1889 else error("'do' without matching 'until'");
1891 assemble_label_no(ln3);
1894 /* -------------------------------------------------------------------- */
1895 /* font on/off -------------------------------------------------------- */
1896 /* -------------------------------------------------------------------- */
1899 misc_keywords.enabled = TRUE;
1901 misc_keywords.enabled = FALSE;
1902 if ((token_type != MISC_KEYWORD_TT)
1903 || ((token_value != ON_MK)
1904 && (token_value != OFF_MK)))
1905 { ebf_error("'on' or 'off'", token_text);
1906 panic_mode_error_recovery();
1910 /* Call glk_set_style(normal or preformatted) */
1913 set_constant_ot(&AO);
1914 if (token_value == ON_MK)
1918 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
1919 AO, AO2, zero_operand);
1922 /* -------------------------------------------------------------------- */
1923 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
1924 /* -------------------------------------------------------------------- */
1926 /* Note that it's legal for any or all of the three sections of a
1927 'for' specification to be empty. This 'for' implementation
1928 often wastes 3 bytes with a redundant branch rather than keep
1929 expression parse trees for long periods (as previous versions
1930 of Inform did, somewhat crudely by simply storing the textual
1931 form of a 'for' loop). It is adequate for now. */
1934 match_open_bracket();
1937 /* Initialisation code */
1938 AO.type = OMITTED_OT;
1939 spare_debug_location1 = statement_debug_location;
1940 AO2.type = OMITTED_OT; flag = 0;
1941 spare_debug_location2 = statement_debug_location;
1943 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1945 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
1946 { sequence_point_follows = TRUE;
1947 statement_debug_location = get_token_location();
1948 code_generate(parse_expression(FORINIT_CONTEXT),
1952 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
1954 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
1955 { assemble_label_no(ln = next_label++);
1957 parse_code_block(ln2, ln, 0);
1958 sequence_point_follows = FALSE;
1959 if (!execution_never_reaches_here)
1961 assemble_label_no(ln2);
1967 if (!match_colon()) break;
1971 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1973 spare_debug_location1 = get_token_location();
1974 AO = parse_expression(CONDITION_CONTEXT);
1975 if (!match_colon()) break;
1980 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1982 spare_debug_location2 = get_token_location();
1983 AO2 = parse_expression(VOID_CONTEXT);
1984 match_close_bracket();
1985 flag = test_for_incdec(AO2);
1992 if ((AO2.type == OMITTED_OT) || (flag != 0))
1994 assemble_label_no(ln);
1995 if (flag==0) assemble_label_no(ln2);
1997 /* The "finished yet?" condition */
1999 if (AO.type != OMITTED_OT)
2000 { sequence_point_follows = TRUE;
2001 statement_debug_location = spare_debug_location1;
2002 code_generate(AO, CONDITION_CONTEXT, ln3);
2008 /* This is the jump which could be avoided with the aid
2009 of long-term expression storage */
2011 sequence_point_follows = FALSE;
2012 assembleg_jump(ln2);
2014 /* The "update" part */
2016 assemble_label_no(ln);
2017 sequence_point_follows = TRUE;
2018 statement_debug_location = spare_debug_location2;
2019 code_generate(AO2, VOID_CONTEXT, -1);
2021 assemble_label_no(ln2);
2023 /* The "finished yet?" condition */
2025 if (AO.type != OMITTED_OT)
2026 { sequence_point_follows = TRUE;
2027 statement_debug_location = spare_debug_location1;
2028 code_generate(AO, CONDITION_CONTEXT, ln3);
2034 /* In this optimised case, update code is at the end
2035 of the loop block, so "continue" goes there */
2037 parse_code_block(ln3, ln2, 0);
2038 assemble_label_no(ln2);
2040 sequence_point_follows = TRUE;
2041 statement_debug_location = spare_debug_location2;
2045 if (AO3.value >= MAX_LOCAL_VARIABLES)
2046 AO3.type = GLOBALVAR_OT;
2048 AO3.type = LOCALVAR_OT;
2049 assembleg_3(add_gc, AO3, one_operand, AO3);
2054 if (AO3.value >= MAX_LOCAL_VARIABLES)
2055 AO3.type = GLOBALVAR_OT;
2057 AO3.type = LOCALVAR_OT;
2058 assembleg_3(sub_gc, AO3, one_operand, AO3);
2064 /* In the unoptimised case, update code is at the
2065 start of the loop block, so "continue" goes there */
2067 parse_code_block(ln3, ln, 0);
2068 if (!execution_never_reaches_here)
2069 { sequence_point_follows = FALSE;
2074 assemble_label_no(ln3);
2077 /* -------------------------------------------------------------------- */
2078 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2079 /* -------------------------------------------------------------------- */
2082 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2083 QUANTITY_CONTEXT, -1);
2084 if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
2091 if ((token_type == SEP_TT)
2092 && (token_value == SEMICOLON_SEP)) {
2094 assembleg_2(copy_gc, stack_pointer, zero_operand);
2098 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
2101 { if ((token_type == SYMBOL_TT)
2102 && (stypes[token_value] != ATTRIBUTE_T))
2103 warning_named("This is not a declared Attribute:",
2108 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2109 QUANTITY_CONTEXT, -1);
2110 if (runtime_error_checking_switch && (!veneer_mode))
2111 { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
2112 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
2113 /* already on stack */
2116 assembleg_store(stack_pointer, AO2);
2119 assembleg_2(stkpeek_gc, one_operand, stack_pointer);
2121 assembleg_store(stack_pointer, AO);
2122 assembleg_3(call_gc, veneer_routine(ln2), two_operand,
2126 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2128 set_constant_ot(&AO2);
2131 INITAOTV(&AO3, BYTECONSTANT_OT, 8);
2132 assembleg_3(add_gc, AO2, AO3, stack_pointer);
2133 AO2 = stack_pointer;
2136 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
2137 assembleg_2(stkpeek_gc, one_operand,
2140 assembleg_2(stkpeek_gc, zero_operand,
2147 assembleg_3(astorebit_gc, AO, AO2, AO3);
2151 /* -------------------------------------------------------------------- */
2152 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2153 /* -------------------------------------------------------------------- */
2159 match_open_bracket();
2160 AO = parse_expression(CONDITION_CONTEXT);
2161 match_close_bracket();
2163 statements.enabled = TRUE;
2165 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
2168 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
2175 code_generate(AO, CONDITION_CONTEXT, ln);
2177 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
2180 if ((token_type != SEP_TT)
2181 || (token_value != SEMICOLON_SEP))
2182 { ebf_error("';'", token_text);
2187 statements.enabled = TRUE;
2190 /* An #if directive around the ELSE clause is legal. */
2191 while ((token_type == SEP_TT) && (token_value == HASH_SEP))
2192 { parse_directive(TRUE);
2193 statements.enabled = TRUE;
2197 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
2200 { ln2 = next_label++;
2201 if (!execution_never_reaches_here)
2202 { sequence_point_follows = FALSE;
2203 assembleg_jump(ln2);
2207 else put_token_back();
2209 if (ln >= 0) assemble_label_no(ln);
2212 { parse_code_block(break_label, continue_label, 0);
2213 if (ln >= 0) assemble_label_no(ln2);
2218 /* -------------------------------------------------------------------- */
2219 /* inversion ---------------------------------------------------------- */
2220 /* -------------------------------------------------------------------- */
2222 case INVERSION_CODE:
2223 INITAOTV(&AO2, DEREFERENCE_OT, GLULX_HEADER_SIZE+8);
2224 assembleg_2(copyb_gc, AO2, stack_pointer);
2225 assembleg_1(streamchar_gc, stack_pointer);
2226 AO2.value = GLULX_HEADER_SIZE+9;
2227 assembleg_2(copyb_gc, AO2, stack_pointer);
2228 assembleg_1(streamchar_gc, stack_pointer);
2229 AO2.value = GLULX_HEADER_SIZE+10;
2230 assembleg_2(copyb_gc, AO2, stack_pointer);
2231 assembleg_1(streamchar_gc, stack_pointer);
2232 AO2.value = GLULX_HEADER_SIZE+11;
2233 assembleg_2(copyb_gc, AO2, stack_pointer);
2234 assembleg_1(streamchar_gc, stack_pointer);
2236 if (/* DISABLES CODE */ (0)) {
2239 set_constant_ot(&AO);
2240 assembleg_1(streamchar_gc, AO);
2242 set_constant_ot(&AO);
2243 assembleg_1(streamchar_gc, AO);
2245 AO2.value = GLULX_HEADER_SIZE+12;
2246 assembleg_2(copyb_gc, AO2, stack_pointer);
2247 assembleg_1(streamchar_gc, stack_pointer);
2248 AO2.value = GLULX_HEADER_SIZE+13;
2249 assembleg_2(copyb_gc, AO2, stack_pointer);
2250 assembleg_1(streamchar_gc, stack_pointer);
2251 AO2.value = GLULX_HEADER_SIZE+14;
2252 assembleg_2(copyb_gc, AO2, stack_pointer);
2253 assembleg_1(streamchar_gc, stack_pointer);
2254 AO2.value = GLULX_HEADER_SIZE+15;
2255 assembleg_2(copyb_gc, AO2, stack_pointer);
2256 assembleg_1(streamchar_gc, stack_pointer);
2260 set_constant_ot(&AO);
2261 assembleg_1(streamchar_gc, AO);
2266 /* -------------------------------------------------------------------- */
2267 /* jump <label> ------------------------------------------------------- */
2268 /* -------------------------------------------------------------------- */
2271 assembleg_jump(parse_label());
2274 /* -------------------------------------------------------------------- */
2275 /* move <expression> to <expression> ---------------------------------- */
2276 /* -------------------------------------------------------------------- */
2279 misc_keywords.enabled = TRUE;
2280 AO = parse_expression(QUANTITY_CONTEXT);
2283 misc_keywords.enabled = FALSE;
2284 if ((token_type != MISC_KEYWORD_TT)
2285 || (token_value != TO_MK))
2286 { ebf_error("'to'", token_text);
2287 panic_mode_error_recovery();
2291 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2292 QUANTITY_CONTEXT, -1);
2293 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
2294 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2295 assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
2298 assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
2302 /* -------------------------------------------------------------------- */
2303 /* new_line ----------------------------------------------------------- */
2304 /* -------------------------------------------------------------------- */
2307 INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
2308 assembleg_1(streamchar_gc, AO);
2311 /* -------------------------------------------------------------------- */
2312 /* objectloop (<initialisation>) <codeblock> -------------------------- */
2313 /* -------------------------------------------------------------------- */
2315 case OBJECTLOOP_CODE:
2317 match_open_bracket();
2319 if (token_type == LOCAL_VARIABLE_TT) {
2320 INITAOTV(&AO, LOCALVAR_OT, token_value);
2322 else if ((token_type == SYMBOL_TT) &&
2323 (stypes[token_value] == GLOBAL_VARIABLE_T)) {
2324 INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]);
2327 ebf_error("'objectloop' variable", token_text);
2328 panic_mode_error_recovery();
2331 misc_keywords.enabled = TRUE;
2332 get_next_token(); flag = TRUE;
2333 misc_keywords.enabled = FALSE;
2334 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2338 if ((token_type == MISC_KEYWORD_TT)
2339 && (token_value == NEAR_MK)) ln = 1;
2340 if ((token_type == MISC_KEYWORD_TT)
2341 && (token_value == FROM_MK)) ln = 2;
2342 if ((token_type == CND_TT) && (token_value == IN_COND))
2345 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2352 /* Old style (Inform 5) objectloops: note that we
2353 implement objectloop (a in b) in the old way since
2354 this runs through objects in a different order from
2355 the new way, and there may be existing Inform code
2357 assembly_operand AO4, AO5;
2360 sequence_point_follows = TRUE;
2361 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2362 QUANTITY_CONTEXT, -1);
2363 match_close_bracket();
2365 if (runtime_error_checking_switch)
2366 AO2 = check_nonzero_at_runtime(AO2, -1,
2368 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2369 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2370 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2371 assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
2372 AO2 = stack_pointer;
2375 if (runtime_error_checking_switch) {
2377 AO2 = check_nonzero_at_runtime(AO2, -1,
2380 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2381 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2382 AO2 = stack_pointer;
2387 assembleg_store(AO, AO2);
2388 assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
2389 assemble_label_no(ln4 = next_label++);
2390 parse_code_block(ln2, ln3 = next_label++, 0);
2391 sequence_point_follows = FALSE;
2392 assemble_label_no(ln3);
2393 if (runtime_error_checking_switch) {
2394 AO2 = check_nonzero_at_runtime(AO, ln2,
2397 && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
2398 && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
2399 { assembly_operand en_ao;
2401 en_ao.value = OBJECTLOOP_BROKEN_RTE;
2402 set_constant_ot(&en_ao);
2403 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2404 assembleg_3(aload_gc, AO, AO4, stack_pointer);
2405 assembleg_2_branch(jeq_gc, stack_pointer, AO5,
2407 assembleg_call_2(veneer_routine(RT__Err_VR),
2408 en_ao, AO, zero_operand);
2409 assembleg_jump(ln2);
2410 assemble_label_no(next_label++);
2416 INITAOTV(&AO4, BYTECONSTANT_OT, 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 INITAOT(&AO2, CONSTANT_OT);
2426 AO2.value = svals[ln];
2427 AO2.marker = OBJECT_MV;
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 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHAIN());
2446 assembleg_3(aload_gc, AO, AO4, AO);
2447 assembleg_1_branch(jnz_gc, AO, ln);
2448 assemble_label_no(ln2);
2451 /* -------------------------------------------------------------------- */
2452 /* (see routine above) ------------------------------------------------ */
2453 /* -------------------------------------------------------------------- */
2457 parse_print_g(FALSE); return;
2458 case PRINT_RET_CODE:
2460 parse_print_g(TRUE); return;
2462 /* -------------------------------------------------------------------- */
2463 /* quit --------------------------------------------------------------- */
2464 /* -------------------------------------------------------------------- */
2467 assembleg_0(quit_gc); break;
2469 /* -------------------------------------------------------------------- */
2470 /* remove <expression> ------------------------------------------------ */
2471 /* -------------------------------------------------------------------- */
2474 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2475 QUANTITY_CONTEXT, -1);
2476 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2477 assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
2480 assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
2484 /* -------------------------------------------------------------------- */
2485 /* return [<expression>] ---------------------------------------------- */
2486 /* -------------------------------------------------------------------- */
2490 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
2491 assembleg_1(return_gc, one_operand);
2495 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
2496 QUANTITY_CONTEXT, -1);
2497 assembleg_1(return_gc, AO);
2500 /* -------------------------------------------------------------------- */
2501 /* rfalse ------------------------------------------------------------- */
2502 /* -------------------------------------------------------------------- */
2505 assembleg_1(return_gc, zero_operand);
2508 /* -------------------------------------------------------------------- */
2509 /* rtrue -------------------------------------------------------------- */
2510 /* -------------------------------------------------------------------- */
2513 assembleg_1(return_gc, one_operand);
2516 /* -------------------------------------------------------------------- */
2517 /* spaces <expression> ------------------------------------------------ */
2518 /* -------------------------------------------------------------------- */
2521 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2522 QUANTITY_CONTEXT, -1);
2524 assembleg_store(temp_var1, AO);
2527 AO.value = 32; set_constant_ot(&AO);
2529 assembleg_2_branch(jlt_gc, temp_var1, one_operand,
2531 assemble_label_no(ln2 = next_label++);
2532 assembleg_1(streamchar_gc, AO);
2533 assembleg_dec(temp_var1);
2534 assembleg_1_branch(jnz_gc, temp_var1, ln2);
2535 assemble_label_no(ln);
2538 /* -------------------------------------------------------------------- */
2539 /* string <expression> <literal-string> ------------------------------- */
2540 /* -------------------------------------------------------------------- */
2543 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2544 QUANTITY_CONTEXT, -1);
2545 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2546 if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) {
2547 memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
2551 if (token_type == DQ_TT)
2552 { INITAOT(&AO4, CONSTANT_OT);
2553 /* This is not actually placed in low memory; Glulx
2554 has no such concept. We use the LOWSTRING flag
2555 for compatibility with older compiler behavior. */
2556 AO4.value = compile_string(token_text, STRCTX_LOWSTRING);
2557 AO4.marker = STRING_MV;
2561 AO4 = parse_expression(CONSTANT_CONTEXT);
2563 assembleg_call_2(veneer_routine(Dynam__String_VR),
2564 AO2, AO4, zero_operand);
2567 /* -------------------------------------------------------------------- */
2568 /* style roman/reverse/bold/underline/fixed --------------------------- */
2569 /* -------------------------------------------------------------------- */
2572 misc_keywords.enabled = TRUE;
2574 misc_keywords.enabled = FALSE;
2575 if ((token_type != MISC_KEYWORD_TT)
2576 || ((token_value != ROMAN_MK)
2577 && (token_value != REVERSE_MK)
2578 && (token_value != BOLD_MK)
2579 && (token_value != UNDERLINE_MK)
2580 && (token_value != FIXED_MK)))
2582 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2584 panic_mode_error_recovery();
2588 /* Call glk_set_style() */
2592 set_constant_ot(&AO);
2596 AO2 = zero_operand; /* normal */
2600 AO2.value = 5; /* alert */
2601 set_constant_ot(&AO2);
2605 AO2.value = 4; /* subheader */
2606 set_constant_ot(&AO2);
2609 AO2 = one_operand; /* emphasized */
2612 AO2 = two_operand; /* preformatted */
2615 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
2616 AO, AO2, zero_operand);
2619 /* -------------------------------------------------------------------- */
2620 /* switch (<expression>) <codeblock> ---------------------------------- */
2621 /* -------------------------------------------------------------------- */
2624 match_open_bracket();
2625 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2626 QUANTITY_CONTEXT, -1);
2627 match_close_bracket();
2629 assembleg_store(temp_var1, AO);
2631 parse_code_block(ln = next_label++, continue_label, 1);
2632 assemble_label_no(ln);
2635 /* -------------------------------------------------------------------- */
2636 /* while (<condition>) <codeblock> ------------------------------------ */
2637 /* -------------------------------------------------------------------- */
2640 assemble_label_no(ln = next_label++);
2641 match_open_bracket();
2643 code_generate(parse_expression(CONDITION_CONTEXT),
2644 CONDITION_CONTEXT, ln2 = next_label++);
2645 match_close_bracket();
2647 parse_code_block(ln2, ln, 0);
2648 sequence_point_follows = FALSE;
2650 assemble_label_no(ln2);
2653 /* -------------------------------------------------------------------- */
2656 error("'default' without matching 'switch'"); break;
2658 error("'else' without matching 'if'"); break;
2660 error("'until' without matching 'do'");
2661 panic_mode_error_recovery(); return;
2663 /* -------------------------------------------------------------------- */
2665 /* And a useful default, which will never be triggered in a complete
2666 Inform compiler, but which is important in development. */
2669 error("*** Statement code gen: Can't generate yet ***\n");
2670 panic_mode_error_recovery(); return;
2673 StatementTerminator:
2676 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
2677 { ebf_error("';'", token_text);
2682 extern void parse_statement(int break_label, int continue_label)
2685 parse_statement_z(break_label, continue_label);
2687 parse_statement_g(break_label, continue_label);
2690 /* ========================================================================= */
2691 /* Data structure management routines */
2692 /* ------------------------------------------------------------------------- */
2694 extern void init_states_vars(void)
2698 extern void states_begin_pass(void)
2702 extern void states_allocate_arrays(void)
2706 extern void states_free_arrays(void)
2710 /* ========================================================================= */