1 /* ------------------------------------------------------------------------- */
2 /* "directs" : Directives (# commands) */
4 /* Part of Inform 6.42 */
5 /* copyright (c) Graham Nelson 1993 - 2024 */
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_termcs; /* Number of terminating characters */
27 int terminating_characters[32];
29 brief_location routine_starts_line; /* Source code location where the current
30 routine starts. (Useful for reporting
31 "unused variable" warnings on the start
32 line rather than the end line.) */
34 static int constant_made_yet; /* Have any constants been defined yet? */
36 #define MAX_IFDEF_STACK (32)
37 static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
39 /* ------------------------------------------------------------------------- */
41 static int ebf_error_recover(char *s1)
43 /* Display an "expected... but found (current token)" error, then
44 skim forward to the next semicolon and return FALSE. This is
45 such a common case in parse_given_directive() that it's worth a
46 utility function. You will see many error paths that look like:
47 return ebf_error_recover(...);
49 ebf_curtoken_error(s1);
50 panic_mode_error_recovery();
54 static int ebf_symbol_error_recover(char *s1, char *type, brief_location report_line)
56 /* Same for ebf_symbol_error(). */
57 ebf_symbol_error(s1, token_text, 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_max_abbreviations(no_abbreviations);
111 panic_mode_error_recovery(); return FALSE;
113 if (!glulx_mode && no_abbreviations==MAX_ABBREVS)
114 { error_max_abbreviations(no_abbreviations);
115 /* This is no longer a memoryerror(); MAX_ABBREVS is an authoring decision for Z-code games. */
116 panic_mode_error_recovery(); return FALSE;
119 if (abbrevs_lookup_table_made)
120 { error("All abbreviations must be declared together");
121 panic_mode_error_recovery(); return FALSE;
123 if (token_type != DQ_TT)
124 { return ebf_error_recover("abbreviation string");
126 make_abbreviation(token_text);
129 /* --------------------------------------------------------------------- */
130 /* Array <arrayname> [static] <array specification> */
131 /* --------------------------------------------------------------------- */
133 case ARRAY_CODE: make_array(); break; /* See "arrays.c" */
135 /* --------------------------------------------------------------------- */
136 /* Attribute newname [alias oldname] */
137 /* --------------------------------------------------------------------- */
140 make_attribute(); break; /* See "objects.c" */
142 /* --------------------------------------------------------------------- */
143 /* Class classname ... */
144 /* --------------------------------------------------------------------- */
147 make_class(NULL); /* See "objects.c" */
150 /* --------------------------------------------------------------------- */
151 /* Constant newname [[=] value] [, ...] */
152 /* --------------------------------------------------------------------- */
155 constant_made_yet=TRUE;
158 get_next_token(); i = token_value;
159 beginning_debug_location = get_token_location_beginning();
161 if (token_type != SYMBOL_TT)
162 { discard_token_location(beginning_debug_location);
163 return ebf_error_recover("new constant name");
166 if (!(symbols[i].flags & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
167 { discard_token_location(beginning_debug_location);
168 return ebf_symbol_error_recover("new constant name", typename(symbols[i].type), symbols[i].line);
171 assign_symbol(i, 0, CONSTANT_T);
172 constant_name = token_text;
176 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
177 { if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
178 { debug_file_printf("<constant>");
179 debug_file_printf("<identifier>%s</identifier>", constant_name);
180 write_debug_symbol_optional_backpatch(i);
181 write_debug_locations(get_token_location_end(beginning_debug_location));
182 debug_file_printf("</constant>");
184 goto ParseConstantSpec;
187 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
188 { if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
189 { debug_file_printf("<constant>");
190 debug_file_printf("<identifier>%s</identifier>", constant_name);
191 write_debug_symbol_optional_backpatch(i);
192 write_debug_locations(get_token_location_end(beginning_debug_location));
193 debug_file_printf("</constant>");
198 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
201 { assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
203 { assign_marked_symbol(i, AO.marker, AO.value,
205 symbols[i].flags |= CHANGE_SFLAG;
206 if (i == grammar_version_symbol)
208 "Grammar__Version must be given an explicit constant value");
211 { assign_symbol(i, AO.value, CONSTANT_T);
212 if (i == grammar_version_symbol)
213 { if ((grammar_version_number != AO.value)
214 && (no_fake_actions > 0))
216 "Once a fake action has been defined it is too late to \
217 change the grammar version. (If you are using the library, move any \
218 Fake_Action directives to a point after the inclusion of \"Parser\".)");
219 grammar_version_number = AO.value;
224 if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
225 { debug_file_printf("<constant>");
226 debug_file_printf("<identifier>%s</identifier>", constant_name);
227 write_debug_symbol_optional_backpatch(i);
228 write_debug_locations
229 (get_token_location_end(beginning_debug_location));
230 debug_file_printf("</constant>");
234 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
235 goto ParseConstantSpec;
239 /* --------------------------------------------------------------------- */
240 /* Default constantname integer */
241 /* --------------------------------------------------------------------- */
245 if (token_type != SYMBOL_TT)
246 return ebf_error_recover("name");
249 if (symbols[token_value].flags & UNKNOWN_SFLAG)
251 symbols[i].flags |= DEFCON_SFLAG;
255 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
258 { assembly_operand AO;
259 AO = parse_expression(CONSTANT_CONTEXT);
261 { if (AO.marker != 0)
262 { assign_marked_symbol(i, AO.marker, AO.value,
264 symbols[i].flags |= CHANGE_SFLAG;
266 else assign_symbol(i, AO.value, CONSTANT_T);
272 /* --------------------------------------------------------------------- */
273 /* Dictionary 'word' */
274 /* Dictionary 'word' val1 */
275 /* Dictionary 'word' val1 val3 */
276 /* --------------------------------------------------------------------- */
278 case DICTIONARY_CODE:
279 /* In Inform 5, this directive had the form
280 Dictionary SYMBOL "word";
281 This was deprecated as of I6 (if not earlier), and is no longer
282 supported at all. The current form just creates a dictionary word,
283 with the given values for dict_par1 and dict_par3. If the word
284 already exists, the values are bit-or'd in with the existing
286 (We don't offer a way to set dict_par2, because that is entirely
287 reserved for the verb number. Or'ing values into it would create
291 if (token_type != SQ_TT && token_type != DQ_TT)
292 return ebf_error_recover("dictionary word");
295 char *wd = token_text;
300 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
306 AO = parse_expression(CONSTANT_CONTEXT);
308 error("A definite value must be given as a Dictionary flag");
313 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
319 if (ZCODE_LESS_DICT_DATA && !glulx_mode)
320 warning("The third dictionary field will be ignored because ZCODE_LESS_DICT_DATA is set");
321 AO = parse_expression(CONSTANT_CONTEXT);
323 error("A definite value must be given as a Dictionary flag");
330 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
331 warning("Dictionary flag values cannot exceed $FF in Z-code");
335 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
336 warning("Dictionary flag values cannot exceed $FFFF in Glulx");
340 dictionary_add(wd, val1, 0, val3);
344 /* --------------------------------------------------------------------- */
346 /* --------------------------------------------------------------------- */
348 case END_CODE: return(TRUE);
351 if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
355 /* --------------------------------------------------------------------- */
357 /* --------------------------------------------------------------------- */
359 case EXTEND_CODE: extend_verb(); return FALSE; /* see "tables.c" */
361 /* --------------------------------------------------------------------- */
362 /* Fake_Action name */
363 /* --------------------------------------------------------------------- */
365 case FAKE_ACTION_CODE:
366 make_fake_action(); break; /* see "verbs.c" */
368 /* --------------------------------------------------------------------- */
369 /* Global <variablename> [ [=] <value> ] */
370 /* --------------------------------------------------------------------- */
372 case GLOBAL_CODE: make_global(); break; /* See "arrays.c" */
374 /* --------------------------------------------------------------------- */
377 /* Note that each time Inform tests an If... condition, it stacks the */
378 /* result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack */
379 /* reveals what clause of the current If... is being compiled: */
381 /* If...; ... Ifnot; ... Endif; */
382 /* top of stack: TRUE FALSE */
384 /* This is used to detect "two Ifnots in same If" errors. */
385 /* --------------------------------------------------------------------- */
395 if (token_type != SYMBOL_TT)
396 return ebf_error_recover("symbol name");
398 /* Special case: a symbol of the form "VN_nnnn" is considered
399 defined if the compiler version number is at least nnnn.
400 Compiler version numbers look like "1640" for Inform 6.40;
402 ("VN_nnnn" isn't a real symbol and can't be used in other
404 if ((token_text[0] == 'V')
405 && (token_text[1] == 'N')
406 && (token_text[2] == '_')
407 && (strlen(token_text)==7))
410 i = strtol(token_text+3, &endstr, 10);
411 if (*endstr == '\0') {
412 /* All characters after the underscore were digits */
413 if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
414 goto HashIfCondition;
418 if (symbols[token_value].flags & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
419 else symbols[token_value].flags |= USED_SFLAG;
420 goto HashIfCondition;
424 error("'Ifnot' without matching 'If...'");
426 if (!(ifdef_stack[ifdef_sp-1]))
427 error("Second 'Ifnot' for the same 'If...' condition");
429 { dont_enter_into_symbol_table = -2; n = 1;
430 directives.enabled = TRUE;
433 release_token_texts();
435 if (token_type == EOF_TT)
436 { error("End of file reached in code 'If...'d out");
437 directives.enabled = FALSE;
440 if (token_type == DIRECTIVE_TT)
455 "Second 'Ifnot' for the same 'If...' condition");
462 dont_enter_into_symbol_table = FALSE;
463 directives.enabled = FALSE;
469 if (!glulx_mode && version_number <= 3) flag = TRUE;
470 goto HashIfCondition;
474 if (!glulx_mode && version_number <= 3) flag = FALSE;
475 goto HashIfCondition;
478 { assembly_operand AO;
479 AO = parse_expression(CONSTANT_CONTEXT);
481 { error("This condition can't be determined");
484 else flag = (AO.value != 0);
486 goto HashIfCondition;
489 { assembly_operand AO;
490 AO = parse_expression(CONSTANT_CONTEXT);
492 { error("This condition can't be determined");
495 else flag = (AO.value == 0);
497 goto HashIfCondition;
501 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
502 return ebf_error_recover("semicolon after 'If...' condition");
504 if (ifdef_sp >= MAX_IFDEF_STACK) {
505 error("'If' directives nested too deeply");
506 panic_mode_error_recovery(); return FALSE;
510 { ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
512 { dont_enter_into_symbol_table = -2; n = 1;
513 directives.enabled = TRUE;
516 release_token_texts();
518 if (token_type == EOF_TT)
519 { error("End of file reached in code 'If...'d out");
520 directives.enabled = FALSE;
523 if (token_type == DIRECTIVE_TT)
537 { ifdef_stack[ifdef_sp++] = FALSE;
543 directives.enabled = FALSE;
544 dont_enter_into_symbol_table = FALSE;
548 /* --------------------------------------------------------------------- */
549 /* Import global <varname> [, ...] */
550 /* --------------------------------------------------------------------- */
553 error("The 'Import' directive is no longer supported.");
556 /* --------------------------------------------------------------------- */
557 /* Include "[>]filename" */
559 /* The ">" character means to load the file from the same directory as */
560 /* the current file, instead of relying on the include path. */
561 /* --------------------------------------------------------------------- */
565 if (token_type != DQ_TT)
566 return ebf_error_recover("filename in double-quotes");
568 { char *name = token_text;
571 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
572 ebf_curtoken_error("semicolon ';' after Include filename");
574 if (strcmp(name, "language__") == 0)
575 load_sourcefile(Language_Name, 0);
576 else if (name[0] == '>')
577 load_sourcefile(name+1, 1);
578 else load_sourcefile(name, 0);
582 /* --------------------------------------------------------------------- */
583 /* Link "filename" */
584 /* --------------------------------------------------------------------- */
588 error("The 'Link' directive is no longer supported.");
591 /* --------------------------------------------------------------------- */
592 /* Lowstring constantname "text of string" */
593 /* --------------------------------------------------------------------- */
594 /* Unlike most constant creations, these do not require backpatching: */
595 /* the low strings always occupy a table at a fixed offset in the */
596 /* Z-machine (after the abbreviations table has finished, at 0x100). */
597 /* --------------------------------------------------------------------- */
601 error("The LowString directive has no meaning in Glulx.");
602 panic_mode_error_recovery(); return FALSE;
604 get_next_token(); i = token_value;
605 if (token_type != SYMBOL_TT)
606 return ebf_error_recover("new low string name");
607 if (!(symbols[i].flags & UNKNOWN_SFLAG))
608 return ebf_symbol_error_recover("new low string name", typename(symbols[i].type), symbols[i].line);
611 if (token_type != DQ_TT)
612 return ebf_error_recover("literal string in double-quotes");
614 assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
617 /* --------------------------------------------------------------------- */
618 /* Message | "information" */
619 /* | error "error message" */
620 /* | fatalerror "fatal error message" */
621 /* | warning "warning message" */
622 /* --------------------------------------------------------------------- */
625 directive_keywords.enabled = TRUE;
627 directive_keywords.enabled = FALSE;
628 if (token_type == DQ_TT)
630 if (hash_printed_since_newline) printf("\n");
631 for (i=0; token_text[i]!=0; i++)
632 { if (token_text[i] == '^') printf("\n");
634 if (token_text[i] == '~') printf("\"");
635 else printf("%c", token_text[i]);
640 if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
642 if (token_type != DQ_TT)
643 { return ebf_error_recover("error message in double-quotes");
645 error(token_text); break;
647 if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
649 if (token_type != DQ_TT)
650 { return ebf_error_recover("fatal error message in double-quotes");
652 fatalerror(token_text); break;
654 if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
656 if (token_type != DQ_TT)
657 { return ebf_error_recover("warning message in double-quotes");
659 warning(token_text); break;
661 return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'");
664 /* --------------------------------------------------------------------- */
665 /* Nearby objname "short name" ... */
666 /* --------------------------------------------------------------------- */
669 make_object(TRUE, NULL, -1, -1, -1);
670 return FALSE; /* See "objects.c" */
672 /* --------------------------------------------------------------------- */
673 /* Object objname "short name" ... */
674 /* --------------------------------------------------------------------- */
677 make_object(FALSE, NULL, -1, -1, -1);
678 return FALSE; /* See "objects.c" */
680 /* --------------------------------------------------------------------- */
681 /* Origsource <file> */
682 /* Origsource <file> <line> */
683 /* Origsource <file> <line> <char> */
686 /* The first three forms declare that all following lines are derived */
687 /* from the named Inform 7 source file (with an optional line number */
688 /* and character number). This will be reported in error messages and */
689 /* in debug output. The declaration holds through the next Origsource */
690 /* directive (but does not apply to included files). */
692 /* The fourth form, with no arguments, clears the declaration. */
694 /* Unlike the Include directive, Origsource does not open the named */
695 /* file or even verify that it exists. The filename is treated as an */
697 /* --------------------------------------------------------------------- */
699 case ORIGSOURCE_CODE:
701 char *origsource_file = NULL;
702 int32 origsource_line = 0;
703 int32 origsource_char = 0;
705 /* Parse some optional tokens followed by a mandatory semicolon. */
708 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
709 if (token_type != DQ_TT) {
710 return ebf_error_recover("a file name in double-quotes");
712 origsource_file = token_text;
715 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
716 if (token_type != NUMBER_TT) {
717 return ebf_error_recover("a file line number");
719 origsource_line = token_value;
720 if (origsource_line < 0)
724 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
725 if (token_type != NUMBER_TT) {
726 return ebf_error_recover("a file line number");
728 origsource_char = token_value;
729 if (origsource_char < 0)
739 set_origsource_location(origsource_file, origsource_line, origsource_char);
743 /* --------------------------------------------------------------------- */
744 /* Property [long] [additive] name */
745 /* Property [long] [additive] name alias oldname */
746 /* Property [long] [additive] name defaultvalue */
747 /* Property [long] individual name */
748 /* --------------------------------------------------------------------- */
750 case PROPERTY_CODE: make_property(); break; /* See "objects.c" */
752 /* --------------------------------------------------------------------- */
753 /* Release <number> */
754 /* --------------------------------------------------------------------- */
757 { assembly_operand AO;
758 AO = parse_expression(CONSTANT_CONTEXT);
760 error("A definite value must be given as release number");
762 release_number = AO.value;
766 /* --------------------------------------------------------------------- */
767 /* Replace routine [routinename] */
768 /* --------------------------------------------------------------------- */
771 /* You can also replace system functions normally implemented in */
772 /* the "hardware" of the Z-machine, like "random()": */
774 system_functions.enabled = TRUE;
775 directives.enabled = FALSE;
776 directive_keywords.enabled = FALSE;
778 /* Don't count the upcoming symbol as a top-level reference
779 *to* the function. */
780 df_dont_note_global_symbols = TRUE;
782 df_dont_note_global_symbols = FALSE;
783 if (token_type == SYSFUN_TT)
784 { if (system_function_usage[token_value] == 1)
785 error("You can't 'Replace' a system function already used");
786 else system_function_usage[token_value] = 2;
788 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
790 error("You can't give a 'Replace'd system function a new name");
791 panic_mode_error_recovery(); return FALSE;
796 if (token_type != SYMBOL_TT)
797 return ebf_error_recover("name of routine to replace");
798 if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
799 return ebf_error_recover("name of routine not yet defined");
801 symbols[token_value].flags |= REPLACE_SFLAG;
803 /* If a second symbol is provided, it will refer to the
804 original (replaced) definition of the routine. */
807 system_functions.enabled = FALSE;
808 df_dont_note_global_symbols = TRUE;
810 df_dont_note_global_symbols = FALSE;
811 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
815 if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG))
816 return ebf_error_recover("semicolon ';' or new routine name");
818 /* Define the original-form symbol as a zero constant. Its
819 value will be overwritten later, when we define the
821 assign_symbol(token_value, 0, CONSTANT_T);
822 add_symbol_replacement_mapping(i, token_value);
826 /* --------------------------------------------------------------------- */
827 /* Serial "yymmdd" */
828 /* --------------------------------------------------------------------- */
832 if ((token_type != DQ_TT) || (strlen(token_text)!=6))
833 { error("The serial number must be a 6-digit date in double-quotes");
834 panic_mode_error_recovery(); return FALSE;
836 for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
837 { error("The serial number must be a 6-digit date in double-quotes");
838 panic_mode_error_recovery(); return FALSE;
840 strcpy(serial_code_buffer, token_text);
841 serial_code_given_in_program = TRUE;
844 /* --------------------------------------------------------------------- */
845 /* Statusline score/time */
846 /* --------------------------------------------------------------------- */
848 case STATUSLINE_CODE:
849 directive_keywords.enabled = TRUE;
851 directive_keywords.enabled = FALSE;
852 if ((token_type != DIR_KEYWORD_TT)
853 || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
854 return ebf_error_recover("'score' or 'time' after 'statusline'");
855 if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
856 else statusline_flag = TIME_STYLE;
859 /* --------------------------------------------------------------------- */
860 /* Stub routinename number-of-locals */
861 /* --------------------------------------------------------------------- */
864 /* The upcoming symbol is a definition; don't count it as a
865 top-level reference *to* the stub function. */
866 df_dont_note_global_symbols = TRUE;
868 df_dont_note_global_symbols = FALSE;
869 if (token_type != SYMBOL_TT)
870 return ebf_error_recover("routine name to stub");
872 i = token_value; flag = FALSE;
874 if (symbols[i].flags & UNKNOWN_SFLAG)
875 { symbols[i].flags |= STUB_SFLAG;
879 get_next_token(); k = token_value;
880 if (token_type != NUMBER_TT)
881 return ebf_error_recover("number of local variables");
883 { error("Must specify 0 to 4 local variables for 'Stub' routine");
889 /* Give these parameter-receiving local variables names
890 for the benefit of the debugging information file,
891 and for assembly tracing to look sensible.
892 (We don't set local_variable.keywords because we're not
893 going to be parsing any code.) */
895 clear_local_variables();
896 if (k >= 1) add_local_variable("dummy1");
897 if (k >= 2) add_local_variable("dummy2");
898 if (k >= 3) add_local_variable("dummy3");
899 if (k >= 4) add_local_variable("dummy4");
902 assemble_routine_header(FALSE, symbols[i].name, FALSE, i),
905 /* Ensure the return value of a stubbed routine is false,
906 since this is necessary to make the library work properly */
909 assemblez_0(rfalse_zc);
911 assembleg_1(return_gc, zero_operand);
913 /* Inhibit "local variable unused" warnings */
915 for (i=1; i<=k; i++) variables[i].usage = 1;
916 sequence_point_follows = FALSE;
917 assemble_routine_end(FALSE, get_token_locations());
921 /* --------------------------------------------------------------------- */
922 /* Switches switchblock */
923 /* (this directive is ignored if the -i switch was set at command line) */
924 /* --------------------------------------------------------------------- */
927 dont_enter_into_symbol_table = TRUE;
929 dont_enter_into_symbol_table = FALSE;
930 if (token_type != UQ_TT)
931 return ebf_error_recover("string of switches");
932 if (!ignore_switches_switch)
934 if (constant_made_yet) {
935 error("A 'Switches' directive must must come before the first constant definition");
940 /* The built-in Main__ routine is number zero. */
941 error("A 'Switches' directive must come before the first routine definition.");
944 obsolete_warning("the Switches directive is deprecated and may produce incorrect results. Use command-line arguments or header comments.");
945 switches(token_text, 0); /* see "inform.c" */
949 /* --------------------------------------------------------------------- */
952 /* Some files are declared as "system files": this information is used */
953 /* by Inform only to skip the definition of a routine X if the designer */
954 /* has indicated his intention to Replace X. */
955 /* --------------------------------------------------------------------- */
958 declare_systemfile(); break; /* see "files.c" */
960 /* --------------------------------------------------------------------- */
961 /* Trace dictionary [on/NUM] */
962 /* objects [on/NUM] */
963 /* symbols [on/NUM] */
965 /* [on/off/NUM] {same as "assembly"} */
966 /* assembly [on/off/NUM] */
967 /* expressions [on/off/NUM] */
968 /* lines [on/off/NUM] {not supported} */
969 /* tokens [on/off/NUM] */
970 /* linker [on/off/NUM] {not supported} */
972 /* The first four trace commands immediately display a compiler table. */
973 /* The rest set or clear an ongoing trace. */
974 /* --------------------------------------------------------------------- */
977 directives.enabled = FALSE;
978 trace_keywords.enabled = TRUE;
980 trace_keywords.enabled = FALSE;
981 directives.enabled = TRUE;
983 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
987 trace_level = &asm_trace_level;
989 goto HandleTraceKeyword;
991 if (token_type == NUMBER_TT) {
994 trace_level = &asm_trace_level;
996 goto HandleTraceKeyword;
999 /* Anything else must be "Trace KEYWORD..." Remember that
1000 'on' and 'off' are trace keywords. */
1002 if (token_type != TRACE_KEYWORD_TT)
1003 return ebf_error_recover("debugging keyword");
1005 trace_keywords.enabled = TRUE;
1007 /* Note that "Trace verbs" doesn't affect list_verbs_setting.
1008 It shows the grammar at this point in the code. Setting
1009 list_verbs_setting shows the grammar at the end of
1011 Same goes for "Trace dictionary" and list_dict_setting, etc. */
1018 trace_level = &asm_trace_level; break;
1019 case EXPRESSIONS_TK:
1020 trace_level = &expr_trace_level; break;
1022 trace_level = &tokens_trace_level; break;
1027 /* show a table rather than changing any trace level */
1028 trace_level = NULL; break;
1030 /* never implememented */
1031 trace_level = NULL; break;
1033 /* no longer implememented */
1034 trace_level = NULL; break;
1036 /* default to "Trace assembly" */
1038 trace_level = &asm_trace_level; break;
1043 if ((token_type == SEP_TT) &&
1044 (token_value == SEMICOLON_SEP))
1047 else if (token_type == NUMBER_TT)
1050 else if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1053 else if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1060 trace_keywords.enabled = FALSE;
1064 if (i == LINES_TK || i == LINKER_TK) {
1065 warning_named("Trace option is not supported:", trace_keywords.keywords[i]);
1069 if (trace_level == NULL && j == 0) {
1070 warning_named("Trace directive to display table at 'off' level has no effect: table", trace_keywords.keywords[i]);
1075 { case DICTIONARY_TK: show_dictionary(j); break;
1076 case OBJECTS_TK: list_object_tree(); break;
1077 case SYMBOLS_TK: list_symbols(j); break;
1078 case VERBS_TK: list_verb_table(); break;
1086 /* --------------------------------------------------------------------- */
1088 /* --------------------------------------------------------------------- */
1092 if (token_type != SYMBOL_TT)
1093 return ebf_error_recover("symbol name");
1095 if (symbols[token_value].flags & UNKNOWN_SFLAG)
1096 { break; /* undef'ing an undefined constant is okay */
1099 if (symbols[token_value].type != CONSTANT_T)
1100 { error_named("Cannot Undef a symbol which is not a defined constant:", symbols[token_value].name);
1104 if (debugfile_switch)
1105 { write_debug_undef(token_value);
1107 /* We remove it from the symbol table. But previous uses of the symbol
1108 were valid, so we don't set neverused true. We also mark it
1109 USED so that it can't trigger "symbol not used" warnings. */
1110 end_symbol_scope(token_value, FALSE);
1111 symbols[token_value].flags |= USED_SFLAG;
1114 /* --------------------------------------------------------------------- */
1116 /* --------------------------------------------------------------------- */
1118 case VERB_CODE: make_verb(); return FALSE; /* see "tables.c" */
1120 /* --------------------------------------------------------------------- */
1121 /* Version <number> */
1122 /* --------------------------------------------------------------------- */
1126 { assembly_operand AO;
1127 AO = parse_expression(CONSTANT_CONTEXT);
1128 /* If a version has already been set on the command line,
1129 that overrides this. */
1130 if (version_set_switch)
1132 warning("The Version directive was overridden by a command-line argument.");
1138 error("A definite value must be given as version number.");
1141 else if (no_routines > 1)
1143 /* The built-in Main__ routine is number zero. */
1144 error("A 'Version' directive must come before the first routine definition.");
1147 else if (glulx_mode)
1149 warning("The Version directive does not work in Glulx. Use \
1150 -vX.Y.Z instead, as either a command-line argument or a header comment.");
1158 { error("The version number must be in the range 3 to 8");
1161 obsolete_warning("the Version directive is deprecated and may produce incorrect results. Use -vN instead, as either a command-line argument or a header comment.");
1163 /* We must now do a small dance to reset the DICT_ENTRY_BYTES
1164 constant, which was defined at startup based on the Z-code
1166 The calculation here is repeated from select_target(). */
1167 DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0);
1168 debtok = get_symbol_index("DICT_ENTRY_BYTES");
1169 if (debtok >= 0 && !(symbols[debtok].flags & UNKNOWN_SFLAG))
1171 if (!(symbols[debtok].flags & REDEFINABLE_SFLAG))
1173 warning("The DICT_ENTRY_BYTES symbol is not marked redefinable");
1175 /* Redefine the symbol... */
1176 assign_symbol(debtok, DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
1180 break; /* see "inform.c" */
1182 /* --------------------------------------------------------------------- */
1183 /* Zcharacter table <num> ... */
1184 /* Zcharacter table + <num> ... */
1185 /* Zcharacter <string> <string> <string> */
1186 /* Zcharacter <char> */
1187 /* --------------------------------------------------------------------- */
1189 case ZCHARACTER_CODE:
1192 error("The Zcharacter directive has no meaning in Glulx.");
1193 panic_mode_error_recovery(); return FALSE;
1196 directive_keywords.enabled = TRUE;
1198 directive_keywords.enabled = FALSE;
1202 new_alphabet(token_text, 0);
1204 if (token_type != DQ_TT)
1205 return ebf_error_recover("double-quoted alphabet string");
1206 new_alphabet(token_text, 1);
1208 if (token_type != DQ_TT)
1209 return ebf_error_recover("double-quoted alphabet string");
1210 new_alphabet(token_text, 2);
1214 map_new_zchar(text_to_unicode(token_text));
1215 if (token_text[textual_form_length] != 0)
1216 return ebf_error_recover("single character value");
1219 case DIR_KEYWORD_TT:
1222 { int plus_flag = FALSE;
1224 if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1228 while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1229 { switch(token_type)
1231 new_zscii_character(token_value, plus_flag);
1232 plus_flag = TRUE; break;
1234 new_zscii_character(text_to_unicode(token_text),
1236 if (token_text[textual_form_length] != 0)
1237 return ebf_error_recover("single character value");
1241 return ebf_error_recover("character or Unicode number");
1245 if (plus_flag) new_zscii_finished();
1249 case TERMINATING_DK:
1251 while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1252 { switch(token_type)
1254 terminating_characters[no_termcs++]
1258 return ebf_error_recover("ZSCII number");
1265 return ebf_error_recover("'table', 'terminating', \
1266 a string or a constant");
1270 return ebf_error_recover("three alphabet strings, \
1271 a 'table' or 'terminating' command or a single character");
1275 /* ===================================================================== */
1279 /* We are now at the end of a syntactically valid directive. It
1280 should be terminated by a semicolon. */
1283 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1284 { ebf_curtoken_error("';'");
1285 /* Put the non-semicolon back. We will continue parsing from
1286 that point, in hope that it's the start of a new directive.
1287 (This recovers cleanly from a missing semicolon at the end
1288 of a directive. It's not so clean if the directive *does*
1289 end with a semicolon, but there's extra garbage before it.) */
1295 /* ========================================================================= */
1296 /* Data structure management routines */
1297 /* ------------------------------------------------------------------------- */
1299 extern void init_directs_vars(void)
1303 extern void directs_begin_pass(void)
1305 no_named_routines = 0;
1307 constant_made_yet = FALSE;
1311 extern void directs_allocate_arrays(void)
1315 extern void directs_free_arrays(void)
1319 /* ========================================================================= */