Update to commit e2647ad952b4d7afc9a186429c181efbc4958786
[inform.git] / src / directs.c
1 /* ------------------------------------------------------------------------- */
2 /*   "directs" : Directives (# commands)                                     */
3 /*                                                                           */
4 /*   Part of Inform 6.35                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2020                                 */
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 static int ifdef_stack[32], ifdef_sp;
38
39 /* ------------------------------------------------------------------------- */
40
41 static int ebf_error_recover(char *s1, char *s2)
42 {
43     /* Display an "expected... but found..." error, then skim forward
44        to the next semicolon and return FALSE. This is such a common
45        case in parse_given_directive() that it's worth a utility
46        function. You will see many error paths that look like:
47           return ebf_error_recover(...);
48     */
49     ebf_error(s1, s2);
50     panic_mode_error_recovery();
51     return FALSE;
52 }
53
54 static int ebf_symbol_error_recover(char *s1, char *name, char *type, brief_location report_line)
55 {
56     /* Same for ebf_symbol_error(). */
57     ebf_symbol_error(s1, name, type, report_line);
58     panic_mode_error_recovery();
59     return FALSE;
60 }
61
62 /* ------------------------------------------------------------------------- */
63
64 extern int parse_given_directive(int internal_flag)
65 {   /*  Internal_flag is FALSE if the directive is encountered normally,
66         TRUE if encountered with a # prefix inside a routine or object
67         definition.
68
69         Returns: FALSE if program continues, TRUE if end of file reached.    */
70
71     int *trace_level = NULL; int32 i, j, k, n, flag;
72     const char *constant_name;
73     debug_location_beginning beginning_debug_location;
74
75     if (internal_flag)
76     {
77         /* Only certain directives, such as #ifdef, are permitted within
78            a routine or object definition. In older versions of Inform,
79            nearly any directive was accepted, but this was -- to quote
80            an old code comment -- "about as well-supported as Wile E. 
81            Coyote one beat before the plummet-lines kick in." */
82         
83         if (token_value != IFV3_CODE && token_value != IFV5_CODE
84             && token_value != IFDEF_CODE && token_value != IFNDEF_CODE
85             && token_value != IFTRUE_CODE && token_value != IFFALSE_CODE
86             && token_value != IFNOT_CODE && token_value != ENDIF_CODE
87             && token_value != MESSAGE_CODE && token_value != ORIGSOURCE_CODE
88             && token_value != TRACE_CODE) {
89             char *dirname = directives.keywords[token_value];
90             error_named("Cannot nest this directive inside a routine or object:", dirname);
91             panic_mode_error_recovery(); return FALSE;
92         }
93     }
94     
95     switch(token_value)
96     {
97
98     /* --------------------------------------------------------------------- */
99     /*   Abbreviate "string1" ["string2" ...]                                */
100     /* --------------------------------------------------------------------- */
101
102     case ABBREVIATE_CODE:
103
104         do
105         {  get_next_token();
106            if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
107                return FALSE;
108
109            /* Z-code has a 64-abbrev limit; Glulx doesn't. */
110            if (!glulx_mode && no_abbreviations==64)
111            {   error("All 64 abbreviations already declared");
112                panic_mode_error_recovery(); return FALSE;
113            }
114            if (no_abbreviations==MAX_ABBREVS)
115                memoryerror("MAX_ABBREVS", MAX_ABBREVS);
116
117            if (abbrevs_lookup_table_made)
118            {   error("All abbreviations must be declared together");
119                panic_mode_error_recovery(); return FALSE;
120            }
121            if (token_type != DQ_TT)
122                return ebf_error_recover("abbreviation string", token_text);
123            if (strlen(token_text)<2)
124            {   error_named("It's not worth abbreviating", token_text);
125                continue;
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 (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
174         {   discard_token_location(beginning_debug_location);
175             return ebf_symbol_error_recover("new constant name", token_text, typename(stypes[i]), slines[i]);
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 && !(sflags[i] & 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 && !(sflags[i] & 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                 sflags[i] |= 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 && !(sflags[i] & 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 (sflags[token_value] & UNKNOWN_SFLAG)
262         {   i = token_value;
263             sflags[i] |= 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                     sflags[i] |= 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 (module_switch && (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                     AO = parse_expression(CONSTANT_CONTEXT);
332                     if (module_switch && (AO.marker != 0))
333                         error("A definite value must be given as a Dictionary flag");
334                     else
335                         val3 = AO.value;
336                 }
337             }
338
339             if (!glulx_mode) {
340                 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
341                     warning("Dictionary flag values cannot exceed $FF in Z-code");
342                 }
343             }
344             else {
345                 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
346                     warning("Dictionary flag values cannot exceed $FFFF in Glulx");
347                 }
348             }
349
350             dictionary_add(wd, val1, 0, val3);
351         }
352         break;
353
354     /* --------------------------------------------------------------------- */
355     /*   End                                                                 */
356     /* --------------------------------------------------------------------- */
357
358     case END_CODE: return(TRUE);
359
360     case ENDIF_CODE:
361         if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
362         else ifdef_sp--;
363         break;
364
365     /* --------------------------------------------------------------------- */
366     /*   Extend ...                                                          */
367     /* --------------------------------------------------------------------- */
368
369     case EXTEND_CODE: extend_verb(); return FALSE;         /* see "tables.c" */
370
371     /* --------------------------------------------------------------------- */
372     /*   Fake_Action name                                                    */
373     /* --------------------------------------------------------------------- */
374
375     case FAKE_ACTION_CODE:
376         make_fake_action(); break;                          /* see "verbs.c" */
377
378     /* --------------------------------------------------------------------- */
379     /*   Global variable [= value / array...]                                */
380     /* --------------------------------------------------------------------- */
381
382     case GLOBAL_CODE: make_global(FALSE, FALSE); break;    /* See "tables.c" */
383
384     /* --------------------------------------------------------------------- */
385     /*   If...                                                               */
386     /*                                                                       */
387     /*   Note that each time Inform tests an If... condition, it stacks the  */
388     /*   result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack  */
389     /*   reveals what clause of the current If... is being compiled:         */
390     /*                                                                       */
391     /*               If...;  ...  Ifnot;  ...  Endif;                        */
392     /*   top of stack:       TRUE        FALSE                               */
393     /*                                                                       */
394     /*   This is used to detect "two Ifnots in same If" errors.              */
395     /* --------------------------------------------------------------------- */
396
397     case IFDEF_CODE:
398         flag = TRUE;
399         goto DefCondition;
400     case IFNDEF_CODE:
401         flag = FALSE;
402
403       DefCondition:
404         get_next_token();
405         if (token_type != SYMBOL_TT)
406             return ebf_error_recover("symbol name", token_text);
407
408         if ((token_text[0] == 'V')
409             && (token_text[1] == 'N')
410             && (token_text[2] == '_')
411             && (strlen(token_text)==7))
412         {   i = atoi(token_text+3);
413             if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
414             goto HashIfCondition;
415         }
416
417         if (sflags[token_value] & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
418         else sflags[token_value] |= USED_SFLAG;
419         goto HashIfCondition;
420
421     case IFNOT_CODE:
422         if (ifdef_sp == 0)
423             error("'Ifnot' without matching 'If...'");
424         else
425         if (!(ifdef_stack[ifdef_sp-1]))
426             error("Second 'Ifnot' for the same 'If...' condition");
427         else
428         {   dont_enter_into_symbol_table = -2; n = 1;
429             directives.enabled = TRUE;
430             do
431             {   get_next_token();
432                 if (token_type == EOF_TT)
433                 {   error("End of file reached in code 'If...'d out");
434                     directives.enabled = FALSE;
435                     return TRUE;
436                 }
437                 if (token_type == DIRECTIVE_TT)
438                 {   switch(token_value)
439                     {   case ENDIF_CODE:
440                             n--; break;
441                         case IFV3_CODE:
442                         case IFV5_CODE:
443                         case IFDEF_CODE:
444                         case IFNDEF_CODE:
445                         case IFTRUE_CODE:
446                         case IFFALSE_CODE:
447                             n++; break;
448                         case IFNOT_CODE:
449                             if (n == 1)
450                             {   error(
451                               "Second 'Ifnot' for the same 'If...' condition");
452                                 break;
453                             }
454                     }
455                 }
456             } while (n > 0);
457             ifdef_sp--; 
458             dont_enter_into_symbol_table = FALSE;
459             directives.enabled = FALSE;
460         }
461         break;
462
463     case IFV3_CODE:
464         flag = FALSE;
465         if (!glulx_mode && version_number <= 3) flag = TRUE;
466         goto HashIfCondition;
467
468     case IFV5_CODE:
469         flag = TRUE;
470         if (!glulx_mode && version_number <= 3) flag = FALSE;
471         goto HashIfCondition;
472
473     case IFTRUE_CODE:
474         {   assembly_operand AO;
475             AO = parse_expression(CONSTANT_CONTEXT);
476             if (module_switch && (AO.marker != 0))
477             {   error("This condition can't be determined");
478                 flag = 0;
479             }
480             else flag = (AO.value != 0);
481         }
482         goto HashIfCondition;
483
484     case IFFALSE_CODE:
485         {   assembly_operand AO;
486             AO = parse_expression(CONSTANT_CONTEXT);
487             if (module_switch && (AO.marker != 0))
488             {   error("This condition can't be determined");
489                 flag = 1;
490             }
491             else flag = (AO.value == 0);
492         }
493         goto HashIfCondition;
494
495     HashIfCondition:
496         get_next_token();
497         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
498             return ebf_error_recover("semicolon after 'If...' condition", token_text);
499
500         if (flag)
501         {   ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
502         else
503         {   dont_enter_into_symbol_table = -2; n = 1;
504             directives.enabled = TRUE;
505             do
506             {   get_next_token();
507                 if (token_type == EOF_TT)
508                 {   error("End of file reached in code 'If...'d out");
509                     directives.enabled = FALSE;
510                     return TRUE;
511                 }
512                 if (token_type == DIRECTIVE_TT)
513                 {
514                     switch(token_value)
515                     {   case ENDIF_CODE:
516                             n--; break;
517                         case IFV3_CODE:
518                         case IFV5_CODE:
519                         case IFDEF_CODE:
520                         case IFNDEF_CODE:
521                         case IFTRUE_CODE:
522                         case IFFALSE_CODE:
523                             n++; break;
524                         case IFNOT_CODE:
525                             if (n == 1)
526                             {   ifdef_stack[ifdef_sp++] = FALSE;
527                                 n--; break;
528                             }
529                     }
530                 }
531             } while (n > 0);
532             directives.enabled = FALSE;
533             dont_enter_into_symbol_table = FALSE;
534         }
535         break;
536
537     /* --------------------------------------------------------------------- */
538     /*   Import global <varname> [, ...]                                     */
539     /*                                                                       */
540     /* (Further imported goods may be allowed later.)                        */
541     /* --------------------------------------------------------------------- */
542
543     case IMPORT_CODE:
544         if (!module_switch)
545         {   error("'Import' can only be used in -M (Module) mode");
546             panic_mode_error_recovery(); return FALSE;
547         }
548         directives.enabled = TRUE;
549         do
550         {   get_next_token();
551             if ((token_type == DIRECTIVE_TT) && (token_value == GLOBAL_CODE))
552                  make_global(FALSE, TRUE);
553             else error_named("'Import' cannot import things of this type:",
554                  token_text);
555             get_next_token();
556         } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
557         put_token_back();
558         directives.enabled = FALSE;
559         break;
560
561     /* --------------------------------------------------------------------- */
562     /*   Include "[>]filename"                                               */
563     /*                                                                       */
564     /* The ">" character means to load the file from the same directory as   */
565     /* the current file, instead of relying on the include path.             */
566     /* --------------------------------------------------------------------- */
567
568     case INCLUDE_CODE:
569         get_next_token();
570         if (token_type != DQ_TT)
571             return ebf_error_recover("filename in double-quotes", token_text);
572
573         {   char *name = token_text;
574
575             get_next_token();
576             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
577                 ebf_error("semicolon ';' after Include filename", token_text);
578
579             if (strcmp(name, "language__") == 0)
580                  load_sourcefile(Language_Name, 0);
581             else if (name[0] == '>')
582                  load_sourcefile(name+1, 1);
583             else load_sourcefile(name, 0);
584             return FALSE;
585         }
586
587     /* --------------------------------------------------------------------- */
588     /*   Link "filename"                                                     */
589     /* --------------------------------------------------------------------- */
590
591     case LINK_CODE:
592         get_next_token();
593         if (token_type != DQ_TT)
594             return ebf_error_recover("filename in double-quotes", token_text);
595         link_module(token_text);                           /* See "linker.c" */
596         break;
597
598     /* --------------------------------------------------------------------- */
599     /*   Lowstring constantname "text of string"                             */
600     /* --------------------------------------------------------------------- */
601     /* Unlike most constant creations, these do not require backpatching:    */
602     /* the low strings always occupy a table at a fixed offset in the        */
603     /* Z-machine (after the abbreviations table has finished, at 0x100).     */
604     /* --------------------------------------------------------------------- */
605
606     case LOWSTRING_CODE:
607         if (module_switch)
608         {   error("'LowString' cannot be used in -M (Module) mode");
609             panic_mode_error_recovery(); return FALSE;
610         }
611         get_next_token(); i = token_value;
612         if (token_type != SYMBOL_TT)
613             return ebf_error_recover("new low string name", token_text);
614         if (!(sflags[i] & UNKNOWN_SFLAG))
615             return ebf_symbol_error_recover("new low string name", token_text, typename(stypes[i]), slines[i]);
616
617         get_next_token();
618         if (token_type != DQ_TT)
619             return ebf_error_recover("literal string in double-quotes", token_text);
620
621         assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T);
622         break;
623
624     /* --------------------------------------------------------------------- */
625     /*   Message | "information"                                             */
626     /*           | error "error message"                                     */
627     /*           | fatalerror "fatal error message"                          */
628     /*           | warning "warning message"                                 */
629     /* --------------------------------------------------------------------- */
630
631     case MESSAGE_CODE:
632         directive_keywords.enabled = TRUE;
633         get_next_token();
634         directive_keywords.enabled = FALSE;
635         if (token_type == DQ_TT)
636         {   int i;
637             if (hash_printed_since_newline) printf("\n");
638             for (i=0; token_text[i]!=0; i++)
639             {   if (token_text[i] == '^') printf("\n");
640                 else
641                 if (token_text[i] == '~') printf("\"");
642                 else printf("%c", token_text[i]);
643             }
644             printf("\n");
645             break;
646         }
647         if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
648         {   get_next_token();
649             if (token_type != DQ_TT)
650             {   return ebf_error_recover("error message in double-quotes", token_text);
651             }
652             error(token_text); break;
653         }
654         if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
655         {   get_next_token();
656             if (token_type != DQ_TT)
657             {   return ebf_error_recover("fatal error message in double-quotes", token_text);
658             }
659             fatalerror(token_text); break;
660         }
661         if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
662         {   get_next_token();
663             if (token_type != DQ_TT)
664             {   return ebf_error_recover("warning message in double-quotes", token_text);
665             }
666             warning(token_text); break;
667         }
668         return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
669             token_text);
670         break;
671
672     /* --------------------------------------------------------------------- */
673     /*   Nearby objname "short name" ...                                     */
674     /* --------------------------------------------------------------------- */
675
676     case NEARBY_CODE:
677         make_object(TRUE, NULL, -1, -1, -1);
678         return FALSE;                                     /* See "objects.c" */
679
680     /* --------------------------------------------------------------------- */
681     /*   Object objname "short name" ...                                     */
682     /* --------------------------------------------------------------------- */
683
684     case OBJECT_CODE:
685         make_object(FALSE, NULL, -1, -1, -1);
686         return FALSE;                                     /* See "objects.c" */
687
688     /* --------------------------------------------------------------------- */
689     /*   Origsource <file>                                                   */
690     /*   Origsource <file> <line>                                            */
691     /*   Origsource <file> <line> <char>                                     */
692     /*   Origsource                                                          */
693     /*                                                                       */
694     /*   The first three forms declare that all following lines are derived  */
695     /*   from the named Inform 7 source file (with an optional line number   */
696     /*   and character number). This will be reported in error messages and  */
697     /*   in debug output. The declaration holds through the next Origsource  */
698     /*   directive (but does not apply to included files).                   */
699     /*                                                                       */
700     /*   The fourth form, with no arguments, clears the declaration.         */
701     /*                                                                       */
702     /*   Unlike the Include directive, Origsource does not open the named    */
703     /*   file or even verify that it exists. The filename is treated as an   */
704     /*   opaque string.                                                      */
705     /* --------------------------------------------------------------------- */
706
707     case ORIGSOURCE_CODE:
708         {
709             char *origsource_file = NULL;
710             int32 origsource_line = 0;
711             int32 origsource_char = 0;
712
713             /* Parse some optional tokens followed by a mandatory semicolon. */
714
715             get_next_token();
716             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
717                 if (token_type != DQ_TT) {
718                     return ebf_error_recover("a file name in double-quotes",
719                         token_text);
720                 }
721                 origsource_file = token_text;
722
723                 get_next_token();
724                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
725                     if (token_type != NUMBER_TT) {
726                         return ebf_error_recover("a file line number",
727                             token_text);
728                     }
729                     origsource_line = token_value;
730                     if (origsource_line < 0)
731                         origsource_line = 0;
732
733                     get_next_token();
734                     if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
735                         if (token_type != NUMBER_TT) {
736                             return ebf_error_recover("a file line number",
737                                 token_text);
738                         }
739                         origsource_char = token_value;
740                         if (origsource_char < 0)
741                             origsource_char = 0;
742                         
743                         get_next_token();
744                     }
745                 }
746             }
747
748             put_token_back();
749
750             set_origsource_location(origsource_file, origsource_line, origsource_char);
751         }
752         break;
753
754     /* --------------------------------------------------------------------- */
755     /*   Property [long] [additive] name [alias oldname]                     */
756     /* --------------------------------------------------------------------- */
757
758     case PROPERTY_CODE: make_property(); break;           /* See "objects.c" */
759
760     /* --------------------------------------------------------------------- */
761     /*   Release <number>                                                    */
762     /* --------------------------------------------------------------------- */
763
764     case RELEASE_CODE:
765         {   assembly_operand AO;
766             AO = parse_expression(CONSTANT_CONTEXT);
767             if (module_switch && (AO.marker != 0))
768                 error("A definite value must be given as release number");
769             else
770                 release_number = AO.value;
771         }
772         break;
773
774     /* --------------------------------------------------------------------- */
775     /*   Replace routine [routinename]                                       */
776     /* --------------------------------------------------------------------- */
777
778     case REPLACE_CODE:
779         /* You can also replace system functions normally implemented in     */
780         /* the "hardware" of the Z-machine, like "random()":                 */
781
782         system_functions.enabled = TRUE;
783         directives.enabled = FALSE;
784         directive_keywords.enabled = FALSE;
785
786         /* Don't count the upcoming symbol as a top-level reference
787            *to* the function. */
788         df_dont_note_global_symbols = TRUE;
789         get_next_token();
790         df_dont_note_global_symbols = FALSE;
791         if (token_type == SYSFUN_TT)
792         {   if (system_function_usage[token_value] == 1)
793                 error("You can't 'Replace' a system function already used");
794             else system_function_usage[token_value] = 2;
795             get_next_token();
796             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
797             {
798                 error("You can't give a 'Replace'd system function a new name");
799                 panic_mode_error_recovery(); return FALSE;
800             }
801             return FALSE;
802         }
803
804         if (token_type != SYMBOL_TT)
805             return ebf_error_recover("name of routine to replace", token_text);
806         if (!(sflags[token_value] & UNKNOWN_SFLAG))
807             return ebf_error_recover("name of routine not yet defined", token_text);
808
809         sflags[token_value] |= REPLACE_SFLAG;
810
811         /* If a second symbol is provided, it will refer to the
812            original (replaced) definition of the routine. */
813         i = token_value;
814
815         system_functions.enabled = FALSE;
816         df_dont_note_global_symbols = TRUE;
817         get_next_token();
818         df_dont_note_global_symbols = FALSE;
819         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
820         {   return FALSE;
821         }
822
823         if (token_type != SYMBOL_TT || !(sflags[token_value] & UNKNOWN_SFLAG))
824             return ebf_error_recover("semicolon ';' or new routine name", token_text);
825
826         /* Define the original-form symbol as a zero constant. Its
827            value will be overwritten later, when we define the
828            replacement. */
829         assign_symbol(token_value, 0, CONSTANT_T);
830         add_symbol_replacement_mapping(i, token_value);
831
832         break;
833
834     /* --------------------------------------------------------------------- */
835     /*   Serial "yymmdd"                                                     */
836     /* --------------------------------------------------------------------- */
837
838     case SERIAL_CODE:
839         get_next_token();
840         if ((token_type != DQ_TT) || (strlen(token_text)!=6))
841         {   error("The serial number must be a 6-digit date in double-quotes");
842             panic_mode_error_recovery(); return FALSE;
843         }
844         for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
845         {   error("The serial number must be a 6-digit date in double-quotes");
846             panic_mode_error_recovery(); return FALSE;
847         }
848         strcpy(serial_code_buffer, token_text);
849         serial_code_given_in_program = TRUE;
850         break;
851
852     /* --------------------------------------------------------------------- */
853     /*   Statusline score/time                                               */
854     /* --------------------------------------------------------------------- */
855
856     case STATUSLINE_CODE:
857         if (module_switch)
858             warning("This does not set the final game's statusline");
859
860         directive_keywords.enabled = TRUE;
861         get_next_token();
862         directive_keywords.enabled = FALSE;
863         if ((token_type != DIR_KEYWORD_TT)
864             || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
865             return ebf_error_recover("'score' or 'time' after 'statusline'", token_text);
866         if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
867         else statusline_flag = TIME_STYLE;
868         break;
869
870     /* --------------------------------------------------------------------- */
871     /*   Stub routinename number-of-locals                                   */
872     /* --------------------------------------------------------------------- */
873
874     case STUB_CODE:
875         /* The upcoming symbol is a definition; don't count it as a
876            top-level reference *to* the stub function. */
877         df_dont_note_global_symbols = TRUE;
878         get_next_token();
879         df_dont_note_global_symbols = FALSE;
880         if (token_type != SYMBOL_TT)
881             return ebf_error_recover("routine name to stub", token_text);
882
883         i = token_value; flag = FALSE;
884
885         if (sflags[i] & UNKNOWN_SFLAG)
886         {   sflags[i] |= STUB_SFLAG;
887             flag = TRUE;
888         }
889
890         get_next_token(); k = token_value;
891         if (token_type != NUMBER_TT)
892             return ebf_error_recover("number of local variables", token_text);
893         if ((k>4) || (k<0))
894         {   error("Must specify 0 to 4 local variables for 'Stub' routine");
895             k = 0;
896         }
897
898         if (flag)
899         {
900             /*  Give these parameter-receiving local variables names
901                 for the benefit of the debugging information file,
902                 and for assembly tracing to look sensible.                   */
903
904             local_variable_texts[0] = "dummy1";
905             local_variable_texts[1] = "dummy2";
906             local_variable_texts[2] = "dummy3";
907             local_variable_texts[3] = "dummy4";
908
909             assign_symbol(i,
910                 assemble_routine_header(k, FALSE, (char *) symbs[i], FALSE, i),
911                 ROUTINE_T);
912
913             /*  Ensure the return value of a stubbed routine is false,
914                 since this is necessary to make the library work properly    */
915
916             if (!glulx_mode)
917                 assemblez_0(rfalse_zc);
918             else
919                 assembleg_1(return_gc, zero_operand);
920
921             /*  Inhibit "local variable unused" warnings  */
922
923             for (i=1; i<=k; i++) variable_usage[i] = 1;
924             sequence_point_follows = FALSE;
925             assemble_routine_end(FALSE, get_token_locations());
926         }
927         break;
928
929     /* --------------------------------------------------------------------- */
930     /*   Switches switchblock                                                */
931     /* (this directive is ignored if the -i switch was set at command line)  */
932     /* --------------------------------------------------------------------- */
933
934     case SWITCHES_CODE:
935         dont_enter_into_symbol_table = TRUE;
936         get_next_token();
937         dont_enter_into_symbol_table = FALSE;
938         if (token_type != DQ_TT)
939             return ebf_error_recover("string of switches", token_text);
940         if (!ignore_switches_switch)
941         {   if (constant_made_yet)
942                 error("A 'Switches' directive must must come before \
943 the first constant definition");
944             switches(token_text, 0);                       /* see "inform.c" */
945         }
946         break;
947
948     /* --------------------------------------------------------------------- */
949     /*   System_file                                                         */
950     /*                                                                       */
951     /* Some files are declared as "system files": this information is used   */
952     /* by Inform only to skip the definition of a routine X if the designer  */
953     /* has indicated his intention to Replace X.                             */
954     /* --------------------------------------------------------------------- */
955
956     case SYSTEM_CODE:
957         declare_systemfile(); break;                        /* see "files.c" */
958
959     /* --------------------------------------------------------------------- */
960     /*   Trace dictionary                                                    */
961     /*         objects                                                       */
962     /*         symbols                                                       */
963     /*         verbs                                                         */
964     /*                      [on/off]                                         */
965     /*         assembly     [on/off]                                         */
966     /*         expressions  [on/off]                                         */
967     /*         lines        [on/off]                                         */
968     /* --------------------------------------------------------------------- */
969
970     case TRACE_CODE:
971         directives.enabled = FALSE;
972         trace_keywords.enabled = TRUE;
973         get_next_token();
974         trace_keywords.enabled = FALSE;
975         directives.enabled = TRUE;
976         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
977         {   asm_trace_level = 1; return FALSE; }
978
979         if (token_type != TRACE_KEYWORD_TT)
980             return ebf_error_recover("debugging keyword", token_text);
981
982         trace_keywords.enabled = TRUE;
983
984         i = token_value; j = 0;
985         switch(i)
986         {   case DICTIONARY_TK: break;
987             case OBJECTS_TK:    break;
988             case VERBS_TK:      break;
989             default:
990                 switch(token_value)
991                 {   case ASSEMBLY_TK:
992                         trace_level = &asm_trace_level;  break;
993                     case EXPRESSIONS_TK:
994                         trace_level = &expr_trace_level; break;
995                     case LINES_TK:
996                         trace_level = &line_trace_level; break;
997                     case TOKENS_TK:
998                         trace_level = &tokens_trace_level; break;
999                     case LINKER_TK:
1000                         trace_level = &linker_trace_level; break;
1001                     case SYMBOLS_TK:
1002                         trace_level = NULL; break;
1003                     default:
1004                         put_token_back();
1005                         trace_level = &asm_trace_level; break;
1006                 }
1007                 j = 1;
1008                 get_next_token();
1009                 if ((token_type == SEP_TT) &&
1010                     (token_value == SEMICOLON_SEP))
1011                 {   put_token_back(); break;
1012                 }
1013                 if (token_type == NUMBER_TT)
1014                 {   j = token_value; break; }
1015                 if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1016                 {   j = 1; break; }
1017                 if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1018                 {   j = 0; break; }
1019                 put_token_back(); break;
1020         }
1021
1022         switch(i)
1023         {   case DICTIONARY_TK: show_dictionary();  break;
1024             case OBJECTS_TK:    list_object_tree(); break;
1025             case SYMBOLS_TK:    list_symbols(j);     break;
1026             case VERBS_TK:      list_verb_table();  break;
1027             default:
1028                 *trace_level = j;
1029                 break;
1030         }
1031         trace_keywords.enabled = FALSE;
1032         break;
1033
1034     /* --------------------------------------------------------------------- */
1035     /*   Undef symbol                                                        */
1036     /* --------------------------------------------------------------------- */
1037
1038     case UNDEF_CODE:
1039         get_next_token();
1040         if (token_type != SYMBOL_TT)
1041             return ebf_error_recover("symbol name", token_text);
1042
1043         if (sflags[token_value] & UNKNOWN_SFLAG)
1044         {   break; /* undef'ing an undefined constant is okay */
1045         }
1046
1047         if (stypes[token_value] != CONSTANT_T)
1048         {   error_named("Cannot Undef a symbol which is not a defined constant:", (char *)symbs[token_value]);
1049             break;
1050         }
1051
1052         if (debugfile_switch)
1053         {   write_debug_undef(token_value);
1054         }
1055         end_symbol_scope(token_value);
1056         sflags[token_value] |= USED_SFLAG;
1057         break;
1058
1059     /* --------------------------------------------------------------------- */
1060     /*   Verb ...                                                            */
1061     /* --------------------------------------------------------------------- */
1062
1063     case VERB_CODE: make_verb(); return FALSE;             /* see "tables.c" */
1064
1065     /* --------------------------------------------------------------------- */
1066     /*   Version <number>                                                    */
1067     /* --------------------------------------------------------------------- */
1068
1069     case VERSION_CODE:
1070
1071         {   assembly_operand AO;
1072             AO = parse_expression(CONSTANT_CONTEXT);
1073             /* If a version has already been set on the command line,
1074                that overrides this. */
1075             if (version_set_switch)
1076             {
1077               warning("The Version directive was overridden by a command-line argument.");
1078               break;
1079             }
1080
1081             if (module_switch && (AO.marker != 0))
1082                 error("A definite value must be given as version number");
1083             else 
1084             if (glulx_mode) 
1085             {
1086               warning("The Version directive does not work in Glulx. Use \
1087 -vX.Y.Z instead, as either a command-line argument or a header comment.");
1088               break;
1089             }
1090             else
1091             {   i = AO.value;
1092                 if ((i<3) || (i>8))
1093                 {   error("The version number must be in the range 3 to 8");
1094                     break;
1095                 }
1096                 select_version(i);
1097             }
1098         }
1099         break;                                             /* see "inform.c" */
1100
1101     /* --------------------------------------------------------------------- */
1102     /*   Zcharacter table <num> ...                                          */
1103     /*   Zcharacter table + <num> ...                                        */
1104     /*   Zcharacter <string> <string> <string>                               */
1105     /*   Zcharacter <char>                                                   */
1106     /* --------------------------------------------------------------------- */
1107
1108     case ZCHARACTER_CODE:
1109
1110         if (glulx_mode) {
1111             error("The Zcharacter directive has no meaning in Glulx.");
1112             panic_mode_error_recovery(); return FALSE;
1113         }
1114
1115         directive_keywords.enabled = TRUE;
1116         get_next_token();
1117         directive_keywords.enabled = FALSE;
1118
1119         switch(token_type)
1120         {   case DQ_TT:
1121                 new_alphabet(token_text, 0);
1122                 get_next_token();
1123                 if (token_type != DQ_TT)
1124                     return ebf_error_recover("double-quoted alphabet string", token_text);
1125                 new_alphabet(token_text, 1);
1126                 get_next_token();
1127                 if (token_type != DQ_TT)
1128                     return ebf_error_recover("double-quoted alphabet string", token_text);
1129                 new_alphabet(token_text, 2);
1130             break;
1131
1132             case SQ_TT:
1133                 map_new_zchar(text_to_unicode(token_text));
1134                 if (token_text[textual_form_length] != 0)
1135                     return ebf_error_recover("single character value", token_text);
1136             break;
1137
1138             case DIR_KEYWORD_TT:
1139             switch(token_value)
1140             {   case TABLE_DK:
1141                 {   int plus_flag = FALSE;
1142                     get_next_token();
1143                     if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1144                     {   plus_flag = TRUE;
1145                         get_next_token();
1146                     }
1147                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1148                     {   switch(token_type)
1149                         {   case NUMBER_TT:
1150                                 new_zscii_character(token_value, plus_flag);
1151                                 plus_flag = TRUE; break;
1152                             case SQ_TT:
1153                                 new_zscii_character(text_to_unicode(token_text),
1154                                     plus_flag);
1155                                 if (token_text[textual_form_length] != 0)
1156                                     return ebf_error_recover("single character value",
1157                                         token_text);
1158                                 plus_flag = TRUE;
1159                                 break;
1160                             default:
1161                                 return ebf_error_recover("character or Unicode number",
1162                                     token_text);
1163                         }
1164                         get_next_token();
1165                     }
1166                     if (plus_flag) new_zscii_finished();
1167                     put_token_back();
1168                 }
1169                     break;
1170                 case TERMINATING_DK:
1171                     get_next_token();
1172                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1173                     {   switch(token_type)
1174                         {   case NUMBER_TT:
1175                                 terminating_characters[no_termcs++]
1176                                     = token_value;
1177                                 break;
1178                             default:
1179                                 return ebf_error_recover("ZSCII number",
1180                                     token_text);
1181                         }
1182                         get_next_token();
1183                     }
1184                     put_token_back();
1185                     break;
1186                 default:
1187                     return ebf_error_recover("'table', 'terminating', \
1188 a string or a constant",
1189                         token_text);
1190             }
1191                 break;
1192             default:
1193                 return ebf_error_recover("three alphabet strings, \
1194 a 'table' or 'terminating' command or a single character", token_text);
1195         }
1196         break;
1197
1198     /* ===================================================================== */
1199
1200     }
1201
1202     /* We are now at the end of a syntactically valid directive. It
1203        should be terminated by a semicolon. */
1204
1205     get_next_token();
1206     if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1207     {   ebf_error("';'", token_text);
1208         /* Put the non-semicolon back. We will continue parsing from
1209            that point, in hope that it's the start of a new directive.
1210            (This recovers cleanly from a missing semicolon at the end
1211            of a directive. It's not so clean if the directive *does*
1212            end with a semicolon, but there's extra garbage before it.) */
1213         put_token_back();
1214     }
1215     return FALSE;
1216 }
1217
1218 /* ========================================================================= */
1219 /*   Data structure management routines                                      */
1220 /* ------------------------------------------------------------------------- */
1221
1222 extern void init_directs_vars(void)
1223 {
1224 }
1225
1226 extern void directs_begin_pass(void)
1227 {   no_routines = 0;
1228     no_named_routines = 0;
1229     no_locals = 0;
1230     no_termcs = 0;
1231     constant_made_yet = FALSE;
1232     ifdef_sp = 0;
1233 }
1234
1235 extern void directs_allocate_arrays(void)
1236 {
1237 }
1238
1239 extern void directs_free_arrays(void)
1240 {
1241 }
1242
1243 /* ========================================================================= */