d8374c367a6e8863eae86cb5d2f5e59826c877fc
[inform.git] / src / directs.c
1 /* ------------------------------------------------------------------------- */
2 /*   "directs" : Directives (# commands)                                     */
3 /*                                                                           */
4 /*   Part of Inform 6.41                                                     */
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> [static] <array specification>                    */
138     /* --------------------------------------------------------------------- */
139
140     case ARRAY_CODE: make_array(); break;                  /* See "arrays.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         get_next_token();
252         if (token_type != SYMBOL_TT)
253             return ebf_error_recover("name", token_text);
254
255         i = -1;
256         if (symbols[token_value].flags & UNKNOWN_SFLAG)
257         {   i = token_value;
258             symbols[i].flags |= DEFCON_SFLAG;
259         }
260
261         get_next_token();
262         if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
263             put_token_back();
264
265         {   assembly_operand AO;
266             AO = parse_expression(CONSTANT_CONTEXT);
267             if (i != -1)
268             {   if (AO.marker != 0)
269                 {   assign_marked_symbol(i, AO.marker, AO.value,
270                         CONSTANT_T);
271                     symbols[i].flags |= CHANGE_SFLAG;
272                 }
273                 else assign_symbol(i, AO.value, CONSTANT_T);
274             }
275         }
276
277         break;
278
279     /* --------------------------------------------------------------------- */
280     /*   Dictionary 'word'                                                   */
281     /*   Dictionary 'word' val1                                              */
282     /*   Dictionary 'word' val1 val3                                         */
283     /* --------------------------------------------------------------------- */
284
285     case DICTIONARY_CODE:
286         /* In Inform 5, this directive had the form
287              Dictionary SYMBOL "word";
288            This was deprecated as of I6 (if not earlier), and is no longer
289            supported at all. The current form just creates a dictionary word,
290            with the given values for dict_par1 and dict_par3. If the word
291            already exists, the values are bit-or'd in with the existing
292            values.
293            (We don't offer a way to set dict_par2, because that is entirely
294            reserved for the verb number. Or'ing values into it would create
295            garbage.)
296          */
297         get_next_token();
298         if (token_type != SQ_TT && token_type != DQ_TT)
299             return ebf_error_recover("dictionary word", token_text);
300
301         {
302             char *wd = token_text;
303             int val1 = 0;
304             int val3 = 0;
305
306             get_next_token();
307             if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
308                 put_token_back();
309             }
310             else {
311                 assembly_operand AO;
312                 put_token_back();
313                 AO = parse_expression(CONSTANT_CONTEXT);
314                 if (AO.marker != 0)
315                     error("A definite value must be given as a Dictionary flag");
316                 else
317                     val1 = AO.value;
318
319                 get_next_token();
320                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
321                     put_token_back();
322                 }
323                 else {
324                     assembly_operand AO;
325                     put_token_back();
326                     if (ZCODE_LESS_DICT_DATA && !glulx_mode)
327                         warning("The third dictionary field will be ignored because ZCODE_LESS_DICT_DATA is set");
328                     AO = parse_expression(CONSTANT_CONTEXT);
329                     if (AO.marker != 0)
330                         error("A definite value must be given as a Dictionary flag");
331                     else
332                         val3 = AO.value;
333                 }
334             }
335
336             if (!glulx_mode) {
337                 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
338                     warning("Dictionary flag values cannot exceed $FF in Z-code");
339                 }
340             }
341             else {
342                 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
343                     warning("Dictionary flag values cannot exceed $FFFF in Glulx");
344                 }
345             }
346
347             dictionary_add(wd, val1, 0, val3);
348         }
349         break;
350
351     /* --------------------------------------------------------------------- */
352     /*   End                                                                 */
353     /* --------------------------------------------------------------------- */
354
355     case END_CODE: return(TRUE);
356
357     case ENDIF_CODE:
358         if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
359         else ifdef_sp--;
360         break;
361
362     /* --------------------------------------------------------------------- */
363     /*   Extend ...                                                          */
364     /* --------------------------------------------------------------------- */
365
366     case EXTEND_CODE: extend_verb(); return FALSE;         /* see "tables.c" */
367
368     /* --------------------------------------------------------------------- */
369     /*   Fake_Action name                                                    */
370     /* --------------------------------------------------------------------- */
371
372     case FAKE_ACTION_CODE:
373         make_fake_action(); break;                          /* see "verbs.c" */
374
375     /* --------------------------------------------------------------------- */
376     /*   Global <variablename> [ [=] <value> ]                               */
377     /* --------------------------------------------------------------------- */
378
379     case GLOBAL_CODE: make_global(); break;                /* See "arrays.c" */
380
381     /* --------------------------------------------------------------------- */
382     /*   If...                                                               */
383     /*                                                                       */
384     /*   Note that each time Inform tests an If... condition, it stacks the  */
385     /*   result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack  */
386     /*   reveals what clause of the current If... is being compiled:         */
387     /*                                                                       */
388     /*               If...;  ...  Ifnot;  ...  Endif;                        */
389     /*   top of stack:       TRUE        FALSE                               */
390     /*                                                                       */
391     /*   This is used to detect "two Ifnots in same If" errors.              */
392     /* --------------------------------------------------------------------- */
393
394     case IFDEF_CODE:
395         flag = TRUE;
396         goto DefCondition;
397     case IFNDEF_CODE:
398         flag = FALSE;
399
400       DefCondition:
401         get_next_token();
402         if (token_type != SYMBOL_TT)
403             return ebf_error_recover("symbol name", token_text);
404
405         /* Special case: a symbol of the form "VN_nnnn" is considered
406            defined if the compiler version number is at least nnnn.
407            Compiler version numbers look like "1640" for Inform 6.40;
408            see RELEASE_NUMBER.
409            ("VN_nnnn" isn't a real symbol and can't be used in other
410            contexts.) */
411         if ((token_text[0] == 'V')
412             && (token_text[1] == 'N')
413             && (token_text[2] == '_')
414             && (strlen(token_text)==7))
415         {
416             char *endstr;
417             i = strtol(token_text+3, &endstr, 10);
418             if (*endstr == '\0') {
419                 /* All characters after the underscore were digits */
420                 if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
421                 goto HashIfCondition;
422             }
423         }
424
425         if (symbols[token_value].flags & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
426         else symbols[token_value].flags |= USED_SFLAG;
427         goto HashIfCondition;
428
429     case IFNOT_CODE:
430         if (ifdef_sp == 0)
431             error("'Ifnot' without matching 'If...'");
432         else
433         if (!(ifdef_stack[ifdef_sp-1]))
434             error("Second 'Ifnot' for the same 'If...' condition");
435         else
436         {   dont_enter_into_symbol_table = -2; n = 1;
437             directives.enabled = TRUE;
438             do
439             {
440                 release_token_texts();
441                 get_next_token();
442                 if (token_type == EOF_TT)
443                 {   error("End of file reached in code 'If...'d out");
444                     directives.enabled = FALSE;
445                     return TRUE;
446                 }
447                 if (token_type == DIRECTIVE_TT)
448                 {
449                     switch(token_value)
450                     {   case ENDIF_CODE:
451                             n--; break;
452                         case IFV3_CODE:
453                         case IFV5_CODE:
454                         case IFDEF_CODE:
455                         case IFNDEF_CODE:
456                         case IFTRUE_CODE:
457                         case IFFALSE_CODE:
458                             n++; break;
459                         case IFNOT_CODE:
460                             if (n == 1)
461                             {   error(
462                               "Second 'Ifnot' for the same 'If...' condition");
463                                 break;
464                             }
465                     }
466                 }
467             } while (n > 0);
468             ifdef_sp--; 
469             dont_enter_into_symbol_table = FALSE;
470             directives.enabled = FALSE;
471         }
472         break;
473
474     case IFV3_CODE:
475         flag = FALSE;
476         if (!glulx_mode && version_number <= 3) flag = TRUE;
477         goto HashIfCondition;
478
479     case IFV5_CODE:
480         flag = TRUE;
481         if (!glulx_mode && version_number <= 3) flag = FALSE;
482         goto HashIfCondition;
483
484     case IFTRUE_CODE:
485         {   assembly_operand AO;
486             AO = parse_expression(CONSTANT_CONTEXT);
487             if (AO.marker != 0)
488             {   error("This condition can't be determined");
489                 flag = 0;
490             }
491             else flag = (AO.value != 0);
492         }
493         goto HashIfCondition;
494
495     case IFFALSE_CODE:
496         {   assembly_operand AO;
497             AO = parse_expression(CONSTANT_CONTEXT);
498             if (AO.marker != 0)
499             {   error("This condition can't be determined");
500                 flag = 1;
501             }
502             else flag = (AO.value == 0);
503         }
504         goto HashIfCondition;
505
506     HashIfCondition:
507         get_next_token();
508         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
509             return ebf_error_recover("semicolon after 'If...' condition", token_text);
510
511         if (ifdef_sp >= MAX_IFDEF_STACK) {
512             error("'If' directives nested too deeply");
513             panic_mode_error_recovery(); return FALSE;
514         }
515         
516         if (flag)
517         {   ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
518         else
519         {   dont_enter_into_symbol_table = -2; n = 1;
520             directives.enabled = TRUE;
521             do
522             {
523                 release_token_texts();
524                 get_next_token();
525                 if (token_type == EOF_TT)
526                 {   error("End of file reached in code 'If...'d out");
527                     directives.enabled = FALSE;
528                     return TRUE;
529                 }
530                 if (token_type == DIRECTIVE_TT)
531                 {
532                     switch(token_value)
533                     {   case ENDIF_CODE:
534                             n--; break;
535                         case IFV3_CODE:
536                         case IFV5_CODE:
537                         case IFDEF_CODE:
538                         case IFNDEF_CODE:
539                         case IFTRUE_CODE:
540                         case IFFALSE_CODE:
541                             n++; break;
542                         case IFNOT_CODE:
543                             if (n == 1)
544                             {   ifdef_stack[ifdef_sp++] = FALSE;
545                                 n--; break;
546                             }
547                     }
548                 }
549             } while (n > 0);
550             directives.enabled = FALSE;
551             dont_enter_into_symbol_table = FALSE;
552         }
553         break;
554
555     /* --------------------------------------------------------------------- */
556     /*   Import global <varname> [, ...]                                     */
557     /* --------------------------------------------------------------------- */
558
559     case IMPORT_CODE:
560         error("The 'Import' directive is no longer supported.");
561         break;
562
563     /* --------------------------------------------------------------------- */
564     /*   Include "[>]filename"                                               */
565     /*                                                                       */
566     /* The ">" character means to load the file from the same directory as   */
567     /* the current file, instead of relying on the include path.             */
568     /* --------------------------------------------------------------------- */
569
570     case INCLUDE_CODE:
571         get_next_token();
572         if (token_type != DQ_TT)
573             return ebf_error_recover("filename in double-quotes", token_text);
574
575         {   char *name = token_text;
576
577             get_next_token();
578             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
579                 ebf_error("semicolon ';' after Include filename", token_text);
580
581             if (strcmp(name, "language__") == 0)
582                  load_sourcefile(Language_Name, 0);
583             else if (name[0] == '>')
584                  load_sourcefile(name+1, 1);
585             else load_sourcefile(name, 0);
586             return FALSE;
587         }
588
589     /* --------------------------------------------------------------------- */
590     /*   Link "filename"                                                     */
591     /* --------------------------------------------------------------------- */
592
593     case LINK_CODE:
594         get_next_token();
595         error("The 'Link' directive is no longer supported.");
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 (glulx_mode) {
608             error("The LowString directive has no meaning in Glulx.");
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 (!(symbols[i].flags & UNKNOWN_SFLAG))
615             return ebf_symbol_error_recover("new low string name", token_text, typename(symbols[i].type), symbols[i].line);
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, STRCTX_LOWSTRING), 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                                     */
756     /*   Property [long] [additive] name alias oldname                       */
757     /*   Property [long] [additive] name defaultvalue                        */
758     /*   Property [long] individual name                                     */
759     /* --------------------------------------------------------------------- */
760
761     case PROPERTY_CODE: make_property(); break;           /* See "objects.c" */
762
763     /* --------------------------------------------------------------------- */
764     /*   Release <number>                                                    */
765     /* --------------------------------------------------------------------- */
766
767     case RELEASE_CODE:
768         {   assembly_operand AO;
769             AO = parse_expression(CONSTANT_CONTEXT);
770             if (AO.marker != 0)
771                 error("A definite value must be given as release number");
772             else
773                 release_number = AO.value;
774         }
775         break;
776
777     /* --------------------------------------------------------------------- */
778     /*   Replace routine [routinename]                                       */
779     /* --------------------------------------------------------------------- */
780
781     case REPLACE_CODE:
782         /* You can also replace system functions normally implemented in     */
783         /* the "hardware" of the Z-machine, like "random()":                 */
784
785         system_functions.enabled = TRUE;
786         directives.enabled = FALSE;
787         directive_keywords.enabled = FALSE;
788
789         /* Don't count the upcoming symbol as a top-level reference
790            *to* the function. */
791         df_dont_note_global_symbols = TRUE;
792         get_next_token();
793         df_dont_note_global_symbols = FALSE;
794         if (token_type == SYSFUN_TT)
795         {   if (system_function_usage[token_value] == 1)
796                 error("You can't 'Replace' a system function already used");
797             else system_function_usage[token_value] = 2;
798             get_next_token();
799             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
800             {
801                 error("You can't give a 'Replace'd system function a new name");
802                 panic_mode_error_recovery(); return FALSE;
803             }
804             return FALSE;
805         }
806
807         if (token_type != SYMBOL_TT)
808             return ebf_error_recover("name of routine to replace", token_text);
809         if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
810             return ebf_error_recover("name of routine not yet defined", token_text);
811
812         symbols[token_value].flags |= REPLACE_SFLAG;
813
814         /* If a second symbol is provided, it will refer to the
815            original (replaced) definition of the routine. */
816         i = token_value;
817
818         system_functions.enabled = FALSE;
819         df_dont_note_global_symbols = TRUE;
820         get_next_token();
821         df_dont_note_global_symbols = FALSE;
822         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
823         {   return FALSE;
824         }
825
826         if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG))
827             return ebf_error_recover("semicolon ';' or new routine name", token_text);
828
829         /* Define the original-form symbol as a zero constant. Its
830            value will be overwritten later, when we define the
831            replacement. */
832         assign_symbol(token_value, 0, CONSTANT_T);
833         add_symbol_replacement_mapping(i, token_value);
834
835         break;
836
837     /* --------------------------------------------------------------------- */
838     /*   Serial "yymmdd"                                                     */
839     /* --------------------------------------------------------------------- */
840
841     case SERIAL_CODE:
842         get_next_token();
843         if ((token_type != DQ_TT) || (strlen(token_text)!=6))
844         {   error("The serial number must be a 6-digit date in double-quotes");
845             panic_mode_error_recovery(); return FALSE;
846         }
847         for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
848         {   error("The serial number must be a 6-digit date in double-quotes");
849             panic_mode_error_recovery(); return FALSE;
850         }
851         strcpy(serial_code_buffer, token_text);
852         serial_code_given_in_program = TRUE;
853         break;
854
855     /* --------------------------------------------------------------------- */
856     /*   Statusline score/time                                               */
857     /* --------------------------------------------------------------------- */
858
859     case STATUSLINE_CODE:
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 (symbols[i].flags & UNKNOWN_SFLAG)
886         {   symbols[i].flags |= 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                 (We don't set local_variable.keywords because we're not
904                 going to be parsing any code.)                               */
905
906             strcpy(local_variable_names[0].text, "dummy1");
907             strcpy(local_variable_names[1].text, "dummy2");
908             strcpy(local_variable_names[2].text, "dummy3");
909             strcpy(local_variable_names[3].text, "dummy4");
910
911             assign_symbol(i,
912                 assemble_routine_header(k, FALSE, symbols[i].name, FALSE, i),
913                 ROUTINE_T);
914
915             /*  Ensure the return value of a stubbed routine is false,
916                 since this is necessary to make the library work properly    */
917
918             if (!glulx_mode)
919                 assemblez_0(rfalse_zc);
920             else
921                 assembleg_1(return_gc, zero_operand);
922
923             /*  Inhibit "local variable unused" warnings  */
924
925             for (i=1; i<=k; i++) variables[i].usage = 1;
926             sequence_point_follows = FALSE;
927             assemble_routine_end(FALSE, get_token_locations());
928         }
929         break;
930
931     /* --------------------------------------------------------------------- */
932     /*   Switches switchblock                                                */
933     /* (this directive is ignored if the -i switch was set at command line)  */
934     /* --------------------------------------------------------------------- */
935
936     case SWITCHES_CODE:
937         dont_enter_into_symbol_table = TRUE;
938         get_next_token();
939         dont_enter_into_symbol_table = FALSE;
940         if (token_type != DQ_TT)
941             return ebf_error_recover("string of switches", token_text);
942         if (!ignore_switches_switch)
943         {
944             if (constant_made_yet) {
945                 error("A 'Switches' directive must must come before the first constant definition");
946                 break;
947             }
948             if (no_routines > 1)
949             {
950                 /* The built-in Main__ routine is number zero. */
951                 error("A 'Switches' directive must come before the first routine definition.");
952                 break;
953             }
954             obsolete_warning("the Switches directive is deprecated and may produce incorrect results. Use command-line arguments or header comments.");
955             switches(token_text, 0);                       /* see "inform.c" */
956         }
957         break;
958
959     /* --------------------------------------------------------------------- */
960     /*   System_file                                                         */
961     /*                                                                       */
962     /* Some files are declared as "system files": this information is used   */
963     /* by Inform only to skip the definition of a routine X if the designer  */
964     /* has indicated his intention to Replace X.                             */
965     /* --------------------------------------------------------------------- */
966
967     case SYSTEM_CODE:
968         declare_systemfile(); break;                        /* see "files.c" */
969
970     /* --------------------------------------------------------------------- */
971     /*   Trace dictionary   [on/NUM]                                         */
972     /*         objects      [on/NUM]                                         */
973     /*         symbols      [on/NUM]                                         */
974     /*         verbs        [on/NUM]                                         */
975     /*                      [on/off/NUM]      {same as "assembly"}           */
976     /*         assembly     [on/off/NUM]                                     */
977     /*         expressions  [on/off/NUM]                                     */
978     /*         lines        [on/off/NUM]      {not supported}                */
979     /*         tokens       [on/off/NUM]                                     */
980     /*         linker       [on/off/NUM]      {not supported}                */
981     /*                                                                       */
982     /* The first four trace commands immediately display a compiler table.   */
983     /* The rest set or clear an ongoing trace.                               */
984     /* --------------------------------------------------------------------- */
985
986     case TRACE_CODE:
987         directives.enabled = FALSE;
988         trace_keywords.enabled = TRUE;
989         get_next_token();
990         trace_keywords.enabled = FALSE;
991         directives.enabled = TRUE;
992         
993         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
994             /* "Trace;" */
995             put_token_back();
996             i = ASSEMBLY_TK;
997             trace_level = &asm_trace_level;
998             j = 1;
999             goto HandleTraceKeyword;
1000         }
1001         if (token_type == NUMBER_TT) {
1002             /* "Trace NUM;" */
1003             i = ASSEMBLY_TK;
1004             trace_level = &asm_trace_level;
1005             j = token_value;
1006             goto HandleTraceKeyword;
1007         }
1008
1009         /* Anything else must be "Trace KEYWORD..." Remember that
1010            'on' and 'off' are trace keywords. */
1011         
1012         if (token_type != TRACE_KEYWORD_TT)
1013             return ebf_error_recover("debugging keyword", token_text);
1014
1015         trace_keywords.enabled = TRUE;
1016
1017         /* Note that "Trace verbs" doesn't affect list_verbs_setting.
1018            It shows the grammar at this point in the code. Setting
1019            list_verbs_setting shows the grammar at the end of 
1020            compilation.
1021            Same goes for "Trace dictionary" and list_dict_setting, etc. */
1022         
1023         i = token_value;
1024
1025         switch(i)
1026         {
1027         case ASSEMBLY_TK:
1028             trace_level = &asm_trace_level;  break;
1029         case EXPRESSIONS_TK:
1030             trace_level = &expr_trace_level; break;
1031         case TOKENS_TK:
1032             trace_level = &tokens_trace_level; break;
1033         case DICTIONARY_TK:
1034         case SYMBOLS_TK:
1035         case OBJECTS_TK:
1036         case VERBS_TK:
1037             /* show a table rather than changing any trace level */
1038             trace_level = NULL; break;
1039         case LINES_TK:
1040             /* never implememented */
1041             trace_level = NULL; break;
1042         case LINKER_TK:
1043             /* no longer implememented */
1044             trace_level = NULL; break;
1045         default:
1046             /* default to "Trace assembly" */
1047             put_token_back();
1048             trace_level = &asm_trace_level; break;
1049         }
1050         
1051         j = 1;
1052         get_next_token();
1053         if ((token_type == SEP_TT) &&
1054             (token_value == SEMICOLON_SEP))
1055         {   put_token_back();
1056         }
1057         else if (token_type == NUMBER_TT)
1058         {   j = token_value;
1059         }
1060         else if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1061         {   j = 1;
1062         }
1063         else if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1064         {   j = 0;
1065         }
1066         else
1067         {   put_token_back();
1068         }
1069
1070         trace_keywords.enabled = FALSE;
1071
1072         HandleTraceKeyword:
1073
1074         if (i == LINES_TK || i == LINKER_TK) {
1075             warning_named("Trace option is not supported:", trace_keywords.keywords[i]);
1076             break;
1077         }
1078         
1079         if (trace_level == NULL && j == 0) {
1080             warning_named("Trace directive to display table at 'off' level has no effect: table", trace_keywords.keywords[i]);
1081             break;
1082         }
1083         
1084         switch(i)
1085         {   case DICTIONARY_TK: show_dictionary(j);  break;
1086             case OBJECTS_TK:    list_object_tree();  break;
1087             case SYMBOLS_TK:    list_symbols(j);     break;
1088             case VERBS_TK:      list_verb_table();   break;
1089             default:
1090                 if (trace_level)
1091                     *trace_level = j;
1092                 break;
1093         }
1094         break;
1095
1096     /* --------------------------------------------------------------------- */
1097     /*   Undef symbol                                                        */
1098     /* --------------------------------------------------------------------- */
1099
1100     case UNDEF_CODE:
1101         get_next_token();
1102         if (token_type != SYMBOL_TT)
1103             return ebf_error_recover("symbol name", token_text);
1104
1105         if (symbols[token_value].flags & UNKNOWN_SFLAG)
1106         {   break; /* undef'ing an undefined constant is okay */
1107         }
1108
1109         if (symbols[token_value].type != CONSTANT_T)
1110         {   error_named("Cannot Undef a symbol which is not a defined constant:", symbols[token_value].name);
1111             break;
1112         }
1113
1114         if (debugfile_switch)
1115         {   write_debug_undef(token_value);
1116         }
1117         end_symbol_scope(token_value);
1118         symbols[token_value].flags |= USED_SFLAG;
1119         break;
1120
1121     /* --------------------------------------------------------------------- */
1122     /*   Verb ...                                                            */
1123     /* --------------------------------------------------------------------- */
1124
1125     case VERB_CODE: make_verb(); return FALSE;             /* see "tables.c" */
1126
1127     /* --------------------------------------------------------------------- */
1128     /*   Version <number>                                                    */
1129     /* --------------------------------------------------------------------- */
1130
1131     case VERSION_CODE:
1132
1133         {   assembly_operand AO;
1134             AO = parse_expression(CONSTANT_CONTEXT);
1135             /* If a version has already been set on the command line,
1136                that overrides this. */
1137             if (version_set_switch)
1138             {
1139               warning("The Version directive was overridden by a command-line argument.");
1140               break;
1141             }
1142
1143             if (AO.marker != 0)
1144             {
1145               error("A definite value must be given as version number.");
1146               break;
1147             }
1148             else if (no_routines > 1)
1149             {
1150               /* The built-in Main__ routine is number zero. */
1151               error("A 'Version' directive must come before the first routine definition.");
1152               break;
1153             }
1154             else if (glulx_mode) 
1155             {
1156               warning("The Version directive does not work in Glulx. Use \
1157 -vX.Y.Z instead, as either a command-line argument or a header comment.");
1158               break;
1159             }
1160             else
1161             {
1162                 int debtok;
1163                 i = AO.value;
1164                 if ((i<3) || (i>8))
1165                 {   error("The version number must be in the range 3 to 8");
1166                     break;
1167                 }
1168                 obsolete_warning("the Version directive is deprecated and may produce incorrect results. Use -vN instead, as either a command-line argument or a header comment.");
1169                 select_version(i);
1170                 /* We must now do a small dance to reset the DICT_ENTRY_BYTES
1171                    constant, which was defined at startup based on the Z-code
1172                    version.
1173                    The calculation here is repeated from select_target(). */
1174                 DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0);
1175                 debtok = symbol_index("DICT_ENTRY_BYTES", -1);
1176                 if (!(symbols[debtok].flags & UNKNOWN_SFLAG))
1177                 {
1178                     if (!(symbols[debtok].flags & REDEFINABLE_SFLAG))
1179                     {
1180                         warning("The DICT_ENTRY_BYTES symbol is not marked redefinable");
1181                     }
1182                     /* Redefine the symbol... */
1183                     assign_symbol(debtok, DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
1184                 }
1185             }
1186         }
1187         break;                                             /* see "inform.c" */
1188
1189     /* --------------------------------------------------------------------- */
1190     /*   Zcharacter table <num> ...                                          */
1191     /*   Zcharacter table + <num> ...                                        */
1192     /*   Zcharacter <string> <string> <string>                               */
1193     /*   Zcharacter <char>                                                   */
1194     /* --------------------------------------------------------------------- */
1195
1196     case ZCHARACTER_CODE:
1197
1198         if (glulx_mode) {
1199             error("The Zcharacter directive has no meaning in Glulx.");
1200             panic_mode_error_recovery(); return FALSE;
1201         }
1202
1203         directive_keywords.enabled = TRUE;
1204         get_next_token();
1205         directive_keywords.enabled = FALSE;
1206
1207         switch(token_type)
1208         {   case DQ_TT:
1209                 new_alphabet(token_text, 0);
1210                 get_next_token();
1211                 if (token_type != DQ_TT)
1212                     return ebf_error_recover("double-quoted alphabet string", token_text);
1213                 new_alphabet(token_text, 1);
1214                 get_next_token();
1215                 if (token_type != DQ_TT)
1216                     return ebf_error_recover("double-quoted alphabet string", token_text);
1217                 new_alphabet(token_text, 2);
1218             break;
1219
1220             case SQ_TT:
1221                 map_new_zchar(text_to_unicode(token_text));
1222                 if (token_text[textual_form_length] != 0)
1223                     return ebf_error_recover("single character value", token_text);
1224             break;
1225
1226             case DIR_KEYWORD_TT:
1227             switch(token_value)
1228             {   case TABLE_DK:
1229                 {   int plus_flag = FALSE;
1230                     get_next_token();
1231                     if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1232                     {   plus_flag = TRUE;
1233                         get_next_token();
1234                     }
1235                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1236                     {   switch(token_type)
1237                         {   case NUMBER_TT:
1238                                 new_zscii_character(token_value, plus_flag);
1239                                 plus_flag = TRUE; break;
1240                             case SQ_TT:
1241                                 new_zscii_character(text_to_unicode(token_text),
1242                                     plus_flag);
1243                                 if (token_text[textual_form_length] != 0)
1244                                     return ebf_error_recover("single character value",
1245                                         token_text);
1246                                 plus_flag = TRUE;
1247                                 break;
1248                             default:
1249                                 return ebf_error_recover("character or Unicode number",
1250                                     token_text);
1251                         }
1252                         get_next_token();
1253                     }
1254                     if (plus_flag) new_zscii_finished();
1255                     put_token_back();
1256                 }
1257                     break;
1258                 case TERMINATING_DK:
1259                     get_next_token();
1260                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1261                     {   switch(token_type)
1262                         {   case NUMBER_TT:
1263                                 terminating_characters[no_termcs++]
1264                                     = token_value;
1265                                 break;
1266                             default:
1267                                 return ebf_error_recover("ZSCII number",
1268                                     token_text);
1269                         }
1270                         get_next_token();
1271                     }
1272                     put_token_back();
1273                     break;
1274                 default:
1275                     return ebf_error_recover("'table', 'terminating', \
1276 a string or a constant",
1277                         token_text);
1278             }
1279                 break;
1280             default:
1281                 return ebf_error_recover("three alphabet strings, \
1282 a 'table' or 'terminating' command or a single character", token_text);
1283         }
1284         break;
1285
1286     /* ===================================================================== */
1287
1288     }
1289
1290     /* We are now at the end of a syntactically valid directive. It
1291        should be terminated by a semicolon. */
1292
1293     get_next_token();
1294     if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1295     {   ebf_error("';'", token_text);
1296         /* Put the non-semicolon back. We will continue parsing from
1297            that point, in hope that it's the start of a new directive.
1298            (This recovers cleanly from a missing semicolon at the end
1299            of a directive. It's not so clean if the directive *does*
1300            end with a semicolon, but there's extra garbage before it.) */
1301         put_token_back();
1302     }
1303     return FALSE;
1304 }
1305
1306 /* ========================================================================= */
1307 /*   Data structure management routines                                      */
1308 /* ------------------------------------------------------------------------- */
1309
1310 extern void init_directs_vars(void)
1311 {
1312 }
1313
1314 extern void directs_begin_pass(void)
1315 {   no_routines = 0;
1316     no_named_routines = 0;
1317     no_locals = 0;
1318     no_termcs = 0;
1319     constant_made_yet = FALSE;
1320     ifdef_sp = 0;
1321 }
1322
1323 extern void directs_allocate_arrays(void)
1324 {
1325 }
1326
1327 extern void directs_free_arrays(void)
1328 {
1329 }
1330
1331 /* ========================================================================= */