1 /* ------------------------------------------------------------------------- */
2 /* "states" : Statement translator */
4 /* Copyright (c) Graham Nelson 1993 - 2020 */
6 /* This file is part of Inform. */
8 /* Inform is free software: you can redistribute it and/or modify */
9 /* it under the terms of the GNU General Public License as published by */
10 /* the Free Software Foundation, either version 3 of the License, or */
11 /* (at your option) any later version. */
13 /* Inform is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16 /* GNU General Public License for more details. */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with Inform. If not, see https://gnu.org/licenses/ */
21 /* ------------------------------------------------------------------------- */
25 static int match_colon(void)
27 if (token_type == SEP_TT)
28 { if (token_value == SEMICOLON_SEP)
29 warning("Unlike C, Inform uses ':' to divide parts \
30 of a 'for' loop specification: replacing ';' with ':'");
32 if (token_value != COLON_SEP)
33 { ebf_error("':'", token_text);
34 panic_mode_error_recovery();
39 { ebf_error("':'", token_text);
40 panic_mode_error_recovery();
46 static void match_open_bracket(void)
48 if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
50 ebf_error("'('", token_text);
53 extern void match_close_bracket(void)
55 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
57 ebf_error("')'", token_text);
60 static void parse_action(void)
61 { int level = 1, args = 0, codegen_action;
62 assembly_operand AO, AO2, AO3, AO4, AO5;
64 /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
65 or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
66 to R_Process() with those four arguments. (The latter form,
67 with double brackets, means "return true afterwards".)
69 The R_Process() function should be supplied by the library,
70 although a stub is defined in the veneer.
72 The NOUN, SECOND, and ACTOR arguments are optional. If not
73 supplied, R_Process() will be called with fewer arguments.
74 (But if you supply ACTOR, it must be preceded by a comma.
75 <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
77 To complicate life, the ACTION argument may be a bare action
78 name or a parenthesized expression. (So <Take> is equivalent
79 to <(##Take)>.) We have to peek at the first token, checking
80 whether it's an open-paren, to distinguish these cases.
82 You may ask why the ACTOR argument is last; the "natural"
83 Inform ordering would be "<floyd, take ball>". True! Sadly,
84 Inform's lexer isn't smart enough to parse this consistently,
88 dont_enter_into_symbol_table = TRUE;
90 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
91 { level = 2; get_next_token();
93 dont_enter_into_symbol_table = FALSE;
95 /* Peek at the next token; see if it's an open-paren. */
96 if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
98 AO2 = parse_expression(ACTION_Q_CONTEXT);
99 codegen_action = TRUE;
102 { codegen_action = FALSE;
103 AO2 = action_of_name(token_text);
110 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
113 AO3 = parse_expression(ACTION_Q_CONTEXT);
117 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
120 AO4 = parse_expression(QUANTITY_CONTEXT);
123 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
125 ebf_error("',' or '>'", token_text);
128 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
130 if (!glulx_mode && (version_number < 4))
132 error("<x, y> syntax is not available in Z-code V3 or earlier");
135 AO5 = parse_expression(QUANTITY_CONTEXT);
137 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
139 ebf_error("'>'", token_text);
145 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
147 ebf_error("'>>'", token_text);
153 AO = veneer_routine(R_Process_VR);
157 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
158 if (version_number>=5)
159 assemblez_2(call_2n_zc, AO, AO2);
161 if (version_number==4)
162 assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
164 assemblez_2_to(call_zc, AO, AO2, temp_var1);
167 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
168 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
169 if (version_number>=5)
170 assemblez_3(call_vn_zc, AO, AO2, AO3);
172 if (version_number==4)
173 assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
175 assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
178 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
179 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
180 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
181 if (version_number>=5)
182 assemblez_4(call_vn_zc, AO, AO2, AO3, AO4);
184 if (version_number==4)
185 assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
187 assemblez_4_to(call_zc, AO, AO2, AO3, AO4, temp_var1);
190 AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
191 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
192 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
193 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
194 if (version_number>=5)
195 assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
197 if (version_number==4)
198 assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
199 /* if V3 or earlier, we've already displayed an error */
204 if (level == 2) assemblez_0(rtrue_zc);
209 AO = veneer_routine(R_Process_VR);
215 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
216 assembleg_call_1(AO, AO2, zero_operand);
220 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
222 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
223 assembleg_call_2(AO, AO2, AO3, zero_operand);
227 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
228 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
230 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
231 assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
235 AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
236 if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
237 assembleg_store(stack_pointer, AO5);
238 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
239 if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
240 assembleg_store(stack_pointer, AO4);
241 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
242 if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
243 assembleg_store(stack_pointer, AO3);
245 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
246 if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
247 assembleg_store(stack_pointer, AO2);
248 assembleg_3(call_gc, AO, four_operand, zero_operand);
253 assembleg_1(return_gc, one_operand);
258 extern int parse_label(void)
262 if ((token_type == SYMBOL_TT) &&
263 (stypes[token_value] == LABEL_T))
264 { sflags[token_value] |= USED_SFLAG;
265 return(svals[token_value]);
268 if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
269 { assign_symbol(token_value, next_label, LABEL_T);
270 define_symbol_label(token_value);
272 sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
273 return(svals[token_value]);
276 ebf_error("label name", token_text);
280 static void parse_print_z(int finally_return)
281 { int count = 0; assembly_operand AO;
283 /* print <printlist> -------------------------------------------------- */
284 /* print_ret <printlist> ---------------------------------------------- */
285 /* <literal-string> --------------------------------------------------- */
287 /* <printlist> is a comma-separated list of items: */
289 /* <literal-string> */
290 /* <other-expression> */
291 /* (char) <expression> */
292 /* (address) <expression> */
293 /* (string) <expression> */
294 /* (a) <expression> */
295 /* (the) <expression> */
296 /* (The) <expression> */
297 /* (name) <expression> */
298 /* (number) <expression> */
299 /* (property) <expression> */
300 /* (<routine>) <expression> */
301 /* (object) <expression> (for use in low-level code only) */
302 /* --------------------------------------------------------------------- */
305 { AI.text = token_text;
306 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
309 if (strlen(token_text) > 32)
310 { INITAOT(&AO, LONG_CONSTANT_OT);
311 AO.marker = STRING_MV;
312 AO.value = compile_string(token_text, FALSE, FALSE);
313 assemblez_1(print_paddr_zc, AO);
316 if ((token_type == SEP_TT)
317 && (token_value == SEMICOLON_SEP))
318 { assemblez_0(new_line_zc);
319 assemblez_0(rtrue_zc);
328 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
329 { assemblez_0(print_ret_zc); return;
333 assemblez_0(print_zc);
337 if (token_value == OPENB_SEP)
338 { misc_keywords.enabled = TRUE;
341 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
342 { assembly_operand AO1;
344 put_token_back(); put_token_back();
345 local_variables.enabled = FALSE;
347 misc_keywords.enabled = FALSE;
348 local_variables.enabled = TRUE;
350 if ((token_type == STATEMENT_TT)
351 &&(token_value == STRING_CODE))
352 { token_type = MISC_KEYWORD_TT;
353 token_value = STRING_MK;
358 case MISC_KEYWORD_TT:
361 if (runtime_error_checking_switch)
362 { AO = veneer_routine(RT__ChPrintC_VR);
367 parse_expression(QUANTITY_CONTEXT),
368 QUANTITY_CONTEXT, -1);
369 assemblez_1(print_char_zc, AO1);
372 if (runtime_error_checking_switch)
373 { AO = veneer_routine(RT__ChPrintA_VR);
378 parse_expression(QUANTITY_CONTEXT),
379 QUANTITY_CONTEXT, -1);
380 assemblez_1(print_addr_zc, AO1);
383 if (runtime_error_checking_switch)
384 { AO = veneer_routine(RT__ChPrintS_VR);
389 parse_expression(QUANTITY_CONTEXT),
390 QUANTITY_CONTEXT, -1);
391 assemblez_1(print_paddr_zc, AO1);
394 if (runtime_error_checking_switch)
395 { AO = veneer_routine(RT__ChPrintO_VR);
400 parse_expression(QUANTITY_CONTEXT),
401 QUANTITY_CONTEXT, -1);
402 assemblez_1(print_obj_zc, AO1);
405 AO = veneer_routine(DefArt_VR);
409 AO = veneer_routine(InDefArt_VR);
412 AO = veneer_routine(CDefArt_VR);
415 AO = veneer_routine(CInDefArt_VR);
418 AO = veneer_routine(PrintShortName_VR);
421 AO = veneer_routine(EnglishNumber_VR);
424 AO = veneer_routine(Print__Pname_VR);
427 error_named("A reserved word was used as a print specification:",
433 if (sflags[token_value] & UNKNOWN_SFLAG)
434 { INITAOT(&AO, LONG_CONSTANT_OT);
435 AO.value = token_value;
436 AO.marker = SYMBOL_MV;
439 { INITAOT(&AO, LONG_CONSTANT_OT);
440 AO.value = svals[token_value];
441 AO.marker = IROUTINE_MV;
442 if (stypes[token_value] != ROUTINE_T)
443 ebf_error("printing routine name", token_text);
445 sflags[token_value] |= USED_SFLAG;
450 if (version_number >= 5)
451 assemblez_2(call_2n_zc, AO,
452 code_generate(parse_expression(QUANTITY_CONTEXT),
453 QUANTITY_CONTEXT, -1));
454 else if (version_number == 4)
455 assemblez_2_to(call_vs_zc, AO,
456 code_generate(parse_expression(QUANTITY_CONTEXT),
457 QUANTITY_CONTEXT, -1), temp_var1);
459 assemblez_2_to(call_zc, AO,
460 code_generate(parse_expression(QUANTITY_CONTEXT),
461 QUANTITY_CONTEXT, -1), temp_var1);
464 default: ebf_error("print specification", token_text);
466 assemblez_1(print_num_zc,
467 code_generate(parse_expression(QUANTITY_CONTEXT),
468 QUANTITY_CONTEXT, -1));
472 put_token_back(); put_token_back(); put_token_back();
473 misc_keywords.enabled = FALSE;
474 assemblez_1(print_num_zc,
475 code_generate(parse_expression(QUANTITY_CONTEXT),
476 QUANTITY_CONTEXT, -1));
481 put_token_back(); misc_keywords.enabled = FALSE;
482 assemblez_1(print_num_zc,
483 code_generate(parse_expression(QUANTITY_CONTEXT),
484 QUANTITY_CONTEXT, -1));
488 PrintTermDone: misc_keywords.enabled = FALSE;
492 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
493 if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
494 { ebf_error("comma", token_text);
495 panic_mode_error_recovery(); return;
497 else get_next_token();
500 if (count == 0) ebf_error("something to print", token_text);
502 { assemblez_0(new_line_zc);
503 assemblez_0(rtrue_zc);
507 static void parse_print_g(int finally_return)
508 { int count = 0; assembly_operand AO, AO2;
510 /* print <printlist> -------------------------------------------------- */
511 /* print_ret <printlist> ---------------------------------------------- */
512 /* <literal-string> --------------------------------------------------- */
514 /* <printlist> is a comma-separated list of items: */
516 /* <literal-string> */
517 /* <other-expression> */
518 /* (char) <expression> */
519 /* (address) <expression> */
520 /* (string) <expression> */
521 /* (a) <expression> */
522 /* (A) <expression> */
523 /* (the) <expression> */
524 /* (The) <expression> */
525 /* (name) <expression> */
526 /* (number) <expression> */
527 /* (property) <expression> */
528 /* (<routine>) <expression> */
529 /* (object) <expression> (for use in low-level code only) */
530 /* --------------------------------------------------------------------- */
534 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
537 /* We can't compile a string into the instruction,
538 so this always goes into the string area. */
539 { INITAOT(&AO, CONSTANT_OT);
540 AO.marker = STRING_MV;
541 AO.value = compile_string(token_text, FALSE, FALSE);
542 assembleg_1(streamstr_gc, AO);
545 if ((token_type == SEP_TT)
546 && (token_value == SEMICOLON_SEP))
547 { INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
548 assembleg_1(streamchar_gc, AO);
549 INITAOTV(&AO, BYTECONSTANT_OT, 1);
550 assembleg_1(return_gc, AO);
560 if (token_value == OPENB_SEP)
561 { misc_keywords.enabled = TRUE;
564 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
565 { assembly_operand AO1;
568 put_token_back(); put_token_back();
569 local_variables.enabled = FALSE;
571 misc_keywords.enabled = FALSE;
572 local_variables.enabled = TRUE;
574 if ((token_type == STATEMENT_TT)
575 &&(token_value == STRING_CODE))
576 { token_type = MISC_KEYWORD_TT;
577 token_value = STRING_MK;
582 case MISC_KEYWORD_TT:
585 if (runtime_error_checking_switch)
586 { AO = veneer_routine(RT__ChPrintC_VR);
591 parse_expression(QUANTITY_CONTEXT),
592 QUANTITY_CONTEXT, -1);
593 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
594 { assembleg_2(stkpeek_gc, zero_operand,
597 INITAOTV(&AO2, HALFCONSTANT_OT, 0x100);
598 assembleg_2_branch(jgeu_gc, AO1, AO2,
601 assembleg_1(streamchar_gc, AO1);
603 assemble_label_no(ln);
604 assembleg_1(streamunichar_gc, AO1);
605 assemble_label_no(ln2);
608 if (runtime_error_checking_switch)
609 AO = veneer_routine(RT__ChPrintA_VR);
611 AO = veneer_routine(Print__Addr_VR);
614 if (runtime_error_checking_switch)
615 { AO = veneer_routine(RT__ChPrintS_VR);
620 parse_expression(QUANTITY_CONTEXT),
621 QUANTITY_CONTEXT, -1);
622 assembleg_1(streamstr_gc, AO1);
625 if (runtime_error_checking_switch)
626 { AO = veneer_routine(RT__ChPrintO_VR);
631 parse_expression(QUANTITY_CONTEXT),
632 QUANTITY_CONTEXT, -1);
633 INITAOT(&AO2, BYTECONSTANT_OT);
634 AO2.value = GOBJFIELD_NAME();
635 assembleg_3(aload_gc, AO1, AO2,
637 assembleg_1(streamstr_gc, stack_pointer);
640 AO = veneer_routine(DefArt_VR);
644 AO = veneer_routine(InDefArt_VR);
647 AO = veneer_routine(CDefArt_VR);
650 AO = veneer_routine(CInDefArt_VR);
653 AO = veneer_routine(PrintShortName_VR);
656 AO = veneer_routine(EnglishNumber_VR);
659 AO = veneer_routine(Print__Pname_VR);
662 error_named("A reserved word was used as a print specification:",
668 if (sflags[token_value] & UNKNOWN_SFLAG)
669 { INITAOT(&AO, CONSTANT_OT);
670 AO.value = token_value;
671 AO.marker = SYMBOL_MV;
674 { INITAOT(&AO, CONSTANT_OT);
675 AO.value = svals[token_value];
676 AO.marker = IROUTINE_MV;
677 if (stypes[token_value] != ROUTINE_T)
678 ebf_error("printing routine name", token_text);
680 sflags[token_value] |= USED_SFLAG;
685 INITAOT(&AO2, ZEROCONSTANT_OT);
687 code_generate(parse_expression(QUANTITY_CONTEXT),
688 QUANTITY_CONTEXT, -1),
692 default: ebf_error("print specification", token_text);
694 assembleg_1(streamnum_gc,
695 code_generate(parse_expression(QUANTITY_CONTEXT),
696 QUANTITY_CONTEXT, -1));
700 put_token_back(); put_token_back(); put_token_back();
701 misc_keywords.enabled = FALSE;
702 assembleg_1(streamnum_gc,
703 code_generate(parse_expression(QUANTITY_CONTEXT),
704 QUANTITY_CONTEXT, -1));
709 put_token_back(); misc_keywords.enabled = FALSE;
710 assembleg_1(streamnum_gc,
711 code_generate(parse_expression(QUANTITY_CONTEXT),
712 QUANTITY_CONTEXT, -1));
716 PrintTermDone: misc_keywords.enabled = FALSE;
720 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
721 if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
722 { ebf_error("comma", token_text);
723 panic_mode_error_recovery(); return;
725 else get_next_token();
728 if (count == 0) ebf_error("something to print", token_text);
731 INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
732 assembleg_1(streamchar_gc, AO);
733 INITAOTV(&AO, BYTECONSTANT_OT, 1);
734 assembleg_1(return_gc, AO);
738 static void parse_statement_z(int break_label, int continue_label)
739 { int ln, ln2, ln3, ln4, flag;
740 assembly_operand AO, AO2, AO3, AO4;
741 debug_location spare_debug_location1, spare_debug_location2;
745 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
746 { /* That is, a full stop, signifying a label */
749 if (token_type == SYMBOL_TT)
751 if (sflags[token_value] & UNKNOWN_SFLAG)
752 { assign_symbol(token_value, next_label, LABEL_T);
753 sflags[token_value] |= USED_SFLAG;
754 assemble_label_no(next_label);
755 define_symbol_label(token_value);
759 { if (stypes[token_value] != LABEL_T) goto LabelError;
760 if (sflags[token_value] & CHANGE_SFLAG)
761 { sflags[token_value] &= (~(CHANGE_SFLAG));
762 assemble_label_no(svals[token_value]);
763 define_symbol_label(token_value);
765 else error_named("Duplicate definition of label:", token_text);
769 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
770 { ebf_error("';'", token_text);
771 put_token_back(); return;
774 /* Interesting point of Inform grammar: a statement can only
775 consist solely of a label when it is immediately followed
779 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
780 { put_token_back(); return;
782 statement_debug_location = get_token_location();
783 parse_statement(break_label, continue_label);
786 LabelError: ebf_error("label name", token_text);
789 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
790 { parse_directive(TRUE);
791 parse_statement(break_label, continue_label); return;
794 if ((token_type == SEP_TT) && (token_value == AT_SEP))
795 { parse_assembly(); return;
798 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
800 if (token_type == DQ_TT)
801 { parse_print_z(TRUE); return;
804 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
805 { parse_action(); goto StatementTerminator; }
807 if (token_type == EOF_TT)
808 { ebf_error("statement", token_text); return; }
810 if (token_type != STATEMENT_TT)
812 AO = parse_expression(VOID_CONTEXT);
813 code_generate(AO, VOID_CONTEXT, -1);
814 if (vivc_flag) { panic_mode_error_recovery(); return; }
815 goto StatementTerminator;
818 statements.enabled = FALSE;
822 /* -------------------------------------------------------------------- */
823 /* box <string-1> ... <string-n> -------------------------------------- */
824 /* -------------------------------------------------------------------- */
827 if (version_number == 3)
828 warning("The 'box' statement has no effect in a version 3 game");
829 INITAOT(&AO3, LONG_CONSTANT_OT);
830 AO3.value = begin_table_array();
831 AO3.marker = ARRAY_MV;
835 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
837 if (token_type != DQ_TT)
838 ebf_error("text of box line in double-quotes",
841 for (i=0, j=0; token_text[i] != 0; j++)
842 if (token_text[i] == '@')
843 { if (token_text[i+1] == '@')
845 while (isdigit(token_text[i])) i++;
849 if (token_text[i] != 0) i++;
850 if (token_text[i] != 0) i++;
854 if (j > ln2) ln2 = j;
857 array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
859 finish_array(ln, FALSE);
861 error("No lines of text given for 'box' display");
863 if (version_number == 3) return;
865 INITAOTV(&AO2, SHORT_CONSTANT_OT, ln2);
866 INITAOTV(&AO4, VARIABLE_OT, 255);
867 assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
871 /* -------------------------------------------------------------------- */
872 /* break -------------------------------------------------------------- */
873 /* -------------------------------------------------------------------- */
876 if (break_label == -1)
877 error("'break' can only be used in a loop or 'switch' block");
879 assemblez_jump(break_label);
882 /* -------------------------------------------------------------------- */
883 /* continue ----------------------------------------------------------- */
884 /* -------------------------------------------------------------------- */
887 if (continue_label == -1)
888 error("'continue' can only be used in a loop block");
890 assemblez_jump(continue_label);
893 /* -------------------------------------------------------------------- */
894 /* do <codeblock> until (<condition>) --------------------------------- */
895 /* -------------------------------------------------------------------- */
898 assemble_label_no(ln = next_label++);
899 ln2 = next_label++; ln3 = next_label++;
900 parse_code_block(ln3, ln2, 0);
901 statements.enabled = TRUE;
903 if ((token_type == STATEMENT_TT)
904 && (token_value == UNTIL_CODE))
905 { assemble_label_no(ln2);
906 match_open_bracket();
907 AO = parse_expression(CONDITION_CONTEXT);
908 match_close_bracket();
909 code_generate(AO, CONDITION_CONTEXT, ln);
911 else error("'do' without matching 'until'");
913 assemble_label_no(ln3);
916 /* -------------------------------------------------------------------- */
917 /* font on/off -------------------------------------------------------- */
918 /* -------------------------------------------------------------------- */
921 misc_keywords.enabled = TRUE;
923 misc_keywords.enabled = FALSE;
924 if ((token_type != MISC_KEYWORD_TT)
925 || ((token_value != ON_MK)
926 && (token_value != OFF_MK)))
927 { ebf_error("'on' or 'off'", token_text);
928 panic_mode_error_recovery();
932 if (version_number >= 5)
933 { /* Use the V5 @set_font opcode, setting font 4
934 (for font off) or 1 (for font on). */
935 INITAOT(&AO, SHORT_CONSTANT_OT);
936 if (token_value == ON_MK)
940 assemblez_1_to(set_font_zc, AO, temp_var1);
944 /* Set the fixed-pitch header bit. */
945 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
946 INITAOTV(&AO2, SHORT_CONSTANT_OT, 8);
947 INITAOTV(&AO3, VARIABLE_OT, 255);
948 assemblez_2_to(loadw_zc, AO, AO2, AO3);
950 if (token_value == ON_MK)
951 { INITAOTV(&AO4, LONG_CONSTANT_OT, 0xfffd);
952 assemblez_2_to(and_zc, AO4, AO3, AO3);
955 { INITAOTV(&AO4, SHORT_CONSTANT_OT, 2);
956 assemblez_2_to(or_zc, AO4, AO3, AO3);
959 assemblez_3(storew_zc, AO, AO2, AO3);
962 /* -------------------------------------------------------------------- */
963 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
964 /* -------------------------------------------------------------------- */
966 /* Note that it's legal for any or all of the three sections of a
967 'for' specification to be empty. This 'for' implementation
968 often wastes 3 bytes with a redundant branch rather than keep
969 expression parse trees for long periods (as previous versions
970 of Inform did, somewhat crudely by simply storing the textual
971 form of a 'for' loop). It is adequate for now. */
974 match_open_bracket();
977 /* Initialisation code */
979 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
981 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
982 { sequence_point_follows = TRUE;
983 statement_debug_location = get_token_location();
984 code_generate(parse_expression(FORINIT_CONTEXT),
988 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
990 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
991 { assemble_label_no(ln = next_label++);
993 parse_code_block(ln2, ln, 0);
994 sequence_point_follows = FALSE;
995 if (!execution_never_reaches_here)
997 assemble_label_no(ln2);
1000 AO.type = OMITTED_OT;
1004 if (!match_colon()) break;
1008 AO.type = OMITTED_OT;
1009 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1011 spare_debug_location1 = get_token_location();
1012 AO = parse_expression(CONDITION_CONTEXT);
1013 if (!match_colon()) break;
1018 AO2.type = OMITTED_OT; flag = 0;
1019 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1021 spare_debug_location2 = get_token_location();
1022 AO2 = parse_expression(VOID_CONTEXT);
1023 match_close_bracket();
1024 flag = test_for_incdec(AO2);
1031 if ((AO2.type == OMITTED_OT) || (flag != 0))
1033 assemble_label_no(ln);
1034 if (flag==0) assemble_label_no(ln2);
1036 /* The "finished yet?" condition */
1038 if (AO.type != OMITTED_OT)
1039 { sequence_point_follows = TRUE;
1040 statement_debug_location = spare_debug_location1;
1041 code_generate(AO, CONDITION_CONTEXT, ln3);
1047 /* This is the jump which could be avoided with the aid
1048 of long-term expression storage */
1050 sequence_point_follows = FALSE;
1051 assemblez_jump(ln2);
1053 /* The "update" part */
1055 assemble_label_no(ln);
1056 sequence_point_follows = TRUE;
1057 statement_debug_location = spare_debug_location2;
1058 code_generate(AO2, VOID_CONTEXT, -1);
1060 assemble_label_no(ln2);
1062 /* The "finished yet?" condition */
1064 if (AO.type != OMITTED_OT)
1065 { sequence_point_follows = TRUE;
1066 statement_debug_location = spare_debug_location1;
1067 code_generate(AO, CONDITION_CONTEXT, ln3);
1073 /* In this optimised case, update code is at the end
1074 of the loop block, so "continue" goes there */
1076 parse_code_block(ln3, ln2, 0);
1077 assemble_label_no(ln2);
1079 sequence_point_follows = TRUE;
1080 statement_debug_location = spare_debug_location2;
1082 { INITAOTV(&AO3, SHORT_CONSTANT_OT, flag);
1084 && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1085 AO3.marker = VARIABLE_MV;
1086 assemblez_1(inc_zc, AO3);
1089 { INITAOTV(&AO3, SHORT_CONSTANT_OT, -flag);
1090 if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
1091 && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1092 AO3.marker = VARIABLE_MV;
1093 assemblez_1(dec_zc, AO3);
1099 /* In the unoptimised case, update code is at the
1100 start of the loop block, so "continue" goes there */
1102 parse_code_block(ln3, ln, 0);
1103 if (!execution_never_reaches_here)
1104 { sequence_point_follows = FALSE;
1109 assemble_label_no(ln3);
1112 /* -------------------------------------------------------------------- */
1113 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
1114 /* -------------------------------------------------------------------- */
1117 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1118 QUANTITY_CONTEXT, -1);
1119 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1120 { INITAOTV(&AO, SHORT_CONSTANT_OT, 252);
1121 if (version_number != 6) assemblez_1(pull_zc, AO);
1122 else assemblez_0_to(pull_zc, AO);
1123 AO.type = VARIABLE_OT;
1128 if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
1130 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
1133 { if ((token_type == SYMBOL_TT)
1134 && (stypes[token_value] != ATTRIBUTE_T))
1135 warning_named("This is not a declared Attribute:",
1140 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1141 QUANTITY_CONTEXT, -1);
1142 if (runtime_error_checking_switch)
1143 { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
1144 if (version_number >= 5)
1145 assemblez_3(call_vn_zc, veneer_routine(ln2),
1149 assemblez_3_to(call_zc, veneer_routine(ln2),
1150 AO, AO2, temp_var1);
1154 assemblez_2(ln, AO, AO2);
1157 /* -------------------------------------------------------------------- */
1158 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
1159 /* -------------------------------------------------------------------- */
1165 match_open_bracket();
1166 AO = parse_expression(CONDITION_CONTEXT);
1167 match_close_bracket();
1169 statements.enabled = TRUE;
1171 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
1174 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
1181 code_generate(AO, CONDITION_CONTEXT, ln);
1183 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
1186 if ((token_type != SEP_TT)
1187 || (token_value != SEMICOLON_SEP))
1188 { ebf_error("';'", token_text);
1193 statements.enabled = TRUE;
1195 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
1198 { ln2 = next_label++;
1199 if (!execution_never_reaches_here)
1200 { sequence_point_follows = FALSE;
1201 assemblez_jump(ln2);
1205 else put_token_back();
1207 if (ln >= 0) assemble_label_no(ln);
1210 { parse_code_block(break_label, continue_label, 0);
1211 if (ln >= 0) assemble_label_no(ln2);
1216 /* -------------------------------------------------------------------- */
1217 /* inversion ---------------------------------------------------------- */
1218 /* -------------------------------------------------------------------- */
1220 case INVERSION_CODE:
1221 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1222 INITAOT(&AO2, SHORT_CONSTANT_OT);
1225 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1226 assemblez_1(print_char_zc, temp_var1);
1228 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1229 assemblez_1(print_char_zc, temp_var1);
1231 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1232 assemblez_1(print_char_zc, temp_var1);
1234 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1235 assemblez_1(print_char_zc, temp_var1);
1238 /* -------------------------------------------------------------------- */
1239 /* jump <label> ------------------------------------------------------- */
1240 /* -------------------------------------------------------------------- */
1243 assemblez_jump(parse_label());
1246 /* -------------------------------------------------------------------- */
1247 /* move <expression> to <expression> ---------------------------------- */
1248 /* -------------------------------------------------------------------- */
1251 misc_keywords.enabled = TRUE;
1252 AO = parse_expression(QUANTITY_CONTEXT);
1255 misc_keywords.enabled = FALSE;
1256 if ((token_type != MISC_KEYWORD_TT)
1257 || (token_value != TO_MK))
1258 { ebf_error("'to'", token_text);
1259 panic_mode_error_recovery();
1263 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1264 QUANTITY_CONTEXT, -1);
1265 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
1266 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1267 { if (version_number >= 5)
1268 assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
1271 { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
1272 AO, AO2, temp_var1);
1276 assemblez_2(insert_obj_zc, AO, AO2);
1279 /* -------------------------------------------------------------------- */
1280 /* new_line ----------------------------------------------------------- */
1281 /* -------------------------------------------------------------------- */
1283 case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
1285 /* -------------------------------------------------------------------- */
1286 /* objectloop (<initialisation>) <codeblock> -------------------------- */
1287 /* -------------------------------------------------------------------- */
1289 case OBJECTLOOP_CODE:
1291 match_open_bracket();
1293 INITAOT(&AO, VARIABLE_OT);
1294 if (token_type == LOCAL_VARIABLE_TT)
1295 AO.value = token_value;
1297 if ((token_type == SYMBOL_TT) &&
1298 (stypes[token_value] == GLOBAL_VARIABLE_T))
1299 AO.value = svals[token_value];
1301 { ebf_error("'objectloop' variable", token_text);
1302 panic_mode_error_recovery(); break;
1304 if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
1305 && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
1306 AO.marker = VARIABLE_MV;
1307 misc_keywords.enabled = TRUE;
1308 get_next_token(); flag = TRUE;
1309 misc_keywords.enabled = FALSE;
1310 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1314 if ((token_type == MISC_KEYWORD_TT)
1315 && (token_value == NEAR_MK)) ln = 1;
1316 if ((token_type == MISC_KEYWORD_TT)
1317 && (token_value == FROM_MK)) ln = 2;
1318 if ((token_type == CND_TT) && (token_value == IN_COND))
1321 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1328 { /* Old style (Inform 5) objectloops: note that we
1329 implement objectloop (a in b) in the old way since
1330 this runs through objects in a different order from
1331 the new way, and there may be existing Inform code
1333 assembly_operand AO4;
1336 sequence_point_follows = TRUE;
1337 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1338 QUANTITY_CONTEXT, -1);
1339 match_close_bracket();
1341 { INITAOTV(&AO3, VARIABLE_OT, 0);
1342 if (runtime_error_checking_switch)
1343 AO2 = check_nonzero_at_runtime(AO2, -1,
1345 assemblez_1_to(get_parent_zc, AO2, AO3);
1346 assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
1350 { INITAOTV(&AO3, VARIABLE_OT, 0);
1351 if (runtime_error_checking_switch)
1353 AO2 = check_nonzero_at_runtime(AO2, -1,
1356 assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
1359 assemblez_store(AO, AO2);
1360 assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
1361 assemble_label_no(ln4 = next_label++);
1362 parse_code_block(ln2, ln3 = next_label++, 0);
1363 sequence_point_follows = FALSE;
1364 assemble_label_no(ln3);
1365 if (runtime_error_checking_switch)
1366 { AO2 = check_nonzero_at_runtime(AO, ln2,
1369 && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
1370 && ((AO4.type != VARIABLE_OT)
1371 ||(AO4.value != AO.value)))
1372 { assembly_operand en_ao;
1373 INITAOTV(&en_ao, SHORT_CONSTANT_OT, OBJECTLOOP_BROKEN_RTE);
1374 assemblez_2_branch(jin_zc, AO, AO4,
1376 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
1378 assemblez_jump(ln2);
1379 assemble_label_no(next_label++);
1383 assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
1384 assemble_label_no(ln2);
1388 sequence_point_follows = TRUE;
1389 INITAOTV(&AO2, SHORT_CONSTANT_OT, 1);
1390 assemblez_store(AO, AO2);
1392 assemble_label_no(ln = next_label++);
1398 sequence_point_follows = TRUE;
1399 code_generate(parse_expression(CONDITION_CONTEXT),
1400 CONDITION_CONTEXT, ln3);
1401 match_close_bracket();
1403 parse_code_block(ln2, ln3, 0);
1405 sequence_point_follows = FALSE;
1406 assemble_label_no(ln3);
1408 INITAOTV(&AO2, LONG_CONSTANT_OT, no_objects);
1409 AO2.marker = NO_OBJS_MV;
1410 assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
1412 assemble_label_no(ln2);
1415 /* -------------------------------------------------------------------- */
1416 /* (see routine above) ------------------------------------------------ */
1417 /* -------------------------------------------------------------------- */
1421 parse_print_z(FALSE); return;
1422 case PRINT_RET_CODE:
1424 parse_print_z(TRUE); return;
1426 /* -------------------------------------------------------------------- */
1427 /* quit --------------------------------------------------------------- */
1428 /* -------------------------------------------------------------------- */
1430 case QUIT_CODE: assemblez_0(quit_zc); break;
1432 /* -------------------------------------------------------------------- */
1433 /* read <expression> <expression> [<Routine>] ------------------------- */
1434 /* -------------------------------------------------------------------- */
1437 INITAOTV(&AO, VARIABLE_OT, 252);
1439 code_generate(parse_expression(QUANTITY_CONTEXT),
1440 QUANTITY_CONTEXT, -1));
1441 if (version_number > 3)
1442 { INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1443 INITAOTV(&AO4, SHORT_CONSTANT_OT, 0);
1444 assemblez_3(storeb_zc, AO, AO3, AO4);
1446 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1447 QUANTITY_CONTEXT, -1);
1450 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1453 { if (version_number == 3)
1455 "In Version 3 no status-line drawing routine can be given");
1457 { assembly_operand AO5;
1458 /* Move the temp4 (buffer) value to the stack,
1459 since the routine might alter temp4. */
1460 assemblez_store(stack_pointer, AO);
1463 AO5 = parse_expression(CONSTANT_CONTEXT);
1465 if (version_number >= 5)
1466 assemblez_1(call_1n_zc, AO5);
1468 assemblez_1_to(call_zc, AO5, temp_var1);
1472 if (version_number > 4)
1473 { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
1475 else assemblez_2(sread_zc, AO, AO2);
1478 /* -------------------------------------------------------------------- */
1479 /* remove <expression> ------------------------------------------------ */
1480 /* -------------------------------------------------------------------- */
1483 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1484 QUANTITY_CONTEXT, -1);
1485 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1486 { if (version_number >= 5)
1487 assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
1490 { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
1495 assemblez_1(remove_obj_zc, AO);
1498 /* -------------------------------------------------------------------- */
1499 /* restore <label> ---------------------------------------------------- */
1500 /* -------------------------------------------------------------------- */
1503 if (version_number < 5)
1504 assemblez_0_branch(restore_zc, parse_label(), TRUE);
1506 { INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
1507 assemblez_0_to(restore_zc, temp_var1);
1508 assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
1512 /* -------------------------------------------------------------------- */
1513 /* return [<expression>] ---------------------------------------------- */
1514 /* -------------------------------------------------------------------- */
1518 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1519 { assemblez_0(rtrue_zc); return; }
1521 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
1522 QUANTITY_CONTEXT, -1);
1523 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
1524 && (AO.marker == 0))
1525 { assemblez_0(rfalse_zc); break; }
1526 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
1527 && (AO.marker == 0))
1528 { assemblez_0(rtrue_zc); break; }
1529 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1530 { assemblez_0(ret_popped_zc); break; }
1531 assemblez_1(ret_zc, AO);
1534 /* -------------------------------------------------------------------- */
1535 /* rfalse ------------------------------------------------------------- */
1536 /* -------------------------------------------------------------------- */
1538 case RFALSE_CODE: assemblez_0(rfalse_zc); break;
1540 /* -------------------------------------------------------------------- */
1541 /* rtrue -------------------------------------------------------------- */
1542 /* -------------------------------------------------------------------- */
1544 case RTRUE_CODE: assemblez_0(rtrue_zc); break;
1546 /* -------------------------------------------------------------------- */
1547 /* save <label> ------------------------------------------------------- */
1548 /* -------------------------------------------------------------------- */
1551 if (version_number < 5)
1552 assemblez_0_branch(save_zc, parse_label(), TRUE);
1554 { INITAOTV(&AO, VARIABLE_OT, 255);
1555 assemblez_0_to(save_zc, AO);
1556 assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
1560 /* -------------------------------------------------------------------- */
1561 /* spaces <expression> ------------------------------------------------ */
1562 /* -------------------------------------------------------------------- */
1565 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1566 QUANTITY_CONTEXT, -1);
1567 INITAOTV(&AO2, VARIABLE_OT, 255);
1569 assemblez_store(AO2, AO);
1571 INITAOTV(&AO, SHORT_CONSTANT_OT, 32);
1572 INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1574 assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
1575 assemble_label_no(ln2 = next_label++);
1576 assemblez_1(print_char_zc, AO);
1578 assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
1579 assemble_label_no(ln);
1582 /* -------------------------------------------------------------------- */
1583 /* string <expression> <literal-string> ------------------------------- */
1584 /* -------------------------------------------------------------------- */
1587 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1588 INITAOTV(&AO2, SHORT_CONSTANT_OT, 12);
1589 INITAOTV(&AO3, VARIABLE_OT, 252);
1590 assemblez_2_to(loadw_zc, AO, AO2, AO3);
1591 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1592 QUANTITY_CONTEXT, -1);
1594 if (token_type == DQ_TT)
1595 { INITAOT(&AO4, LONG_CONSTANT_OT);
1596 AO4.value = compile_string(token_text, TRUE, TRUE);
1600 AO4 = parse_expression(CONSTANT_CONTEXT);
1602 assemblez_3(storew_zc, AO3, AO2, AO4);
1605 /* -------------------------------------------------------------------- */
1606 /* style roman/reverse/bold/underline/fixed --------------------------- */
1607 /* -------------------------------------------------------------------- */
1610 if (version_number==3)
1612 "The 'style' statement cannot be used for Version 3 games");
1613 panic_mode_error_recovery();
1617 misc_keywords.enabled = TRUE;
1619 misc_keywords.enabled = FALSE;
1620 if ((token_type != MISC_KEYWORD_TT)
1621 || ((token_value != ROMAN_MK)
1622 && (token_value != REVERSE_MK)
1623 && (token_value != BOLD_MK)
1624 && (token_value != UNDERLINE_MK)
1625 && (token_value != FIXED_MK)))
1627 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1629 panic_mode_error_recovery();
1633 INITAOT(&AO, SHORT_CONSTANT_OT);
1635 { case ROMAN_MK: AO.value = 0; break;
1636 case REVERSE_MK: AO.value = 1; break;
1637 case BOLD_MK: AO.value = 2; break;
1638 case UNDERLINE_MK: AO.value = 4; break;
1639 case FIXED_MK: AO.value = 8; break;
1641 assemblez_1(set_text_style_zc, AO); break;
1643 /* -------------------------------------------------------------------- */
1644 /* switch (<expression>) <codeblock> ---------------------------------- */
1645 /* -------------------------------------------------------------------- */
1648 match_open_bracket();
1649 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1650 QUANTITY_CONTEXT, -1);
1651 match_close_bracket();
1653 INITAOTV(&AO2, VARIABLE_OT, 255);
1654 assemblez_store(AO2, AO);
1656 parse_code_block(ln = next_label++, continue_label, 1);
1657 assemble_label_no(ln);
1660 /* -------------------------------------------------------------------- */
1661 /* while (<condition>) <codeblock> ------------------------------------ */
1662 /* -------------------------------------------------------------------- */
1665 assemble_label_no(ln = next_label++);
1666 match_open_bracket();
1668 code_generate(parse_expression(CONDITION_CONTEXT),
1669 CONDITION_CONTEXT, ln2 = next_label++);
1670 match_close_bracket();
1672 parse_code_block(ln2, ln, 0);
1673 sequence_point_follows = FALSE;
1675 assemble_label_no(ln2);
1678 /* -------------------------------------------------------------------- */
1681 error("'default' without matching 'switch'"); break;
1683 error("'else' without matching 'if'"); break;
1685 error("'until' without matching 'do'");
1686 panic_mode_error_recovery(); return;
1689 StatementTerminator:
1692 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1693 { ebf_error("';'", token_text);
1698 static void parse_statement_g(int break_label, int continue_label)
1699 { int ln, ln2, ln3, ln4, flag, onstack;
1700 assembly_operand AO, AO2, AO3, AO4;
1701 debug_location spare_debug_location1, spare_debug_location2;
1705 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
1706 { /* That is, a full stop, signifying a label */
1709 if (token_type == SYMBOL_TT)
1711 if (sflags[token_value] & UNKNOWN_SFLAG)
1712 { assign_symbol(token_value, next_label, LABEL_T);
1713 sflags[token_value] |= USED_SFLAG;
1714 assemble_label_no(next_label);
1715 define_symbol_label(token_value);
1719 { if (stypes[token_value] != LABEL_T) goto LabelError;
1720 if (sflags[token_value] & CHANGE_SFLAG)
1721 { sflags[token_value] &= (~(CHANGE_SFLAG));
1722 assemble_label_no(svals[token_value]);
1723 define_symbol_label(token_value);
1725 else error_named("Duplicate definition of label:", token_text);
1729 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1730 { ebf_error("';'", token_text);
1731 put_token_back(); return;
1734 /* Interesting point of Inform grammar: a statement can only
1735 consist solely of a label when it is immediately followed
1739 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
1740 { put_token_back(); return;
1742 /* The following line prevents labels from influencing the positions
1743 of sequence points. */
1744 statement_debug_location = get_token_location();
1745 parse_statement(break_label, continue_label);
1748 LabelError: ebf_error("label name", token_text);
1751 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
1752 { parse_directive(TRUE);
1753 parse_statement(break_label, continue_label); return;
1756 if ((token_type == SEP_TT) && (token_value == AT_SEP))
1757 { parse_assembly(); return;
1760 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
1762 if (token_type == DQ_TT)
1763 { parse_print_g(TRUE); return;
1766 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
1767 { parse_action(); goto StatementTerminator; }
1769 if (token_type == EOF_TT)
1770 { ebf_error("statement", token_text); return; }
1772 if (token_type != STATEMENT_TT)
1774 AO = parse_expression(VOID_CONTEXT);
1775 code_generate(AO, VOID_CONTEXT, -1);
1776 if (vivc_flag) { panic_mode_error_recovery(); return; }
1777 goto StatementTerminator;
1780 statements.enabled = FALSE;
1785 /* -------------------------------------------------------------------- */
1786 /* box <string-1> ... <string-n> -------------------------------------- */
1787 /* -------------------------------------------------------------------- */
1790 INITAOT(&AO3, CONSTANT_OT);
1791 AO3.value = begin_table_array();
1792 AO3.marker = ARRAY_MV;
1796 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
1798 if (token_type != DQ_TT)
1799 ebf_error("text of box line in double-quotes",
1802 for (i=0, j=0; token_text[i] != 0; j++)
1803 if (token_text[i] == '@')
1804 { if (token_text[i+1] == '@')
1806 while (isdigit(token_text[i])) i++;
1810 if (token_text[i] != 0) i++;
1811 if (token_text[i] != 0) i++;
1815 if (j > ln2) ln2 = j;
1818 array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
1820 finish_array(ln, FALSE);
1822 error("No lines of text given for 'box' display");
1825 AO2.value = ln2; set_constant_ot(&AO2);
1826 assembleg_call_2(veneer_routine(Box__Routine_VR),
1827 AO2, AO3, zero_operand);
1830 /* -------------------------------------------------------------------- */
1831 /* break -------------------------------------------------------------- */
1832 /* -------------------------------------------------------------------- */
1835 if (break_label == -1)
1836 error("'break' can only be used in a loop or 'switch' block");
1838 assembleg_jump(break_label);
1841 /* -------------------------------------------------------------------- */
1842 /* continue ----------------------------------------------------------- */
1843 /* -------------------------------------------------------------------- */
1846 if (continue_label == -1)
1847 error("'continue' can only be used in a loop block");
1849 assembleg_jump(continue_label);
1852 /* -------------------------------------------------------------------- */
1853 /* do <codeblock> until (<condition>) --------------------------------- */
1854 /* -------------------------------------------------------------------- */
1857 assemble_label_no(ln = next_label++);
1858 ln2 = next_label++; ln3 = next_label++;
1859 parse_code_block(ln3, ln2, 0);
1860 statements.enabled = TRUE;
1862 if ((token_type == STATEMENT_TT)
1863 && (token_value == UNTIL_CODE))
1864 { assemble_label_no(ln2);
1865 match_open_bracket();
1866 AO = parse_expression(CONDITION_CONTEXT);
1867 match_close_bracket();
1868 code_generate(AO, CONDITION_CONTEXT, ln);
1870 else error("'do' without matching 'until'");
1872 assemble_label_no(ln3);
1875 /* -------------------------------------------------------------------- */
1876 /* font on/off -------------------------------------------------------- */
1877 /* -------------------------------------------------------------------- */
1880 misc_keywords.enabled = TRUE;
1882 misc_keywords.enabled = FALSE;
1883 if ((token_type != MISC_KEYWORD_TT)
1884 || ((token_value != ON_MK)
1885 && (token_value != OFF_MK)))
1886 { ebf_error("'on' or 'off'", token_text);
1887 panic_mode_error_recovery();
1891 /* Call glk_set_style(normal or preformatted) */
1894 set_constant_ot(&AO);
1895 if (token_value == ON_MK)
1899 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
1900 AO, AO2, zero_operand);
1903 /* -------------------------------------------------------------------- */
1904 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
1905 /* -------------------------------------------------------------------- */
1907 /* Note that it's legal for any or all of the three sections of a
1908 'for' specification to be empty. This 'for' implementation
1909 often wastes 3 bytes with a redundant branch rather than keep
1910 expression parse trees for long periods (as previous versions
1911 of Inform did, somewhat crudely by simply storing the textual
1912 form of a 'for' loop). It is adequate for now. */
1915 match_open_bracket();
1918 /* Initialisation code */
1920 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1922 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
1923 { sequence_point_follows = TRUE;
1924 statement_debug_location = get_token_location();
1925 code_generate(parse_expression(FORINIT_CONTEXT),
1929 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
1931 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
1932 { assemble_label_no(ln = next_label++);
1934 parse_code_block(ln2, ln, 0);
1935 sequence_point_follows = FALSE;
1936 if (!execution_never_reaches_here)
1938 assemble_label_no(ln2);
1941 AO.type = OMITTED_OT;
1945 if (!match_colon()) break;
1949 AO.type = OMITTED_OT;
1950 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1952 spare_debug_location1 = get_token_location();
1953 AO = parse_expression(CONDITION_CONTEXT);
1954 if (!match_colon()) break;
1959 AO2.type = OMITTED_OT; flag = 0;
1960 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1962 spare_debug_location2 = get_token_location();
1963 AO2 = parse_expression(VOID_CONTEXT);
1964 match_close_bracket();
1965 flag = test_for_incdec(AO2);
1972 if ((AO2.type == OMITTED_OT) || (flag != 0))
1974 assemble_label_no(ln);
1975 if (flag==0) assemble_label_no(ln2);
1977 /* The "finished yet?" condition */
1979 if (AO.type != OMITTED_OT)
1980 { sequence_point_follows = TRUE;
1981 statement_debug_location = spare_debug_location1;
1982 code_generate(AO, CONDITION_CONTEXT, ln3);
1988 /* This is the jump which could be avoided with the aid
1989 of long-term expression storage */
1991 sequence_point_follows = FALSE;
1992 assembleg_jump(ln2);
1994 /* The "update" part */
1996 assemble_label_no(ln);
1997 sequence_point_follows = TRUE;
1998 statement_debug_location = spare_debug_location2;
1999 code_generate(AO2, VOID_CONTEXT, -1);
2001 assemble_label_no(ln2);
2003 /* The "finished yet?" condition */
2005 if (AO.type != OMITTED_OT)
2006 { sequence_point_follows = TRUE;
2007 statement_debug_location = spare_debug_location1;
2008 code_generate(AO, CONDITION_CONTEXT, ln3);
2014 /* In this optimised case, update code is at the end
2015 of the loop block, so "continue" goes there */
2017 parse_code_block(ln3, ln2, 0);
2018 assemble_label_no(ln2);
2020 sequence_point_follows = TRUE;
2021 statement_debug_location = spare_debug_location2;
2025 if (AO3.value >= MAX_LOCAL_VARIABLES)
2026 AO3.type = GLOBALVAR_OT;
2028 AO3.type = LOCALVAR_OT;
2029 assembleg_3(add_gc, AO3, one_operand, AO3);
2034 if (AO3.value >= MAX_LOCAL_VARIABLES)
2035 AO3.type = GLOBALVAR_OT;
2037 AO3.type = LOCALVAR_OT;
2038 assembleg_3(sub_gc, AO3, one_operand, AO3);
2044 /* In the unoptimised case, update code is at the
2045 start of the loop block, so "continue" goes there */
2047 parse_code_block(ln3, ln, 0);
2048 if (!execution_never_reaches_here)
2049 { sequence_point_follows = FALSE;
2054 assemble_label_no(ln3);
2057 /* -------------------------------------------------------------------- */
2058 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2059 /* -------------------------------------------------------------------- */
2062 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2063 QUANTITY_CONTEXT, -1);
2064 if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
2071 if ((token_type == SEP_TT)
2072 && (token_value == SEMICOLON_SEP)) {
2074 assembleg_2(copy_gc, stack_pointer, zero_operand);
2078 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
2081 { if ((token_type == SYMBOL_TT)
2082 && (stypes[token_value] != ATTRIBUTE_T))
2083 warning_named("This is not a declared Attribute:",
2088 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2089 QUANTITY_CONTEXT, -1);
2090 if (runtime_error_checking_switch && (!veneer_mode))
2091 { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
2092 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
2093 /* already on stack */
2096 assembleg_store(stack_pointer, AO2);
2099 assembleg_2(stkpeek_gc, one_operand, stack_pointer);
2101 assembleg_store(stack_pointer, AO);
2102 assembleg_3(call_gc, veneer_routine(ln2), two_operand,
2106 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2108 set_constant_ot(&AO2);
2111 INITAOTV(&AO3, BYTECONSTANT_OT, 8);
2112 assembleg_3(add_gc, AO2, AO3, stack_pointer);
2113 AO2 = stack_pointer;
2116 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
2117 assembleg_2(stkpeek_gc, one_operand,
2120 assembleg_2(stkpeek_gc, zero_operand,
2127 assembleg_3(astorebit_gc, AO, AO2, AO3);
2131 /* -------------------------------------------------------------------- */
2132 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2133 /* -------------------------------------------------------------------- */
2139 match_open_bracket();
2140 AO = parse_expression(CONDITION_CONTEXT);
2141 match_close_bracket();
2143 statements.enabled = TRUE;
2145 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
2148 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
2155 code_generate(AO, CONDITION_CONTEXT, ln);
2157 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
2160 if ((token_type != SEP_TT)
2161 || (token_value != SEMICOLON_SEP))
2162 { ebf_error("';'", token_text);
2167 statements.enabled = TRUE;
2169 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
2172 { ln2 = next_label++;
2173 if (!execution_never_reaches_here)
2174 { sequence_point_follows = FALSE;
2175 assembleg_jump(ln2);
2179 else put_token_back();
2181 if (ln >= 0) assemble_label_no(ln);
2184 { parse_code_block(break_label, continue_label, 0);
2185 if (ln >= 0) assemble_label_no(ln2);
2190 /* -------------------------------------------------------------------- */
2191 /* inversion ---------------------------------------------------------- */
2192 /* -------------------------------------------------------------------- */
2194 case INVERSION_CODE:
2195 INITAOTV(&AO2, DEREFERENCE_OT, GLULX_HEADER_SIZE+8);
2196 assembleg_2(copyb_gc, AO2, stack_pointer);
2197 assembleg_1(streamchar_gc, stack_pointer);
2198 AO2.value = GLULX_HEADER_SIZE+9;
2199 assembleg_2(copyb_gc, AO2, stack_pointer);
2200 assembleg_1(streamchar_gc, stack_pointer);
2201 AO2.value = GLULX_HEADER_SIZE+10;
2202 assembleg_2(copyb_gc, AO2, stack_pointer);
2203 assembleg_1(streamchar_gc, stack_pointer);
2204 AO2.value = GLULX_HEADER_SIZE+11;
2205 assembleg_2(copyb_gc, AO2, stack_pointer);
2206 assembleg_1(streamchar_gc, stack_pointer);
2208 if (/* DISABLES CODE */ (0)) {
2211 set_constant_ot(&AO);
2212 assembleg_1(streamchar_gc, AO);
2214 set_constant_ot(&AO);
2215 assembleg_1(streamchar_gc, AO);
2217 AO2.value = GLULX_HEADER_SIZE+12;
2218 assembleg_2(copyb_gc, AO2, stack_pointer);
2219 assembleg_1(streamchar_gc, stack_pointer);
2220 AO2.value = GLULX_HEADER_SIZE+13;
2221 assembleg_2(copyb_gc, AO2, stack_pointer);
2222 assembleg_1(streamchar_gc, stack_pointer);
2223 AO2.value = GLULX_HEADER_SIZE+14;
2224 assembleg_2(copyb_gc, AO2, stack_pointer);
2225 assembleg_1(streamchar_gc, stack_pointer);
2226 AO2.value = GLULX_HEADER_SIZE+15;
2227 assembleg_2(copyb_gc, AO2, stack_pointer);
2228 assembleg_1(streamchar_gc, stack_pointer);
2232 set_constant_ot(&AO);
2233 assembleg_1(streamchar_gc, AO);
2238 /* -------------------------------------------------------------------- */
2239 /* jump <label> ------------------------------------------------------- */
2240 /* -------------------------------------------------------------------- */
2243 assembleg_jump(parse_label());
2246 /* -------------------------------------------------------------------- */
2247 /* move <expression> to <expression> ---------------------------------- */
2248 /* -------------------------------------------------------------------- */
2251 misc_keywords.enabled = TRUE;
2252 AO = parse_expression(QUANTITY_CONTEXT);
2255 misc_keywords.enabled = FALSE;
2256 if ((token_type != MISC_KEYWORD_TT)
2257 || (token_value != TO_MK))
2258 { ebf_error("'to'", token_text);
2259 panic_mode_error_recovery();
2263 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2264 QUANTITY_CONTEXT, -1);
2265 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
2266 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2267 assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
2270 assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
2274 /* -------------------------------------------------------------------- */
2275 /* new_line ----------------------------------------------------------- */
2276 /* -------------------------------------------------------------------- */
2279 INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
2280 assembleg_1(streamchar_gc, AO);
2283 /* -------------------------------------------------------------------- */
2284 /* objectloop (<initialisation>) <codeblock> -------------------------- */
2285 /* -------------------------------------------------------------------- */
2287 case OBJECTLOOP_CODE:
2289 match_open_bracket();
2291 if (token_type == LOCAL_VARIABLE_TT) {
2292 INITAOTV(&AO, LOCALVAR_OT, token_value);
2294 else if ((token_type == SYMBOL_TT) &&
2295 (stypes[token_value] == GLOBAL_VARIABLE_T)) {
2296 INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]);
2299 ebf_error("'objectloop' variable", token_text);
2300 panic_mode_error_recovery();
2303 misc_keywords.enabled = TRUE;
2304 get_next_token(); flag = TRUE;
2305 misc_keywords.enabled = FALSE;
2306 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2310 if ((token_type == MISC_KEYWORD_TT)
2311 && (token_value == NEAR_MK)) ln = 1;
2312 if ((token_type == MISC_KEYWORD_TT)
2313 && (token_value == FROM_MK)) ln = 2;
2314 if ((token_type == CND_TT) && (token_value == IN_COND))
2317 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2324 /* Old style (Inform 5) objectloops: note that we
2325 implement objectloop (a in b) in the old way since
2326 this runs through objects in a different order from
2327 the new way, and there may be existing Inform code
2329 assembly_operand AO4, AO5;
2332 sequence_point_follows = TRUE;
2333 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2334 QUANTITY_CONTEXT, -1);
2335 match_close_bracket();
2337 if (runtime_error_checking_switch)
2338 AO2 = check_nonzero_at_runtime(AO2, -1,
2340 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2341 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2342 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2343 assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
2344 AO2 = stack_pointer;
2347 if (runtime_error_checking_switch) {
2349 AO2 = check_nonzero_at_runtime(AO2, -1,
2352 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2353 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2354 AO2 = stack_pointer;
2359 assembleg_store(AO, AO2);
2360 assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
2361 assemble_label_no(ln4 = next_label++);
2362 parse_code_block(ln2, ln3 = next_label++, 0);
2363 sequence_point_follows = FALSE;
2364 assemble_label_no(ln3);
2365 if (runtime_error_checking_switch) {
2366 AO2 = check_nonzero_at_runtime(AO, ln2,
2369 && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
2370 && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
2371 { assembly_operand en_ao;
2373 en_ao.value = OBJECTLOOP_BROKEN_RTE;
2374 set_constant_ot(&en_ao);
2375 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2376 assembleg_3(aload_gc, AO, AO4, stack_pointer);
2377 assembleg_2_branch(jeq_gc, stack_pointer, AO5,
2379 assembleg_call_2(veneer_routine(RT__Err_VR),
2380 en_ao, AO, zero_operand);
2381 assembleg_jump(ln2);
2382 assemble_label_no(next_label++);
2388 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2389 assembleg_3(aload_gc, AO2, AO4, AO);
2390 assembleg_1_branch(jnz_gc, AO, ln4);
2391 assemble_label_no(ln2);
2395 sequence_point_follows = TRUE;
2396 ln = symbol_index("Class", -1);
2397 INITAOT(&AO2, CONSTANT_OT);
2398 AO2.value = svals[ln];
2399 AO2.marker = OBJECT_MV;
2400 assembleg_store(AO, AO2);
2402 assemble_label_no(ln = next_label++);
2408 sequence_point_follows = TRUE;
2409 code_generate(parse_expression(CONDITION_CONTEXT),
2410 CONDITION_CONTEXT, ln3);
2411 match_close_bracket();
2413 parse_code_block(ln2, ln3, 0);
2415 sequence_point_follows = FALSE;
2416 assemble_label_no(ln3);
2417 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHAIN());
2418 assembleg_3(aload_gc, AO, AO4, AO);
2419 assembleg_1_branch(jnz_gc, AO, ln);
2420 assemble_label_no(ln2);
2423 /* -------------------------------------------------------------------- */
2424 /* (see routine above) ------------------------------------------------ */
2425 /* -------------------------------------------------------------------- */
2429 parse_print_g(FALSE); return;
2430 case PRINT_RET_CODE:
2432 parse_print_g(TRUE); return;
2434 /* -------------------------------------------------------------------- */
2435 /* quit --------------------------------------------------------------- */
2436 /* -------------------------------------------------------------------- */
2439 assembleg_0(quit_gc); break;
2441 /* -------------------------------------------------------------------- */
2442 /* remove <expression> ------------------------------------------------ */
2443 /* -------------------------------------------------------------------- */
2446 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2447 QUANTITY_CONTEXT, -1);
2448 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2449 assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
2452 assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
2456 /* -------------------------------------------------------------------- */
2457 /* return [<expression>] ---------------------------------------------- */
2458 /* -------------------------------------------------------------------- */
2462 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
2463 assembleg_1(return_gc, one_operand);
2467 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
2468 QUANTITY_CONTEXT, -1);
2469 assembleg_1(return_gc, AO);
2472 /* -------------------------------------------------------------------- */
2473 /* rfalse ------------------------------------------------------------- */
2474 /* -------------------------------------------------------------------- */
2477 assembleg_1(return_gc, zero_operand);
2480 /* -------------------------------------------------------------------- */
2481 /* rtrue -------------------------------------------------------------- */
2482 /* -------------------------------------------------------------------- */
2485 assembleg_1(return_gc, one_operand);
2488 /* -------------------------------------------------------------------- */
2489 /* spaces <expression> ------------------------------------------------ */
2490 /* -------------------------------------------------------------------- */
2493 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2494 QUANTITY_CONTEXT, -1);
2496 assembleg_store(temp_var1, AO);
2499 AO.value = 32; set_constant_ot(&AO);
2501 assembleg_2_branch(jlt_gc, temp_var1, one_operand,
2503 assemble_label_no(ln2 = next_label++);
2504 assembleg_1(streamchar_gc, AO);
2505 assembleg_dec(temp_var1);
2506 assembleg_1_branch(jnz_gc, temp_var1, ln2);
2507 assemble_label_no(ln);
2510 /* -------------------------------------------------------------------- */
2511 /* string <expression> <literal-string> ------------------------------- */
2512 /* -------------------------------------------------------------------- */
2515 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2516 QUANTITY_CONTEXT, -1);
2518 if (token_type == DQ_TT)
2519 { INITAOT(&AO4, CONSTANT_OT);
2520 AO4.value = compile_string(token_text, TRUE, TRUE);
2521 AO4.marker = STRING_MV;
2525 AO4 = parse_expression(CONSTANT_CONTEXT);
2527 assembleg_call_2(veneer_routine(Dynam__String_VR),
2528 AO2, AO4, zero_operand);
2531 /* -------------------------------------------------------------------- */
2532 /* style roman/reverse/bold/underline/fixed --------------------------- */
2533 /* -------------------------------------------------------------------- */
2536 misc_keywords.enabled = TRUE;
2538 misc_keywords.enabled = FALSE;
2539 if ((token_type != MISC_KEYWORD_TT)
2540 || ((token_value != ROMAN_MK)
2541 && (token_value != REVERSE_MK)
2542 && (token_value != BOLD_MK)
2543 && (token_value != UNDERLINE_MK)
2544 && (token_value != FIXED_MK)))
2546 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2548 panic_mode_error_recovery();
2552 /* Call glk_set_style() */
2556 set_constant_ot(&AO);
2560 AO2 = zero_operand; /* normal */
2564 AO2.value = 5; /* alert */
2565 set_constant_ot(&AO2);
2569 AO2.value = 4; /* subheader */
2570 set_constant_ot(&AO2);
2573 AO2 = one_operand; /* emphasized */
2576 AO2 = two_operand; /* preformatted */
2579 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
2580 AO, AO2, zero_operand);
2583 /* -------------------------------------------------------------------- */
2584 /* switch (<expression>) <codeblock> ---------------------------------- */
2585 /* -------------------------------------------------------------------- */
2588 match_open_bracket();
2589 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2590 QUANTITY_CONTEXT, -1);
2591 match_close_bracket();
2593 assembleg_store(temp_var1, AO);
2595 parse_code_block(ln = next_label++, continue_label, 1);
2596 assemble_label_no(ln);
2599 /* -------------------------------------------------------------------- */
2600 /* while (<condition>) <codeblock> ------------------------------------ */
2601 /* -------------------------------------------------------------------- */
2604 assemble_label_no(ln = next_label++);
2605 match_open_bracket();
2607 code_generate(parse_expression(CONDITION_CONTEXT),
2608 CONDITION_CONTEXT, ln2 = next_label++);
2609 match_close_bracket();
2611 parse_code_block(ln2, ln, 0);
2612 sequence_point_follows = FALSE;
2614 assemble_label_no(ln2);
2617 /* -------------------------------------------------------------------- */
2620 error("'default' without matching 'switch'"); break;
2622 error("'else' without matching 'if'"); break;
2624 error("'until' without matching 'do'");
2625 panic_mode_error_recovery(); return;
2627 /* -------------------------------------------------------------------- */
2629 /* And a useful default, which will never be triggered in a complete
2630 Inform compiler, but which is important in development. */
2633 error("*** Statement code gen: Can't generate yet ***\n");
2634 panic_mode_error_recovery(); return;
2637 StatementTerminator:
2640 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
2641 { ebf_error("';'", token_text);
2646 extern void parse_statement(int break_label, int continue_label)
2649 parse_statement_z(break_label, continue_label);
2651 parse_statement_g(break_label, continue_label);
2654 /* ========================================================================= */
2655 /* Data structure management routines */
2656 /* ------------------------------------------------------------------------- */
2658 extern void init_states_vars(void)
2662 extern void states_begin_pass(void)
2666 extern void states_allocate_arrays(void)
2670 extern void states_free_arrays(void)
2674 /* ========================================================================= */