1 /* ------------------------------------------------------------------------- */
2 /* "states" : Statement translator */
4 /* Part of Inform 6.35 */
5 /* copyright (c) Graham Nelson 1993 - 2020 */
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;
1194 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
1197 { ln2 = next_label++;
1198 if (!execution_never_reaches_here)
1199 { sequence_point_follows = FALSE;
1200 assemblez_jump(ln2);
1204 else put_token_back();
1206 if (ln >= 0) assemble_label_no(ln);
1209 { parse_code_block(break_label, continue_label, 0);
1210 if (ln >= 0) assemble_label_no(ln2);
1215 /* -------------------------------------------------------------------- */
1216 /* inversion ---------------------------------------------------------- */
1217 /* -------------------------------------------------------------------- */
1219 case INVERSION_CODE:
1220 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1221 INITAOT(&AO2, SHORT_CONSTANT_OT);
1224 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1225 assemblez_1(print_char_zc, temp_var1);
1227 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1228 assemblez_1(print_char_zc, temp_var1);
1230 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1231 assemblez_1(print_char_zc, temp_var1);
1233 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1234 assemblez_1(print_char_zc, temp_var1);
1237 /* -------------------------------------------------------------------- */
1238 /* jump <label> ------------------------------------------------------- */
1239 /* -------------------------------------------------------------------- */
1242 assemblez_jump(parse_label());
1245 /* -------------------------------------------------------------------- */
1246 /* move <expression> to <expression> ---------------------------------- */
1247 /* -------------------------------------------------------------------- */
1250 misc_keywords.enabled = TRUE;
1251 AO = parse_expression(QUANTITY_CONTEXT);
1254 misc_keywords.enabled = FALSE;
1255 if ((token_type != MISC_KEYWORD_TT)
1256 || (token_value != TO_MK))
1257 { ebf_error("'to'", token_text);
1258 panic_mode_error_recovery();
1262 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1263 QUANTITY_CONTEXT, -1);
1264 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
1265 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1266 { if (version_number >= 5)
1267 assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
1270 { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
1271 AO, AO2, temp_var1);
1275 assemblez_2(insert_obj_zc, AO, AO2);
1278 /* -------------------------------------------------------------------- */
1279 /* new_line ----------------------------------------------------------- */
1280 /* -------------------------------------------------------------------- */
1282 case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
1284 /* -------------------------------------------------------------------- */
1285 /* objectloop (<initialisation>) <codeblock> -------------------------- */
1286 /* -------------------------------------------------------------------- */
1288 case OBJECTLOOP_CODE:
1290 match_open_bracket();
1292 INITAOT(&AO, VARIABLE_OT);
1293 if (token_type == LOCAL_VARIABLE_TT)
1294 AO.value = token_value;
1296 if ((token_type == SYMBOL_TT) &&
1297 (stypes[token_value] == GLOBAL_VARIABLE_T))
1298 AO.value = svals[token_value];
1300 { ebf_error("'objectloop' variable", token_text);
1301 panic_mode_error_recovery(); break;
1303 if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
1304 && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
1305 AO.marker = VARIABLE_MV;
1306 misc_keywords.enabled = TRUE;
1307 get_next_token(); flag = TRUE;
1308 misc_keywords.enabled = FALSE;
1309 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1313 if ((token_type == MISC_KEYWORD_TT)
1314 && (token_value == NEAR_MK)) ln = 1;
1315 if ((token_type == MISC_KEYWORD_TT)
1316 && (token_value == FROM_MK)) ln = 2;
1317 if ((token_type == CND_TT) && (token_value == IN_COND))
1320 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1327 { /* Old style (Inform 5) objectloops: note that we
1328 implement objectloop (a in b) in the old way since
1329 this runs through objects in a different order from
1330 the new way, and there may be existing Inform code
1332 assembly_operand AO4;
1335 sequence_point_follows = TRUE;
1336 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1337 QUANTITY_CONTEXT, -1);
1338 match_close_bracket();
1340 { INITAOTV(&AO3, VARIABLE_OT, 0);
1341 if (runtime_error_checking_switch)
1342 AO2 = check_nonzero_at_runtime(AO2, -1,
1344 assemblez_1_to(get_parent_zc, AO2, AO3);
1345 assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
1349 { INITAOTV(&AO3, VARIABLE_OT, 0);
1350 if (runtime_error_checking_switch)
1352 AO2 = check_nonzero_at_runtime(AO2, -1,
1355 assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
1358 assemblez_store(AO, AO2);
1359 assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
1360 assemble_label_no(ln4 = next_label++);
1361 parse_code_block(ln2, ln3 = next_label++, 0);
1362 sequence_point_follows = FALSE;
1363 assemble_label_no(ln3);
1364 if (runtime_error_checking_switch)
1365 { AO2 = check_nonzero_at_runtime(AO, ln2,
1368 && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
1369 && ((AO4.type != VARIABLE_OT)
1370 ||(AO4.value != AO.value)))
1371 { assembly_operand en_ao;
1372 INITAOTV(&en_ao, SHORT_CONSTANT_OT, OBJECTLOOP_BROKEN_RTE);
1373 assemblez_2_branch(jin_zc, AO, AO4,
1375 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
1377 assemblez_jump(ln2);
1378 assemble_label_no(next_label++);
1382 assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
1383 assemble_label_no(ln2);
1387 sequence_point_follows = TRUE;
1388 INITAOTV(&AO2, SHORT_CONSTANT_OT, 1);
1389 assemblez_store(AO, AO2);
1391 assemble_label_no(ln = next_label++);
1397 sequence_point_follows = TRUE;
1398 code_generate(parse_expression(CONDITION_CONTEXT),
1399 CONDITION_CONTEXT, ln3);
1400 match_close_bracket();
1402 parse_code_block(ln2, ln3, 0);
1404 sequence_point_follows = FALSE;
1405 assemble_label_no(ln3);
1407 INITAOTV(&AO2, LONG_CONSTANT_OT, no_objects);
1408 AO2.marker = NO_OBJS_MV;
1409 assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
1411 assemble_label_no(ln2);
1414 /* -------------------------------------------------------------------- */
1415 /* (see routine above) ------------------------------------------------ */
1416 /* -------------------------------------------------------------------- */
1420 parse_print_z(FALSE); return;
1421 case PRINT_RET_CODE:
1423 parse_print_z(TRUE); return;
1425 /* -------------------------------------------------------------------- */
1426 /* quit --------------------------------------------------------------- */
1427 /* -------------------------------------------------------------------- */
1429 case QUIT_CODE: assemblez_0(quit_zc); break;
1431 /* -------------------------------------------------------------------- */
1432 /* read <expression> <expression> [<Routine>] ------------------------- */
1433 /* -------------------------------------------------------------------- */
1436 INITAOTV(&AO, VARIABLE_OT, 252);
1438 code_generate(parse_expression(QUANTITY_CONTEXT),
1439 QUANTITY_CONTEXT, -1));
1440 if (version_number > 3)
1441 { INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1442 INITAOTV(&AO4, SHORT_CONSTANT_OT, 0);
1443 assemblez_3(storeb_zc, AO, AO3, AO4);
1445 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1446 QUANTITY_CONTEXT, -1);
1449 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1452 { if (version_number == 3)
1454 "In Version 3 no status-line drawing routine can be given");
1456 { assembly_operand AO5;
1457 /* Move the temp4 (buffer) value to the stack,
1458 since the routine might alter temp4. */
1459 assemblez_store(stack_pointer, AO);
1462 AO5 = parse_expression(CONSTANT_CONTEXT);
1464 if (version_number >= 5)
1465 assemblez_1(call_1n_zc, AO5);
1467 assemblez_1_to(call_zc, AO5, temp_var1);
1471 if (version_number > 4)
1472 { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
1474 else assemblez_2(sread_zc, AO, AO2);
1477 /* -------------------------------------------------------------------- */
1478 /* remove <expression> ------------------------------------------------ */
1479 /* -------------------------------------------------------------------- */
1482 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1483 QUANTITY_CONTEXT, -1);
1484 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1485 { if (version_number >= 5)
1486 assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
1489 { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
1494 assemblez_1(remove_obj_zc, AO);
1497 /* -------------------------------------------------------------------- */
1498 /* restore <label> ---------------------------------------------------- */
1499 /* -------------------------------------------------------------------- */
1502 if (version_number < 5)
1503 assemblez_0_branch(restore_zc, parse_label(), TRUE);
1505 { INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
1506 assemblez_0_to(restore_zc, temp_var1);
1507 assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
1511 /* -------------------------------------------------------------------- */
1512 /* return [<expression>] ---------------------------------------------- */
1513 /* -------------------------------------------------------------------- */
1517 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1518 { assemblez_0(rtrue_zc); return; }
1520 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
1521 QUANTITY_CONTEXT, -1);
1522 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
1523 && (AO.marker == 0))
1524 { assemblez_0(rfalse_zc); break; }
1525 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
1526 && (AO.marker == 0))
1527 { assemblez_0(rtrue_zc); break; }
1528 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1529 { assemblez_0(ret_popped_zc); break; }
1530 assemblez_1(ret_zc, AO);
1533 /* -------------------------------------------------------------------- */
1534 /* rfalse ------------------------------------------------------------- */
1535 /* -------------------------------------------------------------------- */
1537 case RFALSE_CODE: assemblez_0(rfalse_zc); break;
1539 /* -------------------------------------------------------------------- */
1540 /* rtrue -------------------------------------------------------------- */
1541 /* -------------------------------------------------------------------- */
1543 case RTRUE_CODE: assemblez_0(rtrue_zc); break;
1545 /* -------------------------------------------------------------------- */
1546 /* save <label> ------------------------------------------------------- */
1547 /* -------------------------------------------------------------------- */
1550 if (version_number < 5)
1551 assemblez_0_branch(save_zc, parse_label(), TRUE);
1553 { INITAOTV(&AO, VARIABLE_OT, 255);
1554 assemblez_0_to(save_zc, AO);
1555 assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
1559 /* -------------------------------------------------------------------- */
1560 /* spaces <expression> ------------------------------------------------ */
1561 /* -------------------------------------------------------------------- */
1564 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1565 QUANTITY_CONTEXT, -1);
1566 INITAOTV(&AO2, VARIABLE_OT, 255);
1568 assemblez_store(AO2, AO);
1570 INITAOTV(&AO, SHORT_CONSTANT_OT, 32);
1571 INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1573 assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
1574 assemble_label_no(ln2 = next_label++);
1575 assemblez_1(print_char_zc, AO);
1577 assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
1578 assemble_label_no(ln);
1581 /* -------------------------------------------------------------------- */
1582 /* string <expression> <literal-string> ------------------------------- */
1583 /* -------------------------------------------------------------------- */
1586 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1587 INITAOTV(&AO2, SHORT_CONSTANT_OT, 12);
1588 INITAOTV(&AO3, VARIABLE_OT, 252);
1589 assemblez_2_to(loadw_zc, AO, AO2, AO3);
1590 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1591 QUANTITY_CONTEXT, -1);
1593 if (token_type == DQ_TT)
1594 { INITAOT(&AO4, LONG_CONSTANT_OT);
1595 AO4.value = compile_string(token_text, TRUE, TRUE);
1599 AO4 = parse_expression(CONSTANT_CONTEXT);
1601 assemblez_3(storew_zc, AO3, AO2, AO4);
1604 /* -------------------------------------------------------------------- */
1605 /* style roman/reverse/bold/underline/fixed --------------------------- */
1606 /* -------------------------------------------------------------------- */
1609 if (version_number==3)
1611 "The 'style' statement cannot be used for Version 3 games");
1612 panic_mode_error_recovery();
1616 misc_keywords.enabled = TRUE;
1618 misc_keywords.enabled = FALSE;
1619 if ((token_type != MISC_KEYWORD_TT)
1620 || ((token_value != ROMAN_MK)
1621 && (token_value != REVERSE_MK)
1622 && (token_value != BOLD_MK)
1623 && (token_value != UNDERLINE_MK)
1624 && (token_value != FIXED_MK)))
1626 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1628 panic_mode_error_recovery();
1632 INITAOT(&AO, SHORT_CONSTANT_OT);
1634 { case ROMAN_MK: AO.value = 0; break;
1635 case REVERSE_MK: AO.value = 1; break;
1636 case BOLD_MK: AO.value = 2; break;
1637 case UNDERLINE_MK: AO.value = 4; break;
1638 case FIXED_MK: AO.value = 8; break;
1640 assemblez_1(set_text_style_zc, AO); break;
1642 /* -------------------------------------------------------------------- */
1643 /* switch (<expression>) <codeblock> ---------------------------------- */
1644 /* -------------------------------------------------------------------- */
1647 match_open_bracket();
1648 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1649 QUANTITY_CONTEXT, -1);
1650 match_close_bracket();
1652 INITAOTV(&AO2, VARIABLE_OT, 255);
1653 assemblez_store(AO2, AO);
1655 parse_code_block(ln = next_label++, continue_label, 1);
1656 assemble_label_no(ln);
1659 /* -------------------------------------------------------------------- */
1660 /* while (<condition>) <codeblock> ------------------------------------ */
1661 /* -------------------------------------------------------------------- */
1664 assemble_label_no(ln = next_label++);
1665 match_open_bracket();
1667 code_generate(parse_expression(CONDITION_CONTEXT),
1668 CONDITION_CONTEXT, ln2 = next_label++);
1669 match_close_bracket();
1671 parse_code_block(ln2, ln, 0);
1672 sequence_point_follows = FALSE;
1674 assemble_label_no(ln2);
1677 /* -------------------------------------------------------------------- */
1680 error("'default' without matching 'switch'"); break;
1682 error("'else' without matching 'if'"); break;
1684 error("'until' without matching 'do'");
1685 panic_mode_error_recovery(); return;
1688 StatementTerminator:
1691 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1692 { ebf_error("';'", token_text);
1697 static void parse_statement_g(int break_label, int continue_label)
1698 { int ln, ln2, ln3, ln4, flag, onstack;
1699 assembly_operand AO, AO2, AO3, AO4;
1700 debug_location spare_debug_location1, spare_debug_location2;
1704 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
1705 { /* That is, a full stop, signifying a label */
1708 if (token_type == SYMBOL_TT)
1710 if (sflags[token_value] & UNKNOWN_SFLAG)
1711 { assign_symbol(token_value, next_label, LABEL_T);
1712 sflags[token_value] |= USED_SFLAG;
1713 assemble_label_no(next_label);
1714 define_symbol_label(token_value);
1718 { if (stypes[token_value] != LABEL_T) goto LabelError;
1719 if (sflags[token_value] & CHANGE_SFLAG)
1720 { sflags[token_value] &= (~(CHANGE_SFLAG));
1721 assemble_label_no(svals[token_value]);
1722 define_symbol_label(token_value);
1724 else error_named("Duplicate definition of label:", token_text);
1728 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1729 { ebf_error("';'", token_text);
1730 put_token_back(); return;
1733 /* Interesting point of Inform grammar: a statement can only
1734 consist solely of a label when it is immediately followed
1738 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
1739 { put_token_back(); return;
1741 /* The following line prevents labels from influencing the positions
1742 of sequence points. */
1743 statement_debug_location = get_token_location();
1744 parse_statement(break_label, continue_label);
1747 LabelError: ebf_error("label name", token_text);
1750 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
1751 { parse_directive(TRUE);
1752 parse_statement(break_label, continue_label); return;
1755 if ((token_type == SEP_TT) && (token_value == AT_SEP))
1756 { parse_assembly(); return;
1759 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
1761 if (token_type == DQ_TT)
1762 { parse_print_g(TRUE); return;
1765 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
1766 { parse_action(); goto StatementTerminator; }
1768 if (token_type == EOF_TT)
1769 { ebf_error("statement", token_text); return; }
1771 if (token_type != STATEMENT_TT)
1773 AO = parse_expression(VOID_CONTEXT);
1774 code_generate(AO, VOID_CONTEXT, -1);
1775 if (vivc_flag) { panic_mode_error_recovery(); return; }
1776 goto StatementTerminator;
1779 statements.enabled = FALSE;
1784 /* -------------------------------------------------------------------- */
1785 /* box <string-1> ... <string-n> -------------------------------------- */
1786 /* -------------------------------------------------------------------- */
1789 INITAOT(&AO3, CONSTANT_OT);
1790 AO3.value = begin_table_array();
1791 AO3.marker = ARRAY_MV;
1795 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
1797 if (token_type != DQ_TT)
1798 ebf_error("text of box line in double-quotes",
1801 for (i=0, j=0; token_text[i] != 0; j++)
1802 if (token_text[i] == '@')
1803 { if (token_text[i+1] == '@')
1805 while (isdigit(token_text[i])) i++;
1809 if (token_text[i] != 0) i++;
1810 if (token_text[i] != 0) i++;
1814 if (j > ln2) ln2 = j;
1817 array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
1819 finish_array(ln, FALSE);
1821 error("No lines of text given for 'box' display");
1824 AO2.value = ln2; set_constant_ot(&AO2);
1825 assembleg_call_2(veneer_routine(Box__Routine_VR),
1826 AO2, AO3, zero_operand);
1829 /* -------------------------------------------------------------------- */
1830 /* break -------------------------------------------------------------- */
1831 /* -------------------------------------------------------------------- */
1834 if (break_label == -1)
1835 error("'break' can only be used in a loop or 'switch' block");
1837 assembleg_jump(break_label);
1840 /* -------------------------------------------------------------------- */
1841 /* continue ----------------------------------------------------------- */
1842 /* -------------------------------------------------------------------- */
1845 if (continue_label == -1)
1846 error("'continue' can only be used in a loop block");
1848 assembleg_jump(continue_label);
1851 /* -------------------------------------------------------------------- */
1852 /* do <codeblock> until (<condition>) --------------------------------- */
1853 /* -------------------------------------------------------------------- */
1856 assemble_label_no(ln = next_label++);
1857 ln2 = next_label++; ln3 = next_label++;
1858 parse_code_block(ln3, ln2, 0);
1859 statements.enabled = TRUE;
1861 if ((token_type == STATEMENT_TT)
1862 && (token_value == UNTIL_CODE))
1863 { assemble_label_no(ln2);
1864 match_open_bracket();
1865 AO = parse_expression(CONDITION_CONTEXT);
1866 match_close_bracket();
1867 code_generate(AO, CONDITION_CONTEXT, ln);
1869 else error("'do' without matching 'until'");
1871 assemble_label_no(ln3);
1874 /* -------------------------------------------------------------------- */
1875 /* font on/off -------------------------------------------------------- */
1876 /* -------------------------------------------------------------------- */
1879 misc_keywords.enabled = TRUE;
1881 misc_keywords.enabled = FALSE;
1882 if ((token_type != MISC_KEYWORD_TT)
1883 || ((token_value != ON_MK)
1884 && (token_value != OFF_MK)))
1885 { ebf_error("'on' or 'off'", token_text);
1886 panic_mode_error_recovery();
1890 /* Call glk_set_style(normal or preformatted) */
1893 set_constant_ot(&AO);
1894 if (token_value == ON_MK)
1898 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
1899 AO, AO2, zero_operand);
1902 /* -------------------------------------------------------------------- */
1903 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
1904 /* -------------------------------------------------------------------- */
1906 /* Note that it's legal for any or all of the three sections of a
1907 'for' specification to be empty. This 'for' implementation
1908 often wastes 3 bytes with a redundant branch rather than keep
1909 expression parse trees for long periods (as previous versions
1910 of Inform did, somewhat crudely by simply storing the textual
1911 form of a 'for' loop). It is adequate for now. */
1914 match_open_bracket();
1917 /* Initialisation code */
1919 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1921 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
1922 { sequence_point_follows = TRUE;
1923 statement_debug_location = get_token_location();
1924 code_generate(parse_expression(FORINIT_CONTEXT),
1928 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
1930 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
1931 { assemble_label_no(ln = next_label++);
1933 parse_code_block(ln2, ln, 0);
1934 sequence_point_follows = FALSE;
1935 if (!execution_never_reaches_here)
1937 assemble_label_no(ln2);
1940 AO.type = OMITTED_OT;
1944 if (!match_colon()) break;
1948 AO.type = OMITTED_OT;
1949 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1951 spare_debug_location1 = get_token_location();
1952 AO = parse_expression(CONDITION_CONTEXT);
1953 if (!match_colon()) break;
1958 AO2.type = OMITTED_OT; flag = 0;
1959 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1961 spare_debug_location2 = get_token_location();
1962 AO2 = parse_expression(VOID_CONTEXT);
1963 match_close_bracket();
1964 flag = test_for_incdec(AO2);
1971 if ((AO2.type == OMITTED_OT) || (flag != 0))
1973 assemble_label_no(ln);
1974 if (flag==0) assemble_label_no(ln2);
1976 /* The "finished yet?" condition */
1978 if (AO.type != OMITTED_OT)
1979 { sequence_point_follows = TRUE;
1980 statement_debug_location = spare_debug_location1;
1981 code_generate(AO, CONDITION_CONTEXT, ln3);
1987 /* This is the jump which could be avoided with the aid
1988 of long-term expression storage */
1990 sequence_point_follows = FALSE;
1991 assembleg_jump(ln2);
1993 /* The "update" part */
1995 assemble_label_no(ln);
1996 sequence_point_follows = TRUE;
1997 statement_debug_location = spare_debug_location2;
1998 code_generate(AO2, VOID_CONTEXT, -1);
2000 assemble_label_no(ln2);
2002 /* The "finished yet?" condition */
2004 if (AO.type != OMITTED_OT)
2005 { sequence_point_follows = TRUE;
2006 statement_debug_location = spare_debug_location1;
2007 code_generate(AO, CONDITION_CONTEXT, ln3);
2013 /* In this optimised case, update code is at the end
2014 of the loop block, so "continue" goes there */
2016 parse_code_block(ln3, ln2, 0);
2017 assemble_label_no(ln2);
2019 sequence_point_follows = TRUE;
2020 statement_debug_location = spare_debug_location2;
2024 if (AO3.value >= MAX_LOCAL_VARIABLES)
2025 AO3.type = GLOBALVAR_OT;
2027 AO3.type = LOCALVAR_OT;
2028 assembleg_3(add_gc, AO3, one_operand, AO3);
2033 if (AO3.value >= MAX_LOCAL_VARIABLES)
2034 AO3.type = GLOBALVAR_OT;
2036 AO3.type = LOCALVAR_OT;
2037 assembleg_3(sub_gc, AO3, one_operand, AO3);
2043 /* In the unoptimised case, update code is at the
2044 start of the loop block, so "continue" goes there */
2046 parse_code_block(ln3, ln, 0);
2047 if (!execution_never_reaches_here)
2048 { sequence_point_follows = FALSE;
2053 assemble_label_no(ln3);
2056 /* -------------------------------------------------------------------- */
2057 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2058 /* -------------------------------------------------------------------- */
2061 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2062 QUANTITY_CONTEXT, -1);
2063 if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
2070 if ((token_type == SEP_TT)
2071 && (token_value == SEMICOLON_SEP)) {
2073 assembleg_2(copy_gc, stack_pointer, zero_operand);
2077 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
2080 { if ((token_type == SYMBOL_TT)
2081 && (stypes[token_value] != ATTRIBUTE_T))
2082 warning_named("This is not a declared Attribute:",
2087 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2088 QUANTITY_CONTEXT, -1);
2089 if (runtime_error_checking_switch && (!veneer_mode))
2090 { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
2091 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
2092 /* already on stack */
2095 assembleg_store(stack_pointer, AO2);
2098 assembleg_2(stkpeek_gc, one_operand, stack_pointer);
2100 assembleg_store(stack_pointer, AO);
2101 assembleg_3(call_gc, veneer_routine(ln2), two_operand,
2105 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2107 set_constant_ot(&AO2);
2110 INITAOTV(&AO3, BYTECONSTANT_OT, 8);
2111 assembleg_3(add_gc, AO2, AO3, stack_pointer);
2112 AO2 = stack_pointer;
2115 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
2116 assembleg_2(stkpeek_gc, one_operand,
2119 assembleg_2(stkpeek_gc, zero_operand,
2126 assembleg_3(astorebit_gc, AO, AO2, AO3);
2130 /* -------------------------------------------------------------------- */
2131 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2132 /* -------------------------------------------------------------------- */
2138 match_open_bracket();
2139 AO = parse_expression(CONDITION_CONTEXT);
2140 match_close_bracket();
2142 statements.enabled = TRUE;
2144 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
2147 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
2154 code_generate(AO, CONDITION_CONTEXT, ln);
2156 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
2159 if ((token_type != SEP_TT)
2160 || (token_value != SEMICOLON_SEP))
2161 { ebf_error("';'", token_text);
2166 statements.enabled = TRUE;
2168 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
2171 { ln2 = next_label++;
2172 if (!execution_never_reaches_here)
2173 { sequence_point_follows = FALSE;
2174 assembleg_jump(ln2);
2178 else put_token_back();
2180 if (ln >= 0) assemble_label_no(ln);
2183 { parse_code_block(break_label, continue_label, 0);
2184 if (ln >= 0) assemble_label_no(ln2);
2189 /* -------------------------------------------------------------------- */
2190 /* inversion ---------------------------------------------------------- */
2191 /* -------------------------------------------------------------------- */
2193 case INVERSION_CODE:
2194 INITAOTV(&AO2, DEREFERENCE_OT, GLULX_HEADER_SIZE+8);
2195 assembleg_2(copyb_gc, AO2, stack_pointer);
2196 assembleg_1(streamchar_gc, stack_pointer);
2197 AO2.value = GLULX_HEADER_SIZE+9;
2198 assembleg_2(copyb_gc, AO2, stack_pointer);
2199 assembleg_1(streamchar_gc, stack_pointer);
2200 AO2.value = GLULX_HEADER_SIZE+10;
2201 assembleg_2(copyb_gc, AO2, stack_pointer);
2202 assembleg_1(streamchar_gc, stack_pointer);
2203 AO2.value = GLULX_HEADER_SIZE+11;
2204 assembleg_2(copyb_gc, AO2, stack_pointer);
2205 assembleg_1(streamchar_gc, stack_pointer);
2207 if (/* DISABLES CODE */ (0)) {
2210 set_constant_ot(&AO);
2211 assembleg_1(streamchar_gc, AO);
2213 set_constant_ot(&AO);
2214 assembleg_1(streamchar_gc, AO);
2216 AO2.value = GLULX_HEADER_SIZE+12;
2217 assembleg_2(copyb_gc, AO2, stack_pointer);
2218 assembleg_1(streamchar_gc, stack_pointer);
2219 AO2.value = GLULX_HEADER_SIZE+13;
2220 assembleg_2(copyb_gc, AO2, stack_pointer);
2221 assembleg_1(streamchar_gc, stack_pointer);
2222 AO2.value = GLULX_HEADER_SIZE+14;
2223 assembleg_2(copyb_gc, AO2, stack_pointer);
2224 assembleg_1(streamchar_gc, stack_pointer);
2225 AO2.value = GLULX_HEADER_SIZE+15;
2226 assembleg_2(copyb_gc, AO2, stack_pointer);
2227 assembleg_1(streamchar_gc, stack_pointer);
2231 set_constant_ot(&AO);
2232 assembleg_1(streamchar_gc, AO);
2237 /* -------------------------------------------------------------------- */
2238 /* jump <label> ------------------------------------------------------- */
2239 /* -------------------------------------------------------------------- */
2242 assembleg_jump(parse_label());
2245 /* -------------------------------------------------------------------- */
2246 /* move <expression> to <expression> ---------------------------------- */
2247 /* -------------------------------------------------------------------- */
2250 misc_keywords.enabled = TRUE;
2251 AO = parse_expression(QUANTITY_CONTEXT);
2254 misc_keywords.enabled = FALSE;
2255 if ((token_type != MISC_KEYWORD_TT)
2256 || (token_value != TO_MK))
2257 { ebf_error("'to'", token_text);
2258 panic_mode_error_recovery();
2262 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2263 QUANTITY_CONTEXT, -1);
2264 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
2265 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2266 assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
2269 assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
2273 /* -------------------------------------------------------------------- */
2274 /* new_line ----------------------------------------------------------- */
2275 /* -------------------------------------------------------------------- */
2278 INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
2279 assembleg_1(streamchar_gc, AO);
2282 /* -------------------------------------------------------------------- */
2283 /* objectloop (<initialisation>) <codeblock> -------------------------- */
2284 /* -------------------------------------------------------------------- */
2286 case OBJECTLOOP_CODE:
2288 match_open_bracket();
2290 if (token_type == LOCAL_VARIABLE_TT) {
2291 INITAOTV(&AO, LOCALVAR_OT, token_value);
2293 else if ((token_type == SYMBOL_TT) &&
2294 (stypes[token_value] == GLOBAL_VARIABLE_T)) {
2295 INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]);
2298 ebf_error("'objectloop' variable", token_text);
2299 panic_mode_error_recovery();
2302 misc_keywords.enabled = TRUE;
2303 get_next_token(); flag = TRUE;
2304 misc_keywords.enabled = FALSE;
2305 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2309 if ((token_type == MISC_KEYWORD_TT)
2310 && (token_value == NEAR_MK)) ln = 1;
2311 if ((token_type == MISC_KEYWORD_TT)
2312 && (token_value == FROM_MK)) ln = 2;
2313 if ((token_type == CND_TT) && (token_value == IN_COND))
2316 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2323 /* Old style (Inform 5) objectloops: note that we
2324 implement objectloop (a in b) in the old way since
2325 this runs through objects in a different order from
2326 the new way, and there may be existing Inform code
2328 assembly_operand AO4, AO5;
2331 sequence_point_follows = TRUE;
2332 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2333 QUANTITY_CONTEXT, -1);
2334 match_close_bracket();
2336 if (runtime_error_checking_switch)
2337 AO2 = check_nonzero_at_runtime(AO2, -1,
2339 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2340 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2341 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2342 assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
2343 AO2 = stack_pointer;
2346 if (runtime_error_checking_switch) {
2348 AO2 = check_nonzero_at_runtime(AO2, -1,
2351 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2352 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2353 AO2 = stack_pointer;
2358 assembleg_store(AO, AO2);
2359 assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
2360 assemble_label_no(ln4 = next_label++);
2361 parse_code_block(ln2, ln3 = next_label++, 0);
2362 sequence_point_follows = FALSE;
2363 assemble_label_no(ln3);
2364 if (runtime_error_checking_switch) {
2365 AO2 = check_nonzero_at_runtime(AO, ln2,
2368 && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
2369 && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
2370 { assembly_operand en_ao;
2372 en_ao.value = OBJECTLOOP_BROKEN_RTE;
2373 set_constant_ot(&en_ao);
2374 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2375 assembleg_3(aload_gc, AO, AO4, stack_pointer);
2376 assembleg_2_branch(jeq_gc, stack_pointer, AO5,
2378 assembleg_call_2(veneer_routine(RT__Err_VR),
2379 en_ao, AO, zero_operand);
2380 assembleg_jump(ln2);
2381 assemble_label_no(next_label++);
2387 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2388 assembleg_3(aload_gc, AO2, AO4, AO);
2389 assembleg_1_branch(jnz_gc, AO, ln4);
2390 assemble_label_no(ln2);
2394 sequence_point_follows = TRUE;
2395 ln = symbol_index("Class", -1);
2396 INITAOT(&AO2, CONSTANT_OT);
2397 AO2.value = svals[ln];
2398 AO2.marker = OBJECT_MV;
2399 assembleg_store(AO, AO2);
2401 assemble_label_no(ln = next_label++);
2407 sequence_point_follows = TRUE;
2408 code_generate(parse_expression(CONDITION_CONTEXT),
2409 CONDITION_CONTEXT, ln3);
2410 match_close_bracket();
2412 parse_code_block(ln2, ln3, 0);
2414 sequence_point_follows = FALSE;
2415 assemble_label_no(ln3);
2416 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHAIN());
2417 assembleg_3(aload_gc, AO, AO4, AO);
2418 assembleg_1_branch(jnz_gc, AO, ln);
2419 assemble_label_no(ln2);
2422 /* -------------------------------------------------------------------- */
2423 /* (see routine above) ------------------------------------------------ */
2424 /* -------------------------------------------------------------------- */
2428 parse_print_g(FALSE); return;
2429 case PRINT_RET_CODE:
2431 parse_print_g(TRUE); return;
2433 /* -------------------------------------------------------------------- */
2434 /* quit --------------------------------------------------------------- */
2435 /* -------------------------------------------------------------------- */
2438 assembleg_0(quit_gc); break;
2440 /* -------------------------------------------------------------------- */
2441 /* remove <expression> ------------------------------------------------ */
2442 /* -------------------------------------------------------------------- */
2445 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2446 QUANTITY_CONTEXT, -1);
2447 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2448 assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
2451 assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
2455 /* -------------------------------------------------------------------- */
2456 /* return [<expression>] ---------------------------------------------- */
2457 /* -------------------------------------------------------------------- */
2461 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
2462 assembleg_1(return_gc, one_operand);
2466 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
2467 QUANTITY_CONTEXT, -1);
2468 assembleg_1(return_gc, AO);
2471 /* -------------------------------------------------------------------- */
2472 /* rfalse ------------------------------------------------------------- */
2473 /* -------------------------------------------------------------------- */
2476 assembleg_1(return_gc, zero_operand);
2479 /* -------------------------------------------------------------------- */
2480 /* rtrue -------------------------------------------------------------- */
2481 /* -------------------------------------------------------------------- */
2484 assembleg_1(return_gc, one_operand);
2487 /* -------------------------------------------------------------------- */
2488 /* spaces <expression> ------------------------------------------------ */
2489 /* -------------------------------------------------------------------- */
2492 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2493 QUANTITY_CONTEXT, -1);
2495 assembleg_store(temp_var1, AO);
2498 AO.value = 32; set_constant_ot(&AO);
2500 assembleg_2_branch(jlt_gc, temp_var1, one_operand,
2502 assemble_label_no(ln2 = next_label++);
2503 assembleg_1(streamchar_gc, AO);
2504 assembleg_dec(temp_var1);
2505 assembleg_1_branch(jnz_gc, temp_var1, ln2);
2506 assemble_label_no(ln);
2509 /* -------------------------------------------------------------------- */
2510 /* string <expression> <literal-string> ------------------------------- */
2511 /* -------------------------------------------------------------------- */
2514 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2515 QUANTITY_CONTEXT, -1);
2517 if (token_type == DQ_TT)
2518 { INITAOT(&AO4, CONSTANT_OT);
2519 AO4.value = compile_string(token_text, TRUE, TRUE);
2520 AO4.marker = STRING_MV;
2524 AO4 = parse_expression(CONSTANT_CONTEXT);
2526 assembleg_call_2(veneer_routine(Dynam__String_VR),
2527 AO2, AO4, zero_operand);
2530 /* -------------------------------------------------------------------- */
2531 /* style roman/reverse/bold/underline/fixed --------------------------- */
2532 /* -------------------------------------------------------------------- */
2535 misc_keywords.enabled = TRUE;
2537 misc_keywords.enabled = FALSE;
2538 if ((token_type != MISC_KEYWORD_TT)
2539 || ((token_value != ROMAN_MK)
2540 && (token_value != REVERSE_MK)
2541 && (token_value != BOLD_MK)
2542 && (token_value != UNDERLINE_MK)
2543 && (token_value != FIXED_MK)))
2545 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2547 panic_mode_error_recovery();
2551 /* Call glk_set_style() */
2555 set_constant_ot(&AO);
2559 AO2 = zero_operand; /* normal */
2563 AO2.value = 5; /* alert */
2564 set_constant_ot(&AO2);
2568 AO2.value = 4; /* subheader */
2569 set_constant_ot(&AO2);
2572 AO2 = one_operand; /* emphasized */
2575 AO2 = two_operand; /* preformatted */
2578 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
2579 AO, AO2, zero_operand);
2582 /* -------------------------------------------------------------------- */
2583 /* switch (<expression>) <codeblock> ---------------------------------- */
2584 /* -------------------------------------------------------------------- */
2587 match_open_bracket();
2588 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2589 QUANTITY_CONTEXT, -1);
2590 match_close_bracket();
2592 assembleg_store(temp_var1, AO);
2594 parse_code_block(ln = next_label++, continue_label, 1);
2595 assemble_label_no(ln);
2598 /* -------------------------------------------------------------------- */
2599 /* while (<condition>) <codeblock> ------------------------------------ */
2600 /* -------------------------------------------------------------------- */
2603 assemble_label_no(ln = next_label++);
2604 match_open_bracket();
2606 code_generate(parse_expression(CONDITION_CONTEXT),
2607 CONDITION_CONTEXT, ln2 = next_label++);
2608 match_close_bracket();
2610 parse_code_block(ln2, ln, 0);
2611 sequence_point_follows = FALSE;
2613 assemble_label_no(ln2);
2616 /* -------------------------------------------------------------------- */
2619 error("'default' without matching 'switch'"); break;
2621 error("'else' without matching 'if'"); break;
2623 error("'until' without matching 'do'");
2624 panic_mode_error_recovery(); return;
2626 /* -------------------------------------------------------------------- */
2628 /* And a useful default, which will never be triggered in a complete
2629 Inform compiler, but which is important in development. */
2632 error("*** Statement code gen: Can't generate yet ***\n");
2633 panic_mode_error_recovery(); return;
2636 StatementTerminator:
2639 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
2640 { ebf_error("';'", token_text);
2645 extern void parse_statement(int break_label, int continue_label)
2648 parse_statement_z(break_label, continue_label);
2650 parse_statement_g(break_label, continue_label);
2653 /* ========================================================================= */
2654 /* Data structure management routines */
2655 /* ------------------------------------------------------------------------- */
2657 extern void init_states_vars(void)
2661 extern void states_begin_pass(void)
2665 extern void states_allocate_arrays(void)
2669 extern void states_free_arrays(void)
2673 /* ========================================================================= */