Imported Upstream version 6.33.1~b2+dfsg.1
[debian_inform6.git] / src / states.c
blobe57c4980a7f73b54ceaba1024bcaf22028131842
1 /* ------------------------------------------------------------------------- */
2 /* "states" : Statement translator */
3 /* */
4 /* Part of Inform 6.33 */
5 /* copyright (c) Graham Nelson 1993 - 2014 */
6 /* */
7 /* ------------------------------------------------------------------------- */
9 #include "header.h"
11 static int match_colon(void)
12 { get_next_token();
13 if (token_type == SEP_TT)
14 { if (token_value == SEMICOLON_SEP)
15 warning("Unlike C, Inform uses ':' to divide parts \
16 of a 'for' loop specification: replacing ';' with ':'");
17 else
18 if (token_value != COLON_SEP)
19 { ebf_error("':'", token_text);
20 panic_mode_error_recovery();
21 return(FALSE);
24 else
25 { ebf_error("':'", token_text);
26 panic_mode_error_recovery();
27 return(FALSE);
29 return(TRUE);
32 static void match_open_bracket(void)
33 { get_next_token();
34 if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
35 put_token_back();
36 ebf_error("'('", token_text);
39 extern void match_close_bracket(void)
40 { get_next_token();
41 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
42 put_token_back();
43 ebf_error("')'", token_text);
46 static void parse_action(void)
47 { int level = 1, args = 0, codegen_action;
48 assembly_operand AO, AO2, AO3, AO4, AO5;
50 /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
51 or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
52 to R_Process() with those four arguments. (The latter form,
53 with double brackets, means "return true afterwards".)
55 The R_Process() function should be supplied by the library,
56 although a stub is defined in the veneer.
58 The NOUN, SECOND, and ACTOR arguments are optional. If not
59 supplied, R_Process() will be called with fewer arguments.
60 (But if you supply ACTOR, it must be preceded by a comma.
61 <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
63 To complicate life, the ACTION argument may be a bare action
64 name or a parenthesized expression. (So <Take> is equivalent
65 to <(##Take)>.) We have to peek at the first token, checking
66 whether it's an open-paren, to distinguish these cases.
68 You may ask why the ACTOR argument is last; the "natural"
69 Inform ordering would be "<floyd, take ball>". True! Sadly,
70 Inform's lexer isn't smart enough to parse this consistently,
71 so we can't do it.
74 dont_enter_into_symbol_table = TRUE;
75 get_next_token();
76 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
77 { level = 2; get_next_token();
79 dont_enter_into_symbol_table = FALSE;
81 /* Peek at the next token; see if it's an open-paren. */
82 if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
83 { put_token_back();
84 AO2 = parse_expression(ACTION_Q_CONTEXT);
85 codegen_action = TRUE;
87 else
88 { codegen_action = FALSE;
89 AO2 = action_of_name(token_text);
92 get_next_token();
93 AO3 = zero_operand;
94 AO4 = zero_operand;
95 AO5 = zero_operand;
96 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
97 { put_token_back();
98 args = 1;
99 AO3 = parse_expression(ACTION_Q_CONTEXT);
101 get_next_token();
103 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
104 { put_token_back();
105 args = 2;
106 AO4 = parse_expression(QUANTITY_CONTEXT);
107 get_next_token();
109 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
111 ebf_error("',' or '>'", token_text);
114 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
116 if (!glulx_mode && (version_number < 4))
118 error("<x, y> syntax is not available in Z-code V3 or earlier");
120 args = 3;
121 AO5 = parse_expression(QUANTITY_CONTEXT);
122 get_next_token();
123 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
125 ebf_error("'>'", token_text);
129 if (level == 2)
130 { get_next_token();
131 if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
132 { put_token_back();
133 ebf_error("'>>'", token_text);
137 if (!glulx_mode) {
139 AO = veneer_routine(R_Process_VR);
141 switch(args)
142 { case 0:
143 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
144 if (version_number>=5)
145 assemblez_2(call_2n_zc, AO, AO2);
146 else
147 if (version_number==4)
148 assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
149 else
150 assemblez_2_to(call_zc, AO, AO2, temp_var1);
151 break;
152 case 1:
153 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
154 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
155 if (version_number>=5)
156 assemblez_3(call_vn_zc, AO, AO2, AO3);
157 else
158 if (version_number==4)
159 assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
160 else
161 assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
162 break;
163 case 2:
164 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
165 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
166 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
167 if (version_number>=5)
168 assemblez_4(call_vn_zc, AO, AO2, AO3, AO4);
169 else
170 if (version_number==4)
171 assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
172 else
173 assemblez_4(call_zc, AO, AO2, AO3, AO4);
174 break;
175 case 3:
176 AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
177 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
178 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
179 if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
180 if (version_number>=5)
181 assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
182 else
183 if (version_number==4)
184 assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
185 /* if V3 or earlier, we've already displayed an error */
186 break;
187 break;
190 if (level == 2) assemblez_0(rtrue_zc);
193 else {
195 AO = veneer_routine(R_Process_VR);
197 switch (args) {
199 case 0:
200 if (codegen_action)
201 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
202 assembleg_call_1(AO, AO2, zero_operand);
203 break;
205 case 1:
206 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
207 if (codegen_action)
208 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
209 assembleg_call_2(AO, AO2, AO3, zero_operand);
210 break;
212 case 2:
213 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
214 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
215 if (codegen_action)
216 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
217 assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
218 break;
220 case 3:
221 AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
222 if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
223 assembleg_store(stack_pointer, AO5);
224 AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
225 if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
226 assembleg_store(stack_pointer, AO4);
227 AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
228 if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
229 assembleg_store(stack_pointer, AO3);
230 if (codegen_action)
231 AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
232 if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
233 assembleg_store(stack_pointer, AO2);
234 assembleg_3(call_gc, AO, four_operand, zero_operand);
235 break;
238 if (level == 2)
239 assembleg_1(return_gc, one_operand);
244 extern int parse_label(void)
246 get_next_token();
248 if ((token_type == SYMBOL_TT) &&
249 (stypes[token_value] == LABEL_T))
250 { sflags[token_value] |= USED_SFLAG;
251 return(svals[token_value]);
254 if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
255 { assign_symbol(token_value, next_label, LABEL_T);
256 define_symbol_label(token_value);
257 next_label++;
258 sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
259 return(svals[token_value]);
262 ebf_error("label name", token_text);
263 return 0;
266 static void parse_print_z(int finally_return)
267 { int count = 0; assembly_operand AO;
269 /* print <printlist> -------------------------------------------------- */
270 /* print_ret <printlist> ---------------------------------------------- */
271 /* <literal-string> --------------------------------------------------- */
272 /* */
273 /* <printlist> is a comma-separated list of items: */
274 /* */
275 /* <literal-string> */
276 /* <other-expression> */
277 /* (char) <expression> */
278 /* (address) <expression> */
279 /* (string) <expression> */
280 /* (a) <expression> */
281 /* (the) <expression> */
282 /* (The) <expression> */
283 /* (name) <expression> */
284 /* (number) <expression> */
285 /* (property) <expression> */
286 /* (<routine>) <expression> */
287 /* (object) <expression> (for use in low-level code only) */
288 /* --------------------------------------------------------------------- */
291 { AI.text = token_text;
292 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
293 switch(token_type)
294 { case DQ_TT:
295 if (strlen(token_text) > 32)
296 { AO.marker = STRING_MV;
297 AO.type = LONG_CONSTANT_OT;
298 AO.value = compile_string(token_text, FALSE, FALSE);
299 assemblez_1(print_paddr_zc, AO);
300 if (finally_return)
301 { get_next_token();
302 if ((token_type == SEP_TT)
303 && (token_value == SEMICOLON_SEP))
304 { assemblez_0(new_line_zc);
305 assemblez_0(rtrue_zc);
306 return;
308 put_token_back();
310 break;
312 if (finally_return)
313 { get_next_token();
314 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
315 { assemblez_0(print_ret_zc); return;
317 put_token_back();
319 assemblez_0(print_zc);
320 break;
322 case SEP_TT:
323 if (token_value == OPENB_SEP)
324 { misc_keywords.enabled = TRUE;
325 get_next_token();
326 get_next_token();
327 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
328 { assembly_operand AO1;
330 put_token_back(); put_token_back();
331 local_variables.enabled = FALSE;
332 get_next_token();
333 misc_keywords.enabled = FALSE;
334 local_variables.enabled = TRUE;
336 if ((token_type == STATEMENT_TT)
337 &&(token_value == STRING_CODE))
338 { token_type = MISC_KEYWORD_TT;
339 token_value = STRING_MK;
342 switch(token_type)
344 case MISC_KEYWORD_TT:
345 switch(token_value)
346 { case CHAR_MK:
347 if (runtime_error_checking_switch)
348 { AO = veneer_routine(RT__ChPrintC_VR);
349 goto PrintByRoutine;
351 get_next_token();
352 AO1 = code_generate(
353 parse_expression(QUANTITY_CONTEXT),
354 QUANTITY_CONTEXT, -1);
355 assemblez_1(print_char_zc, AO1);
356 goto PrintTermDone;
357 case ADDRESS_MK:
358 if (runtime_error_checking_switch)
359 { AO = veneer_routine(RT__ChPrintA_VR);
360 goto PrintByRoutine;
362 get_next_token();
363 AO1 = code_generate(
364 parse_expression(QUANTITY_CONTEXT),
365 QUANTITY_CONTEXT, -1);
366 assemblez_1(print_addr_zc, AO1);
367 goto PrintTermDone;
368 case STRING_MK:
369 if (runtime_error_checking_switch)
370 { AO = veneer_routine(RT__ChPrintS_VR);
371 goto PrintByRoutine;
373 get_next_token();
374 AO1 = code_generate(
375 parse_expression(QUANTITY_CONTEXT),
376 QUANTITY_CONTEXT, -1);
377 assemblez_1(print_paddr_zc, AO1);
378 goto PrintTermDone;
379 case OBJECT_MK:
380 if (runtime_error_checking_switch)
381 { AO = veneer_routine(RT__ChPrintO_VR);
382 goto PrintByRoutine;
384 get_next_token();
385 AO1 = code_generate(
386 parse_expression(QUANTITY_CONTEXT),
387 QUANTITY_CONTEXT, -1);
388 assemblez_1(print_obj_zc, AO1);
389 goto PrintTermDone;
390 case THE_MK:
391 AO = veneer_routine(DefArt_VR);
392 goto PrintByRoutine;
393 case AN_MK:
394 case A_MK:
395 AO = veneer_routine(InDefArt_VR);
396 goto PrintByRoutine;
397 case CAP_THE_MK:
398 AO = veneer_routine(CDefArt_VR);
399 goto PrintByRoutine;
400 case CAP_A_MK:
401 AO = veneer_routine(CInDefArt_VR);
402 goto PrintByRoutine;
403 case NAME_MK:
404 AO = veneer_routine(PrintShortName_VR);
405 goto PrintByRoutine;
406 case NUMBER_MK:
407 AO = veneer_routine(EnglishNumber_VR);
408 goto PrintByRoutine;
409 case PROPERTY_MK:
410 AO = veneer_routine(Print__Pname_VR);
411 goto PrintByRoutine;
412 default:
413 error_named("A reserved word was used as a print specification:",
414 token_text);
416 break;
418 case SYMBOL_TT:
419 if (sflags[token_value] & UNKNOWN_SFLAG)
420 { AO.type = LONG_CONSTANT_OT;
421 AO.value = token_value;
422 AO.marker = SYMBOL_MV;
424 else
425 { AO.type = LONG_CONSTANT_OT;
426 AO.value = svals[token_value];
427 AO.marker = IROUTINE_MV;
428 if (stypes[token_value] != ROUTINE_T)
429 ebf_error("printing routine name", token_text);
431 sflags[token_value] |= USED_SFLAG;
433 PrintByRoutine:
435 get_next_token();
436 if (version_number >= 5)
437 assemblez_2(call_2n_zc, AO,
438 code_generate(parse_expression(QUANTITY_CONTEXT),
439 QUANTITY_CONTEXT, -1));
440 else if (version_number == 4)
441 assemblez_2_to(call_vs_zc, AO,
442 code_generate(parse_expression(QUANTITY_CONTEXT),
443 QUANTITY_CONTEXT, -1), temp_var1);
444 else
445 assemblez_2_to(call_zc, AO,
446 code_generate(parse_expression(QUANTITY_CONTEXT),
447 QUANTITY_CONTEXT, -1), temp_var1);
448 goto PrintTermDone;
450 default: ebf_error("print specification", token_text);
451 get_next_token();
452 assemblez_1(print_num_zc,
453 code_generate(parse_expression(QUANTITY_CONTEXT),
454 QUANTITY_CONTEXT, -1));
455 goto PrintTermDone;
458 put_token_back(); put_token_back(); put_token_back();
459 misc_keywords.enabled = FALSE;
460 assemblez_1(print_num_zc,
461 code_generate(parse_expression(QUANTITY_CONTEXT),
462 QUANTITY_CONTEXT, -1));
463 break;
466 default:
467 put_token_back(); misc_keywords.enabled = FALSE;
468 assemblez_1(print_num_zc,
469 code_generate(parse_expression(QUANTITY_CONTEXT),
470 QUANTITY_CONTEXT, -1));
471 break;
474 PrintTermDone: misc_keywords.enabled = FALSE;
476 count++;
477 get_next_token();
478 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
479 if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
480 { ebf_error("comma", token_text);
481 panic_mode_error_recovery(); return;
483 else get_next_token();
484 } while(TRUE);
486 if (count == 0) ebf_error("something to print", token_text);
487 if (finally_return)
488 { assemblez_0(new_line_zc);
489 assemblez_0(rtrue_zc);
493 static void parse_print_g(int finally_return)
494 { int count = 0; assembly_operand AO, AO2;
496 /* print <printlist> -------------------------------------------------- */
497 /* print_ret <printlist> ---------------------------------------------- */
498 /* <literal-string> --------------------------------------------------- */
499 /* */
500 /* <printlist> is a comma-separated list of items: */
501 /* */
502 /* <literal-string> */
503 /* <other-expression> */
504 /* (char) <expression> */
505 /* (address) <expression> */
506 /* (string) <expression> */
507 /* (a) <expression> */
508 /* (A) <expression> */
509 /* (the) <expression> */
510 /* (The) <expression> */
511 /* (name) <expression> */
512 /* (number) <expression> */
513 /* (property) <expression> */
514 /* (<routine>) <expression> */
515 /* (object) <expression> (for use in low-level code only) */
516 /* --------------------------------------------------------------------- */
520 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
521 switch(token_type)
522 { case DQ_TT:
523 /* We can't compile a string into the instruction,
524 so this always goes into the string area. */
525 { AO.marker = STRING_MV;
526 AO.type = CONSTANT_OT;
527 AO.value = compile_string(token_text, FALSE, FALSE);
528 assembleg_1(streamstr_gc, AO);
529 if (finally_return)
530 { get_next_token();
531 if ((token_type == SEP_TT)
532 && (token_value == SEMICOLON_SEP))
533 { AO.type = BYTECONSTANT_OT;
534 AO.value = 0x0A; AO.marker = 0;
535 assembleg_1(streamchar_gc, AO);
536 AO.type = BYTECONSTANT_OT;
537 AO.value = 1; AO.marker = 0;
538 assembleg_1(return_gc, AO);
539 return;
541 put_token_back();
543 break;
545 break;
547 case SEP_TT:
548 if (token_value == OPENB_SEP)
549 { misc_keywords.enabled = TRUE;
550 get_next_token();
551 get_next_token();
552 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
553 { assembly_operand AO1;
554 int ln, ln2;
556 put_token_back(); put_token_back();
557 local_variables.enabled = FALSE;
558 get_next_token();
559 misc_keywords.enabled = FALSE;
560 local_variables.enabled = TRUE;
562 if ((token_type == STATEMENT_TT)
563 &&(token_value == STRING_CODE))
564 { token_type = MISC_KEYWORD_TT;
565 token_value = STRING_MK;
568 switch(token_type)
570 case MISC_KEYWORD_TT:
571 switch(token_value)
572 { case CHAR_MK:
573 if (runtime_error_checking_switch)
574 { AO = veneer_routine(RT__ChPrintC_VR);
575 goto PrintByRoutine;
577 get_next_token();
578 AO1 = code_generate(
579 parse_expression(QUANTITY_CONTEXT),
580 QUANTITY_CONTEXT, -1);
581 if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
582 { assembleg_2(stkpeek_gc, zero_operand,
583 stack_pointer);
585 AO2.type = HALFCONSTANT_OT; AO2.value = 0x100; AO2.marker = 0;
586 assembleg_2_branch(jgeu_gc, AO1, AO2,
587 ln = next_label++);
588 ln2 = next_label++;
589 assembleg_1(streamchar_gc, AO1);
590 assembleg_jump(ln2);
591 assemble_label_no(ln);
592 assembleg_1(streamunichar_gc, AO1);
593 assemble_label_no(ln2);
594 goto PrintTermDone;
595 case ADDRESS_MK:
596 if (runtime_error_checking_switch)
597 AO = veneer_routine(RT__ChPrintA_VR);
598 else
599 AO = veneer_routine(Print__Addr_VR);
600 goto PrintByRoutine;
601 case STRING_MK:
602 if (runtime_error_checking_switch)
603 { AO = veneer_routine(RT__ChPrintS_VR);
604 goto PrintByRoutine;
606 get_next_token();
607 AO1 = code_generate(
608 parse_expression(QUANTITY_CONTEXT),
609 QUANTITY_CONTEXT, -1);
610 assembleg_1(streamstr_gc, AO1);
611 goto PrintTermDone;
612 case OBJECT_MK:
613 if (runtime_error_checking_switch)
614 { AO = veneer_routine(RT__ChPrintO_VR);
615 goto PrintByRoutine;
617 get_next_token();
618 AO1 = code_generate(
619 parse_expression(QUANTITY_CONTEXT),
620 QUANTITY_CONTEXT, -1);
621 AO2.type = BYTECONSTANT_OT;
622 AO2.value = GOBJFIELD_NAME();
623 AO2.marker = 0;
624 assembleg_3(aload_gc, AO1, AO2,
625 stack_pointer);
626 assembleg_1(streamstr_gc, stack_pointer);
627 goto PrintTermDone;
628 case THE_MK:
629 AO = veneer_routine(DefArt_VR);
630 goto PrintByRoutine;
631 case AN_MK:
632 case A_MK:
633 AO = veneer_routine(InDefArt_VR);
634 goto PrintByRoutine;
635 case CAP_THE_MK:
636 AO = veneer_routine(CDefArt_VR);
637 goto PrintByRoutine;
638 case CAP_A_MK:
639 AO = veneer_routine(CInDefArt_VR);
640 goto PrintByRoutine;
641 case NAME_MK:
642 AO = veneer_routine(PrintShortName_VR);
643 goto PrintByRoutine;
644 case NUMBER_MK:
645 AO = veneer_routine(EnglishNumber_VR);
646 goto PrintByRoutine;
647 case PROPERTY_MK:
648 AO = veneer_routine(Print__Pname_VR);
649 goto PrintByRoutine;
650 default:
651 error_named("A reserved word was used as a print specification:",
652 token_text);
654 break;
656 case SYMBOL_TT:
657 if (sflags[token_value] & UNKNOWN_SFLAG)
658 { AO.type = CONSTANT_OT;
659 AO.value = token_value;
660 AO.marker = SYMBOL_MV;
662 else
663 { AO.type = CONSTANT_OT;
664 AO.value = svals[token_value];
665 AO.marker = IROUTINE_MV;
666 if (stypes[token_value] != ROUTINE_T)
667 ebf_error("printing routine name", token_text);
669 sflags[token_value] |= USED_SFLAG;
671 PrintByRoutine:
673 get_next_token();
674 AO2.type = ZEROCONSTANT_OT;
675 AO2.value = 0; AO2.marker = 0;
676 assembleg_call_1(AO,
677 code_generate(parse_expression(QUANTITY_CONTEXT),
678 QUANTITY_CONTEXT, -1),
679 AO2);
680 goto PrintTermDone;
682 default: ebf_error("print specification", token_text);
683 get_next_token();
684 assembleg_1(streamnum_gc,
685 code_generate(parse_expression(QUANTITY_CONTEXT),
686 QUANTITY_CONTEXT, -1));
687 goto PrintTermDone;
690 put_token_back(); put_token_back(); put_token_back();
691 misc_keywords.enabled = FALSE;
692 assembleg_1(streamnum_gc,
693 code_generate(parse_expression(QUANTITY_CONTEXT),
694 QUANTITY_CONTEXT, -1));
695 break;
698 default:
699 put_token_back(); misc_keywords.enabled = FALSE;
700 assembleg_1(streamnum_gc,
701 code_generate(parse_expression(QUANTITY_CONTEXT),
702 QUANTITY_CONTEXT, -1));
703 break;
706 PrintTermDone: misc_keywords.enabled = FALSE;
708 count++;
709 get_next_token();
710 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
711 if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
712 { ebf_error("comma", token_text);
713 panic_mode_error_recovery(); return;
715 else get_next_token();
716 } while(TRUE);
718 if (count == 0) ebf_error("something to print", token_text);
719 if (finally_return)
721 AO.type = BYTECONSTANT_OT; AO.value = 0x0A; AO.marker = 0;
722 assembleg_1(streamchar_gc, AO);
723 AO.type = BYTECONSTANT_OT; AO.value = 1; AO.marker = 0;
724 assembleg_1(return_gc, AO);
728 static void parse_statement_z(int break_label, int continue_label)
729 { int ln, ln2, ln3, ln4, flag;
730 assembly_operand AO, AO2, AO3, AO4;
731 debug_location spare_debug_location1, spare_debug_location2;
733 ASSERT_ZCODE();
735 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
736 { /* That is, a full stop, signifying a label */
738 get_next_token();
739 if (token_type == SYMBOL_TT)
741 if (sflags[token_value] & UNKNOWN_SFLAG)
742 { assign_symbol(token_value, next_label, LABEL_T);
743 sflags[token_value] |= USED_SFLAG;
744 assemble_label_no(next_label);
745 define_symbol_label(token_value);
746 next_label++;
748 else
749 { if (stypes[token_value] != LABEL_T) goto LabelError;
750 if (sflags[token_value] & CHANGE_SFLAG)
751 { sflags[token_value] &= (~(CHANGE_SFLAG));
752 assemble_label_no(svals[token_value]);
753 define_symbol_label(token_value);
755 else error_named("Duplicate definition of label:", token_text);
758 get_next_token();
759 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
760 { ebf_error("';'", token_text);
761 put_token_back(); return;
764 /* Interesting point of Inform grammar: a statement can only
765 consist solely of a label when it is immediately followed
766 by a "}". */
768 get_next_token();
769 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
770 { put_token_back(); return;
772 statement_debug_location = get_token_location();
773 parse_statement(break_label, continue_label);
774 return;
776 LabelError: ebf_error("label name", token_text);
779 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
780 { parse_directive(TRUE);
781 parse_statement(break_label, continue_label); return;
784 if ((token_type == SEP_TT) && (token_value == AT_SEP))
785 { parse_assembly(); return;
788 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
790 if (token_type == DQ_TT)
791 { parse_print_z(TRUE); return;
794 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
795 { parse_action(); goto StatementTerminator; }
797 if (token_type == EOF_TT)
798 { ebf_error("statement", token_text); return; }
800 if (token_type != STATEMENT_TT)
801 { put_token_back();
802 AO = parse_expression(VOID_CONTEXT);
803 code_generate(AO, VOID_CONTEXT, -1);
804 if (vivc_flag) { panic_mode_error_recovery(); return; }
805 goto StatementTerminator;
808 statements.enabled = FALSE;
810 switch(token_value)
812 /* -------------------------------------------------------------------- */
813 /* box <string-1> ... <string-n> -------------------------------------- */
814 /* -------------------------------------------------------------------- */
816 case BOX_CODE:
817 if (version_number == 3)
818 warning("The 'box' statement has no effect in a version 3 game");
819 AO3.type = LONG_CONSTANT_OT;
820 AO3.value = begin_table_array();
821 AO3.marker = ARRAY_MV;
822 ln = 0; ln2 = 0;
824 { get_next_token();
825 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
826 break;
827 if (token_type != DQ_TT)
828 ebf_error("text of box line in double-quotes",
829 token_text);
830 { int i, j;
831 for (i=0, j=0; token_text[i] != 0; j++)
832 if (token_text[i] == '@')
833 { if (token_text[i+1] == '@')
834 { i = i + 2;
835 while (isdigit(token_text[i])) i++;
837 else
838 { i++;
839 if (token_text[i] != 0) i++;
840 if (token_text[i] != 0) i++;
843 else i++;
844 if (j > ln2) ln2 = j;
846 put_token_back();
847 array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
848 } while (TRUE);
849 finish_array(ln);
850 if (ln == 0)
851 error("No lines of text given for 'box' display");
853 if (version_number == 3) return;
855 AO2.type = SHORT_CONSTANT_OT; AO2.value = ln2; AO2.marker = 0;
856 AO4.type = VARIABLE_OT; AO4.value = 255; AO4.marker = 0;
857 assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
858 AO2, AO3, AO4);
859 return;
861 /* -------------------------------------------------------------------- */
862 /* break -------------------------------------------------------------- */
863 /* -------------------------------------------------------------------- */
865 case BREAK_CODE:
866 if (break_label == -1)
867 error("'break' can only be used in a loop or 'switch' block");
868 else
869 assemblez_jump(break_label);
870 break;
872 /* -------------------------------------------------------------------- */
873 /* continue ----------------------------------------------------------- */
874 /* -------------------------------------------------------------------- */
876 case CONTINUE_CODE:
877 if (continue_label == -1)
878 error("'continue' can only be used in a loop block");
879 else
880 assemblez_jump(continue_label);
881 break;
883 /* -------------------------------------------------------------------- */
884 /* do <codeblock> until (<condition>) --------------------------------- */
885 /* -------------------------------------------------------------------- */
887 case DO_CODE:
888 assemble_label_no(ln = next_label++);
889 ln2 = next_label++; ln3 = next_label++;
890 parse_code_block(ln3, ln2, 0);
891 statements.enabled = TRUE;
892 get_next_token();
893 if ((token_type == STATEMENT_TT)
894 && (token_value == UNTIL_CODE))
895 { assemble_label_no(ln2);
896 match_open_bracket();
897 AO = parse_expression(CONDITION_CONTEXT);
898 match_close_bracket();
899 code_generate(AO, CONDITION_CONTEXT, ln);
901 else error("'do' without matching 'until'");
903 assemble_label_no(ln3);
904 break;
906 /* -------------------------------------------------------------------- */
907 /* font on/off -------------------------------------------------------- */
908 /* -------------------------------------------------------------------- */
910 case FONT_CODE:
911 misc_keywords.enabled = TRUE;
912 get_next_token();
913 misc_keywords.enabled = FALSE;
914 if ((token_type != MISC_KEYWORD_TT)
915 || ((token_value != ON_MK)
916 && (token_value != OFF_MK)))
917 { ebf_error("'on' or 'off'", token_text);
918 panic_mode_error_recovery();
919 break;
922 if (version_number >= 5)
923 { /* Use the V5 @set_font opcode, setting font 4
924 (for font off) or 1 (for font on). */
925 AO.type = SHORT_CONSTANT_OT; AO.marker = 0;
926 if (token_value == ON_MK)
927 AO.value = 1;
928 else
929 AO.value = 4;
930 assemblez_1_to(set_font_zc, AO, temp_var1);
931 break;
934 /* Set the fixed-pitch header bit. */
935 AO.type = SHORT_CONSTANT_OT;
936 AO.value = 0;
937 AO.marker = 0;
938 AO2.type = SHORT_CONSTANT_OT;
939 AO2.value = 8;
940 AO2.marker = 0;
941 AO3.type = VARIABLE_OT;
942 AO3.value = 255;
943 AO3.marker = 0;
944 assemblez_2_to(loadw_zc, AO, AO2, AO3);
946 if (token_value == ON_MK)
947 { AO4.type = LONG_CONSTANT_OT;
948 AO4.value = 0xfffd;
949 AO4.marker = 0;
950 assemblez_2_to(and_zc, AO4, AO3, AO3);
952 else
953 { AO4.type = SHORT_CONSTANT_OT;
954 AO4.value = 2;
955 AO4.marker = 0;
956 assemblez_2_to(or_zc, AO4, AO3, AO3);
959 assemblez_3(storew_zc, AO, AO2, AO3);
960 break;
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. */
973 case FOR_CODE:
974 match_open_bracket();
975 get_next_token();
977 /* Initialisation code */
979 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
980 { put_token_back();
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),
985 VOID_CONTEXT, -1);
987 get_next_token();
988 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
989 { get_next_token();
990 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
991 { assemble_label_no(ln = next_label++);
992 ln2 = next_label++;
993 parse_code_block(ln2, ln, 0);
994 sequence_point_follows = FALSE;
995 if (!execution_never_reaches_here)
996 assemblez_jump(ln);
997 assemble_label_no(ln2);
998 return;
1000 AO.type = OMITTED_OT;
1001 goto ParseUpdate;
1003 put_token_back();
1004 if (!match_colon()) break;
1007 get_next_token();
1008 AO.type = OMITTED_OT;
1009 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1010 { put_token_back();
1011 spare_debug_location1 = get_token_location();
1012 AO = parse_expression(CONDITION_CONTEXT);
1013 if (!match_colon()) break;
1015 get_next_token();
1017 ParseUpdate:
1018 AO2.type = OMITTED_OT; flag = 0;
1019 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1020 { put_token_back();
1021 spare_debug_location2 = get_token_location();
1022 AO2 = parse_expression(VOID_CONTEXT);
1023 match_close_bracket();
1024 flag = test_for_incdec(AO2);
1027 ln = next_label++;
1028 ln2 = next_label++;
1029 ln3 = next_label++;
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);
1045 else
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);
1071 if (flag != 0)
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;
1081 if (flag > 0)
1082 { AO3.type = SHORT_CONSTANT_OT;
1083 AO3.value = flag;
1084 if (module_switch
1085 && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1086 AO3.marker = VARIABLE_MV;
1087 else AO3.marker = 0;
1088 assemblez_1(inc_zc, AO3);
1090 else
1091 { AO3.type = SHORT_CONSTANT_OT;
1092 AO3.value = -flag;
1093 if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
1094 && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1095 AO3.marker = VARIABLE_MV;
1096 else AO3.marker = 0;
1097 assemblez_1(dec_zc, AO3);
1099 assemblez_jump(ln);
1101 else
1103 /* In the unoptimised case, update code is at the
1104 start of the loop block, so "continue" goes there */
1106 parse_code_block(ln3, ln, 0);
1107 if (!execution_never_reaches_here)
1108 { sequence_point_follows = FALSE;
1109 assemblez_jump(ln);
1113 assemble_label_no(ln3);
1114 return;
1116 /* -------------------------------------------------------------------- */
1117 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
1118 /* -------------------------------------------------------------------- */
1120 case GIVE_CODE:
1121 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1122 QUANTITY_CONTEXT, -1);
1123 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1124 { AO.value = 252;
1125 AO.marker = 0;
1126 AO.type = SHORT_CONSTANT_OT;
1127 if (version_number != 6) assemblez_1(pull_zc, AO);
1128 else assemblez_0_to(pull_zc, AO);
1129 AO.type = VARIABLE_OT;
1133 { get_next_token();
1134 if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
1135 return;
1136 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
1137 ln = clear_attr_zc;
1138 else
1139 { if ((token_type == SYMBOL_TT)
1140 && (stypes[token_value] != ATTRIBUTE_T))
1141 warning_named("This is not a declared Attribute:",
1142 token_text);
1143 ln = set_attr_zc;
1144 put_token_back();
1146 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1147 QUANTITY_CONTEXT, -1);
1148 if (runtime_error_checking_switch)
1149 { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
1150 if (version_number >= 5)
1151 assemblez_3(call_vn_zc, veneer_routine(ln2),
1152 AO, AO2);
1153 else
1155 assemblez_3_to(call_zc, veneer_routine(ln2),
1156 AO, AO2, temp_var1);
1159 else
1160 assemblez_2(ln, AO, AO2);
1161 } while(TRUE);
1163 /* -------------------------------------------------------------------- */
1164 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
1165 /* -------------------------------------------------------------------- */
1167 case IF_CODE:
1168 flag = FALSE;
1170 match_open_bracket();
1171 AO = parse_expression(CONDITION_CONTEXT);
1172 match_close_bracket();
1174 statements.enabled = TRUE;
1175 get_next_token();
1176 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
1177 ln = -4;
1178 else
1179 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
1180 ln = -3;
1181 else
1182 { put_token_back();
1183 ln = next_label++;
1186 code_generate(AO, CONDITION_CONTEXT, ln);
1188 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
1189 else
1190 { get_next_token();
1191 if ((token_type != SEP_TT)
1192 || (token_value != SEMICOLON_SEP))
1193 { ebf_error("';'", token_text);
1194 put_token_back();
1198 statements.enabled = TRUE;
1199 get_next_token();
1200 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
1201 { flag = TRUE;
1202 if (ln >= 0)
1203 { ln2 = next_label++;
1204 if (!execution_never_reaches_here)
1205 { sequence_point_follows = FALSE;
1206 assemblez_jump(ln2);
1210 else put_token_back();
1212 if (ln >= 0) assemble_label_no(ln);
1214 if (flag)
1215 { parse_code_block(break_label, continue_label, 0);
1216 if (ln >= 0) assemble_label_no(ln2);
1219 return;
1221 /* -------------------------------------------------------------------- */
1222 /* inversion ---------------------------------------------------------- */
1223 /* -------------------------------------------------------------------- */
1225 case INVERSION_CODE:
1226 AO.marker = 0;
1227 AO.type = SHORT_CONSTANT_OT;
1228 AO.value = 0;
1230 AO2.marker = 0;
1231 AO2.type = SHORT_CONSTANT_OT;
1233 AO2.value = 60;
1234 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1235 assemblez_1(print_char_zc, temp_var1);
1236 AO2.value = 61;
1237 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1238 assemblez_1(print_char_zc, temp_var1);
1239 AO2.value = 62;
1240 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1241 assemblez_1(print_char_zc, temp_var1);
1242 AO2.value = 63;
1243 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1244 assemblez_1(print_char_zc, temp_var1);
1245 break;
1247 /* -------------------------------------------------------------------- */
1248 /* jump <label> ------------------------------------------------------- */
1249 /* -------------------------------------------------------------------- */
1251 case JUMP_CODE:
1252 assemblez_jump(parse_label());
1253 break;
1255 /* -------------------------------------------------------------------- */
1256 /* move <expression> to <expression> ---------------------------------- */
1257 /* -------------------------------------------------------------------- */
1259 case MOVE_CODE:
1260 misc_keywords.enabled = TRUE;
1261 AO = parse_expression(QUANTITY_CONTEXT);
1263 get_next_token();
1264 misc_keywords.enabled = FALSE;
1265 if ((token_type != MISC_KEYWORD_TT)
1266 || (token_value != TO_MK))
1267 { ebf_error("'to'", token_text);
1268 panic_mode_error_recovery();
1269 return;
1272 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1273 QUANTITY_CONTEXT, -1);
1274 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
1275 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1276 { if (version_number >= 5)
1277 assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
1278 AO, AO2);
1279 else
1280 { assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
1281 AO, AO2, temp_var1);
1284 else
1285 assemblez_2(insert_obj_zc, AO, AO2);
1286 break;
1288 /* -------------------------------------------------------------------- */
1289 /* new_line ----------------------------------------------------------- */
1290 /* -------------------------------------------------------------------- */
1292 case NEW_LINE_CODE: assemblez_0(new_line_zc); break;
1294 /* -------------------------------------------------------------------- */
1295 /* objectloop (<initialisation>) <codeblock> -------------------------- */
1296 /* -------------------------------------------------------------------- */
1298 case OBJECTLOOP_CODE:
1300 match_open_bracket();
1301 get_next_token();
1302 if (token_type == LOCAL_VARIABLE_TT)
1303 AO.value = token_value;
1304 else
1305 if ((token_type == SYMBOL_TT) &&
1306 (stypes[token_value] == GLOBAL_VARIABLE_T))
1307 AO.value = svals[token_value];
1308 else
1309 { ebf_error("'objectloop' variable", token_text);
1310 panic_mode_error_recovery(); break;
1312 AO.type = VARIABLE_OT;
1313 if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
1314 && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
1315 AO.marker = VARIABLE_MV;
1316 else AO.marker = 0;
1317 misc_keywords.enabled = TRUE;
1318 get_next_token(); flag = TRUE;
1319 misc_keywords.enabled = FALSE;
1320 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1321 flag = FALSE;
1323 ln = 0;
1324 if ((token_type == MISC_KEYWORD_TT)
1325 && (token_value == NEAR_MK)) ln = 1;
1326 if ((token_type == MISC_KEYWORD_TT)
1327 && (token_value == FROM_MK)) ln = 2;
1328 if ((token_type == CND_TT) && (token_value == IN_COND))
1329 { get_next_token();
1330 get_next_token();
1331 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1332 ln = 3;
1333 put_token_back();
1334 put_token_back();
1337 if (ln > 0)
1338 { /* Old style (Inform 5) objectloops: note that we
1339 implement objectloop (a in b) in the old way since
1340 this runs through objects in a different order from
1341 the new way, and there may be existing Inform code
1342 relying on this. */
1343 assembly_operand AO4;
1345 sequence_point_follows = TRUE;
1346 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1347 QUANTITY_CONTEXT, -1);
1348 match_close_bracket();
1349 if (ln == 1)
1350 { AO3.type = VARIABLE_OT; AO3.value = 0; AO3.marker = 0;
1351 if (runtime_error_checking_switch)
1352 AO2 = check_nonzero_at_runtime(AO2, -1,
1353 OBJECTLOOP_RTE);
1354 assemblez_1_to(get_parent_zc, AO2, AO3);
1355 assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
1356 AO2 = AO3;
1358 if (ln == 3)
1359 { AO3.type = VARIABLE_OT; AO3.value = 0; AO3.marker = 0;
1360 if (runtime_error_checking_switch)
1361 { AO4 = AO2;
1362 AO2 = check_nonzero_at_runtime(AO2, -1,
1363 CHILD_RTE);
1365 assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
1366 AO2 = AO3;
1368 assemblez_store(AO, AO2);
1369 assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
1370 assemble_label_no(ln4 = next_label++);
1371 parse_code_block(ln2, ln3 = next_label++, 0);
1372 sequence_point_follows = FALSE;
1373 assemble_label_no(ln3);
1374 if (runtime_error_checking_switch)
1375 { AO2 = check_nonzero_at_runtime(AO, ln2,
1376 OBJECTLOOP2_RTE);
1377 if ((ln == 3)
1378 && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
1379 && ((AO4.type != VARIABLE_OT)
1380 ||(AO4.value != AO.value)))
1381 { assembly_operand en_ao;
1382 en_ao.value = OBJECTLOOP_BROKEN_RTE;
1383 en_ao.marker = 0;
1384 en_ao.type = SHORT_CONSTANT_OT;
1385 assemblez_2_branch(jin_zc, AO, AO4,
1386 next_label, TRUE);
1387 assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
1388 en_ao, AO);
1389 assemblez_jump(ln2);
1390 assemble_label_no(next_label++);
1393 else AO2 = AO;
1394 assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
1395 assemble_label_no(ln2);
1396 return;
1399 sequence_point_follows = TRUE;
1400 AO2.type = SHORT_CONSTANT_OT; AO2.value = 1; AO2.marker = 0;
1401 assemblez_store(AO, AO2);
1403 assemble_label_no(ln = next_label++);
1404 ln2 = next_label++;
1405 ln3 = next_label++;
1406 if (flag)
1407 { put_token_back();
1408 put_token_back();
1409 sequence_point_follows = TRUE;
1410 code_generate(parse_expression(CONDITION_CONTEXT),
1411 CONDITION_CONTEXT, ln3);
1412 match_close_bracket();
1414 parse_code_block(ln2, ln3, 0);
1416 sequence_point_follows = FALSE;
1417 assemble_label_no(ln3);
1418 assemblez_inc(AO);
1419 AO2.type = LONG_CONSTANT_OT; AO2.value = no_objects;
1420 AO2.marker = NO_OBJS_MV;
1421 assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
1422 assemblez_jump(ln);
1423 assemble_label_no(ln2);
1424 return;
1426 /* -------------------------------------------------------------------- */
1427 /* (see routine above) ------------------------------------------------ */
1428 /* -------------------------------------------------------------------- */
1430 case PRINT_CODE:
1431 get_next_token();
1432 parse_print_z(FALSE); return;
1433 case PRINT_RET_CODE:
1434 get_next_token();
1435 parse_print_z(TRUE); return;
1437 /* -------------------------------------------------------------------- */
1438 /* quit --------------------------------------------------------------- */
1439 /* -------------------------------------------------------------------- */
1441 case QUIT_CODE: assemblez_0(quit_zc); break;
1443 /* -------------------------------------------------------------------- */
1444 /* read <expression> <expression> [<Routine>] ------------------------- */
1445 /* -------------------------------------------------------------------- */
1447 case READ_CODE:
1448 AO.type = VARIABLE_OT; AO.value = 252; AO.marker = 0;
1449 assemblez_store(AO,
1450 code_generate(parse_expression(QUANTITY_CONTEXT),
1451 QUANTITY_CONTEXT, -1));
1452 if (version_number > 3)
1453 { AO3.type = SHORT_CONSTANT_OT; AO3.value = 1;AO3.marker = 0;
1454 AO4.type = SHORT_CONSTANT_OT; AO4.value = 0;AO4.marker = 0;
1455 assemblez_3(storeb_zc, AO, AO3, AO4);
1457 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1458 QUANTITY_CONTEXT, -1);
1460 get_next_token();
1461 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1462 put_token_back();
1463 else
1464 { if (version_number == 3)
1465 error(
1466 "In Version 3 no status-line drawing routine can be given");
1467 else
1468 { assembly_operand AO5;
1469 /* Move the temp4 (buffer) value to the stack,
1470 since the routine might alter temp4. */
1471 assemblez_store(stack_pointer, AO);
1472 AO = stack_pointer;
1473 put_token_back();
1474 AO5 = parse_expression(CONSTANT_CONTEXT);
1476 if (version_number >= 5)
1477 assemblez_1(call_1n_zc, AO5);
1478 else
1479 assemblez_1_to(call_zc, AO5, temp_var1);
1483 if (version_number > 4)
1484 { assemblez_2_to(aread_zc, AO, AO2, temp_var1);
1486 else assemblez_2(sread_zc, AO, AO2);
1487 break;
1489 /* -------------------------------------------------------------------- */
1490 /* remove <expression> ------------------------------------------------ */
1491 /* -------------------------------------------------------------------- */
1493 case REMOVE_CODE:
1494 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1495 QUANTITY_CONTEXT, -1);
1496 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1497 { if (version_number >= 5)
1498 assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
1499 AO);
1500 else
1501 { assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
1502 AO, temp_var1);
1505 else
1506 assemblez_1(remove_obj_zc, AO);
1507 break;
1509 /* -------------------------------------------------------------------- */
1510 /* restore <label> ---------------------------------------------------- */
1511 /* -------------------------------------------------------------------- */
1513 case RESTORE_CODE:
1514 if (version_number < 5)
1515 assemblez_0_branch(restore_zc, parse_label(), TRUE);
1516 else
1517 { AO2.type = SHORT_CONSTANT_OT; AO2.value = 2;
1518 AO2.marker = 0;
1519 assemblez_0_to(restore_zc, temp_var1);
1520 assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
1522 break;
1524 /* -------------------------------------------------------------------- */
1525 /* return [<expression>] ---------------------------------------------- */
1526 /* -------------------------------------------------------------------- */
1528 case RETURN_CODE:
1529 get_next_token();
1530 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1531 { assemblez_0(rtrue_zc); return; }
1532 put_token_back();
1533 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
1534 QUANTITY_CONTEXT, -1);
1535 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
1536 && (AO.marker == 0))
1537 { assemblez_0(rfalse_zc); break; }
1538 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
1539 && (AO.marker == 0))
1540 { assemblez_0(rtrue_zc); break; }
1541 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1542 { assemblez_0(ret_popped_zc); break; }
1543 assemblez_1(ret_zc, AO);
1544 break;
1546 /* -------------------------------------------------------------------- */
1547 /* rfalse ------------------------------------------------------------- */
1548 /* -------------------------------------------------------------------- */
1550 case RFALSE_CODE: assemblez_0(rfalse_zc); break;
1552 /* -------------------------------------------------------------------- */
1553 /* rtrue -------------------------------------------------------------- */
1554 /* -------------------------------------------------------------------- */
1556 case RTRUE_CODE: assemblez_0(rtrue_zc); break;
1558 /* -------------------------------------------------------------------- */
1559 /* save <label> ------------------------------------------------------- */
1560 /* -------------------------------------------------------------------- */
1562 case SAVE_CODE:
1563 if (version_number < 5)
1564 assemblez_0_branch(save_zc, parse_label(), TRUE);
1565 else
1566 { AO.type = VARIABLE_OT; AO.value = 255; AO.marker = 0;
1567 assemblez_0_to(save_zc, AO);
1568 assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
1570 break;
1572 /* -------------------------------------------------------------------- */
1573 /* spaces <expression> ------------------------------------------------ */
1574 /* -------------------------------------------------------------------- */
1576 case SPACES_CODE:
1577 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1578 QUANTITY_CONTEXT, -1);
1579 AO2.type = VARIABLE_OT; AO2.value = 255; AO2.marker = 0;
1581 assemblez_store(AO2, AO);
1583 AO.type = SHORT_CONSTANT_OT; AO.value = 32; AO.marker = 0;
1584 AO3.type = SHORT_CONSTANT_OT; AO3.value = 1; AO3.marker = 0;
1586 assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
1587 assemble_label_no(ln2 = next_label++);
1588 assemblez_1(print_char_zc, AO);
1589 assemblez_dec(AO2);
1590 assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
1591 assemble_label_no(ln);
1592 break;
1594 /* -------------------------------------------------------------------- */
1595 /* string <expression> <literal-string> ------------------------------- */
1596 /* -------------------------------------------------------------------- */
1598 case STRING_CODE:
1599 AO.type = SHORT_CONSTANT_OT; AO.value = 0; AO.marker = 0;
1600 AO2.type = SHORT_CONSTANT_OT; AO2.value = 12; AO2.marker = 0;
1601 AO3.type = VARIABLE_OT; AO3.value = 252; AO3.marker = 0;
1602 assemblez_2_to(loadw_zc, AO, AO2, AO3);
1603 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1604 QUANTITY_CONTEXT, -1);
1605 get_next_token();
1606 if (token_type == DQ_TT)
1607 { AO4.value = compile_string(token_text, TRUE, TRUE);
1608 AO4.marker = 0;
1609 AO4.type = LONG_CONSTANT_OT;
1611 else
1612 { put_token_back();
1613 AO4 = parse_expression(CONSTANT_CONTEXT);
1615 assemblez_3(storew_zc, AO3, AO2, AO4);
1616 break;
1618 /* -------------------------------------------------------------------- */
1619 /* style roman/reverse/bold/underline/fixed --------------------------- */
1620 /* -------------------------------------------------------------------- */
1622 case STYLE_CODE:
1623 if (version_number==3)
1624 { error(
1625 "The 'style' statement cannot be used for Version 3 games");
1626 panic_mode_error_recovery();
1627 break;
1630 misc_keywords.enabled = TRUE;
1631 get_next_token();
1632 misc_keywords.enabled = FALSE;
1633 if ((token_type != MISC_KEYWORD_TT)
1634 || ((token_value != ROMAN_MK)
1635 && (token_value != REVERSE_MK)
1636 && (token_value != BOLD_MK)
1637 && (token_value != UNDERLINE_MK)
1638 && (token_value != FIXED_MK)))
1639 { ebf_error(
1640 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1641 token_text);
1642 panic_mode_error_recovery();
1643 break;
1646 AO.type = SHORT_CONSTANT_OT; AO.marker = 0;
1647 switch(token_value)
1648 { case ROMAN_MK: AO.value = 0; break;
1649 case REVERSE_MK: AO.value = 1; break;
1650 case BOLD_MK: AO.value = 2; break;
1651 case UNDERLINE_MK: AO.value = 4; break;
1652 case FIXED_MK: AO.value = 8; break;
1654 assemblez_1(set_text_style_zc, AO); break;
1656 /* -------------------------------------------------------------------- */
1657 /* switch (<expression>) <codeblock> ---------------------------------- */
1658 /* -------------------------------------------------------------------- */
1660 case SWITCH_CODE:
1661 match_open_bracket();
1662 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1663 QUANTITY_CONTEXT, -1);
1664 match_close_bracket();
1666 AO2.type = VARIABLE_OT; AO2.value = 255; AO2.marker = 0;
1667 assemblez_store(AO2, AO);
1669 parse_code_block(ln = next_label++, continue_label, 1);
1670 assemble_label_no(ln);
1671 return;
1673 /* -------------------------------------------------------------------- */
1674 /* while (<condition>) <codeblock> ------------------------------------ */
1675 /* -------------------------------------------------------------------- */
1677 case WHILE_CODE:
1678 assemble_label_no(ln = next_label++);
1679 match_open_bracket();
1681 code_generate(parse_expression(CONDITION_CONTEXT),
1682 CONDITION_CONTEXT, ln2 = next_label++);
1683 match_close_bracket();
1685 parse_code_block(ln2, ln, 0);
1686 sequence_point_follows = FALSE;
1687 assemblez_jump(ln);
1688 assemble_label_no(ln2);
1689 return;
1691 /* -------------------------------------------------------------------- */
1693 case SDEFAULT_CODE:
1694 error("'default' without matching 'switch'"); break;
1695 case ELSE_CODE:
1696 error("'else' without matching 'if'"); break;
1697 case UNTIL_CODE:
1698 error("'until' without matching 'do'");
1699 panic_mode_error_recovery(); return;
1702 StatementTerminator:
1704 get_next_token();
1705 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1706 { ebf_error("';'", token_text);
1707 put_token_back();
1711 static void parse_statement_g(int break_label, int continue_label)
1712 { int ln, ln2, ln3, ln4, flag, onstack;
1713 assembly_operand AO, AO2, AO3, AO4;
1714 debug_location spare_debug_location1, spare_debug_location2;
1716 ASSERT_GLULX();
1718 if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
1719 { /* That is, a full stop, signifying a label */
1721 get_next_token();
1722 if (token_type == SYMBOL_TT)
1724 if (sflags[token_value] & UNKNOWN_SFLAG)
1725 { assign_symbol(token_value, next_label, LABEL_T);
1726 sflags[token_value] |= USED_SFLAG;
1727 assemble_label_no(next_label);
1728 define_symbol_label(token_value);
1729 next_label++;
1731 else
1732 { if (stypes[token_value] != LABEL_T) goto LabelError;
1733 if (sflags[token_value] & CHANGE_SFLAG)
1734 { sflags[token_value] &= (~(CHANGE_SFLAG));
1735 assemble_label_no(svals[token_value]);
1736 define_symbol_label(token_value);
1738 else error_named("Duplicate definition of label:", token_text);
1741 get_next_token();
1742 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1743 { ebf_error("';'", token_text);
1744 put_token_back(); return;
1747 /* Interesting point of Inform grammar: a statement can only
1748 consist solely of a label when it is immediately followed
1749 by a "}". */
1751 get_next_token();
1752 if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
1753 { put_token_back(); return;
1755 /* The following line prevents labels from influencing the positions
1756 of sequence points. */
1757 statement_debug_location = get_token_location();
1758 parse_statement(break_label, continue_label);
1759 return;
1761 LabelError: ebf_error("label name", token_text);
1764 if ((token_type == SEP_TT) && (token_value == HASH_SEP))
1765 { parse_directive(TRUE);
1766 parse_statement(break_label, continue_label); return;
1769 if ((token_type == SEP_TT) && (token_value == AT_SEP))
1770 { parse_assembly(); return;
1773 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
1775 if (token_type == DQ_TT)
1776 { parse_print_g(TRUE); return;
1779 if ((token_type == SEP_TT) && (token_value == LESS_SEP))
1780 { parse_action(); goto StatementTerminator; }
1782 if (token_type == EOF_TT)
1783 { ebf_error("statement", token_text); return; }
1785 if (token_type != STATEMENT_TT)
1786 { put_token_back();
1787 AO = parse_expression(VOID_CONTEXT);
1788 code_generate(AO, VOID_CONTEXT, -1);
1789 if (vivc_flag) { panic_mode_error_recovery(); return; }
1790 goto StatementTerminator;
1793 statements.enabled = FALSE;
1795 switch(token_value)
1798 /* -------------------------------------------------------------------- */
1799 /* box <string-1> ... <string-n> -------------------------------------- */
1800 /* -------------------------------------------------------------------- */
1802 case BOX_CODE:
1803 AO3.type = CONSTANT_OT;
1804 AO3.value = begin_table_array();
1805 AO3.marker = ARRAY_MV;
1806 ln = 0; ln2 = 0;
1808 { get_next_token();
1809 if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
1810 break;
1811 if (token_type != DQ_TT)
1812 ebf_error("text of box line in double-quotes",
1813 token_text);
1814 { int i, j;
1815 for (i=0, j=0; token_text[i] != 0; j++)
1816 if (token_text[i] == '@')
1817 { if (token_text[i+1] == '@')
1818 { i = i + 2;
1819 while (isdigit(token_text[i])) i++;
1821 else
1822 { i++;
1823 if (token_text[i] != 0) i++;
1824 if (token_text[i] != 0) i++;
1827 else i++;
1828 if (j > ln2) ln2 = j;
1830 put_token_back();
1831 array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
1832 } while (TRUE);
1833 finish_array(ln);
1834 if (ln == 0)
1835 error("No lines of text given for 'box' display");
1837 AO2.value = ln2; AO2.marker = 0; set_constant_ot(&AO2);
1838 assembleg_call_2(veneer_routine(Box__Routine_VR),
1839 AO2, AO3, zero_operand);
1840 return;
1842 /* -------------------------------------------------------------------- */
1843 /* break -------------------------------------------------------------- */
1844 /* -------------------------------------------------------------------- */
1846 case BREAK_CODE:
1847 if (break_label == -1)
1848 error("'break' can only be used in a loop or 'switch' block");
1849 else
1850 assembleg_jump(break_label);
1851 break;
1853 /* -------------------------------------------------------------------- */
1854 /* continue ----------------------------------------------------------- */
1855 /* -------------------------------------------------------------------- */
1857 case CONTINUE_CODE:
1858 if (continue_label == -1)
1859 error("'continue' can only be used in a loop block");
1860 else
1861 assembleg_jump(continue_label);
1862 break;
1864 /* -------------------------------------------------------------------- */
1865 /* do <codeblock> until (<condition>) --------------------------------- */
1866 /* -------------------------------------------------------------------- */
1868 case DO_CODE:
1869 assemble_label_no(ln = next_label++);
1870 ln2 = next_label++; ln3 = next_label++;
1871 parse_code_block(ln3, ln2, 0);
1872 statements.enabled = TRUE;
1873 get_next_token();
1874 if ((token_type == STATEMENT_TT)
1875 && (token_value == UNTIL_CODE))
1876 { assemble_label_no(ln2);
1877 match_open_bracket();
1878 AO = parse_expression(CONDITION_CONTEXT);
1879 match_close_bracket();
1880 code_generate(AO, CONDITION_CONTEXT, ln);
1882 else error("'do' without matching 'until'");
1884 assemble_label_no(ln3);
1885 break;
1887 /* -------------------------------------------------------------------- */
1888 /* font on/off -------------------------------------------------------- */
1889 /* -------------------------------------------------------------------- */
1891 case FONT_CODE:
1892 misc_keywords.enabled = TRUE;
1893 get_next_token();
1894 misc_keywords.enabled = FALSE;
1895 if ((token_type != MISC_KEYWORD_TT)
1896 || ((token_value != ON_MK)
1897 && (token_value != OFF_MK)))
1898 { ebf_error("'on' or 'off'", token_text);
1899 panic_mode_error_recovery();
1900 break;
1903 /* Call glk_set_style(normal or preformatted) */
1904 AO.value = 0x0086;
1905 AO.marker = 0;
1906 set_constant_ot(&AO);
1907 if (token_value == ON_MK)
1908 AO2 = zero_operand;
1909 else
1910 AO2 = two_operand;
1911 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
1912 AO, AO2, zero_operand);
1913 break;
1915 /* -------------------------------------------------------------------- */
1916 /* for (<initialisation> : <continue-condition> : <updating>) --------- */
1917 /* -------------------------------------------------------------------- */
1919 /* Note that it's legal for any or all of the three sections of a
1920 'for' specification to be empty. This 'for' implementation
1921 often wastes 3 bytes with a redundant branch rather than keep
1922 expression parse trees for long periods (as previous versions
1923 of Inform did, somewhat crudely by simply storing the textual
1924 form of a 'for' loop). It is adequate for now. */
1926 case FOR_CODE:
1927 match_open_bracket();
1928 get_next_token();
1930 /* Initialisation code */
1932 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1933 { put_token_back();
1934 if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
1935 { sequence_point_follows = TRUE;
1936 statement_debug_location = get_token_location();
1937 code_generate(parse_expression(FORINIT_CONTEXT),
1938 VOID_CONTEXT, -1);
1940 get_next_token();
1941 if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
1942 { get_next_token();
1943 if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
1944 { assemble_label_no(ln = next_label++);
1945 ln2 = next_label++;
1946 parse_code_block(ln2, ln, 0);
1947 sequence_point_follows = FALSE;
1948 if (!execution_never_reaches_here)
1949 assembleg_jump(ln);
1950 assemble_label_no(ln2);
1951 return;
1953 AO.type = OMITTED_OT;
1954 goto ParseUpdate;
1956 put_token_back();
1957 if (!match_colon()) break;
1960 get_next_token();
1961 AO.type = OMITTED_OT;
1962 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1963 { put_token_back();
1964 spare_debug_location1 = get_token_location();
1965 AO = parse_expression(CONDITION_CONTEXT);
1966 if (!match_colon()) break;
1968 get_next_token();
1970 ParseUpdate:
1971 AO2.type = OMITTED_OT; flag = 0;
1972 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1973 { put_token_back();
1974 spare_debug_location2 = get_token_location();
1975 AO2 = parse_expression(VOID_CONTEXT);
1976 match_close_bracket();
1977 flag = test_for_incdec(AO2);
1980 ln = next_label++;
1981 ln2 = next_label++;
1982 ln3 = next_label++;
1984 if ((AO2.type == OMITTED_OT) || (flag != 0))
1986 assemble_label_no(ln);
1987 if (flag==0) assemble_label_no(ln2);
1989 /* The "finished yet?" condition */
1991 if (AO.type != OMITTED_OT)
1992 { sequence_point_follows = TRUE;
1993 statement_debug_location = spare_debug_location1;
1994 code_generate(AO, CONDITION_CONTEXT, ln3);
1998 else
2000 /* This is the jump which could be avoided with the aid
2001 of long-term expression storage */
2003 sequence_point_follows = FALSE;
2004 assembleg_jump(ln2);
2006 /* The "update" part */
2008 assemble_label_no(ln);
2009 sequence_point_follows = TRUE;
2010 statement_debug_location = spare_debug_location2;
2011 code_generate(AO2, VOID_CONTEXT, -1);
2013 assemble_label_no(ln2);
2015 /* The "finished yet?" condition */
2017 if (AO.type != OMITTED_OT)
2018 { sequence_point_follows = TRUE;
2019 statement_debug_location = spare_debug_location1;
2020 code_generate(AO, CONDITION_CONTEXT, ln3);
2024 if (flag != 0)
2026 /* In this optimised case, update code is at the end
2027 of the loop block, so "continue" goes there */
2029 parse_code_block(ln3, ln2, 0);
2030 assemble_label_no(ln2);
2032 sequence_point_follows = TRUE;
2033 statement_debug_location = spare_debug_location2;
2034 if (flag > 0)
2035 { AO3.value = flag;
2036 if (AO3.value >= MAX_LOCAL_VARIABLES)
2037 AO3.type = GLOBALVAR_OT;
2038 else
2039 AO3.type = LOCALVAR_OT;
2040 AO3.marker = 0;
2041 assembleg_3(add_gc, AO3, one_operand, AO3);
2043 else
2044 { AO3.value = -flag;
2045 if (AO3.value >= MAX_LOCAL_VARIABLES)
2046 AO3.type = GLOBALVAR_OT;
2047 else
2048 AO3.type = LOCALVAR_OT;
2049 AO3.marker = 0;
2050 assembleg_3(sub_gc, AO3, one_operand, AO3);
2052 assembleg_jump(ln);
2054 else
2056 /* In the unoptimised case, update code is at the
2057 start of the loop block, so "continue" goes there */
2059 parse_code_block(ln3, ln, 0);
2060 if (!execution_never_reaches_here)
2061 { sequence_point_follows = FALSE;
2062 assembleg_jump(ln);
2066 assemble_label_no(ln3);
2067 return;
2069 /* -------------------------------------------------------------------- */
2070 /* give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2071 /* -------------------------------------------------------------------- */
2073 case GIVE_CODE:
2074 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2075 QUANTITY_CONTEXT, -1);
2076 if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
2077 onstack = TRUE;
2078 else
2079 onstack = FALSE;
2082 { get_next_token();
2083 if ((token_type == SEP_TT)
2084 && (token_value == SEMICOLON_SEP)) {
2085 if (onstack) {
2086 assembleg_2(copy_gc, stack_pointer, zero_operand);
2088 return;
2090 if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
2091 ln = 0;
2092 else
2093 { if ((token_type == SYMBOL_TT)
2094 && (stypes[token_value] != ATTRIBUTE_T))
2095 warning_named("This is not a declared Attribute:",
2096 token_text);
2097 ln = 1;
2098 put_token_back();
2100 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2101 QUANTITY_CONTEXT, -1);
2102 if (runtime_error_checking_switch && (!veneer_mode))
2103 { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
2104 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
2105 /* already on stack */
2107 else {
2108 assembleg_store(stack_pointer, AO2);
2110 if (onstack)
2111 assembleg_2(stkpeek_gc, one_operand, stack_pointer);
2112 else
2113 assembleg_store(stack_pointer, AO);
2114 assembleg_3(call_gc, veneer_routine(ln2), two_operand,
2115 zero_operand);
2117 else {
2118 if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2119 AO2.value += 8;
2120 set_constant_ot(&AO2);
2122 else {
2123 AO3.value = 8;
2124 AO3.marker = 0;
2125 AO3.type = BYTECONSTANT_OT;
2126 assembleg_3(add_gc, AO2, AO3, stack_pointer);
2127 AO2 = stack_pointer;
2129 if (onstack) {
2130 if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
2131 assembleg_2(stkpeek_gc, one_operand,
2132 stack_pointer);
2133 else
2134 assembleg_2(stkpeek_gc, zero_operand,
2135 stack_pointer);
2137 if (ln)
2138 AO3 = one_operand;
2139 else
2140 AO3 = zero_operand;
2141 assembleg_3(astorebit_gc, AO, AO2, AO3);
2143 } while(TRUE);
2145 /* -------------------------------------------------------------------- */
2146 /* if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2147 /* -------------------------------------------------------------------- */
2149 case IF_CODE:
2150 flag = FALSE;
2152 match_open_bracket();
2153 AO = parse_expression(CONDITION_CONTEXT);
2154 match_close_bracket();
2156 statements.enabled = TRUE;
2157 get_next_token();
2158 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
2159 ln = -4;
2160 else
2161 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
2162 ln = -3;
2163 else
2164 { put_token_back();
2165 ln = next_label++;
2168 code_generate(AO, CONDITION_CONTEXT, ln);
2170 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
2171 else
2172 { get_next_token();
2173 if ((token_type != SEP_TT)
2174 || (token_value != SEMICOLON_SEP))
2175 { ebf_error("';'", token_text);
2176 put_token_back();
2180 statements.enabled = TRUE;
2181 get_next_token();
2182 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
2183 { flag = TRUE;
2184 if (ln >= 0)
2185 { ln2 = next_label++;
2186 if (!execution_never_reaches_here)
2187 { sequence_point_follows = FALSE;
2188 assembleg_jump(ln2);
2192 else put_token_back();
2194 if (ln >= 0) assemble_label_no(ln);
2196 if (flag)
2197 { parse_code_block(break_label, continue_label, 0);
2198 if (ln >= 0) assemble_label_no(ln2);
2201 return;
2203 /* -------------------------------------------------------------------- */
2204 /* inversion ---------------------------------------------------------- */
2205 /* -------------------------------------------------------------------- */
2207 case INVERSION_CODE:
2208 AO2.marker = 0;
2209 AO2.type = DEREFERENCE_OT;
2210 AO2.value = GLULX_HEADER_SIZE+8;
2211 assembleg_2(copyb_gc, AO2, stack_pointer);
2212 assembleg_1(streamchar_gc, stack_pointer);
2213 AO2.value = GLULX_HEADER_SIZE+9;
2214 assembleg_2(copyb_gc, AO2, stack_pointer);
2215 assembleg_1(streamchar_gc, stack_pointer);
2216 AO2.value = GLULX_HEADER_SIZE+10;
2217 assembleg_2(copyb_gc, AO2, stack_pointer);
2218 assembleg_1(streamchar_gc, stack_pointer);
2219 AO2.value = GLULX_HEADER_SIZE+11;
2220 assembleg_2(copyb_gc, AO2, stack_pointer);
2221 assembleg_1(streamchar_gc, stack_pointer);
2223 if (0) {
2224 AO.marker = 0;
2225 AO.value = '(';
2226 set_constant_ot(&AO);
2227 assembleg_1(streamchar_gc, AO);
2228 AO.value = 'G';
2229 set_constant_ot(&AO);
2230 assembleg_1(streamchar_gc, AO);
2232 AO2.value = GLULX_HEADER_SIZE+12;
2233 assembleg_2(copyb_gc, AO2, stack_pointer);
2234 assembleg_1(streamchar_gc, stack_pointer);
2235 AO2.value = GLULX_HEADER_SIZE+13;
2236 assembleg_2(copyb_gc, AO2, stack_pointer);
2237 assembleg_1(streamchar_gc, stack_pointer);
2238 AO2.value = GLULX_HEADER_SIZE+14;
2239 assembleg_2(copyb_gc, AO2, stack_pointer);
2240 assembleg_1(streamchar_gc, stack_pointer);
2241 AO2.value = GLULX_HEADER_SIZE+15;
2242 assembleg_2(copyb_gc, AO2, stack_pointer);
2243 assembleg_1(streamchar_gc, stack_pointer);
2245 AO.marker = 0;
2246 AO.value = ')';
2247 set_constant_ot(&AO);
2248 assembleg_1(streamchar_gc, AO);
2251 break;
2253 /* -------------------------------------------------------------------- */
2254 /* jump <label> ------------------------------------------------------- */
2255 /* -------------------------------------------------------------------- */
2257 case JUMP_CODE:
2258 assembleg_jump(parse_label());
2259 break;
2261 /* -------------------------------------------------------------------- */
2262 /* move <expression> to <expression> ---------------------------------- */
2263 /* -------------------------------------------------------------------- */
2265 case MOVE_CODE:
2266 misc_keywords.enabled = TRUE;
2267 AO = parse_expression(QUANTITY_CONTEXT);
2269 get_next_token();
2270 misc_keywords.enabled = FALSE;
2271 if ((token_type != MISC_KEYWORD_TT)
2272 || (token_value != TO_MK))
2273 { ebf_error("'to'", token_text);
2274 panic_mode_error_recovery();
2275 return;
2278 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2279 QUANTITY_CONTEXT, -1);
2280 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
2281 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2282 assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
2283 zero_operand);
2284 else
2285 assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
2286 zero_operand);
2287 break;
2289 /* -------------------------------------------------------------------- */
2290 /* new_line ----------------------------------------------------------- */
2291 /* -------------------------------------------------------------------- */
2293 case NEW_LINE_CODE:
2294 AO.type = BYTECONSTANT_OT; AO.value = 0x0A; AO.marker = 0;
2295 assembleg_1(streamchar_gc, AO);
2296 break;
2298 /* -------------------------------------------------------------------- */
2299 /* objectloop (<initialisation>) <codeblock> -------------------------- */
2300 /* -------------------------------------------------------------------- */
2302 case OBJECTLOOP_CODE:
2304 match_open_bracket();
2305 get_next_token();
2306 if (token_type == LOCAL_VARIABLE_TT) {
2307 AO.value = token_value;
2308 AO.type = LOCALVAR_OT;
2309 AO.marker = 0;
2311 else if ((token_type == SYMBOL_TT) &&
2312 (stypes[token_value] == GLOBAL_VARIABLE_T)) {
2313 AO.value = svals[token_value];
2314 AO.type = GLOBALVAR_OT;
2315 AO.marker = 0;
2317 else {
2318 ebf_error("'objectloop' variable", token_text);
2319 panic_mode_error_recovery();
2320 break;
2322 misc_keywords.enabled = TRUE;
2323 get_next_token(); flag = TRUE;
2324 misc_keywords.enabled = FALSE;
2325 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2326 flag = FALSE;
2328 ln = 0;
2329 if ((token_type == MISC_KEYWORD_TT)
2330 && (token_value == NEAR_MK)) ln = 1;
2331 if ((token_type == MISC_KEYWORD_TT)
2332 && (token_value == FROM_MK)) ln = 2;
2333 if ((token_type == CND_TT) && (token_value == IN_COND))
2334 { get_next_token();
2335 get_next_token();
2336 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2337 ln = 3;
2338 put_token_back();
2339 put_token_back();
2342 if (ln != 0) {
2343 /* Old style (Inform 5) objectloops: note that we
2344 implement objectloop (a in b) in the old way since
2345 this runs through objects in a different order from
2346 the new way, and there may be existing Inform code
2347 relying on this. */
2348 assembly_operand AO4, AO5;
2350 sequence_point_follows = TRUE;
2351 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2352 QUANTITY_CONTEXT, -1);
2353 match_close_bracket();
2354 if (ln == 1) {
2355 if (runtime_error_checking_switch)
2356 AO2 = check_nonzero_at_runtime(AO2, -1,
2357 OBJECTLOOP_RTE);
2358 AO4.type = BYTECONSTANT_OT;
2359 AO4.value = GOBJFIELD_PARENT();
2360 AO4.marker = 0;
2361 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2362 AO4.type = BYTECONSTANT_OT;
2363 AO4.value = GOBJFIELD_CHILD();
2364 AO4.marker = 0;
2365 assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
2366 AO2 = stack_pointer;
2368 else if (ln == 3) {
2369 if (runtime_error_checking_switch) {
2370 AO5 = AO2;
2371 AO2 = check_nonzero_at_runtime(AO2, -1,
2372 CHILD_RTE);
2374 AO4.type = BYTECONSTANT_OT;
2375 AO4.value = GOBJFIELD_CHILD();
2376 AO4.marker = 0;
2377 assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2378 AO2 = stack_pointer;
2380 else {
2381 /* do nothing */
2383 assembleg_store(AO, AO2);
2384 assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
2385 assemble_label_no(ln4 = next_label++);
2386 parse_code_block(ln2, ln3 = next_label++, 0);
2387 sequence_point_follows = FALSE;
2388 assemble_label_no(ln3);
2389 if (runtime_error_checking_switch) {
2390 AO2 = check_nonzero_at_runtime(AO, ln2,
2391 OBJECTLOOP2_RTE);
2392 if ((ln == 3)
2393 && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
2394 && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
2395 { assembly_operand en_ao;
2396 en_ao.value = OBJECTLOOP_BROKEN_RTE;
2397 en_ao.marker = 0;
2398 set_constant_ot(&en_ao);
2399 AO4.type = BYTECONSTANT_OT;
2400 AO4.value = GOBJFIELD_PARENT();
2401 AO4.marker = 0;
2402 assembleg_3(aload_gc, AO, AO4, stack_pointer);
2403 assembleg_2_branch(jeq_gc, stack_pointer, AO5,
2404 next_label);
2405 assembleg_call_2(veneer_routine(RT__Err_VR),
2406 en_ao, AO, zero_operand);
2407 assembleg_jump(ln2);
2408 assemble_label_no(next_label++);
2411 else {
2412 AO2 = AO;
2414 AO4.type = BYTECONSTANT_OT;
2415 AO4.value = GOBJFIELD_SIBLING();
2416 AO4.marker = 0;
2417 assembleg_3(aload_gc, AO2, AO4, AO);
2418 assembleg_1_branch(jnz_gc, AO, ln4);
2419 assemble_label_no(ln2);
2420 return;
2423 sequence_point_follows = TRUE;
2424 ln = symbol_index("Class", -1);
2425 AO2.value = svals[ln];
2426 AO2.marker = OBJECT_MV;
2427 AO2.type = CONSTANT_OT;
2428 assembleg_store(AO, AO2);
2430 assemble_label_no(ln = next_label++);
2431 ln2 = next_label++;
2432 ln3 = next_label++;
2433 if (flag)
2434 { put_token_back();
2435 put_token_back();
2436 sequence_point_follows = TRUE;
2437 code_generate(parse_expression(CONDITION_CONTEXT),
2438 CONDITION_CONTEXT, ln3);
2439 match_close_bracket();
2441 parse_code_block(ln2, ln3, 0);
2443 sequence_point_follows = FALSE;
2444 assemble_label_no(ln3);
2445 AO4.type = BYTECONSTANT_OT;
2446 AO4.value = GOBJFIELD_CHAIN();
2447 AO4.marker = 0;
2448 assembleg_3(aload_gc, AO, AO4, AO);
2449 assembleg_1_branch(jnz_gc, AO, ln);
2450 assemble_label_no(ln2);
2451 return;
2453 /* -------------------------------------------------------------------- */
2454 /* (see routine above) ------------------------------------------------ */
2455 /* -------------------------------------------------------------------- */
2457 case PRINT_CODE:
2458 get_next_token();
2459 parse_print_g(FALSE); return;
2460 case PRINT_RET_CODE:
2461 get_next_token();
2462 parse_print_g(TRUE); return;
2464 /* -------------------------------------------------------------------- */
2465 /* quit --------------------------------------------------------------- */
2466 /* -------------------------------------------------------------------- */
2468 case QUIT_CODE:
2469 assembleg_0(quit_gc); break;
2471 /* -------------------------------------------------------------------- */
2472 /* remove <expression> ------------------------------------------------ */
2473 /* -------------------------------------------------------------------- */
2475 case REMOVE_CODE:
2476 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2477 QUANTITY_CONTEXT, -1);
2478 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2479 assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
2480 zero_operand);
2481 else
2482 assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
2483 zero_operand);
2484 break;
2486 /* -------------------------------------------------------------------- */
2487 /* return [<expression>] ---------------------------------------------- */
2488 /* -------------------------------------------------------------------- */
2490 case RETURN_CODE:
2491 get_next_token();
2492 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
2493 AO.type = BYTECONSTANT_OT; AO.value = 1; AO.marker = 0;
2494 assembleg_1(return_gc, AO);
2495 return;
2497 put_token_back();
2498 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
2499 QUANTITY_CONTEXT, -1);
2500 assembleg_1(return_gc, AO);
2501 break;
2503 /* -------------------------------------------------------------------- */
2504 /* rfalse ------------------------------------------------------------- */
2505 /* -------------------------------------------------------------------- */
2507 case RFALSE_CODE:
2508 assembleg_1(return_gc, zero_operand);
2509 break;
2511 /* -------------------------------------------------------------------- */
2512 /* rtrue -------------------------------------------------------------- */
2513 /* -------------------------------------------------------------------- */
2515 case RTRUE_CODE:
2516 assembleg_1(return_gc, one_operand);
2517 break;
2519 /* -------------------------------------------------------------------- */
2520 /* spaces <expression> ------------------------------------------------ */
2521 /* -------------------------------------------------------------------- */
2523 case SPACES_CODE:
2524 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2525 QUANTITY_CONTEXT, -1);
2527 assembleg_store(temp_var1, AO);
2529 AO.value = 32; AO.marker = 0; set_constant_ot(&AO);
2531 assembleg_2_branch(jlt_gc, temp_var1, one_operand,
2532 ln = next_label++);
2533 assemble_label_no(ln2 = next_label++);
2534 assembleg_1(streamchar_gc, AO);
2535 assembleg_dec(temp_var1);
2536 assembleg_1_branch(jnz_gc, temp_var1, ln2);
2537 assemble_label_no(ln);
2538 break;
2540 /* -------------------------------------------------------------------- */
2541 /* string <expression> <literal-string> ------------------------------- */
2542 /* -------------------------------------------------------------------- */
2544 case STRING_CODE:
2545 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2546 QUANTITY_CONTEXT, -1);
2547 get_next_token();
2548 if (token_type == DQ_TT)
2549 { AO4.value = compile_string(token_text, TRUE, TRUE);
2550 AO4.marker = STRING_MV;
2551 AO4.type = CONSTANT_OT;
2553 else
2554 { put_token_back();
2555 AO4 = parse_expression(CONSTANT_CONTEXT);
2557 assembleg_call_2(veneer_routine(Dynam__String_VR),
2558 AO2, AO4, zero_operand);
2559 break;
2561 /* -------------------------------------------------------------------- */
2562 /* style roman/reverse/bold/underline/fixed --------------------------- */
2563 /* -------------------------------------------------------------------- */
2565 case STYLE_CODE:
2566 misc_keywords.enabled = TRUE;
2567 get_next_token();
2568 misc_keywords.enabled = FALSE;
2569 if ((token_type != MISC_KEYWORD_TT)
2570 || ((token_value != ROMAN_MK)
2571 && (token_value != REVERSE_MK)
2572 && (token_value != BOLD_MK)
2573 && (token_value != UNDERLINE_MK)
2574 && (token_value != FIXED_MK)))
2575 { ebf_error(
2576 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2577 token_text);
2578 panic_mode_error_recovery();
2579 break;
2582 /* Call glk_set_style() */
2584 AO.value = 0x0086;
2585 AO.marker = 0;
2586 set_constant_ot(&AO);
2587 switch(token_value)
2588 { case ROMAN_MK:
2589 AO2 = zero_operand; /* normal */
2590 break;
2591 case REVERSE_MK:
2592 AO2.value = 5; /* alert */
2593 AO2.marker = 0;
2594 set_constant_ot(&AO2);
2595 break;
2596 case BOLD_MK:
2597 AO2.value = 4; /* subheader */
2598 AO2.marker = 0;
2599 set_constant_ot(&AO2);
2600 break;
2601 case UNDERLINE_MK:
2602 AO2 = one_operand; /* emphasized */
2603 break;
2604 case FIXED_MK:
2605 AO2 = two_operand; /* preformatted */
2606 break;
2608 assembleg_call_2(veneer_routine(Glk__Wrap_VR),
2609 AO, AO2, zero_operand);
2610 break;
2612 /* -------------------------------------------------------------------- */
2613 /* switch (<expression>) <codeblock> ---------------------------------- */
2614 /* -------------------------------------------------------------------- */
2616 case SWITCH_CODE:
2617 match_open_bracket();
2618 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2619 QUANTITY_CONTEXT, -1);
2620 match_close_bracket();
2622 assembleg_store(temp_var1, AO);
2624 parse_code_block(ln = next_label++, continue_label, 1);
2625 assemble_label_no(ln);
2626 return;
2628 /* -------------------------------------------------------------------- */
2629 /* while (<condition>) <codeblock> ------------------------------------ */
2630 /* -------------------------------------------------------------------- */
2632 case WHILE_CODE:
2633 assemble_label_no(ln = next_label++);
2634 match_open_bracket();
2636 code_generate(parse_expression(CONDITION_CONTEXT),
2637 CONDITION_CONTEXT, ln2 = next_label++);
2638 match_close_bracket();
2640 parse_code_block(ln2, ln, 0);
2641 sequence_point_follows = FALSE;
2642 assembleg_jump(ln);
2643 assemble_label_no(ln2);
2644 return;
2646 /* -------------------------------------------------------------------- */
2648 case SDEFAULT_CODE:
2649 error("'default' without matching 'switch'"); break;
2650 case ELSE_CODE:
2651 error("'else' without matching 'if'"); break;
2652 case UNTIL_CODE:
2653 error("'until' without matching 'do'");
2654 panic_mode_error_recovery(); return;
2656 /* -------------------------------------------------------------------- */
2658 /* And a useful default, which will never be triggered in a complete
2659 Inform compiler, but which is important in development. */
2661 default:
2662 error("*** Statement code gen: Can't generate yet ***\n");
2663 panic_mode_error_recovery(); return;
2666 StatementTerminator:
2668 get_next_token();
2669 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
2670 { ebf_error("';'", token_text);
2671 put_token_back();
2675 extern void parse_statement(int break_label, int continue_label)
2677 if (!glulx_mode)
2678 parse_statement_z(break_label, continue_label);
2679 else
2680 parse_statement_g(break_label, continue_label);
2683 /* ========================================================================= */
2684 /* Data structure management routines */
2685 /* ------------------------------------------------------------------------- */
2687 extern void init_states_vars(void)
2691 extern void states_begin_pass(void)
2695 extern void states_allocate_arrays(void)
2699 extern void states_free_arrays(void)
2703 /* ========================================================================= */