1 /* ------------------------------------------------------------------------- */
2 /* "directs" : Directives (# commands) */
4 /* Part of Inform 6.35 */
5 /* copyright (c) Graham Nelson 1993 - 2021 */
7 /* Inform is free software: you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation, either version 3 of the License, or */
10 /* (at your option) any later version. */
12 /* Inform is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with Inform. If not, see https://gnu.org/licenses/ */
20 /* ------------------------------------------------------------------------- */
24 int no_routines, /* Number of routines compiled so far */
25 no_named_routines, /* Number not embedded in objects */
26 no_locals, /* Number of locals in current routine */
27 no_termcs; /* Number of terminating characters */
28 int terminating_characters[32];
30 brief_location routine_starts_line; /* Source code location where the current
31 routine starts. (Useful for reporting
32 "unused variable" warnings on the start
33 line rather than the end line.) */
35 static int constant_made_yet; /* Have any constants been defined yet? */
37 static int ifdef_stack[32], ifdef_sp;
39 /* ------------------------------------------------------------------------- */
41 static int ebf_error_recover(char *s1, char *s2)
43 /* Display an "expected... but found..." error, then skim forward
44 to the next semicolon and return FALSE. This is such a common
45 case in parse_given_directive() that it's worth a utility
46 function. You will see many error paths that look like:
47 return ebf_error_recover(...);
50 panic_mode_error_recovery();
54 static int ebf_symbol_error_recover(char *s1, char *name, char *type, brief_location report_line)
56 /* Same for ebf_symbol_error(). */
57 ebf_symbol_error(s1, name, type, report_line);
58 panic_mode_error_recovery();
62 /* ------------------------------------------------------------------------- */
64 extern int parse_given_directive(int internal_flag)
65 { /* Internal_flag is FALSE if the directive is encountered normally,
66 TRUE if encountered with a # prefix inside a routine or object
69 Returns: FALSE if program continues, TRUE if end of file reached. */
71 int *trace_level = NULL; int32 i, j, k, n, flag;
72 const char *constant_name;
73 debug_location_beginning beginning_debug_location;
77 /* Only certain directives, such as #ifdef, are permitted within
78 a routine or object definition. In older versions of Inform,
79 nearly any directive was accepted, but this was -- to quote
80 an old code comment -- "about as well-supported as Wile E.
81 Coyote one beat before the plummet-lines kick in." */
83 if (token_value != IFV3_CODE && token_value != IFV5_CODE
84 && token_value != IFDEF_CODE && token_value != IFNDEF_CODE
85 && token_value != IFTRUE_CODE && token_value != IFFALSE_CODE
86 && token_value != IFNOT_CODE && token_value != ENDIF_CODE
87 && token_value != MESSAGE_CODE && token_value != ORIGSOURCE_CODE
88 && token_value != TRACE_CODE) {
89 char *dirname = directives.keywords[token_value];
90 error_named("Cannot nest this directive inside a routine or object:", dirname);
91 panic_mode_error_recovery(); return FALSE;
98 /* --------------------------------------------------------------------- */
99 /* Abbreviate "string1" ["string2" ...] */
100 /* --------------------------------------------------------------------- */
102 case ABBREVIATE_CODE:
106 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
109 if (!glulx_mode && no_abbreviations==96)
110 { error("All 96 Z-machine abbreviations already declared");
111 panic_mode_error_recovery(); return FALSE;
113 if (no_abbreviations==MAX_ABBREVS)
114 memoryerror("MAX_ABBREVS", MAX_ABBREVS);
116 if (abbrevs_lookup_table_made)
117 { error("All abbreviations must be declared together");
118 panic_mode_error_recovery(); return FALSE;
120 if (token_type != DQ_TT)
121 return ebf_error_recover("abbreviation string", token_text);
122 if (strlen(token_text)<2)
123 { error_named("It's not worth abbreviating", token_text);
126 /* Abbreviation string with null must fit in a MAX_ABBREV_LENGTH
128 if (strlen(token_text)>=MAX_ABBREV_LENGTH)
129 { error_named("Abbreviation too long", token_text);
132 make_abbreviation(token_text);
135 /* --------------------------------------------------------------------- */
136 /* Array arrayname array... */
137 /* --------------------------------------------------------------------- */
139 case ARRAY_CODE: make_global(TRUE, FALSE); break; /* See "tables.c" */
141 /* --------------------------------------------------------------------- */
142 /* Attribute newname [alias oldname] */
143 /* --------------------------------------------------------------------- */
146 make_attribute(); break; /* See "objects.c" */
148 /* --------------------------------------------------------------------- */
149 /* Class classname ... */
150 /* --------------------------------------------------------------------- */
153 make_class(NULL); /* See "objects.c" */
156 /* --------------------------------------------------------------------- */
157 /* Constant newname [[=] value] [, ...] */
158 /* --------------------------------------------------------------------- */
161 constant_made_yet=TRUE;
164 get_next_token(); i = token_value;
165 beginning_debug_location = get_token_location_beginning();
167 if (token_type != SYMBOL_TT)
168 { discard_token_location(beginning_debug_location);
169 return ebf_error_recover("new constant name", token_text);
172 if (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
173 { discard_token_location(beginning_debug_location);
174 return ebf_symbol_error_recover("new constant name", token_text, typename(stypes[i]), slines[i]);
177 assign_symbol(i, 0, CONSTANT_T);
178 constant_name = token_text;
182 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
183 { if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
184 { debug_file_printf("<constant>");
185 debug_file_printf("<identifier>%s</identifier>", constant_name);
186 write_debug_symbol_optional_backpatch(i);
187 write_debug_locations(get_token_location_end(beginning_debug_location));
188 debug_file_printf("</constant>");
190 goto ParseConstantSpec;
193 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
194 { if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
195 { debug_file_printf("<constant>");
196 debug_file_printf("<identifier>%s</identifier>", constant_name);
197 write_debug_symbol_optional_backpatch(i);
198 write_debug_locations(get_token_location_end(beginning_debug_location));
199 debug_file_printf("</constant>");
204 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
207 { assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
209 { assign_marked_symbol(i, AO.marker, AO.value,
211 sflags[i] |= CHANGE_SFLAG;
212 if (i == grammar_version_symbol)
214 "Grammar__Version must be given an explicit constant value");
217 { assign_symbol(i, AO.value, CONSTANT_T);
218 if (i == grammar_version_symbol)
219 { if ((grammar_version_number != AO.value)
220 && (no_fake_actions > 0))
222 "Once a fake action has been defined it is too late to \
223 change the grammar version. (If you are using the library, move any \
224 Fake_Action directives to a point after the inclusion of \"Parser\".)");
225 grammar_version_number = AO.value;
230 if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
231 { debug_file_printf("<constant>");
232 debug_file_printf("<identifier>%s</identifier>", constant_name);
233 write_debug_symbol_optional_backpatch(i);
234 write_debug_locations
235 (get_token_location_end(beginning_debug_location));
236 debug_file_printf("</constant>");
240 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
241 goto ParseConstantSpec;
245 /* --------------------------------------------------------------------- */
246 /* Default constantname integer */
247 /* --------------------------------------------------------------------- */
251 { error("'Default' cannot be used in -M (Module) mode");
252 panic_mode_error_recovery(); return FALSE;
256 if (token_type != SYMBOL_TT)
257 return ebf_error_recover("name", token_text);
260 if (sflags[token_value] & UNKNOWN_SFLAG)
262 sflags[i] |= DEFCON_SFLAG;
266 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
269 { assembly_operand AO;
270 AO = parse_expression(CONSTANT_CONTEXT);
272 { if (AO.marker != 0)
273 { assign_marked_symbol(i, AO.marker, AO.value,
275 sflags[i] |= CHANGE_SFLAG;
277 else assign_symbol(i, AO.value, CONSTANT_T);
283 /* --------------------------------------------------------------------- */
284 /* Dictionary 'word' */
285 /* Dictionary 'word' val1 */
286 /* Dictionary 'word' val1 val3 */
287 /* --------------------------------------------------------------------- */
289 case DICTIONARY_CODE:
290 /* In Inform 5, this directive had the form
291 Dictionary SYMBOL "word";
292 This was deprecated as of I6 (if not earlier), and is no longer
293 supported at all. The current form just creates a dictionary word,
294 with the given values for dict_par1 and dict_par3. If the word
295 already exists, the values are bit-or'd in with the existing
297 (We don't offer a way to set dict_par2, because that is entirely
298 reserved for the verb number. Or'ing values into it would create
302 if (token_type != SQ_TT && token_type != DQ_TT)
303 return ebf_error_recover("dictionary word", token_text);
306 char *wd = token_text;
311 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
317 AO = parse_expression(CONSTANT_CONTEXT);
318 if (module_switch && (AO.marker != 0))
319 error("A definite value must be given as a Dictionary flag");
324 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
330 AO = parse_expression(CONSTANT_CONTEXT);
331 if (module_switch && (AO.marker != 0))
332 error("A definite value must be given as a Dictionary flag");
339 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
340 warning("Dictionary flag values cannot exceed $FF in Z-code");
344 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
345 warning("Dictionary flag values cannot exceed $FFFF in Glulx");
349 dictionary_add(wd, val1, 0, val3);
353 /* --------------------------------------------------------------------- */
355 /* --------------------------------------------------------------------- */
357 case END_CODE: return(TRUE);
360 if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
364 /* --------------------------------------------------------------------- */
366 /* --------------------------------------------------------------------- */
368 case EXTEND_CODE: extend_verb(); return FALSE; /* see "tables.c" */
370 /* --------------------------------------------------------------------- */
371 /* Fake_Action name */
372 /* --------------------------------------------------------------------- */
374 case FAKE_ACTION_CODE:
375 make_fake_action(); break; /* see "verbs.c" */
377 /* --------------------------------------------------------------------- */
378 /* Global variable [= value / array...] */
379 /* --------------------------------------------------------------------- */
381 case GLOBAL_CODE: make_global(FALSE, FALSE); break; /* See "tables.c" */
383 /* --------------------------------------------------------------------- */
386 /* Note that each time Inform tests an If... condition, it stacks the */
387 /* result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack */
388 /* reveals what clause of the current If... is being compiled: */
390 /* If...; ... Ifnot; ... Endif; */
391 /* top of stack: TRUE FALSE */
393 /* This is used to detect "two Ifnots in same If" errors. */
394 /* --------------------------------------------------------------------- */
404 if (token_type != SYMBOL_TT)
405 return ebf_error_recover("symbol name", token_text);
407 if ((token_text[0] == 'V')
408 && (token_text[1] == 'N')
409 && (token_text[2] == '_')
410 && (strlen(token_text)==7))
411 { i = atoi(token_text+3);
412 if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
413 goto HashIfCondition;
416 if (sflags[token_value] & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
417 else sflags[token_value] |= USED_SFLAG;
418 goto HashIfCondition;
422 error("'Ifnot' without matching 'If...'");
424 if (!(ifdef_stack[ifdef_sp-1]))
425 error("Second 'Ifnot' for the same 'If...' condition");
427 { dont_enter_into_symbol_table = -2; n = 1;
428 directives.enabled = TRUE;
431 if (token_type == EOF_TT)
432 { error("End of file reached in code 'If...'d out");
433 directives.enabled = FALSE;
436 if (token_type == DIRECTIVE_TT)
437 { switch(token_value)
450 "Second 'Ifnot' for the same 'If...' condition");
457 dont_enter_into_symbol_table = FALSE;
458 directives.enabled = FALSE;
464 if (!glulx_mode && version_number <= 3) flag = TRUE;
465 goto HashIfCondition;
469 if (!glulx_mode && version_number <= 3) flag = FALSE;
470 goto HashIfCondition;
473 { assembly_operand AO;
474 AO = parse_expression(CONSTANT_CONTEXT);
475 if (module_switch && (AO.marker != 0))
476 { error("This condition can't be determined");
479 else flag = (AO.value != 0);
481 goto HashIfCondition;
484 { assembly_operand AO;
485 AO = parse_expression(CONSTANT_CONTEXT);
486 if (module_switch && (AO.marker != 0))
487 { error("This condition can't be determined");
490 else flag = (AO.value == 0);
492 goto HashIfCondition;
496 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
497 return ebf_error_recover("semicolon after 'If...' condition", token_text);
500 { ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
502 { dont_enter_into_symbol_table = -2; n = 1;
503 directives.enabled = TRUE;
506 if (token_type == EOF_TT)
507 { error("End of file reached in code 'If...'d out");
508 directives.enabled = FALSE;
511 if (token_type == DIRECTIVE_TT)
525 { ifdef_stack[ifdef_sp++] = FALSE;
531 directives.enabled = FALSE;
532 dont_enter_into_symbol_table = FALSE;
536 /* --------------------------------------------------------------------- */
537 /* Import global <varname> [, ...] */
539 /* (Further imported goods may be allowed later.) */
540 /* --------------------------------------------------------------------- */
544 { error("'Import' can only be used in -M (Module) mode");
545 panic_mode_error_recovery(); return FALSE;
547 directives.enabled = TRUE;
550 if ((token_type == DIRECTIVE_TT) && (token_value == GLOBAL_CODE))
551 make_global(FALSE, TRUE);
552 else error_named("'Import' cannot import things of this type:",
555 } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
557 directives.enabled = FALSE;
560 /* --------------------------------------------------------------------- */
561 /* Include "[>]filename" */
563 /* The ">" character means to load the file from the same directory as */
564 /* the current file, instead of relying on the include path. */
565 /* --------------------------------------------------------------------- */
569 if (token_type != DQ_TT)
570 return ebf_error_recover("filename in double-quotes", token_text);
572 { char *name = token_text;
575 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
576 ebf_error("semicolon ';' after Include filename", token_text);
578 if (strcmp(name, "language__") == 0)
579 load_sourcefile(Language_Name, 0);
580 else if (name[0] == '>')
581 load_sourcefile(name+1, 1);
582 else load_sourcefile(name, 0);
586 /* --------------------------------------------------------------------- */
587 /* Link "filename" */
588 /* --------------------------------------------------------------------- */
592 if (token_type != DQ_TT)
593 return ebf_error_recover("filename in double-quotes", token_text);
594 link_module(token_text); /* See "linker.c" */
597 /* --------------------------------------------------------------------- */
598 /* Lowstring constantname "text of string" */
599 /* --------------------------------------------------------------------- */
600 /* Unlike most constant creations, these do not require backpatching: */
601 /* the low strings always occupy a table at a fixed offset in the */
602 /* Z-machine (after the abbreviations table has finished, at 0x100). */
603 /* --------------------------------------------------------------------- */
607 { error("'LowString' cannot be used in -M (Module) mode");
608 panic_mode_error_recovery(); return FALSE;
611 error("The LowString directive has no meaning in Glulx.");
612 panic_mode_error_recovery(); return FALSE;
614 get_next_token(); i = token_value;
615 if (token_type != SYMBOL_TT)
616 return ebf_error_recover("new low string name", token_text);
617 if (!(sflags[i] & UNKNOWN_SFLAG))
618 return ebf_symbol_error_recover("new low string name", token_text, typename(stypes[i]), slines[i]);
621 if (token_type != DQ_TT)
622 return ebf_error_recover("literal string in double-quotes", token_text);
624 assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T);
627 /* --------------------------------------------------------------------- */
628 /* Message | "information" */
629 /* | error "error message" */
630 /* | fatalerror "fatal error message" */
631 /* | warning "warning message" */
632 /* --------------------------------------------------------------------- */
635 directive_keywords.enabled = TRUE;
637 directive_keywords.enabled = FALSE;
638 if (token_type == DQ_TT)
640 if (hash_printed_since_newline) printf("\n");
641 for (i=0; token_text[i]!=0; i++)
642 { if (token_text[i] == '^') printf("\n");
644 if (token_text[i] == '~') printf("\"");
645 else printf("%c", token_text[i]);
650 if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
652 if (token_type != DQ_TT)
653 { return ebf_error_recover("error message in double-quotes", token_text);
655 error(token_text); break;
657 if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
659 if (token_type != DQ_TT)
660 { return ebf_error_recover("fatal error message in double-quotes", token_text);
662 fatalerror(token_text); break;
664 if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
666 if (token_type != DQ_TT)
667 { return ebf_error_recover("warning message in double-quotes", token_text);
669 warning(token_text); break;
671 return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
675 /* --------------------------------------------------------------------- */
676 /* Nearby objname "short name" ... */
677 /* --------------------------------------------------------------------- */
680 make_object(TRUE, NULL, -1, -1, -1);
681 return FALSE; /* See "objects.c" */
683 /* --------------------------------------------------------------------- */
684 /* Object objname "short name" ... */
685 /* --------------------------------------------------------------------- */
688 make_object(FALSE, NULL, -1, -1, -1);
689 return FALSE; /* See "objects.c" */
691 /* --------------------------------------------------------------------- */
692 /* Origsource <file> */
693 /* Origsource <file> <line> */
694 /* Origsource <file> <line> <char> */
697 /* The first three forms declare that all following lines are derived */
698 /* from the named Inform 7 source file (with an optional line number */
699 /* and character number). This will be reported in error messages and */
700 /* in debug output. The declaration holds through the next Origsource */
701 /* directive (but does not apply to included files). */
703 /* The fourth form, with no arguments, clears the declaration. */
705 /* Unlike the Include directive, Origsource does not open the named */
706 /* file or even verify that it exists. The filename is treated as an */
708 /* --------------------------------------------------------------------- */
710 case ORIGSOURCE_CODE:
712 char *origsource_file = NULL;
713 int32 origsource_line = 0;
714 int32 origsource_char = 0;
716 /* Parse some optional tokens followed by a mandatory semicolon. */
719 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
720 if (token_type != DQ_TT) {
721 return ebf_error_recover("a file name in double-quotes",
724 origsource_file = token_text;
727 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
728 if (token_type != NUMBER_TT) {
729 return ebf_error_recover("a file line number",
732 origsource_line = token_value;
733 if (origsource_line < 0)
737 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
738 if (token_type != NUMBER_TT) {
739 return ebf_error_recover("a file line number",
742 origsource_char = token_value;
743 if (origsource_char < 0)
753 set_origsource_location(origsource_file, origsource_line, origsource_char);
757 /* --------------------------------------------------------------------- */
758 /* Property [long] [additive] name [alias oldname] */
759 /* --------------------------------------------------------------------- */
761 case PROPERTY_CODE: make_property(); break; /* See "objects.c" */
763 /* --------------------------------------------------------------------- */
764 /* Release <number> */
765 /* --------------------------------------------------------------------- */
768 { assembly_operand AO;
769 AO = parse_expression(CONSTANT_CONTEXT);
770 if (module_switch && (AO.marker != 0))
771 error("A definite value must be given as release number");
773 release_number = AO.value;
777 /* --------------------------------------------------------------------- */
778 /* Replace routine [routinename] */
779 /* --------------------------------------------------------------------- */
782 /* You can also replace system functions normally implemented in */
783 /* the "hardware" of the Z-machine, like "random()": */
785 system_functions.enabled = TRUE;
786 directives.enabled = FALSE;
787 directive_keywords.enabled = FALSE;
789 /* Don't count the upcoming symbol as a top-level reference
790 *to* the function. */
791 df_dont_note_global_symbols = TRUE;
793 df_dont_note_global_symbols = FALSE;
794 if (token_type == SYSFUN_TT)
795 { if (system_function_usage[token_value] == 1)
796 error("You can't 'Replace' a system function already used");
797 else system_function_usage[token_value] = 2;
799 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
801 error("You can't give a 'Replace'd system function a new name");
802 panic_mode_error_recovery(); return FALSE;
807 if (token_type != SYMBOL_TT)
808 return ebf_error_recover("name of routine to replace", token_text);
809 if (!(sflags[token_value] & UNKNOWN_SFLAG))
810 return ebf_error_recover("name of routine not yet defined", token_text);
812 sflags[token_value] |= REPLACE_SFLAG;
814 /* If a second symbol is provided, it will refer to the
815 original (replaced) definition of the routine. */
818 system_functions.enabled = FALSE;
819 df_dont_note_global_symbols = TRUE;
821 df_dont_note_global_symbols = FALSE;
822 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
826 if (token_type != SYMBOL_TT || !(sflags[token_value] & UNKNOWN_SFLAG))
827 return ebf_error_recover("semicolon ';' or new routine name", token_text);
829 /* Define the original-form symbol as a zero constant. Its
830 value will be overwritten later, when we define the
832 assign_symbol(token_value, 0, CONSTANT_T);
833 add_symbol_replacement_mapping(i, token_value);
837 /* --------------------------------------------------------------------- */
838 /* Serial "yymmdd" */
839 /* --------------------------------------------------------------------- */
843 if ((token_type != DQ_TT) || (strlen(token_text)!=6))
844 { error("The serial number must be a 6-digit date in double-quotes");
845 panic_mode_error_recovery(); return FALSE;
847 for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
848 { error("The serial number must be a 6-digit date in double-quotes");
849 panic_mode_error_recovery(); return FALSE;
851 strcpy(serial_code_buffer, token_text);
852 serial_code_given_in_program = TRUE;
855 /* --------------------------------------------------------------------- */
856 /* Statusline score/time */
857 /* --------------------------------------------------------------------- */
859 case STATUSLINE_CODE:
861 warning("This does not set the final game's statusline");
863 directive_keywords.enabled = TRUE;
865 directive_keywords.enabled = FALSE;
866 if ((token_type != DIR_KEYWORD_TT)
867 || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
868 return ebf_error_recover("'score' or 'time' after 'statusline'", token_text);
869 if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
870 else statusline_flag = TIME_STYLE;
873 /* --------------------------------------------------------------------- */
874 /* Stub routinename number-of-locals */
875 /* --------------------------------------------------------------------- */
878 /* The upcoming symbol is a definition; don't count it as a
879 top-level reference *to* the stub function. */
880 df_dont_note_global_symbols = TRUE;
882 df_dont_note_global_symbols = FALSE;
883 if (token_type != SYMBOL_TT)
884 return ebf_error_recover("routine name to stub", token_text);
886 i = token_value; flag = FALSE;
888 if (sflags[i] & UNKNOWN_SFLAG)
889 { sflags[i] |= STUB_SFLAG;
893 get_next_token(); k = token_value;
894 if (token_type != NUMBER_TT)
895 return ebf_error_recover("number of local variables", token_text);
897 { error("Must specify 0 to 4 local variables for 'Stub' routine");
903 /* Give these parameter-receiving local variables names
904 for the benefit of the debugging information file,
905 and for assembly tracing to look sensible. */
907 local_variable_texts[0] = "dummy1";
908 local_variable_texts[1] = "dummy2";
909 local_variable_texts[2] = "dummy3";
910 local_variable_texts[3] = "dummy4";
913 assemble_routine_header(k, FALSE, (char *) symbs[i], FALSE, i),
916 /* Ensure the return value of a stubbed routine is false,
917 since this is necessary to make the library work properly */
920 assemblez_0(rfalse_zc);
922 assembleg_1(return_gc, zero_operand);
924 /* Inhibit "local variable unused" warnings */
926 for (i=1; i<=k; i++) variable_usage[i] = 1;
927 sequence_point_follows = FALSE;
928 assemble_routine_end(FALSE, get_token_locations());
932 /* --------------------------------------------------------------------- */
933 /* Switches switchblock */
934 /* (this directive is ignored if the -i switch was set at command line) */
935 /* --------------------------------------------------------------------- */
938 dont_enter_into_symbol_table = TRUE;
940 dont_enter_into_symbol_table = FALSE;
941 if (token_type != DQ_TT)
942 return ebf_error_recover("string of switches", token_text);
943 if (!ignore_switches_switch)
944 { if (constant_made_yet)
945 error("A 'Switches' directive must must come before \
946 the first constant definition");
947 switches(token_text, 0); /* see "inform.c" */
951 /* --------------------------------------------------------------------- */
954 /* Some files are declared as "system files": this information is used */
955 /* by Inform only to skip the definition of a routine X if the designer */
956 /* has indicated his intention to Replace X. */
957 /* --------------------------------------------------------------------- */
960 declare_systemfile(); break; /* see "files.c" */
962 /* --------------------------------------------------------------------- */
963 /* Trace dictionary */
968 /* assembly [on/off] */
969 /* expressions [on/off] */
971 /* --------------------------------------------------------------------- */
974 directives.enabled = FALSE;
975 trace_keywords.enabled = TRUE;
977 trace_keywords.enabled = FALSE;
978 directives.enabled = TRUE;
979 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
980 { asm_trace_level = 1; return FALSE; }
982 if (token_type != TRACE_KEYWORD_TT)
983 return ebf_error_recover("debugging keyword", token_text);
985 trace_keywords.enabled = TRUE;
987 i = token_value; j = 0;
989 { case DICTIONARY_TK: break;
990 case OBJECTS_TK: break;
991 case VERBS_TK: break;
995 trace_level = &asm_trace_level; break;
997 trace_level = &expr_trace_level; break;
999 trace_level = &line_trace_level; break;
1001 trace_level = &tokens_trace_level; break;
1003 trace_level = &linker_trace_level; break;
1005 trace_level = NULL; break;
1008 trace_level = &asm_trace_level; break;
1012 if ((token_type == SEP_TT) &&
1013 (token_value == SEMICOLON_SEP))
1014 { put_token_back(); break;
1016 if (token_type == NUMBER_TT)
1017 { j = token_value; break; }
1018 if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1020 if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1022 put_token_back(); break;
1026 { case DICTIONARY_TK: show_dictionary(); break;
1027 case OBJECTS_TK: list_object_tree(); break;
1028 case SYMBOLS_TK: list_symbols(j); break;
1029 case VERBS_TK: list_verb_table(); break;
1034 trace_keywords.enabled = FALSE;
1037 /* --------------------------------------------------------------------- */
1039 /* --------------------------------------------------------------------- */
1043 if (token_type != SYMBOL_TT)
1044 return ebf_error_recover("symbol name", token_text);
1046 if (sflags[token_value] & UNKNOWN_SFLAG)
1047 { break; /* undef'ing an undefined constant is okay */
1050 if (stypes[token_value] != CONSTANT_T)
1051 { error_named("Cannot Undef a symbol which is not a defined constant:", (char *)symbs[token_value]);
1055 if (debugfile_switch)
1056 { write_debug_undef(token_value);
1058 end_symbol_scope(token_value);
1059 sflags[token_value] |= USED_SFLAG;
1062 /* --------------------------------------------------------------------- */
1064 /* --------------------------------------------------------------------- */
1066 case VERB_CODE: make_verb(); return FALSE; /* see "tables.c" */
1068 /* --------------------------------------------------------------------- */
1069 /* Version <number> */
1070 /* --------------------------------------------------------------------- */
1074 { assembly_operand AO;
1075 AO = parse_expression(CONSTANT_CONTEXT);
1076 /* If a version has already been set on the command line,
1077 that overrides this. */
1078 if (version_set_switch)
1080 warning("The Version directive was overridden by a command-line argument.");
1084 if (module_switch && (AO.marker != 0))
1085 error("A definite value must be given as version number");
1089 warning("The Version directive does not work in Glulx. Use \
1090 -vX.Y.Z instead, as either a command-line argument or a header comment.");
1096 { error("The version number must be in the range 3 to 8");
1102 break; /* see "inform.c" */
1104 /* --------------------------------------------------------------------- */
1105 /* Zcharacter table <num> ... */
1106 /* Zcharacter table + <num> ... */
1107 /* Zcharacter <string> <string> <string> */
1108 /* Zcharacter <char> */
1109 /* --------------------------------------------------------------------- */
1111 case ZCHARACTER_CODE:
1114 error("The Zcharacter directive has no meaning in Glulx.");
1115 panic_mode_error_recovery(); return FALSE;
1118 directive_keywords.enabled = TRUE;
1120 directive_keywords.enabled = FALSE;
1124 new_alphabet(token_text, 0);
1126 if (token_type != DQ_TT)
1127 return ebf_error_recover("double-quoted alphabet string", token_text);
1128 new_alphabet(token_text, 1);
1130 if (token_type != DQ_TT)
1131 return ebf_error_recover("double-quoted alphabet string", token_text);
1132 new_alphabet(token_text, 2);
1136 map_new_zchar(text_to_unicode(token_text));
1137 if (token_text[textual_form_length] != 0)
1138 return ebf_error_recover("single character value", token_text);
1141 case DIR_KEYWORD_TT:
1144 { int plus_flag = FALSE;
1146 if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1150 while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1151 { switch(token_type)
1153 new_zscii_character(token_value, plus_flag);
1154 plus_flag = TRUE; break;
1156 new_zscii_character(text_to_unicode(token_text),
1158 if (token_text[textual_form_length] != 0)
1159 return ebf_error_recover("single character value",
1164 return ebf_error_recover("character or Unicode number",
1169 if (plus_flag) new_zscii_finished();
1173 case TERMINATING_DK:
1175 while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1176 { switch(token_type)
1178 terminating_characters[no_termcs++]
1182 return ebf_error_recover("ZSCII number",
1190 return ebf_error_recover("'table', 'terminating', \
1191 a string or a constant",
1196 return ebf_error_recover("three alphabet strings, \
1197 a 'table' or 'terminating' command or a single character", token_text);
1201 /* ===================================================================== */
1205 /* We are now at the end of a syntactically valid directive. It
1206 should be terminated by a semicolon. */
1209 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1210 { ebf_error("';'", token_text);
1211 /* Put the non-semicolon back. We will continue parsing from
1212 that point, in hope that it's the start of a new directive.
1213 (This recovers cleanly from a missing semicolon at the end
1214 of a directive. It's not so clean if the directive *does*
1215 end with a semicolon, but there's extra garbage before it.) */
1221 /* ========================================================================= */
1222 /* Data structure management routines */
1223 /* ------------------------------------------------------------------------- */
1225 extern void init_directs_vars(void)
1229 extern void directs_begin_pass(void)
1231 no_named_routines = 0;
1234 constant_made_yet = FALSE;
1238 extern void directs_allocate_arrays(void)
1242 extern void directs_free_arrays(void)
1246 /* ========================================================================= */