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, FALSE, FALSE);
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, FALSE, FALSE);
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 */
978 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
980 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
981 { sequence_point_follows = TRUE;
982 statement_debug_location = get_token_location();
983 code_generate(parse_expression(FORINIT_CONTEXT),
987 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
989 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
990 { assemble_label_no(ln = next_label++);
992 parse_code_block(ln2, ln, 0);
993 sequence_point_follows = FALSE;
994 if (!execution_never_reaches_here)
996 assemble_label_no(ln2);
999 AO.type = OMITTED_OT;
1003 if (!match_colon()) break;
1007 AO.type = OMITTED_OT;
1008 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1010 spare_debug_location1 = get_token_location();
1011 AO = parse_expression(CONDITION_CONTEXT);
1012 if (!match_colon()) break;
1017 AO2.type = OMITTED_OT; flag = 0;
1018 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1020 spare_debug_location2 = get_token_location();
1021 AO2 = parse_expression(VOID_CONTEXT);
1022 match_close_bracket();
1023 flag = test_for_incdec(AO2);
1030 if ((AO2.type == OMITTED_OT) || (flag != 0))
1032 assemble_label_no(ln);
1033 if (flag==0) assemble_label_no(ln2);
1035 /* The "finished yet?" condition */
1037 if (AO.type != OMITTED_OT)
1038 { sequence_point_follows = TRUE;
1039 statement_debug_location = spare_debug_location1;
1040 code_generate(AO, CONDITION_CONTEXT, ln3);
1046 /* This is the jump which could be avoided with the aid
1047 of long-term expression storage */
1049 sequence_point_follows = FALSE;
1050 assemblez_jump(ln2);
1052 /* The "update" part */
1054 assemble_label_no(ln);
1055 sequence_point_follows = TRUE;
1056 statement_debug_location = spare_debug_location2;
1057 code_generate(AO2, VOID_CONTEXT, -1);
1059 assemble_label_no(ln2);
1061 /* The "finished yet?" condition */
1063 if (AO.type != OMITTED_OT)
1064 { sequence_point_follows = TRUE;
1065 statement_debug_location = spare_debug_location1;
1066 code_generate(AO, CONDITION_CONTEXT, ln3);
1072 /* In this optimised case, update code is at the end
1073 of the loop block, so "continue" goes there */
1075 parse_code_block(ln3, ln2, 0);
1076 assemble_label_no(ln2);
1078 sequence_point_follows = TRUE;
1079 statement_debug_location = spare_debug_location2;
1081 { INITAOTV(&AO3, SHORT_CONSTANT_OT, flag);
1083 && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1084 AO3.marker = VARIABLE_MV;
1085 assemblez_1(inc_zc, AO3);
1088 { INITAOTV(&AO3, SHORT_CONSTANT_OT, -flag);
1089 if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
1090 && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1091 AO3.marker = VARIABLE_MV;
1092 assemblez_1(dec_zc, AO3);
1098 /* In the unoptimised case, update code is at the
1099 start of the loop block, so "continue" goes there */
1101 parse_code_block(ln3, ln, 0);
1102 if (!execution_never_reaches_here)
1103 { sequence_point_follows = FALSE;
1108 assemble_label_no(ln3);
1111 /* -------------------------------------------------------------------- */
1112 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
1113 /* -------------------------------------------------------------------- */
1116 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1117 QUANTITY_CONTEXT, -1);
1118 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1119 { INITAOTV(&AO, SHORT_CONSTANT_OT, 252);
1120 if (version_number != 6) assemblez_1(pull_zc, AO);
1121 else assemblez_0_to(pull_zc, AO);
1122 AO.type = VARIABLE_OT;
1127 if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
1129 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
1132 { if ((token_type == SYMBOL_TT)
1133 && (stypes[token_value] != ATTRIBUTE_T))
1134 warning_named("This is not a declared Attribute:",
1139 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1140 QUANTITY_CONTEXT, -1);
1141 if (runtime_error_checking_switch)
1142 { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
1143 if (version_number >= 5)
1144 assemblez_3(call_vn_zc, veneer_routine(ln2),
1148 assemblez_3_to(call_zc, veneer_routine(ln2),
1149 AO, AO2, temp_var1);
1153 assemblez_2(ln, AO, AO2);
1156 /* -------------------------------------------------------------------- */
1157 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
1158 /* -------------------------------------------------------------------- */
1164 match_open_bracket();
1165 AO = parse_expression(CONDITION_CONTEXT);
1166 match_close_bracket();
1168 statements.enabled = TRUE;
1170 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
1173 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
1180 code_generate(AO, CONDITION_CONTEXT, ln);
1182 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
1185 if ((token_type != SEP_TT)
1186 || (token_value != SEMICOLON_SEP))
1187 { ebf_error("';'", token_text);
1192 statements.enabled = TRUE;
1195 /* An #if directive around the ELSE clause is legal. */
1196 while ((token_type == SEP_TT) && (token_value == HASH_SEP))
1197 { parse_directive(TRUE);
1198 statements.enabled = TRUE;
1202 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
1205 { ln2 = next_label++;
1206 if (!execution_never_reaches_here)
1207 { sequence_point_follows = FALSE;
1208 assemblez_jump(ln2);
1212 else put_token_back();
1214 if (ln >= 0) assemble_label_no(ln);
1217 { parse_code_block(break_label, continue_label, 0);
1218 if (ln >= 0) assemble_label_no(ln2);
1223 /* -------------------------------------------------------------------- */
1224 /* inversion ---------------------------------------------------------- */
1225 /* -------------------------------------------------------------------- */
1227 case INVERSION_CODE:
1228 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1229 INITAOT(&AO2, SHORT_CONSTANT_OT);
1232 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1233 assemblez_1(print_char_zc, temp_var1);
1235 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1236 assemblez_1(print_char_zc, temp_var1);
1238 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1239 assemblez_1(print_char_zc, temp_var1);
1241 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1242 assemblez_1(print_char_zc, temp_var1);
1245 /* -------------------------------------------------------------------- */
1246 /* jump <label> ------------------------------------------------------- */
1247 /* -------------------------------------------------------------------- */
1250 assemblez_jump(parse_label());
1253 /* -------------------------------------------------------------------- */
1254 /* move <expression> to <expression> ---------------------------------- */
1255 /* -------------------------------------------------------------------- */
1258 misc_keywords.enabled = TRUE;
1259 AO = parse_expression(QUANTITY_CONTEXT);
1262 misc_keywords.enabled = FALSE;
1263 if ((token_type != MISC_KEYWORD_TT)
1264 || (token_value != TO_MK))
1265 { ebf_error("'to'", token_text);
1266 panic_mode_error_recovery();
1270 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1271 QUANTITY_CONTEXT, -1);
1272 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
1273 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1274 { if (version_number >= 5)
1275 assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
1278 { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
1279 AO, AO2, temp_var1);
1283 assemblez_2(insert_obj_zc, AO, AO2);
1286 /* -------------------------------------------------------------------- */
1287 /* new_line ----------------------------------------------------------- */
1288 /* -------------------------------------------------------------------- */
1290 case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
1292 /* -------------------------------------------------------------------- */
1293 /* objectloop (<initialisation>) <codeblock> -------------------------- */
1294 /* -------------------------------------------------------------------- */
1296 case OBJECTLOOP_CODE:
1298 match_open_bracket();
1300 INITAOT(&AO, VARIABLE_OT);
1301 if (token_type == LOCAL_VARIABLE_TT)
1302 AO.value = token_value;
1304 if ((token_type == SYMBOL_TT) &&
1305 (stypes[token_value] == GLOBAL_VARIABLE_T))
1306 AO.value = svals[token_value];
1308 { ebf_error("'objectloop' variable", token_text);
1309 panic_mode_error_recovery(); break;
1311 if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
1312 && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
1313 AO.marker = VARIABLE_MV;
1314 misc_keywords.enabled = TRUE;
1315 get_next_token(); flag = TRUE;
1316 misc_keywords.enabled = FALSE;
1317 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1321 if ((token_type == MISC_KEYWORD_TT)
1322 && (token_value == NEAR_MK)) ln = 1;
1323 if ((token_type == MISC_KEYWORD_TT)
1324 && (token_value == FROM_MK)) ln = 2;
1325 if ((token_type == CND_TT) && (token_value == IN_COND))
1328 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1335 { /* Old style (Inform 5) objectloops: note that we
1336 implement objectloop (a in b) in the old way since
1337 this runs through objects in a different order from
1338 the new way, and there may be existing Inform code
1340 assembly_operand AO4;
1343 sequence_point_follows = TRUE;
1344 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1345 QUANTITY_CONTEXT, -1);
1346 match_close_bracket();
1348 { INITAOTV(&AO3, VARIABLE_OT, 0);
1349 if (runtime_error_checking_switch)
1350 AO2 = check_nonzero_at_runtime(AO2, -1,
1352 assemblez_1_to(get_parent_zc, AO2, AO3);
1353 assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
1357 { INITAOTV(&AO3, VARIABLE_OT, 0);
1358 if (runtime_error_checking_switch)
1360 AO2 = check_nonzero_at_runtime(AO2, -1,
1363 assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
1366 assemblez_store(AO, AO2);
1367 assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
1368 assemble_label_no(ln4 = next_label++);
1369 parse_code_block(ln2, ln3 = next_label++, 0);
1370 sequence_point_follows = FALSE;
1371 assemble_label_no(ln3);
1372 if (runtime_error_checking_switch)
1373 { AO2 = check_nonzero_at_runtime(AO, ln2,
1376 && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
1377 && ((AO4.type != VARIABLE_OT)
1378 ||(AO4.value != AO.value)))
1379 { assembly_operand en_ao;
1380 INITAOTV(&en_ao, SHORT_CONSTANT_OT, OBJECTLOOP_BROKEN_RTE);
1381 assemblez_2_branch(jin_zc, AO, AO4,
1383 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
1385 assemblez_jump(ln2);
1386 assemble_label_no(next_label++);
1390 assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
1391 assemble_label_no(ln2);
1395 sequence_point_follows = TRUE;
1396 INITAOTV(&AO2, SHORT_CONSTANT_OT, 1);
1397 assemblez_store(AO, AO2);
1399 assemble_label_no(ln = next_label++);
1405 sequence_point_follows = TRUE;
1406 code_generate(parse_expression(CONDITION_CONTEXT),
1407 CONDITION_CONTEXT, ln3);
1408 match_close_bracket();
1410 parse_code_block(ln2, ln3, 0);
1412 sequence_point_follows = FALSE;
1413 assemble_label_no(ln3);
1415 INITAOTV(&AO2, LONG_CONSTANT_OT, no_objects);
1416 AO2.marker = NO_OBJS_MV;
1417 assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
1419 assemble_label_no(ln2);
1422 /* -------------------------------------------------------------------- */
1423 /* (see routine above) ------------------------------------------------ */
1424 /* -------------------------------------------------------------------- */
1428 parse_print_z(FALSE); return;
1429 case PRINT_RET_CODE:
1431 parse_print_z(TRUE); return;
1433 /* -------------------------------------------------------------------- */
1434 /* quit --------------------------------------------------------------- */
1435 /* -------------------------------------------------------------------- */
1437 case QUIT_CODE: assemblez_0(quit_zc); break;
1439 /* -------------------------------------------------------------------- */
1440 /* read <expression> <expression> [<Routine>] ------------------------- */
1441 /* -------------------------------------------------------------------- */
1444 INITAOTV(&AO, VARIABLE_OT, 252);
1446 code_generate(parse_expression(QUANTITY_CONTEXT),
1447 QUANTITY_CONTEXT, -1));
1448 if (version_number > 3)
1449 { INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1450 INITAOTV(&AO4, SHORT_CONSTANT_OT, 0);
1451 assemblez_3(storeb_zc, AO, AO3, AO4);
1453 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1454 QUANTITY_CONTEXT, -1);
1457 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1460 { if (version_number == 3)
1462 "In Version 3 no status-line drawing routine can be given");
1464 { assembly_operand AO5;
1465 /* Move the temp4 (buffer) value to the stack,
1466 since the routine might alter temp4. */
1467 assemblez_store(stack_pointer, AO);
1470 AO5 = parse_expression(CONSTANT_CONTEXT);
1472 if (version_number >= 5)
1473 assemblez_1(call_1n_zc, AO5);
1475 assemblez_1_to(call_zc, AO5, temp_var1);
1479 if (version_number > 4)
1480 { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
1482 else assemblez_2(sread_zc, AO, AO2);
1485 /* -------------------------------------------------------------------- */
1486 /* remove <expression> ------------------------------------------------ */
1487 /* -------------------------------------------------------------------- */
1490 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1491 QUANTITY_CONTEXT, -1);
1492 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1493 { if (version_number >= 5)
1494 assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
1497 { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
1502 assemblez_1(remove_obj_zc, AO);
1505 /* -------------------------------------------------------------------- */
1506 /* restore <label> ---------------------------------------------------- */
1507 /* -------------------------------------------------------------------- */
1510 if (version_number < 5)
1511 assemblez_0_branch(restore_zc, parse_label(), TRUE);
1513 { INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
1514 assemblez_0_to(restore_zc, temp_var1);
1515 assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
1519 /* -------------------------------------------------------------------- */
1520 /* return [<expression>] ---------------------------------------------- */
1521 /* -------------------------------------------------------------------- */
1525 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1526 { assemblez_0(rtrue_zc); return; }
1528 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
1529 QUANTITY_CONTEXT, -1);
1530 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
1531 && (AO.marker == 0))
1532 { assemblez_0(rfalse_zc); break; }
1533 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
1534 && (AO.marker == 0))
1535 { assemblez_0(rtrue_zc); break; }
1536 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1537 { assemblez_0(ret_popped_zc); break; }
1538 assemblez_1(ret_zc, AO);
1541 /* -------------------------------------------------------------------- */
1542 /* rfalse ------------------------------------------------------------- */
1543 /* -------------------------------------------------------------------- */
1545 case RFALSE_CODE: assemblez_0(rfalse_zc); break;
1547 /* -------------------------------------------------------------------- */
1548 /* rtrue -------------------------------------------------------------- */
1549 /* -------------------------------------------------------------------- */
1551 case RTRUE_CODE: assemblez_0(rtrue_zc); break;
1553 /* -------------------------------------------------------------------- */
1554 /* save <label> ------------------------------------------------------- */
1555 /* -------------------------------------------------------------------- */
1558 if (version_number < 5)
1559 assemblez_0_branch(save_zc, parse_label(), TRUE);
1561 { INITAOTV(&AO, VARIABLE_OT, 255);
1562 assemblez_0_to(save_zc, AO);
1563 assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
1567 /* -------------------------------------------------------------------- */
1568 /* spaces <expression> ------------------------------------------------ */
1569 /* -------------------------------------------------------------------- */
1572 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1573 QUANTITY_CONTEXT, -1);
1574 INITAOTV(&AO2, VARIABLE_OT, 255);
1576 assemblez_store(AO2, AO);
1578 INITAOTV(&AO, SHORT_CONSTANT_OT, 32);
1579 INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1581 assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
1582 assemble_label_no(ln2 = next_label++);
1583 assemblez_1(print_char_zc, AO);
1585 assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
1586 assemble_label_no(ln);
1589 /* -------------------------------------------------------------------- */
1590 /* string <expression> <literal-string> ------------------------------- */
1591 /* -------------------------------------------------------------------- */
1594 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1595 INITAOTV(&AO2, SHORT_CONSTANT_OT, 12);
1596 INITAOTV(&AO3, VARIABLE_OT, 252);
1597 assemblez_2_to(loadw_zc, AO, AO2, AO3);
1598 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1599 QUANTITY_CONTEXT, -1);
1600 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
1601 if (AO2.value >= 96)
1602 { error("Z-machine dynamic strings are limited to 96");
1605 if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) {
1606 memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
1610 if (token_type == DQ_TT)
1611 { INITAOT(&AO4, LONG_CONSTANT_OT);
1612 AO4.value = compile_string(token_text, TRUE, TRUE);
1616 AO4 = parse_expression(CONSTANT_CONTEXT);
1618 assemblez_3(storew_zc, AO3, AO2, AO4);
1621 /* -------------------------------------------------------------------- */
1622 /* style roman/reverse/bold/underline/fixed --------------------------- */
1623 /* -------------------------------------------------------------------- */
1626 if (version_number==3)
1628 "The 'style' statement cannot be used for Version 3 games");
1629 panic_mode_error_recovery();
1633 misc_keywords.enabled = TRUE;
1635 misc_keywords.enabled = FALSE;
1636 if ((token_type != MISC_KEYWORD_TT)
1637 || ((token_value != ROMAN_MK)
1638 && (token_value != REVERSE_MK)
1639 && (token_value != BOLD_MK)
1640 && (token_value != UNDERLINE_MK)
1641 && (token_value != FIXED_MK)))
1643 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1645 panic_mode_error_recovery();
1649 INITAOT(&AO, SHORT_CONSTANT_OT);
1651 { case ROMAN_MK: AO.value = 0; break;
1652 case REVERSE_MK: AO.value = 1; break;
1653 case BOLD_MK: AO.value = 2; break;
1654 case UNDERLINE_MK: AO.value = 4; break;
1655 case FIXED_MK: AO.value = 8; break;
1657 assemblez_1(set_text_style_zc, AO); break;
1659 /* -------------------------------------------------------------------- */
1660 /* switch (<expression>) <codeblock> ---------------------------------- */
1661 /* -------------------------------------------------------------------- */
1664 match_open_bracket();
1665 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1666 QUANTITY_CONTEXT, -1);
1667 match_close_bracket();
1669 INITAOTV(&AO2, VARIABLE_OT, 255);
1670 assemblez_store(AO2, AO);
1672 parse_code_block(ln = next_label++, continue_label, 1);
1673 assemble_label_no(ln);
1676 /* -------------------------------------------------------------------- */
1677 /* while (<condition>) <codeblock> ------------------------------------ */
1678 /* -------------------------------------------------------------------- */
1681 assemble_label_no(ln = next_label++);
1682 match_open_bracket();
1684 code_generate(parse_expression(CONDITION_CONTEXT),
1685 CONDITION_CONTEXT, ln2 = next_label++);
1686 match_close_bracket();
1688 parse_code_block(ln2, ln, 0);
1689 sequence_point_follows = FALSE;
1691 assemble_label_no(ln2);
1694 /* -------------------------------------------------------------------- */
1697 error("'default' without matching 'switch'"); break;
1699 error("'else' without matching 'if'"); break;
1701 error("'until' without matching 'do'");
1702 panic_mode_error_recovery(); return;
1705 StatementTerminator:
1708 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1709 { ebf_error("';'", token_text);
1714 static void parse_statement_g(int break_label, int continue_label)
1715 { int ln, ln2, ln3, ln4, flag, onstack;
1716 assembly_operand AO, AO2, AO3, AO4;
1717 debug_location spare_debug_location1, spare_debug_location2;
1721 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
1722 { /* That is, a full stop, signifying a label */
1725 if (token_type == SYMBOL_TT)
1727 if (sflags[token_value] & UNKNOWN_SFLAG)
1728 { assign_symbol(token_value, next_label, LABEL_T);
1729 sflags[token_value] |= USED_SFLAG;
1730 assemble_label_no(next_label);
1731 define_symbol_label(token_value);
1735 { if (stypes[token_value] != LABEL_T) goto LabelError;
1736 if (sflags[token_value] & CHANGE_SFLAG)
1737 { sflags[token_value] &= (~(CHANGE_SFLAG));
1738 assemble_label_no(svals[token_value]);
1739 define_symbol_label(token_value);
1741 else error_named("Duplicate definition of label:", token_text);
1745 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1746 { ebf_error("';'", token_text);
1747 put_token_back(); return;
1750 /* Interesting point of Inform grammar: a statement can only
1751 consist solely of a label when it is immediately followed
1755 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
1756 { put_token_back(); return;
1758 /* The following line prevents labels from influencing the positions
1759 of sequence points. */
1760 statement_debug_location = get_token_location();
1761 parse_statement(break_label, continue_label);
1764 LabelError: ebf_error("label name", token_text);
1767 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
1768 { parse_directive(TRUE);
1769 parse_statement(break_label, continue_label); return;
1772 if ((token_type == SEP_TT) && (token_value == AT_SEP))
1773 { parse_assembly(); return;
1776 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
1778 if (token_type == DQ_TT)
1779 { parse_print_g(TRUE); return;
1782 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
1783 { parse_action(); goto StatementTerminator; }
1785 if (token_type == EOF_TT)
1786 { ebf_error("statement", token_text); return; }
1788 if (token_type != STATEMENT_TT)
1790 AO = parse_expression(VOID_CONTEXT);
1791 code_generate(AO, VOID_CONTEXT, -1);
1792 if (vivc_flag) { panic_mode_error_recovery(); return; }
1793 goto StatementTerminator;
1796 statements.enabled = FALSE;
1801 /* -------------------------------------------------------------------- */
1802 /* box <string-1> ... <string-n> -------------------------------------- */
1803 /* -------------------------------------------------------------------- */
1806 INITAOT(&AO3, CONSTANT_OT);
1807 AO3.value = begin_table_array();
1808 AO3.marker = ARRAY_MV;
1812 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
1814 if (token_type != DQ_TT)
1815 ebf_error("text of box line in double-quotes",
1818 for (i=0, j=0; token_text[i] != 0; j++)
1819 if (token_text[i] == '@')
1820 { if (token_text[i+1] == '@')
1822 while (isdigit(token_text[i])) i++;
1826 if (token_text[i] != 0) i++;
1827 if (token_text[i] != 0) i++;
1831 if (j > ln2) ln2 = j;
1834 array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
1836 finish_array(ln, FALSE);
1838 error("No lines of text given for 'box' display");
1841 AO2.value = ln2; set_constant_ot(&AO2);
1842 assembleg_call_2(veneer_routine(Box__Routine_VR),
1843 AO2, AO3, zero_operand);
1846 /* -------------------------------------------------------------------- */
1847 /* break -------------------------------------------------------------- */
1848 /* -------------------------------------------------------------------- */
1851 if (break_label == -1)
1852 error("'break' can only be used in a loop or 'switch' block");
1854 assembleg_jump(break_label);
1857 /* -------------------------------------------------------------------- */
1858 /* continue ----------------------------------------------------------- */
1859 /* -------------------------------------------------------------------- */
1862 if (continue_label == -1)
1863 error("'continue' can only be used in a loop block");
1865 assembleg_jump(continue_label);
1868 /* -------------------------------------------------------------------- */
1869 /* do <codeblock> until (<condition>) --------------------------------- */
1870 /* -------------------------------------------------------------------- */
1873 assemble_label_no(ln = next_label++);
1874 ln2 = next_label++; ln3 = next_label++;
1875 parse_code_block(ln3, ln2, 0);
1876 statements.enabled = TRUE;
1878 if ((token_type == STATEMENT_TT)
1879 && (token_value == UNTIL_CODE))
1880 { assemble_label_no(ln2);
1881 match_open_bracket();
1882 AO = parse_expression(CONDITION_CONTEXT);
1883 match_close_bracket();
1884 code_generate(AO, CONDITION_CONTEXT, ln);
1886 else error("'do' without matching 'until'");
1888 assemble_label_no(ln3);
1891 /* -------------------------------------------------------------------- */
1892 /* font on/off -------------------------------------------------------- */
1893 /* -------------------------------------------------------------------- */
1896 misc_keywords.enabled = TRUE;
1898 misc_keywords.enabled = FALSE;
1899 if ((token_type != MISC_KEYWORD_TT)
1900 || ((token_value != ON_MK)
1901 && (token_value != OFF_MK)))
1902 { ebf_error("'on' or 'off'", token_text);
1903 panic_mode_error_recovery();
1907 /* Call glk_set_style(normal or preformatted) */
1910 set_constant_ot(&AO);
1911 if (token_value == ON_MK)
1915 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
1916 AO, AO2, zero_operand);
1919 /* -------------------------------------------------------------------- */
1920 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
1921 /* -------------------------------------------------------------------- */
1923 /* Note that it's legal for any or all of the three sections of a
1924 'for' specification to be empty. This 'for' implementation
1925 often wastes 3 bytes with a redundant branch rather than keep
1926 expression parse trees for long periods (as previous versions
1927 of Inform did, somewhat crudely by simply storing the textual
1928 form of a 'for' loop). It is adequate for now. */
1931 match_open_bracket();
1934 /* Initialisation code */
1936 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1938 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
1939 { sequence_point_follows = TRUE;
1940 statement_debug_location = get_token_location();
1941 code_generate(parse_expression(FORINIT_CONTEXT),
1945 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
1947 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
1948 { assemble_label_no(ln = next_label++);
1950 parse_code_block(ln2, ln, 0);
1951 sequence_point_follows = FALSE;
1952 if (!execution_never_reaches_here)
1954 assemble_label_no(ln2);
1957 AO.type = OMITTED_OT;
1961 if (!match_colon()) break;
1965 AO.type = OMITTED_OT;
1966 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1968 spare_debug_location1 = get_token_location();
1969 AO = parse_expression(CONDITION_CONTEXT);
1970 if (!match_colon()) break;
1975 AO2.type = OMITTED_OT; flag = 0;
1976 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1978 spare_debug_location2 = get_token_location();
1979 AO2 = parse_expression(VOID_CONTEXT);
1980 match_close_bracket();
1981 flag = test_for_incdec(AO2);
1988 if ((AO2.type == OMITTED_OT) || (flag != 0))
1990 assemble_label_no(ln);
1991 if (flag==0) assemble_label_no(ln2);
1993 /* The "finished yet?" condition */
1995 if (AO.type != OMITTED_OT)
1996 { sequence_point_follows = TRUE;
1997 statement_debug_location = spare_debug_location1;
1998 code_generate(AO, CONDITION_CONTEXT, ln3);
2004 /* This is the jump which could be avoided with the aid
2005 of long-term expression storage */
2007 sequence_point_follows = FALSE;
2008 assembleg_jump(ln2);
2010 /* The "update" part */
2012 assemble_label_no(ln);
2013 sequence_point_follows = TRUE;
2014 statement_debug_location = spare_debug_location2;
2015 code_generate(AO2, VOID_CONTEXT, -1);
2017 assemble_label_no(ln2);
2019 /* The "finished yet?" condition */
2021 if (AO.type != OMITTED_OT)
2022 { sequence_point_follows = TRUE;
2023 statement_debug_location = spare_debug_location1;
2024 code_generate(AO, CONDITION_CONTEXT, ln3);
2030 /* In this optimised case, update code is at the end
2031 of the loop block, so "continue" goes there */
2033 parse_code_block(ln3, ln2, 0);
2034 assemble_label_no(ln2);
2036 sequence_point_follows = TRUE;
2037 statement_debug_location = spare_debug_location2;
2041 if (AO3.value >= MAX_LOCAL_VARIABLES)
2042 AO3.type = GLOBALVAR_OT;
2044 AO3.type = LOCALVAR_OT;
2045 assembleg_3(add_gc, AO3, one_operand, AO3);
2050 if (AO3.value >= MAX_LOCAL_VARIABLES)
2051 AO3.type = GLOBALVAR_OT;
2053 AO3.type = LOCALVAR_OT;
2054 assembleg_3(sub_gc, AO3, one_operand, AO3);
2060 /* In the unoptimised case, update code is at the
2061 start of the loop block, so "continue" goes there */
2063 parse_code_block(ln3, ln, 0);
2064 if (!execution_never_reaches_here)
2065 { sequence_point_follows = FALSE;
2070 assemble_label_no(ln3);
2073 /* -------------------------------------------------------------------- */
2074 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2075 /* -------------------------------------------------------------------- */
2078 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2079 QUANTITY_CONTEXT, -1);
2080 if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
2087 if ((token_type == SEP_TT)
2088 && (token_value == SEMICOLON_SEP)) {
2090 assembleg_2(copy_gc, stack_pointer, zero_operand);
2094 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
2097 { if ((token_type == SYMBOL_TT)
2098 && (stypes[token_value] != ATTRIBUTE_T))
2099 warning_named("This is not a declared Attribute:",
2104 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2105 QUANTITY_CONTEXT, -1);
2106 if (runtime_error_checking_switch && (!veneer_mode))
2107 { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
2108 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
2109 /* already on stack */
2112 assembleg_store(stack_pointer, AO2);
2115 assembleg_2(stkpeek_gc, one_operand, stack_pointer);
2117 assembleg_store(stack_pointer, AO);
2118 assembleg_3(call_gc, veneer_routine(ln2), two_operand,
2122 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2124 set_constant_ot(&AO2);
2127 INITAOTV(&AO3, BYTECONSTANT_OT, 8);
2128 assembleg_3(add_gc, AO2, AO3, stack_pointer);
2129 AO2 = stack_pointer;
2132 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
2133 assembleg_2(stkpeek_gc, one_operand,
2136 assembleg_2(stkpeek_gc, zero_operand,
2143 assembleg_3(astorebit_gc, AO, AO2, AO3);
2147 /* -------------------------------------------------------------------- */
2148 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2149 /* -------------------------------------------------------------------- */
2155 match_open_bracket();
2156 AO = parse_expression(CONDITION_CONTEXT);
2157 match_close_bracket();
2159 statements.enabled = TRUE;
2161 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
2164 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
2171 code_generate(AO, CONDITION_CONTEXT, ln);
2173 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
2176 if ((token_type != SEP_TT)
2177 || (token_value != SEMICOLON_SEP))
2178 { ebf_error("';'", token_text);
2183 statements.enabled = TRUE;
2186 /* An #if directive around the ELSE clause is legal. */
2187 while ((token_type == SEP_TT) && (token_value == HASH_SEP))
2188 { parse_directive(TRUE);
2189 statements.enabled = TRUE;
2193 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
2196 { ln2 = next_label++;
2197 if (!execution_never_reaches_here)
2198 { sequence_point_follows = FALSE;
2199 assembleg_jump(ln2);
2203 else put_token_back();
2205 if (ln >= 0) assemble_label_no(ln);
2208 { parse_code_block(break_label, continue_label, 0);
2209 if (ln >= 0) assemble_label_no(ln2);
2214 /* -------------------------------------------------------------------- */
2215 /* inversion ---------------------------------------------------------- */
2216 /* -------------------------------------------------------------------- */
2218 case INVERSION_CODE:
2219 INITAOTV(&AO2, DEREFERENCE_OT, GLULX_HEADER_SIZE+8);
2220 assembleg_2(copyb_gc, AO2, stack_pointer);
2221 assembleg_1(streamchar_gc, stack_pointer);
2222 AO2.value = GLULX_HEADER_SIZE+9;
2223 assembleg_2(copyb_gc, AO2, stack_pointer);
2224 assembleg_1(streamchar_gc, stack_pointer);
2225 AO2.value = GLULX_HEADER_SIZE+10;
2226 assembleg_2(copyb_gc, AO2, stack_pointer);
2227 assembleg_1(streamchar_gc, stack_pointer);
2228 AO2.value = GLULX_HEADER_SIZE+11;
2229 assembleg_2(copyb_gc, AO2, stack_pointer);
2230 assembleg_1(streamchar_gc, stack_pointer);
2232 if (/* DISABLES CODE */ (0)) {
2235 set_constant_ot(&AO);
2236 assembleg_1(streamchar_gc, AO);
2238 set_constant_ot(&AO);
2239 assembleg_1(streamchar_gc, AO);
2241 AO2.value = GLULX_HEADER_SIZE+12;
2242 assembleg_2(copyb_gc, AO2, stack_pointer);
2243 assembleg_1(streamchar_gc, stack_pointer);
2244 AO2.value = GLULX_HEADER_SIZE+13;
2245 assembleg_2(copyb_gc, AO2, stack_pointer);
2246 assembleg_1(streamchar_gc, stack_pointer);
2247 AO2.value = GLULX_HEADER_SIZE+14;
2248 assembleg_2(copyb_gc, AO2, stack_pointer);
2249 assembleg_1(streamchar_gc, stack_pointer);
2250 AO2.value = GLULX_HEADER_SIZE+15;
2251 assembleg_2(copyb_gc, AO2, stack_pointer);
2252 assembleg_1(streamchar_gc, stack_pointer);
2256 set_constant_ot(&AO);
2257 assembleg_1(streamchar_gc, AO);
2262 /* -------------------------------------------------------------------- */
2263 /* jump <label> ------------------------------------------------------- */
2264 /* -------------------------------------------------------------------- */
2267 assembleg_jump(parse_label());
2270 /* -------------------------------------------------------------------- */
2271 /* move <expression> to <expression> ---------------------------------- */
2272 /* -------------------------------------------------------------------- */
2275 misc_keywords.enabled = TRUE;
2276 AO = parse_expression(QUANTITY_CONTEXT);
2279 misc_keywords.enabled = FALSE;
2280 if ((token_type != MISC_KEYWORD_TT)
2281 || (token_value != TO_MK))
2282 { ebf_error("'to'", token_text);
2283 panic_mode_error_recovery();
2287 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2288 QUANTITY_CONTEXT, -1);
2289 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
2290 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2291 assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
2294 assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
2298 /* -------------------------------------------------------------------- */
2299 /* new_line ----------------------------------------------------------- */
2300 /* -------------------------------------------------------------------- */
2303 INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
2304 assembleg_1(streamchar_gc, AO);
2307 /* -------------------------------------------------------------------- */
2308 /* objectloop (<initialisation>) <codeblock> -------------------------- */
2309 /* -------------------------------------------------------------------- */
2311 case OBJECTLOOP_CODE:
2313 match_open_bracket();
2315 if (token_type == LOCAL_VARIABLE_TT) {
2316 INITAOTV(&AO, LOCALVAR_OT, token_value);
2318 else if ((token_type == SYMBOL_TT) &&
2319 (stypes[token_value] == GLOBAL_VARIABLE_T)) {
2320 INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]);
2323 ebf_error("'objectloop' variable", token_text);
2324 panic_mode_error_recovery();
2327 misc_keywords.enabled = TRUE;
2328 get_next_token(); flag = TRUE;
2329 misc_keywords.enabled = FALSE;
2330 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2334 if ((token_type == MISC_KEYWORD_TT)
2335 && (token_value == NEAR_MK)) ln = 1;
2336 if ((token_type == MISC_KEYWORD_TT)
2337 && (token_value == FROM_MK)) ln = 2;
2338 if ((token_type == CND_TT) && (token_value == IN_COND))
2341 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2348 /* Old style (Inform 5) objectloops: note that we
2349 implement objectloop (a in b) in the old way since
2350 this runs through objects in a different order from
2351 the new way, and there may be existing Inform code
2353 assembly_operand AO4, AO5;
2356 sequence_point_follows = TRUE;
2357 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2358 QUANTITY_CONTEXT, -1);
2359 match_close_bracket();
2361 if (runtime_error_checking_switch)
2362 AO2 = check_nonzero_at_runtime(AO2, -1,
2364 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2365 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2366 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2367 assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
2368 AO2 = stack_pointer;
2371 if (runtime_error_checking_switch) {
2373 AO2 = check_nonzero_at_runtime(AO2, -1,
2376 INITAOTV(&AO4, BYTECONSTANT_OT, 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;
2397 en_ao.value = OBJECTLOOP_BROKEN_RTE;
2398 set_constant_ot(&en_ao);
2399 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2400 assembleg_3(aload_gc, AO, AO4, stack_pointer);
2401 assembleg_2_branch(jeq_gc, stack_pointer, AO5,
2403 assembleg_call_2(veneer_routine(RT__Err_VR),
2404 en_ao, AO, zero_operand);
2405 assembleg_jump(ln2);
2406 assemble_label_no(next_label++);
2412 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2413 assembleg_3(aload_gc, AO2, AO4, AO);
2414 assembleg_1_branch(jnz_gc, AO, ln4);
2415 assemble_label_no(ln2);
2419 sequence_point_follows = TRUE;
2420 ln = symbol_index("Class", -1);
2421 INITAOT(&AO2, CONSTANT_OT);
2422 AO2.value = svals[ln];
2423 AO2.marker = OBJECT_MV;
2424 assembleg_store(AO, AO2);
2426 assemble_label_no(ln = next_label++);
2432 sequence_point_follows = TRUE;
2433 code_generate(parse_expression(CONDITION_CONTEXT),
2434 CONDITION_CONTEXT, ln3);
2435 match_close_bracket();
2437 parse_code_block(ln2, ln3, 0);
2439 sequence_point_follows = FALSE;
2440 assemble_label_no(ln3);
2441 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHAIN());
2442 assembleg_3(aload_gc, AO, AO4, AO);
2443 assembleg_1_branch(jnz_gc, AO, ln);
2444 assemble_label_no(ln2);
2447 /* -------------------------------------------------------------------- */
2448 /* (see routine above) ------------------------------------------------ */
2449 /* -------------------------------------------------------------------- */
2453 parse_print_g(FALSE); return;
2454 case PRINT_RET_CODE:
2456 parse_print_g(TRUE); return;
2458 /* -------------------------------------------------------------------- */
2459 /* quit --------------------------------------------------------------- */
2460 /* -------------------------------------------------------------------- */
2463 assembleg_0(quit_gc); break;
2465 /* -------------------------------------------------------------------- */
2466 /* remove <expression> ------------------------------------------------ */
2467 /* -------------------------------------------------------------------- */
2470 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2471 QUANTITY_CONTEXT, -1);
2472 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2473 assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
2476 assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
2480 /* -------------------------------------------------------------------- */
2481 /* return [<expression>] ---------------------------------------------- */
2482 /* -------------------------------------------------------------------- */
2486 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
2487 assembleg_1(return_gc, one_operand);
2491 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
2492 QUANTITY_CONTEXT, -1);
2493 assembleg_1(return_gc, AO);
2496 /* -------------------------------------------------------------------- */
2497 /* rfalse ------------------------------------------------------------- */
2498 /* -------------------------------------------------------------------- */
2501 assembleg_1(return_gc, zero_operand);
2504 /* -------------------------------------------------------------------- */
2505 /* rtrue -------------------------------------------------------------- */
2506 /* -------------------------------------------------------------------- */
2509 assembleg_1(return_gc, one_operand);
2512 /* -------------------------------------------------------------------- */
2513 /* spaces <expression> ------------------------------------------------ */
2514 /* -------------------------------------------------------------------- */
2517 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2518 QUANTITY_CONTEXT, -1);
2520 assembleg_store(temp_var1, AO);
2523 AO.value = 32; set_constant_ot(&AO);
2525 assembleg_2_branch(jlt_gc, temp_var1, one_operand,
2527 assemble_label_no(ln2 = next_label++);
2528 assembleg_1(streamchar_gc, AO);
2529 assembleg_dec(temp_var1);
2530 assembleg_1_branch(jnz_gc, temp_var1, ln2);
2531 assemble_label_no(ln);
2534 /* -------------------------------------------------------------------- */
2535 /* string <expression> <literal-string> ------------------------------- */
2536 /* -------------------------------------------------------------------- */
2539 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2540 QUANTITY_CONTEXT, -1);
2541 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2542 if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) {
2543 memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
2547 if (token_type == DQ_TT)
2548 { INITAOT(&AO4, CONSTANT_OT);
2549 AO4.value = compile_string(token_text, TRUE, TRUE);
2550 AO4.marker = STRING_MV;
2554 AO4 = parse_expression(CONSTANT_CONTEXT);
2556 assembleg_call_2(veneer_routine(Dynam__String_VR),
2557 AO2, AO4, zero_operand);
2560 /* -------------------------------------------------------------------- */
2561 /* style roman/reverse/bold/underline/fixed --------------------------- */
2562 /* -------------------------------------------------------------------- */
2565 misc_keywords.enabled = TRUE;
2567 misc_keywords.enabled = FALSE;
2568 if ((token_type != MISC_KEYWORD_TT)
2569 || ((token_value != ROMAN_MK)
2570 && (token_value != REVERSE_MK)
2571 && (token_value != BOLD_MK)
2572 && (token_value != UNDERLINE_MK)
2573 && (token_value != FIXED_MK)))
2575 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2577 panic_mode_error_recovery();
2581 /* Call glk_set_style() */
2585 set_constant_ot(&AO);
2589 AO2 = zero_operand; /* normal */
2593 AO2.value = 5; /* alert */
2594 set_constant_ot(&AO2);
2598 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 /* ========================================================================= */