1 /* ------------------------------------------------------------------------- */
2 /* "directs" : Directives (# commands) */
4 /* Part of Inform 6.40 */
5 /* copyright (c) Graham Nelson 1993 - 2022 */
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 #define MAX_IFDEF_STACK (32)
38 static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
40 /* ------------------------------------------------------------------------- */
42 static int ebf_error_recover(char *s1, char *s2)
44 /* Display an "expected... but found..." error, then skim forward
45 to the next semicolon and return FALSE. This is such a common
46 case in parse_given_directive() that it's worth a utility
47 function. You will see many error paths that look like:
48 return ebf_error_recover(...);
51 panic_mode_error_recovery();
55 static int ebf_symbol_error_recover(char *s1, char *name, char *type, brief_location report_line)
57 /* Same for ebf_symbol_error(). */
58 ebf_symbol_error(s1, name, type, report_line);
59 panic_mode_error_recovery();
63 /* ------------------------------------------------------------------------- */
65 extern int parse_given_directive(int internal_flag)
66 { /* Internal_flag is FALSE if the directive is encountered normally,
67 TRUE if encountered with a # prefix inside a routine or object
70 Returns: FALSE if program continues, TRUE if end of file reached. */
72 int *trace_level = NULL; int32 i, j, k, n, flag;
73 const char *constant_name;
74 debug_location_beginning beginning_debug_location;
78 /* Only certain directives, such as #ifdef, are permitted within
79 a routine or object definition. In older versions of Inform,
80 nearly any directive was accepted, but this was -- to quote
81 an old code comment -- "about as well-supported as Wile E.
82 Coyote one beat before the plummet-lines kick in." */
84 if (token_value != IFV3_CODE && token_value != IFV5_CODE
85 && token_value != IFDEF_CODE && token_value != IFNDEF_CODE
86 && token_value != IFTRUE_CODE && token_value != IFFALSE_CODE
87 && token_value != IFNOT_CODE && token_value != ENDIF_CODE
88 && token_value != MESSAGE_CODE && token_value != ORIGSOURCE_CODE
89 && token_value != TRACE_CODE) {
90 char *dirname = directives.keywords[token_value];
91 error_named("Cannot nest this directive inside a routine or object:", dirname);
92 panic_mode_error_recovery(); return FALSE;
99 /* --------------------------------------------------------------------- */
100 /* Abbreviate "string1" ["string2" ...] */
101 /* --------------------------------------------------------------------- */
103 case ABBREVIATE_CODE:
107 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
110 if (!glulx_mode && no_abbreviations==96)
111 { error_max_abbreviations(no_abbreviations);
112 panic_mode_error_recovery(); return FALSE;
114 if (!glulx_mode && no_abbreviations==MAX_ABBREVS)
115 { error_max_abbreviations(no_abbreviations);
116 /* This is no longer a memoryerror(); MAX_ABBREVS is an authoring decision for Z-code games. */
117 panic_mode_error_recovery(); return FALSE;
120 if (abbrevs_lookup_table_made)
121 { error("All abbreviations must be declared together");
122 panic_mode_error_recovery(); return FALSE;
124 if (token_type != DQ_TT)
125 { return ebf_error_recover("abbreviation string", token_text);
127 /* Abbreviation string with null must fit in a MAX_ABBREV_LENGTH
129 if (strlen(token_text)>=MAX_ABBREV_LENGTH)
130 { error_named("Abbreviation too long", token_text);
133 make_abbreviation(token_text);
136 /* --------------------------------------------------------------------- */
137 /* Array arrayname array... */
138 /* --------------------------------------------------------------------- */
140 case ARRAY_CODE: make_global(TRUE, FALSE); break; /* See "tables.c" */
142 /* --------------------------------------------------------------------- */
143 /* Attribute newname [alias oldname] */
144 /* --------------------------------------------------------------------- */
147 make_attribute(); break; /* See "objects.c" */
149 /* --------------------------------------------------------------------- */
150 /* Class classname ... */
151 /* --------------------------------------------------------------------- */
154 make_class(NULL); /* See "objects.c" */
157 /* --------------------------------------------------------------------- */
158 /* Constant newname [[=] value] [, ...] */
159 /* --------------------------------------------------------------------- */
162 constant_made_yet=TRUE;
165 get_next_token(); i = token_value;
166 beginning_debug_location = get_token_location_beginning();
168 if (token_type != SYMBOL_TT)
169 { discard_token_location(beginning_debug_location);
170 return ebf_error_recover("new constant name", token_text);
173 if (!(symbols[i].flags & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
174 { discard_token_location(beginning_debug_location);
175 return ebf_symbol_error_recover("new constant name", token_text, typename(symbols[i].type), symbols[i].line);
178 assign_symbol(i, 0, CONSTANT_T);
179 constant_name = token_text;
183 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
184 { if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
185 { debug_file_printf("<constant>");
186 debug_file_printf("<identifier>%s</identifier>", constant_name);
187 write_debug_symbol_optional_backpatch(i);
188 write_debug_locations(get_token_location_end(beginning_debug_location));
189 debug_file_printf("</constant>");
191 goto ParseConstantSpec;
194 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
195 { if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
196 { debug_file_printf("<constant>");
197 debug_file_printf("<identifier>%s</identifier>", constant_name);
198 write_debug_symbol_optional_backpatch(i);
199 write_debug_locations(get_token_location_end(beginning_debug_location));
200 debug_file_printf("</constant>");
205 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
208 { assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
210 { assign_marked_symbol(i, AO.marker, AO.value,
212 symbols[i].flags |= CHANGE_SFLAG;
213 if (i == grammar_version_symbol)
215 "Grammar__Version must be given an explicit constant value");
218 { assign_symbol(i, AO.value, CONSTANT_T);
219 if (i == grammar_version_symbol)
220 { if ((grammar_version_number != AO.value)
221 && (no_fake_actions > 0))
223 "Once a fake action has been defined it is too late to \
224 change the grammar version. (If you are using the library, move any \
225 Fake_Action directives to a point after the inclusion of \"Parser\".)");
226 grammar_version_number = AO.value;
231 if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
232 { debug_file_printf("<constant>");
233 debug_file_printf("<identifier>%s</identifier>", constant_name);
234 write_debug_symbol_optional_backpatch(i);
235 write_debug_locations
236 (get_token_location_end(beginning_debug_location));
237 debug_file_printf("</constant>");
241 if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
242 goto ParseConstantSpec;
246 /* --------------------------------------------------------------------- */
247 /* Default constantname integer */
248 /* --------------------------------------------------------------------- */
252 { error("'Default' cannot be used in -M (Module) mode");
253 panic_mode_error_recovery(); return FALSE;
257 if (token_type != SYMBOL_TT)
258 return ebf_error_recover("name", token_text);
261 if (symbols[token_value].flags & UNKNOWN_SFLAG)
263 symbols[i].flags |= DEFCON_SFLAG;
267 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
270 { assembly_operand AO;
271 AO = parse_expression(CONSTANT_CONTEXT);
273 { if (AO.marker != 0)
274 { assign_marked_symbol(i, AO.marker, AO.value,
276 symbols[i].flags |= CHANGE_SFLAG;
278 else assign_symbol(i, AO.value, CONSTANT_T);
284 /* --------------------------------------------------------------------- */
285 /* Dictionary 'word' */
286 /* Dictionary 'word' val1 */
287 /* Dictionary 'word' val1 val3 */
288 /* --------------------------------------------------------------------- */
290 case DICTIONARY_CODE:
291 /* In Inform 5, this directive had the form
292 Dictionary SYMBOL "word";
293 This was deprecated as of I6 (if not earlier), and is no longer
294 supported at all. The current form just creates a dictionary word,
295 with the given values for dict_par1 and dict_par3. If the word
296 already exists, the values are bit-or'd in with the existing
298 (We don't offer a way to set dict_par2, because that is entirely
299 reserved for the verb number. Or'ing values into it would create
303 if (token_type != SQ_TT && token_type != DQ_TT)
304 return ebf_error_recover("dictionary word", token_text);
307 char *wd = token_text;
312 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
318 AO = parse_expression(CONSTANT_CONTEXT);
320 error("A definite value must be given as a Dictionary flag");
325 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
331 if (ZCODE_LESS_DICT_DATA && !glulx_mode)
332 warning("The third dictionary field will be ignored because ZCODE_LESS_DICT_DATA is set");
333 AO = parse_expression(CONSTANT_CONTEXT);
335 error("A definite value must be given as a Dictionary flag");
342 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
343 warning("Dictionary flag values cannot exceed $FF in Z-code");
347 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
348 warning("Dictionary flag values cannot exceed $FFFF in Glulx");
352 dictionary_add(wd, val1, 0, val3);
356 /* --------------------------------------------------------------------- */
358 /* --------------------------------------------------------------------- */
360 case END_CODE: return(TRUE);
363 if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
367 /* --------------------------------------------------------------------- */
369 /* --------------------------------------------------------------------- */
371 case EXTEND_CODE: extend_verb(); return FALSE; /* see "tables.c" */
373 /* --------------------------------------------------------------------- */
374 /* Fake_Action name */
375 /* --------------------------------------------------------------------- */
377 case FAKE_ACTION_CODE:
378 make_fake_action(); break; /* see "verbs.c" */
380 /* --------------------------------------------------------------------- */
381 /* Global variable [= value / array...] */
382 /* --------------------------------------------------------------------- */
384 case GLOBAL_CODE: make_global(FALSE, FALSE); break; /* See "tables.c" */
386 /* --------------------------------------------------------------------- */
389 /* Note that each time Inform tests an If... condition, it stacks the */
390 /* result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack */
391 /* reveals what clause of the current If... is being compiled: */
393 /* If...; ... Ifnot; ... Endif; */
394 /* top of stack: TRUE FALSE */
396 /* This is used to detect "two Ifnots in same If" errors. */
397 /* --------------------------------------------------------------------- */
407 if (token_type != SYMBOL_TT)
408 return ebf_error_recover("symbol name", token_text);
410 /* Special case: a symbol of the form "VN_nnnn" is considered
411 defined if the compiler version number is at least nnnn.
412 Compiler version numbers look like "1640" for Inform 6.40;
414 ("VN_nnnn" isn't a real symbol and can't be used in other
416 if ((token_text[0] == 'V')
417 && (token_text[1] == 'N')
418 && (token_text[2] == '_')
419 && (strlen(token_text)==7))
422 i = strtol(token_text+3, &endstr, 10);
423 if (*endstr == '\0') {
424 /* All characters after the underscore were digits */
425 if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
426 goto HashIfCondition;
430 if (symbols[token_value].flags & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
431 else symbols[token_value].flags |= USED_SFLAG;
432 goto HashIfCondition;
436 error("'Ifnot' without matching 'If...'");
438 if (!(ifdef_stack[ifdef_sp-1]))
439 error("Second 'Ifnot' for the same 'If...' condition");
441 { dont_enter_into_symbol_table = -2; n = 1;
442 directives.enabled = TRUE;
445 release_token_texts();
447 if (token_type == EOF_TT)
448 { error("End of file reached in code 'If...'d out");
449 directives.enabled = FALSE;
452 if (token_type == DIRECTIVE_TT)
467 "Second 'Ifnot' for the same 'If...' condition");
474 dont_enter_into_symbol_table = FALSE;
475 directives.enabled = FALSE;
481 if (!glulx_mode && version_number <= 3) flag = TRUE;
482 goto HashIfCondition;
486 if (!glulx_mode && version_number <= 3) flag = FALSE;
487 goto HashIfCondition;
490 { assembly_operand AO;
491 AO = parse_expression(CONSTANT_CONTEXT);
493 { error("This condition can't be determined");
496 else flag = (AO.value != 0);
498 goto HashIfCondition;
501 { assembly_operand AO;
502 AO = parse_expression(CONSTANT_CONTEXT);
504 { error("This condition can't be determined");
507 else flag = (AO.value == 0);
509 goto HashIfCondition;
513 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
514 return ebf_error_recover("semicolon after 'If...' condition", token_text);
516 if (ifdef_sp >= MAX_IFDEF_STACK) {
517 error("'If' directives nested too deeply");
518 panic_mode_error_recovery(); return FALSE;
522 { ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
524 { dont_enter_into_symbol_table = -2; n = 1;
525 directives.enabled = TRUE;
528 release_token_texts();
530 if (token_type == EOF_TT)
531 { error("End of file reached in code 'If...'d out");
532 directives.enabled = FALSE;
535 if (token_type == DIRECTIVE_TT)
549 { ifdef_stack[ifdef_sp++] = FALSE;
555 directives.enabled = FALSE;
556 dont_enter_into_symbol_table = FALSE;
560 /* --------------------------------------------------------------------- */
561 /* Import global <varname> [, ...] */
563 /* (Further imported goods may be allowed later.) */
564 /* --------------------------------------------------------------------- */
568 { error("'Import' can only be used in -M (Module) mode");
569 panic_mode_error_recovery(); return FALSE;
571 directives.enabled = TRUE;
574 if ((token_type == DIRECTIVE_TT) && (token_value == GLOBAL_CODE))
575 make_global(FALSE, TRUE);
576 else error_named("'Import' cannot import things of this type:",
579 } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
581 directives.enabled = FALSE;
584 /* --------------------------------------------------------------------- */
585 /* Include "[>]filename" */
587 /* The ">" character means to load the file from the same directory as */
588 /* the current file, instead of relying on the include path. */
589 /* --------------------------------------------------------------------- */
593 if (token_type != DQ_TT)
594 return ebf_error_recover("filename in double-quotes", token_text);
596 { char *name = token_text;
599 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
600 ebf_error("semicolon ';' after Include filename", token_text);
602 if (strcmp(name, "language__") == 0)
603 load_sourcefile(Language_Name, 0);
604 else if (name[0] == '>')
605 load_sourcefile(name+1, 1);
606 else load_sourcefile(name, 0);
610 /* --------------------------------------------------------------------- */
611 /* Link "filename" */
612 /* --------------------------------------------------------------------- */
616 if (token_type != DQ_TT)
617 return ebf_error_recover("filename in double-quotes", token_text);
618 if (strlen(token_text) >= PATHLEN-1) {
619 error_numbered("'Link' filename is too long; max length is", PATHLEN-1);
622 link_module(token_text); /* See "linker.c" */
625 /* --------------------------------------------------------------------- */
626 /* Lowstring constantname "text of string" */
627 /* --------------------------------------------------------------------- */
628 /* Unlike most constant creations, these do not require backpatching: */
629 /* the low strings always occupy a table at a fixed offset in the */
630 /* Z-machine (after the abbreviations table has finished, at 0x100). */
631 /* --------------------------------------------------------------------- */
635 { error("'LowString' cannot be used in -M (Module) mode");
636 panic_mode_error_recovery(); return FALSE;
639 error("The LowString directive has no meaning in Glulx.");
640 panic_mode_error_recovery(); return FALSE;
642 get_next_token(); i = token_value;
643 if (token_type != SYMBOL_TT)
644 return ebf_error_recover("new low string name", token_text);
645 if (!(symbols[i].flags & UNKNOWN_SFLAG))
646 return ebf_symbol_error_recover("new low string name", token_text, typename(symbols[i].type), symbols[i].line);
649 if (token_type != DQ_TT)
650 return ebf_error_recover("literal string in double-quotes", token_text);
652 assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
655 /* --------------------------------------------------------------------- */
656 /* Message | "information" */
657 /* | error "error message" */
658 /* | fatalerror "fatal error message" */
659 /* | warning "warning message" */
660 /* --------------------------------------------------------------------- */
663 directive_keywords.enabled = TRUE;
665 directive_keywords.enabled = FALSE;
666 if (token_type == DQ_TT)
668 if (hash_printed_since_newline) printf("\n");
669 for (i=0; token_text[i]!=0; i++)
670 { if (token_text[i] == '^') printf("\n");
672 if (token_text[i] == '~') printf("\"");
673 else printf("%c", token_text[i]);
678 if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
680 if (token_type != DQ_TT)
681 { return ebf_error_recover("error message in double-quotes", token_text);
683 error(token_text); break;
685 if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
687 if (token_type != DQ_TT)
688 { return ebf_error_recover("fatal error message in double-quotes", token_text);
690 fatalerror(token_text); break;
692 if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
694 if (token_type != DQ_TT)
695 { return ebf_error_recover("warning message in double-quotes", token_text);
697 warning(token_text); break;
699 return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
703 /* --------------------------------------------------------------------- */
704 /* Nearby objname "short name" ... */
705 /* --------------------------------------------------------------------- */
708 make_object(TRUE, NULL, -1, -1, -1);
709 return FALSE; /* See "objects.c" */
711 /* --------------------------------------------------------------------- */
712 /* Object objname "short name" ... */
713 /* --------------------------------------------------------------------- */
716 make_object(FALSE, NULL, -1, -1, -1);
717 return FALSE; /* See "objects.c" */
719 /* --------------------------------------------------------------------- */
720 /* Origsource <file> */
721 /* Origsource <file> <line> */
722 /* Origsource <file> <line> <char> */
725 /* The first three forms declare that all following lines are derived */
726 /* from the named Inform 7 source file (with an optional line number */
727 /* and character number). This will be reported in error messages and */
728 /* in debug output. The declaration holds through the next Origsource */
729 /* directive (but does not apply to included files). */
731 /* The fourth form, with no arguments, clears the declaration. */
733 /* Unlike the Include directive, Origsource does not open the named */
734 /* file or even verify that it exists. The filename is treated as an */
736 /* --------------------------------------------------------------------- */
738 case ORIGSOURCE_CODE:
740 char *origsource_file = NULL;
741 int32 origsource_line = 0;
742 int32 origsource_char = 0;
744 /* Parse some optional tokens followed by a mandatory semicolon. */
747 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
748 if (token_type != DQ_TT) {
749 return ebf_error_recover("a file name in double-quotes",
752 origsource_file = token_text;
755 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
756 if (token_type != NUMBER_TT) {
757 return ebf_error_recover("a file line number",
760 origsource_line = token_value;
761 if (origsource_line < 0)
765 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
766 if (token_type != NUMBER_TT) {
767 return ebf_error_recover("a file line number",
770 origsource_char = token_value;
771 if (origsource_char < 0)
781 set_origsource_location(origsource_file, origsource_line, origsource_char);
785 /* --------------------------------------------------------------------- */
786 /* Property [long] [additive] name */
787 /* Property [long] [additive] name alias oldname */
788 /* Property [long] [additive] name defaultvalue */
789 /* Property [long] individual name */
790 /* --------------------------------------------------------------------- */
792 case PROPERTY_CODE: make_property(); break; /* See "objects.c" */
794 /* --------------------------------------------------------------------- */
795 /* Release <number> */
796 /* --------------------------------------------------------------------- */
799 { assembly_operand AO;
800 AO = parse_expression(CONSTANT_CONTEXT);
802 error("A definite value must be given as release number");
804 release_number = AO.value;
808 /* --------------------------------------------------------------------- */
809 /* Replace routine [routinename] */
810 /* --------------------------------------------------------------------- */
813 /* You can also replace system functions normally implemented in */
814 /* the "hardware" of the Z-machine, like "random()": */
816 system_functions.enabled = TRUE;
817 directives.enabled = FALSE;
818 directive_keywords.enabled = FALSE;
820 /* Don't count the upcoming symbol as a top-level reference
821 *to* the function. */
822 df_dont_note_global_symbols = TRUE;
824 df_dont_note_global_symbols = FALSE;
825 if (token_type == SYSFUN_TT)
826 { if (system_function_usage[token_value] == 1)
827 error("You can't 'Replace' a system function already used");
828 else system_function_usage[token_value] = 2;
830 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
832 error("You can't give a 'Replace'd system function a new name");
833 panic_mode_error_recovery(); return FALSE;
838 if (token_type != SYMBOL_TT)
839 return ebf_error_recover("name of routine to replace", token_text);
840 if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
841 return ebf_error_recover("name of routine not yet defined", token_text);
843 symbols[token_value].flags |= REPLACE_SFLAG;
845 /* If a second symbol is provided, it will refer to the
846 original (replaced) definition of the routine. */
849 system_functions.enabled = FALSE;
850 df_dont_note_global_symbols = TRUE;
852 df_dont_note_global_symbols = FALSE;
853 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
857 if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG))
858 return ebf_error_recover("semicolon ';' or new routine name", token_text);
860 /* Define the original-form symbol as a zero constant. Its
861 value will be overwritten later, when we define the
863 assign_symbol(token_value, 0, CONSTANT_T);
864 add_symbol_replacement_mapping(i, token_value);
868 /* --------------------------------------------------------------------- */
869 /* Serial "yymmdd" */
870 /* --------------------------------------------------------------------- */
874 if ((token_type != DQ_TT) || (strlen(token_text)!=6))
875 { error("The serial number must be a 6-digit date in double-quotes");
876 panic_mode_error_recovery(); return FALSE;
878 for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
879 { error("The serial number must be a 6-digit date in double-quotes");
880 panic_mode_error_recovery(); return FALSE;
882 strcpy(serial_code_buffer, token_text);
883 serial_code_given_in_program = TRUE;
886 /* --------------------------------------------------------------------- */
887 /* Statusline score/time */
888 /* --------------------------------------------------------------------- */
890 case STATUSLINE_CODE:
892 warning("This does not set the final game's statusline");
894 directive_keywords.enabled = TRUE;
896 directive_keywords.enabled = FALSE;
897 if ((token_type != DIR_KEYWORD_TT)
898 || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
899 return ebf_error_recover("'score' or 'time' after 'statusline'", token_text);
900 if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
901 else statusline_flag = TIME_STYLE;
904 /* --------------------------------------------------------------------- */
905 /* Stub routinename number-of-locals */
906 /* --------------------------------------------------------------------- */
909 /* The upcoming symbol is a definition; don't count it as a
910 top-level reference *to* the stub function. */
911 df_dont_note_global_symbols = TRUE;
913 df_dont_note_global_symbols = FALSE;
914 if (token_type != SYMBOL_TT)
915 return ebf_error_recover("routine name to stub", token_text);
917 i = token_value; flag = FALSE;
919 if (symbols[i].flags & UNKNOWN_SFLAG)
920 { symbols[i].flags |= STUB_SFLAG;
924 get_next_token(); k = token_value;
925 if (token_type != NUMBER_TT)
926 return ebf_error_recover("number of local variables", token_text);
928 { error("Must specify 0 to 4 local variables for 'Stub' routine");
934 /* Give these parameter-receiving local variables names
935 for the benefit of the debugging information file,
936 and for assembly tracing to look sensible.
937 (We don't set local_variable.keywords because we're not
938 going to be parsing any code.) */
940 strcpy(local_variable_names[0].text, "dummy1");
941 strcpy(local_variable_names[1].text, "dummy2");
942 strcpy(local_variable_names[2].text, "dummy3");
943 strcpy(local_variable_names[3].text, "dummy4");
946 assemble_routine_header(k, FALSE, symbols[i].name, FALSE, i),
949 /* Ensure the return value of a stubbed routine is false,
950 since this is necessary to make the library work properly */
953 assemblez_0(rfalse_zc);
955 assembleg_1(return_gc, zero_operand);
957 /* Inhibit "local variable unused" warnings */
959 for (i=1; i<=k; i++) variables[i].usage = 1;
960 sequence_point_follows = FALSE;
961 assemble_routine_end(FALSE, get_token_locations());
965 /* --------------------------------------------------------------------- */
966 /* Switches switchblock */
967 /* (this directive is ignored if the -i switch was set at command line) */
968 /* --------------------------------------------------------------------- */
971 dont_enter_into_symbol_table = TRUE;
973 dont_enter_into_symbol_table = FALSE;
974 if (token_type != DQ_TT)
975 return ebf_error_recover("string of switches", token_text);
976 if (!ignore_switches_switch)
977 { if (constant_made_yet)
978 error("A 'Switches' directive must must come before \
979 the first constant definition");
980 switches(token_text, 0); /* see "inform.c" */
984 /* --------------------------------------------------------------------- */
987 /* Some files are declared as "system files": this information is used */
988 /* by Inform only to skip the definition of a routine X if the designer */
989 /* has indicated his intention to Replace X. */
990 /* --------------------------------------------------------------------- */
993 declare_systemfile(); break; /* see "files.c" */
995 /* --------------------------------------------------------------------- */
996 /* Trace dictionary [on/NUM] */
997 /* objects [on/NUM] */
998 /* symbols [on/NUM] */
1000 /* [on/off/NUM] {same as "assembly"} */
1001 /* assembly [on/off/NUM] */
1002 /* expressions [on/off/NUM] */
1003 /* lines [on/off/NUM] */
1004 /* tokens [on/off/NUM] */
1005 /* linker [on/off/NUM] */
1007 /* The first four trace commands immediately display a compiler table. */
1008 /* The rest set or clear an ongoing trace. */
1009 /* --------------------------------------------------------------------- */
1012 directives.enabled = FALSE;
1013 trace_keywords.enabled = TRUE;
1015 trace_keywords.enabled = FALSE;
1016 directives.enabled = TRUE;
1018 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
1022 trace_level = &asm_trace_level;
1024 goto HandleTraceKeyword;
1026 if (token_type == NUMBER_TT) {
1029 trace_level = &asm_trace_level;
1031 goto HandleTraceKeyword;
1034 /* Anything else must be "Trace KEYWORD..." Remember that
1035 'on' and 'off' are trace keywords. */
1037 if (token_type != TRACE_KEYWORD_TT)
1038 return ebf_error_recover("debugging keyword", token_text);
1040 trace_keywords.enabled = TRUE;
1042 /* Note that "Trace verbs" doesn't affect list_verbs_setting.
1043 It shows the grammar at this point in the code. Setting
1044 list_verbs_setting shows the grammar at the end of
1046 Same goes for "Trace dictionary" and list_dict_setting, etc. */
1053 trace_level = &asm_trace_level; break;
1054 case EXPRESSIONS_TK:
1055 trace_level = &expr_trace_level; break;
1057 trace_level = &tokens_trace_level; break;
1059 trace_level = &linker_trace_level; break;
1064 trace_level = NULL; break;
1066 /* never implememented */
1067 trace_level = NULL; break;
1070 trace_level = &asm_trace_level; break;
1075 if ((token_type == SEP_TT) &&
1076 (token_value == SEMICOLON_SEP))
1079 else if (token_type == NUMBER_TT)
1082 else if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1085 else if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1092 trace_keywords.enabled = FALSE;
1096 if (i == LINES_TK) {
1097 warning_named("Trace option is not supported:", trace_keywords.keywords[i]);
1101 if (trace_level == NULL && j == 0) {
1102 warning_named("Trace directive to display table at 'off' level has no effect: table", trace_keywords.keywords[i]);
1107 { case DICTIONARY_TK: show_dictionary(j); break;
1108 case OBJECTS_TK: list_object_tree(); break;
1109 case SYMBOLS_TK: list_symbols(j); break;
1110 case VERBS_TK: list_verb_table(); break;
1118 /* --------------------------------------------------------------------- */
1120 /* --------------------------------------------------------------------- */
1124 if (token_type != SYMBOL_TT)
1125 return ebf_error_recover("symbol name", token_text);
1127 if (symbols[token_value].flags & UNKNOWN_SFLAG)
1128 { break; /* undef'ing an undefined constant is okay */
1131 if (symbols[token_value].type != CONSTANT_T)
1132 { error_named("Cannot Undef a symbol which is not a defined constant:", symbols[token_value].name);
1136 if (debugfile_switch)
1137 { write_debug_undef(token_value);
1139 end_symbol_scope(token_value);
1140 symbols[token_value].flags |= USED_SFLAG;
1143 /* --------------------------------------------------------------------- */
1145 /* --------------------------------------------------------------------- */
1147 case VERB_CODE: make_verb(); return FALSE; /* see "tables.c" */
1149 /* --------------------------------------------------------------------- */
1150 /* Version <number> */
1151 /* --------------------------------------------------------------------- */
1155 { assembly_operand AO;
1156 AO = parse_expression(CONSTANT_CONTEXT);
1157 /* If a version has already been set on the command line,
1158 that overrides this. */
1159 if (version_set_switch)
1161 warning("The Version directive was overridden by a command-line argument.");
1167 error("A definite value must be given as version number.");
1170 else if (no_routines > 1)
1172 /* The built-in Main__ routine is number zero. */
1173 error("A 'Version' directive must come before the first routine definition.");
1176 else if (glulx_mode)
1178 warning("The Version directive does not work in Glulx. Use \
1179 -vX.Y.Z instead, as either a command-line argument or a header comment.");
1187 { error("The version number must be in the range 3 to 8");
1191 /* We must now do a small dance to reset the DICT_ENTRY_BYTES
1192 constant, which was defined at startup based on the Z-code
1194 The calculation here is repeated from select_target(). */
1195 DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0);
1196 debtok = symbol_index("DICT_ENTRY_BYTES", -1);
1197 if (!(symbols[debtok].flags & UNKNOWN_SFLAG))
1199 if (!(symbols[debtok].flags & REDEFINABLE_SFLAG))
1201 warning("The DICT_ENTRY_BYTES symbol is not marked redefinable");
1203 /* Redefine the symbol... */
1204 assign_symbol(debtok, DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
1208 break; /* see "inform.c" */
1210 /* --------------------------------------------------------------------- */
1211 /* Zcharacter table <num> ... */
1212 /* Zcharacter table + <num> ... */
1213 /* Zcharacter <string> <string> <string> */
1214 /* Zcharacter <char> */
1215 /* --------------------------------------------------------------------- */
1217 case ZCHARACTER_CODE:
1220 error("The Zcharacter directive has no meaning in Glulx.");
1221 panic_mode_error_recovery(); return FALSE;
1224 directive_keywords.enabled = TRUE;
1226 directive_keywords.enabled = FALSE;
1230 new_alphabet(token_text, 0);
1232 if (token_type != DQ_TT)
1233 return ebf_error_recover("double-quoted alphabet string", token_text);
1234 new_alphabet(token_text, 1);
1236 if (token_type != DQ_TT)
1237 return ebf_error_recover("double-quoted alphabet string", token_text);
1238 new_alphabet(token_text, 2);
1242 map_new_zchar(text_to_unicode(token_text));
1243 if (token_text[textual_form_length] != 0)
1244 return ebf_error_recover("single character value", token_text);
1247 case DIR_KEYWORD_TT:
1250 { int plus_flag = FALSE;
1252 if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1256 while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1257 { switch(token_type)
1259 new_zscii_character(token_value, plus_flag);
1260 plus_flag = TRUE; break;
1262 new_zscii_character(text_to_unicode(token_text),
1264 if (token_text[textual_form_length] != 0)
1265 return ebf_error_recover("single character value",
1270 return ebf_error_recover("character or Unicode number",
1275 if (plus_flag) new_zscii_finished();
1279 case TERMINATING_DK:
1281 while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1282 { switch(token_type)
1284 terminating_characters[no_termcs++]
1288 return ebf_error_recover("ZSCII number",
1296 return ebf_error_recover("'table', 'terminating', \
1297 a string or a constant",
1302 return ebf_error_recover("three alphabet strings, \
1303 a 'table' or 'terminating' command or a single character", token_text);
1307 /* ===================================================================== */
1311 /* We are now at the end of a syntactically valid directive. It
1312 should be terminated by a semicolon. */
1315 if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1316 { ebf_error("';'", token_text);
1317 /* Put the non-semicolon back. We will continue parsing from
1318 that point, in hope that it's the start of a new directive.
1319 (This recovers cleanly from a missing semicolon at the end
1320 of a directive. It's not so clean if the directive *does*
1321 end with a semicolon, but there's extra garbage before it.) */
1327 /* ========================================================================= */
1328 /* Data structure management routines */
1329 /* ------------------------------------------------------------------------- */
1331 extern void init_directs_vars(void)
1335 extern void directs_begin_pass(void)
1337 no_named_routines = 0;
1340 constant_made_yet = FALSE;
1344 extern void directs_allocate_arrays(void)
1348 extern void directs_free_arrays(void)
1352 /* ========================================================================= */