388ac861bcae9ba46f13fbc033ab4a5b4824f03a
[inform.git] / src / directs.c
1 /* ------------------------------------------------------------------------- */
2 /*   "directs" : Directives (# commands)                                     */
3 /*                                                                           */
4 /*   Part of Inform 6.40                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2022                                 */
6 /*                                                                           */
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.                                       */
11 /*                                                                           */
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.                              */
16 /*                                                                           */
17 /* You should have received a copy of the GNU General Public License         */
18 /* along with Inform. If not, see https://gnu.org/licenses/                  */
19 /*                                                                           */
20 /* ------------------------------------------------------------------------- */
21
22 #include "header.h"
23
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];
29
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.)        */
34
35 static int constant_made_yet;      /* Have any constants been defined yet?   */
36
37 #define MAX_IFDEF_STACK (32)
38 static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
39
40 /* ------------------------------------------------------------------------- */
41
42 static int ebf_error_recover(char *s1, char *s2)
43 {
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(...);
49     */
50     ebf_error(s1, s2);
51     panic_mode_error_recovery();
52     return FALSE;
53 }
54
55 static int ebf_symbol_error_recover(char *s1, char *name, char *type, brief_location report_line)
56 {
57     /* Same for ebf_symbol_error(). */
58     ebf_symbol_error(s1, name, type, report_line);
59     panic_mode_error_recovery();
60     return FALSE;
61 }
62
63 /* ------------------------------------------------------------------------- */
64
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
68         definition.
69
70         Returns: FALSE if program continues, TRUE if end of file reached.    */
71
72     int *trace_level = NULL; int32 i, j, k, n, flag;
73     const char *constant_name;
74     debug_location_beginning beginning_debug_location;
75
76     if (internal_flag)
77     {
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." */
83         
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;
93         }
94     }
95     
96     switch(token_value)
97     {
98
99     /* --------------------------------------------------------------------- */
100     /*   Abbreviate "string1" ["string2" ...]                                */
101     /* --------------------------------------------------------------------- */
102
103     case ABBREVIATE_CODE:
104
105         do
106         {  get_next_token();
107            if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
108                return FALSE;
109
110            if (!glulx_mode && no_abbreviations==96)
111            {   error_max_abbreviations(no_abbreviations);
112                panic_mode_error_recovery(); return FALSE;
113            }
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;
118            }
119
120            if (abbrevs_lookup_table_made)
121            {   error("All abbreviations must be declared together");
122                panic_mode_error_recovery(); return FALSE;
123            }
124            if (token_type != DQ_TT)
125            {   return ebf_error_recover("abbreviation string", token_text);
126            }
127            /* Abbreviation string with null must fit in a MAX_ABBREV_LENGTH
128               array. */
129            if (strlen(token_text)>=MAX_ABBREV_LENGTH)
130            {   error_named("Abbreviation too long", token_text);
131                continue;
132            }
133            make_abbreviation(token_text);
134         } while (TRUE);
135
136     /* --------------------------------------------------------------------- */
137     /*   Array arrayname array...                                            */
138     /* --------------------------------------------------------------------- */
139
140     case ARRAY_CODE: make_global(TRUE, FALSE); break;      /* See "tables.c" */
141
142     /* --------------------------------------------------------------------- */
143     /*   Attribute newname [alias oldname]                                   */
144     /* --------------------------------------------------------------------- */
145
146     case ATTRIBUTE_CODE:
147         make_attribute(); break;                          /* See "objects.c" */
148
149     /* --------------------------------------------------------------------- */
150     /*   Class classname ...                                                 */
151     /* --------------------------------------------------------------------- */
152
153     case CLASS_CODE: 
154         make_class(NULL);                                 /* See "objects.c" */
155         return FALSE;
156
157     /* --------------------------------------------------------------------- */
158     /*   Constant newname [[=] value] [, ...]                                */
159     /* --------------------------------------------------------------------- */
160
161     case CONSTANT_CODE:
162         constant_made_yet=TRUE;
163
164       ParseConstantSpec:
165         get_next_token(); i = token_value;
166         beginning_debug_location = get_token_location_beginning();
167
168         if (token_type != SYMBOL_TT)
169         {   discard_token_location(beginning_debug_location);
170             return ebf_error_recover("new constant name", token_text);
171         }
172
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);
176         }
177
178         assign_symbol(i, 0, CONSTANT_T);
179         constant_name = token_text;
180
181         get_next_token();
182
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>");
190             }
191             goto ParseConstantSpec;
192         }
193
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>");
201             }
202             return FALSE;
203         }
204
205         if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
206             put_token_back();
207
208         {   assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
209             if (AO.marker != 0)
210             {   assign_marked_symbol(i, AO.marker, AO.value,
211                     CONSTANT_T);
212                 symbols[i].flags |= CHANGE_SFLAG;
213                 if (i == grammar_version_symbol)
214                     error(
215                 "Grammar__Version must be given an explicit constant value");
216             }
217             else
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))
222                         error(
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;
227                 }
228             }
229         }
230
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>");
238         }
239
240         get_next_token();
241         if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
242             goto ParseConstantSpec;
243         put_token_back();
244         break;
245
246     /* --------------------------------------------------------------------- */
247     /*   Default constantname integer                                        */
248     /* --------------------------------------------------------------------- */
249
250     case DEFAULT_CODE:
251         if (module_switch)
252         {   error("'Default' cannot be used in -M (Module) mode");
253             panic_mode_error_recovery(); return FALSE;
254         }
255
256         get_next_token();
257         if (token_type != SYMBOL_TT)
258             return ebf_error_recover("name", token_text);
259
260         i = -1;
261         if (symbols[token_value].flags & UNKNOWN_SFLAG)
262         {   i = token_value;
263             symbols[i].flags |= DEFCON_SFLAG;
264         }
265
266         get_next_token();
267         if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
268             put_token_back();
269
270         {   assembly_operand AO;
271             AO = parse_expression(CONSTANT_CONTEXT);
272             if (i != -1)
273             {   if (AO.marker != 0)
274                 {   assign_marked_symbol(i, AO.marker, AO.value,
275                         CONSTANT_T);
276                     symbols[i].flags |= CHANGE_SFLAG;
277                 }
278                 else assign_symbol(i, AO.value, CONSTANT_T);
279             }
280         }
281
282         break;
283
284     /* --------------------------------------------------------------------- */
285     /*   Dictionary 'word'                                                   */
286     /*   Dictionary 'word' val1                                              */
287     /*   Dictionary 'word' val1 val3                                         */
288     /* --------------------------------------------------------------------- */
289
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
297            values.
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
300            garbage.)
301          */
302         get_next_token();
303         if (token_type != SQ_TT && token_type != DQ_TT)
304             return ebf_error_recover("dictionary word", token_text);
305
306         {
307             char *wd = token_text;
308             int val1 = 0;
309             int val3 = 0;
310
311             get_next_token();
312             if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
313                 put_token_back();
314             }
315             else {
316                 assembly_operand AO;
317                 put_token_back();
318                 AO = parse_expression(CONSTANT_CONTEXT);
319                 if (AO.marker != 0)
320                     error("A definite value must be given as a Dictionary flag");
321                 else
322                     val1 = AO.value;
323
324                 get_next_token();
325                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
326                     put_token_back();
327                 }
328                 else {
329                     assembly_operand AO;
330                     put_token_back();
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);
334                     if (AO.marker != 0)
335                         error("A definite value must be given as a Dictionary flag");
336                     else
337                         val3 = AO.value;
338                 }
339             }
340
341             if (!glulx_mode) {
342                 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
343                     warning("Dictionary flag values cannot exceed $FF in Z-code");
344                 }
345             }
346             else {
347                 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
348                     warning("Dictionary flag values cannot exceed $FFFF in Glulx");
349                 }
350             }
351
352             dictionary_add(wd, val1, 0, val3);
353         }
354         break;
355
356     /* --------------------------------------------------------------------- */
357     /*   End                                                                 */
358     /* --------------------------------------------------------------------- */
359
360     case END_CODE: return(TRUE);
361
362     case ENDIF_CODE:
363         if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
364         else ifdef_sp--;
365         break;
366
367     /* --------------------------------------------------------------------- */
368     /*   Extend ...                                                          */
369     /* --------------------------------------------------------------------- */
370
371     case EXTEND_CODE: extend_verb(); return FALSE;         /* see "tables.c" */
372
373     /* --------------------------------------------------------------------- */
374     /*   Fake_Action name                                                    */
375     /* --------------------------------------------------------------------- */
376
377     case FAKE_ACTION_CODE:
378         make_fake_action(); break;                          /* see "verbs.c" */
379
380     /* --------------------------------------------------------------------- */
381     /*   Global variable [= value / array...]                                */
382     /* --------------------------------------------------------------------- */
383
384     case GLOBAL_CODE: make_global(FALSE, FALSE); break;    /* See "tables.c" */
385
386     /* --------------------------------------------------------------------- */
387     /*   If...                                                               */
388     /*                                                                       */
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:         */
392     /*                                                                       */
393     /*               If...;  ...  Ifnot;  ...  Endif;                        */
394     /*   top of stack:       TRUE        FALSE                               */
395     /*                                                                       */
396     /*   This is used to detect "two Ifnots in same If" errors.              */
397     /* --------------------------------------------------------------------- */
398
399     case IFDEF_CODE:
400         flag = TRUE;
401         goto DefCondition;
402     case IFNDEF_CODE:
403         flag = FALSE;
404
405       DefCondition:
406         get_next_token();
407         if (token_type != SYMBOL_TT)
408             return ebf_error_recover("symbol name", token_text);
409
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;
413            see RELEASE_NUMBER.
414            ("VN_nnnn" isn't a real symbol and can't be used in other
415            contexts.) */
416         if ((token_text[0] == 'V')
417             && (token_text[1] == 'N')
418             && (token_text[2] == '_')
419             && (strlen(token_text)==7))
420         {
421             char *endstr;
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;
427             }
428         }
429
430         if (symbols[token_value].flags & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
431         else symbols[token_value].flags |= USED_SFLAG;
432         goto HashIfCondition;
433
434     case IFNOT_CODE:
435         if (ifdef_sp == 0)
436             error("'Ifnot' without matching 'If...'");
437         else
438         if (!(ifdef_stack[ifdef_sp-1]))
439             error("Second 'Ifnot' for the same 'If...' condition");
440         else
441         {   dont_enter_into_symbol_table = -2; n = 1;
442             directives.enabled = TRUE;
443             do
444             {
445                 release_token_texts();
446                 get_next_token();
447                 if (token_type == EOF_TT)
448                 {   error("End of file reached in code 'If...'d out");
449                     directives.enabled = FALSE;
450                     return TRUE;
451                 }
452                 if (token_type == DIRECTIVE_TT)
453                 {
454                     switch(token_value)
455                     {   case ENDIF_CODE:
456                             n--; break;
457                         case IFV3_CODE:
458                         case IFV5_CODE:
459                         case IFDEF_CODE:
460                         case IFNDEF_CODE:
461                         case IFTRUE_CODE:
462                         case IFFALSE_CODE:
463                             n++; break;
464                         case IFNOT_CODE:
465                             if (n == 1)
466                             {   error(
467                               "Second 'Ifnot' for the same 'If...' condition");
468                                 break;
469                             }
470                     }
471                 }
472             } while (n > 0);
473             ifdef_sp--; 
474             dont_enter_into_symbol_table = FALSE;
475             directives.enabled = FALSE;
476         }
477         break;
478
479     case IFV3_CODE:
480         flag = FALSE;
481         if (!glulx_mode && version_number <= 3) flag = TRUE;
482         goto HashIfCondition;
483
484     case IFV5_CODE:
485         flag = TRUE;
486         if (!glulx_mode && version_number <= 3) flag = FALSE;
487         goto HashIfCondition;
488
489     case IFTRUE_CODE:
490         {   assembly_operand AO;
491             AO = parse_expression(CONSTANT_CONTEXT);
492             if (AO.marker != 0)
493             {   error("This condition can't be determined");
494                 flag = 0;
495             }
496             else flag = (AO.value != 0);
497         }
498         goto HashIfCondition;
499
500     case IFFALSE_CODE:
501         {   assembly_operand AO;
502             AO = parse_expression(CONSTANT_CONTEXT);
503             if (AO.marker != 0)
504             {   error("This condition can't be determined");
505                 flag = 1;
506             }
507             else flag = (AO.value == 0);
508         }
509         goto HashIfCondition;
510
511     HashIfCondition:
512         get_next_token();
513         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
514             return ebf_error_recover("semicolon after 'If...' condition", token_text);
515
516         if (ifdef_sp >= MAX_IFDEF_STACK) {
517             error("'If' directives nested too deeply");
518             panic_mode_error_recovery(); return FALSE;
519         }
520         
521         if (flag)
522         {   ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
523         else
524         {   dont_enter_into_symbol_table = -2; n = 1;
525             directives.enabled = TRUE;
526             do
527             {
528                 release_token_texts();
529                 get_next_token();
530                 if (token_type == EOF_TT)
531                 {   error("End of file reached in code 'If...'d out");
532                     directives.enabled = FALSE;
533                     return TRUE;
534                 }
535                 if (token_type == DIRECTIVE_TT)
536                 {
537                     switch(token_value)
538                     {   case ENDIF_CODE:
539                             n--; break;
540                         case IFV3_CODE:
541                         case IFV5_CODE:
542                         case IFDEF_CODE:
543                         case IFNDEF_CODE:
544                         case IFTRUE_CODE:
545                         case IFFALSE_CODE:
546                             n++; break;
547                         case IFNOT_CODE:
548                             if (n == 1)
549                             {   ifdef_stack[ifdef_sp++] = FALSE;
550                                 n--; break;
551                             }
552                     }
553                 }
554             } while (n > 0);
555             directives.enabled = FALSE;
556             dont_enter_into_symbol_table = FALSE;
557         }
558         break;
559
560     /* --------------------------------------------------------------------- */
561     /*   Import global <varname> [, ...]                                     */
562     /*                                                                       */
563     /* (Further imported goods may be allowed later.)                        */
564     /* --------------------------------------------------------------------- */
565
566     case IMPORT_CODE:
567         if (!module_switch)
568         {   error("'Import' can only be used in -M (Module) mode");
569             panic_mode_error_recovery(); return FALSE;
570         }
571         directives.enabled = TRUE;
572         do
573         {   get_next_token();
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:",
577                  token_text);
578             get_next_token();
579         } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
580         put_token_back();
581         directives.enabled = FALSE;
582         break;
583
584     /* --------------------------------------------------------------------- */
585     /*   Include "[>]filename"                                               */
586     /*                                                                       */
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     /* --------------------------------------------------------------------- */
590
591     case INCLUDE_CODE:
592         get_next_token();
593         if (token_type != DQ_TT)
594             return ebf_error_recover("filename in double-quotes", token_text);
595
596         {   char *name = token_text;
597
598             get_next_token();
599             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
600                 ebf_error("semicolon ';' after Include filename", token_text);
601
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);
607             return FALSE;
608         }
609
610     /* --------------------------------------------------------------------- */
611     /*   Link "filename"                                                     */
612     /* --------------------------------------------------------------------- */
613
614     case LINK_CODE:
615         get_next_token();
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);
620             break;
621         }
622         link_module(token_text);                           /* See "linker.c" */
623         break;
624
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     /* --------------------------------------------------------------------- */
632
633     case LOWSTRING_CODE:
634         if (module_switch)
635         {   error("'LowString' cannot be used in -M (Module) mode");
636             panic_mode_error_recovery(); return FALSE;
637         }
638         if (glulx_mode) {
639             error("The LowString directive has no meaning in Glulx.");
640             panic_mode_error_recovery(); return FALSE;
641         }
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);
647
648         get_next_token();
649         if (token_type != DQ_TT)
650             return ebf_error_recover("literal string in double-quotes", token_text);
651
652         assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
653         break;
654
655     /* --------------------------------------------------------------------- */
656     /*   Message | "information"                                             */
657     /*           | error "error message"                                     */
658     /*           | fatalerror "fatal error message"                          */
659     /*           | warning "warning message"                                 */
660     /* --------------------------------------------------------------------- */
661
662     case MESSAGE_CODE:
663         directive_keywords.enabled = TRUE;
664         get_next_token();
665         directive_keywords.enabled = FALSE;
666         if (token_type == DQ_TT)
667         {   int i;
668             if (hash_printed_since_newline) printf("\n");
669             for (i=0; token_text[i]!=0; i++)
670             {   if (token_text[i] == '^') printf("\n");
671                 else
672                 if (token_text[i] == '~') printf("\"");
673                 else printf("%c", token_text[i]);
674             }
675             printf("\n");
676             break;
677         }
678         if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
679         {   get_next_token();
680             if (token_type != DQ_TT)
681             {   return ebf_error_recover("error message in double-quotes", token_text);
682             }
683             error(token_text); break;
684         }
685         if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
686         {   get_next_token();
687             if (token_type != DQ_TT)
688             {   return ebf_error_recover("fatal error message in double-quotes", token_text);
689             }
690             fatalerror(token_text); break;
691         }
692         if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
693         {   get_next_token();
694             if (token_type != DQ_TT)
695             {   return ebf_error_recover("warning message in double-quotes", token_text);
696             }
697             warning(token_text); break;
698         }
699         return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
700             token_text);
701         break;
702
703     /* --------------------------------------------------------------------- */
704     /*   Nearby objname "short name" ...                                     */
705     /* --------------------------------------------------------------------- */
706
707     case NEARBY_CODE:
708         make_object(TRUE, NULL, -1, -1, -1);
709         return FALSE;                                     /* See "objects.c" */
710
711     /* --------------------------------------------------------------------- */
712     /*   Object objname "short name" ...                                     */
713     /* --------------------------------------------------------------------- */
714
715     case OBJECT_CODE:
716         make_object(FALSE, NULL, -1, -1, -1);
717         return FALSE;                                     /* See "objects.c" */
718
719     /* --------------------------------------------------------------------- */
720     /*   Origsource <file>                                                   */
721     /*   Origsource <file> <line>                                            */
722     /*   Origsource <file> <line> <char>                                     */
723     /*   Origsource                                                          */
724     /*                                                                       */
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).                   */
730     /*                                                                       */
731     /*   The fourth form, with no arguments, clears the declaration.         */
732     /*                                                                       */
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   */
735     /*   opaque string.                                                      */
736     /* --------------------------------------------------------------------- */
737
738     case ORIGSOURCE_CODE:
739         {
740             char *origsource_file = NULL;
741             int32 origsource_line = 0;
742             int32 origsource_char = 0;
743
744             /* Parse some optional tokens followed by a mandatory semicolon. */
745
746             get_next_token();
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",
750                         token_text);
751                 }
752                 origsource_file = token_text;
753
754                 get_next_token();
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",
758                             token_text);
759                     }
760                     origsource_line = token_value;
761                     if (origsource_line < 0)
762                         origsource_line = 0;
763
764                     get_next_token();
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",
768                                 token_text);
769                         }
770                         origsource_char = token_value;
771                         if (origsource_char < 0)
772                             origsource_char = 0;
773                         
774                         get_next_token();
775                     }
776                 }
777             }
778
779             put_token_back();
780
781             set_origsource_location(origsource_file, origsource_line, origsource_char);
782         }
783         break;
784
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     /* --------------------------------------------------------------------- */
791
792     case PROPERTY_CODE: make_property(); break;           /* See "objects.c" */
793
794     /* --------------------------------------------------------------------- */
795     /*   Release <number>                                                    */
796     /* --------------------------------------------------------------------- */
797
798     case RELEASE_CODE:
799         {   assembly_operand AO;
800             AO = parse_expression(CONSTANT_CONTEXT);
801             if (AO.marker != 0)
802                 error("A definite value must be given as release number");
803             else
804                 release_number = AO.value;
805         }
806         break;
807
808     /* --------------------------------------------------------------------- */
809     /*   Replace routine [routinename]                                       */
810     /* --------------------------------------------------------------------- */
811
812     case REPLACE_CODE:
813         /* You can also replace system functions normally implemented in     */
814         /* the "hardware" of the Z-machine, like "random()":                 */
815
816         system_functions.enabled = TRUE;
817         directives.enabled = FALSE;
818         directive_keywords.enabled = FALSE;
819
820         /* Don't count the upcoming symbol as a top-level reference
821            *to* the function. */
822         df_dont_note_global_symbols = TRUE;
823         get_next_token();
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;
829             get_next_token();
830             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
831             {
832                 error("You can't give a 'Replace'd system function a new name");
833                 panic_mode_error_recovery(); return FALSE;
834             }
835             return FALSE;
836         }
837
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);
842
843         symbols[token_value].flags |= REPLACE_SFLAG;
844
845         /* If a second symbol is provided, it will refer to the
846            original (replaced) definition of the routine. */
847         i = token_value;
848
849         system_functions.enabled = FALSE;
850         df_dont_note_global_symbols = TRUE;
851         get_next_token();
852         df_dont_note_global_symbols = FALSE;
853         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
854         {   return FALSE;
855         }
856
857         if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG))
858             return ebf_error_recover("semicolon ';' or new routine name", token_text);
859
860         /* Define the original-form symbol as a zero constant. Its
861            value will be overwritten later, when we define the
862            replacement. */
863         assign_symbol(token_value, 0, CONSTANT_T);
864         add_symbol_replacement_mapping(i, token_value);
865
866         break;
867
868     /* --------------------------------------------------------------------- */
869     /*   Serial "yymmdd"                                                     */
870     /* --------------------------------------------------------------------- */
871
872     case SERIAL_CODE:
873         get_next_token();
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;
877         }
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;
881         }
882         strcpy(serial_code_buffer, token_text);
883         serial_code_given_in_program = TRUE;
884         break;
885
886     /* --------------------------------------------------------------------- */
887     /*   Statusline score/time                                               */
888     /* --------------------------------------------------------------------- */
889
890     case STATUSLINE_CODE:
891         if (module_switch)
892             warning("This does not set the final game's statusline");
893
894         directive_keywords.enabled = TRUE;
895         get_next_token();
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;
902         break;
903
904     /* --------------------------------------------------------------------- */
905     /*   Stub routinename number-of-locals                                   */
906     /* --------------------------------------------------------------------- */
907
908     case STUB_CODE:
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;
912         get_next_token();
913         df_dont_note_global_symbols = FALSE;
914         if (token_type != SYMBOL_TT)
915             return ebf_error_recover("routine name to stub", token_text);
916
917         i = token_value; flag = FALSE;
918
919         if (symbols[i].flags & UNKNOWN_SFLAG)
920         {   symbols[i].flags |= STUB_SFLAG;
921             flag = TRUE;
922         }
923
924         get_next_token(); k = token_value;
925         if (token_type != NUMBER_TT)
926             return ebf_error_recover("number of local variables", token_text);
927         if ((k>4) || (k<0))
928         {   error("Must specify 0 to 4 local variables for 'Stub' routine");
929             k = 0;
930         }
931
932         if (flag)
933         {
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.)                               */
939
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");
944
945             assign_symbol(i,
946                 assemble_routine_header(k, FALSE, symbols[i].name, FALSE, i),
947                 ROUTINE_T);
948
949             /*  Ensure the return value of a stubbed routine is false,
950                 since this is necessary to make the library work properly    */
951
952             if (!glulx_mode)
953                 assemblez_0(rfalse_zc);
954             else
955                 assembleg_1(return_gc, zero_operand);
956
957             /*  Inhibit "local variable unused" warnings  */
958
959             for (i=1; i<=k; i++) variables[i].usage = 1;
960             sequence_point_follows = FALSE;
961             assemble_routine_end(FALSE, get_token_locations());
962         }
963         break;
964
965     /* --------------------------------------------------------------------- */
966     /*   Switches switchblock                                                */
967     /* (this directive is ignored if the -i switch was set at command line)  */
968     /* --------------------------------------------------------------------- */
969
970     case SWITCHES_CODE:
971         dont_enter_into_symbol_table = TRUE;
972         get_next_token();
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" */
981         }
982         break;
983
984     /* --------------------------------------------------------------------- */
985     /*   System_file                                                         */
986     /*                                                                       */
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     /* --------------------------------------------------------------------- */
991
992     case SYSTEM_CODE:
993         declare_systemfile(); break;                        /* see "files.c" */
994
995     /* --------------------------------------------------------------------- */
996     /*   Trace dictionary   [on/NUM]                                         */
997     /*         objects      [on/NUM]                                         */
998     /*         symbols      [on/NUM]                                         */
999     /*         verbs        [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]                                     */
1006     /*                                                                       */
1007     /* The first four trace commands immediately display a compiler table.   */
1008     /* The rest set or clear an ongoing trace.                               */
1009     /* --------------------------------------------------------------------- */
1010
1011     case TRACE_CODE:
1012         directives.enabled = FALSE;
1013         trace_keywords.enabled = TRUE;
1014         get_next_token();
1015         trace_keywords.enabled = FALSE;
1016         directives.enabled = TRUE;
1017         
1018         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
1019             /* "Trace;" */
1020             put_token_back();
1021             i = ASSEMBLY_TK;
1022             trace_level = &asm_trace_level;
1023             j = 1;
1024             goto HandleTraceKeyword;
1025         }
1026         if (token_type == NUMBER_TT) {
1027             /* "Trace NUM;" */
1028             i = ASSEMBLY_TK;
1029             trace_level = &asm_trace_level;
1030             j = token_value;
1031             goto HandleTraceKeyword;
1032         }
1033
1034         /* Anything else must be "Trace KEYWORD..." Remember that
1035            'on' and 'off' are trace keywords. */
1036         
1037         if (token_type != TRACE_KEYWORD_TT)
1038             return ebf_error_recover("debugging keyword", token_text);
1039
1040         trace_keywords.enabled = TRUE;
1041
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 
1045            compilation.
1046            Same goes for "Trace dictionary" and list_dict_setting, etc. */
1047         
1048         i = token_value;
1049
1050         switch(i)
1051         {
1052         case ASSEMBLY_TK:
1053             trace_level = &asm_trace_level;  break;
1054         case EXPRESSIONS_TK:
1055             trace_level = &expr_trace_level; break;
1056         case TOKENS_TK:
1057             trace_level = &tokens_trace_level; break;
1058         case LINKER_TK:
1059             trace_level = &linker_trace_level; break;
1060         case DICTIONARY_TK:
1061         case SYMBOLS_TK:
1062         case OBJECTS_TK:
1063         case VERBS_TK:
1064             trace_level = NULL; break;
1065         case LINES_TK:
1066             /* never implememented */
1067             trace_level = NULL; break;
1068         default:
1069             put_token_back();
1070             trace_level = &asm_trace_level; break;
1071         }
1072         
1073         j = 1;
1074         get_next_token();
1075         if ((token_type == SEP_TT) &&
1076             (token_value == SEMICOLON_SEP))
1077         {   put_token_back();
1078         }
1079         else if (token_type == NUMBER_TT)
1080         {   j = token_value;
1081         }
1082         else if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1083         {   j = 1;
1084         }
1085         else if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1086         {   j = 0;
1087         }
1088         else
1089         {   put_token_back();
1090         }
1091
1092         trace_keywords.enabled = FALSE;
1093
1094         HandleTraceKeyword:
1095
1096         if (i == LINES_TK) {
1097             warning_named("Trace option is not supported:", trace_keywords.keywords[i]);
1098             break;
1099         }
1100         
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]);
1103             break;
1104         }
1105         
1106         switch(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;
1111             default:
1112                 if (trace_level)
1113                     *trace_level = j;
1114                 break;
1115         }
1116         break;
1117
1118     /* --------------------------------------------------------------------- */
1119     /*   Undef symbol                                                        */
1120     /* --------------------------------------------------------------------- */
1121
1122     case UNDEF_CODE:
1123         get_next_token();
1124         if (token_type != SYMBOL_TT)
1125             return ebf_error_recover("symbol name", token_text);
1126
1127         if (symbols[token_value].flags & UNKNOWN_SFLAG)
1128         {   break; /* undef'ing an undefined constant is okay */
1129         }
1130
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);
1133             break;
1134         }
1135
1136         if (debugfile_switch)
1137         {   write_debug_undef(token_value);
1138         }
1139         end_symbol_scope(token_value);
1140         symbols[token_value].flags |= USED_SFLAG;
1141         break;
1142
1143     /* --------------------------------------------------------------------- */
1144     /*   Verb ...                                                            */
1145     /* --------------------------------------------------------------------- */
1146
1147     case VERB_CODE: make_verb(); return FALSE;             /* see "tables.c" */
1148
1149     /* --------------------------------------------------------------------- */
1150     /*   Version <number>                                                    */
1151     /* --------------------------------------------------------------------- */
1152
1153     case VERSION_CODE:
1154
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)
1160             {
1161               warning("The Version directive was overridden by a command-line argument.");
1162               break;
1163             }
1164
1165             if (AO.marker != 0)
1166             {
1167               error("A definite value must be given as version number.");
1168               break;
1169             }
1170             else if (no_routines > 1)
1171             {
1172               /* The built-in Main__ routine is number zero. */
1173               error("A 'Version' directive must come before the first routine definition.");
1174               break;
1175             }
1176             else if (glulx_mode) 
1177             {
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.");
1180               break;
1181             }
1182             else
1183             {
1184                 int debtok;
1185                 i = AO.value;
1186                 if ((i<3) || (i>8))
1187                 {   error("The version number must be in the range 3 to 8");
1188                     break;
1189                 }
1190                 select_version(i);
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
1193                    version.
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))
1198                 {
1199                     if (!(symbols[debtok].flags & REDEFINABLE_SFLAG))
1200                     {
1201                         warning("The DICT_ENTRY_BYTES symbol is not marked redefinable");
1202                     }
1203                     /* Redefine the symbol... */
1204                     assign_symbol(debtok, DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
1205                 }
1206             }
1207         }
1208         break;                                             /* see "inform.c" */
1209
1210     /* --------------------------------------------------------------------- */
1211     /*   Zcharacter table <num> ...                                          */
1212     /*   Zcharacter table + <num> ...                                        */
1213     /*   Zcharacter <string> <string> <string>                               */
1214     /*   Zcharacter <char>                                                   */
1215     /* --------------------------------------------------------------------- */
1216
1217     case ZCHARACTER_CODE:
1218
1219         if (glulx_mode) {
1220             error("The Zcharacter directive has no meaning in Glulx.");
1221             panic_mode_error_recovery(); return FALSE;
1222         }
1223
1224         directive_keywords.enabled = TRUE;
1225         get_next_token();
1226         directive_keywords.enabled = FALSE;
1227
1228         switch(token_type)
1229         {   case DQ_TT:
1230                 new_alphabet(token_text, 0);
1231                 get_next_token();
1232                 if (token_type != DQ_TT)
1233                     return ebf_error_recover("double-quoted alphabet string", token_text);
1234                 new_alphabet(token_text, 1);
1235                 get_next_token();
1236                 if (token_type != DQ_TT)
1237                     return ebf_error_recover("double-quoted alphabet string", token_text);
1238                 new_alphabet(token_text, 2);
1239             break;
1240
1241             case SQ_TT:
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);
1245             break;
1246
1247             case DIR_KEYWORD_TT:
1248             switch(token_value)
1249             {   case TABLE_DK:
1250                 {   int plus_flag = FALSE;
1251                     get_next_token();
1252                     if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1253                     {   plus_flag = TRUE;
1254                         get_next_token();
1255                     }
1256                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1257                     {   switch(token_type)
1258                         {   case NUMBER_TT:
1259                                 new_zscii_character(token_value, plus_flag);
1260                                 plus_flag = TRUE; break;
1261                             case SQ_TT:
1262                                 new_zscii_character(text_to_unicode(token_text),
1263                                     plus_flag);
1264                                 if (token_text[textual_form_length] != 0)
1265                                     return ebf_error_recover("single character value",
1266                                         token_text);
1267                                 plus_flag = TRUE;
1268                                 break;
1269                             default:
1270                                 return ebf_error_recover("character or Unicode number",
1271                                     token_text);
1272                         }
1273                         get_next_token();
1274                     }
1275                     if (plus_flag) new_zscii_finished();
1276                     put_token_back();
1277                 }
1278                     break;
1279                 case TERMINATING_DK:
1280                     get_next_token();
1281                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1282                     {   switch(token_type)
1283                         {   case NUMBER_TT:
1284                                 terminating_characters[no_termcs++]
1285                                     = token_value;
1286                                 break;
1287                             default:
1288                                 return ebf_error_recover("ZSCII number",
1289                                     token_text);
1290                         }
1291                         get_next_token();
1292                     }
1293                     put_token_back();
1294                     break;
1295                 default:
1296                     return ebf_error_recover("'table', 'terminating', \
1297 a string or a constant",
1298                         token_text);
1299             }
1300                 break;
1301             default:
1302                 return ebf_error_recover("three alphabet strings, \
1303 a 'table' or 'terminating' command or a single character", token_text);
1304         }
1305         break;
1306
1307     /* ===================================================================== */
1308
1309     }
1310
1311     /* We are now at the end of a syntactically valid directive. It
1312        should be terminated by a semicolon. */
1313
1314     get_next_token();
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.) */
1322         put_token_back();
1323     }
1324     return FALSE;
1325 }
1326
1327 /* ========================================================================= */
1328 /*   Data structure management routines                                      */
1329 /* ------------------------------------------------------------------------- */
1330
1331 extern void init_directs_vars(void)
1332 {
1333 }
1334
1335 extern void directs_begin_pass(void)
1336 {   no_routines = 0;
1337     no_named_routines = 0;
1338     no_locals = 0;
1339     no_termcs = 0;
1340     constant_made_yet = FALSE;
1341     ifdef_sp = 0;
1342 }
1343
1344 extern void directs_allocate_arrays(void)
1345 {
1346 }
1347
1348 extern void directs_free_arrays(void)
1349 {
1350 }
1351
1352 /* ========================================================================= */