Update to Inform v6.42
[inform.git] / src / directs.c
1 /* ------------------------------------------------------------------------- */
2 /*   "directs" : Directives (# commands)                                     */
3 /*                                                                           */
4 /*   Part of Inform 6.42                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2024                                 */
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_termcs;                     /* Number of terminating characters       */
27 int terminating_characters[32];
28
29 brief_location routine_starts_line; /* Source code location where the current
30                                       routine starts.  (Useful for reporting
31                                       "unused variable" warnings on the start
32                                       line rather than the end line.)        */
33
34 static int constant_made_yet;      /* Have any constants been defined yet?   */
35
36 #define MAX_IFDEF_STACK (32)
37 static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp;
38
39 /* ------------------------------------------------------------------------- */
40
41 static int ebf_error_recover(char *s1)
42 {
43     /* Display an "expected... but found (current token)" error, then
44        skim forward to the next semicolon and return FALSE. This is
45        such a common case in parse_given_directive() that it's worth a
46        utility function. You will see many error paths that look like:
47           return ebf_error_recover(...);
48     */
49     ebf_curtoken_error(s1);
50     panic_mode_error_recovery();
51     return FALSE;
52 }
53
54 static int ebf_symbol_error_recover(char *s1, char *type, brief_location report_line)
55 {
56     /* Same for ebf_symbol_error(). */
57     ebf_symbol_error(s1, token_text, 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            if (!glulx_mode && no_abbreviations==96)
110            {   error_max_abbreviations(no_abbreviations);
111                panic_mode_error_recovery(); return FALSE;
112            }
113            if (!glulx_mode && no_abbreviations==MAX_ABBREVS)
114            {   error_max_abbreviations(no_abbreviations);
115                /* This is no longer a memoryerror(); MAX_ABBREVS is an authoring decision for Z-code games. */
116                panic_mode_error_recovery(); return FALSE;
117            }
118
119            if (abbrevs_lookup_table_made)
120            {   error("All abbreviations must be declared together");
121                panic_mode_error_recovery(); return FALSE;
122            }
123            if (token_type != DQ_TT)
124            {   return ebf_error_recover("abbreviation string");
125            }
126            make_abbreviation(token_text);
127         } while (TRUE);
128
129     /* --------------------------------------------------------------------- */
130     /*   Array <arrayname> [static] <array specification>                    */
131     /* --------------------------------------------------------------------- */
132
133     case ARRAY_CODE: make_array(); break;                  /* See "arrays.c" */
134
135     /* --------------------------------------------------------------------- */
136     /*   Attribute newname [alias oldname]                                   */
137     /* --------------------------------------------------------------------- */
138
139     case ATTRIBUTE_CODE:
140         make_attribute(); break;                          /* See "objects.c" */
141
142     /* --------------------------------------------------------------------- */
143     /*   Class classname ...                                                 */
144     /* --------------------------------------------------------------------- */
145
146     case CLASS_CODE: 
147         make_class(NULL);                                 /* See "objects.c" */
148         return FALSE;
149
150     /* --------------------------------------------------------------------- */
151     /*   Constant newname [[=] value] [, ...]                                */
152     /* --------------------------------------------------------------------- */
153
154     case CONSTANT_CODE:
155         constant_made_yet=TRUE;
156
157       ParseConstantSpec:
158         get_next_token(); i = token_value;
159         beginning_debug_location = get_token_location_beginning();
160
161         if (token_type != SYMBOL_TT)
162         {   discard_token_location(beginning_debug_location);
163             return ebf_error_recover("new constant name");
164         }
165
166         if (!(symbols[i].flags & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG)))
167         {   discard_token_location(beginning_debug_location);
168             return ebf_symbol_error_recover("new constant name", typename(symbols[i].type), symbols[i].line);
169         }
170
171         assign_symbol(i, 0, CONSTANT_T);
172         constant_name = token_text;
173
174         get_next_token();
175
176         if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
177         {   if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
178             {   debug_file_printf("<constant>");
179                 debug_file_printf("<identifier>%s</identifier>", constant_name);
180                 write_debug_symbol_optional_backpatch(i);
181                 write_debug_locations(get_token_location_end(beginning_debug_location));
182                 debug_file_printf("</constant>");
183             }
184             goto ParseConstantSpec;
185         }
186
187         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
188         {   if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
189             {   debug_file_printf("<constant>");
190                 debug_file_printf("<identifier>%s</identifier>", constant_name);
191                 write_debug_symbol_optional_backpatch(i);
192                 write_debug_locations(get_token_location_end(beginning_debug_location));
193                 debug_file_printf("</constant>");
194             }
195             return FALSE;
196         }
197
198         if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
199             put_token_back();
200
201         {   assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
202             if (AO.marker != 0)
203             {   assign_marked_symbol(i, AO.marker, AO.value,
204                     CONSTANT_T);
205                 symbols[i].flags |= CHANGE_SFLAG;
206                 if (i == grammar_version_symbol)
207                     error(
208                 "Grammar__Version must be given an explicit constant value");
209             }
210             else
211             {   assign_symbol(i, AO.value, CONSTANT_T);
212                 if (i == grammar_version_symbol)
213                 {   if ((grammar_version_number != AO.value)
214                         && (no_fake_actions > 0))
215                         error(
216                 "Once a fake action has been defined it is too late to \
217 change the grammar version. (If you are using the library, move any \
218 Fake_Action directives to a point after the inclusion of \"Parser\".)");
219                     grammar_version_number = AO.value;
220                 }
221             }
222         }
223
224         if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
225         {   debug_file_printf("<constant>");
226             debug_file_printf("<identifier>%s</identifier>", constant_name);
227             write_debug_symbol_optional_backpatch(i);
228             write_debug_locations
229                 (get_token_location_end(beginning_debug_location));
230             debug_file_printf("</constant>");
231         }
232
233         get_next_token();
234         if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
235             goto ParseConstantSpec;
236         put_token_back();
237         break;
238
239     /* --------------------------------------------------------------------- */
240     /*   Default constantname integer                                        */
241     /* --------------------------------------------------------------------- */
242
243     case DEFAULT_CODE:
244         get_next_token();
245         if (token_type != SYMBOL_TT)
246             return ebf_error_recover("name");
247
248         i = -1;
249         if (symbols[token_value].flags & UNKNOWN_SFLAG)
250         {   i = token_value;
251             symbols[i].flags |= DEFCON_SFLAG;
252         }
253
254         get_next_token();
255         if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
256             put_token_back();
257
258         {   assembly_operand AO;
259             AO = parse_expression(CONSTANT_CONTEXT);
260             if (i != -1)
261             {   if (AO.marker != 0)
262                 {   assign_marked_symbol(i, AO.marker, AO.value,
263                         CONSTANT_T);
264                     symbols[i].flags |= CHANGE_SFLAG;
265                 }
266                 else assign_symbol(i, AO.value, CONSTANT_T);
267             }
268         }
269
270         break;
271
272     /* --------------------------------------------------------------------- */
273     /*   Dictionary 'word'                                                   */
274     /*   Dictionary 'word' val1                                              */
275     /*   Dictionary 'word' val1 val3                                         */
276     /* --------------------------------------------------------------------- */
277
278     case DICTIONARY_CODE:
279         /* In Inform 5, this directive had the form
280              Dictionary SYMBOL "word";
281            This was deprecated as of I6 (if not earlier), and is no longer
282            supported at all. The current form just creates a dictionary word,
283            with the given values for dict_par1 and dict_par3. If the word
284            already exists, the values are bit-or'd in with the existing
285            values.
286            (We don't offer a way to set dict_par2, because that is entirely
287            reserved for the verb number. Or'ing values into it would create
288            garbage.)
289          */
290         get_next_token();
291         if (token_type != SQ_TT && token_type != DQ_TT)
292             return ebf_error_recover("dictionary word");
293
294         {
295             char *wd = token_text;
296             int val1 = 0;
297             int val3 = 0;
298
299             get_next_token();
300             if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
301                 put_token_back();
302             }
303             else {
304                 assembly_operand AO;
305                 put_token_back();
306                 AO = parse_expression(CONSTANT_CONTEXT);
307                 if (AO.marker != 0)
308                     error("A definite value must be given as a Dictionary flag");
309                 else
310                     val1 = AO.value;
311
312                 get_next_token();
313                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
314                     put_token_back();
315                 }
316                 else {
317                     assembly_operand AO;
318                     put_token_back();
319                     if (ZCODE_LESS_DICT_DATA && !glulx_mode)
320                         warning("The third dictionary field will be ignored because ZCODE_LESS_DICT_DATA is set");
321                     AO = parse_expression(CONSTANT_CONTEXT);
322                     if (AO.marker != 0)
323                         error("A definite value must be given as a Dictionary flag");
324                     else
325                         val3 = AO.value;
326                 }
327             }
328
329             if (!glulx_mode) {
330                 if ((val1 & ~0xFF) || (val3 & ~0xFF)) {
331                     warning("Dictionary flag values cannot exceed $FF in Z-code");
332                 }
333             }
334             else {
335                 if ((val1 & ~0xFFFF) || (val3 & ~0xFFFF)) {
336                     warning("Dictionary flag values cannot exceed $FFFF in Glulx");
337                 }
338             }
339
340             dictionary_add(wd, val1, 0, val3);
341         }
342         break;
343
344     /* --------------------------------------------------------------------- */
345     /*   End                                                                 */
346     /* --------------------------------------------------------------------- */
347
348     case END_CODE: return(TRUE);
349
350     case ENDIF_CODE:
351         if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
352         else ifdef_sp--;
353         break;
354
355     /* --------------------------------------------------------------------- */
356     /*   Extend ...                                                          */
357     /* --------------------------------------------------------------------- */
358
359     case EXTEND_CODE: extend_verb(); return FALSE;         /* see "tables.c" */
360
361     /* --------------------------------------------------------------------- */
362     /*   Fake_Action name                                                    */
363     /* --------------------------------------------------------------------- */
364
365     case FAKE_ACTION_CODE:
366         make_fake_action(); break;                          /* see "verbs.c" */
367
368     /* --------------------------------------------------------------------- */
369     /*   Global <variablename> [ [=] <value> ]                               */
370     /* --------------------------------------------------------------------- */
371
372     case GLOBAL_CODE: make_global(); break;                /* See "arrays.c" */
373
374     /* --------------------------------------------------------------------- */
375     /*   If...                                                               */
376     /*                                                                       */
377     /*   Note that each time Inform tests an If... condition, it stacks the  */
378     /*   result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack  */
379     /*   reveals what clause of the current If... is being compiled:         */
380     /*                                                                       */
381     /*               If...;  ...  Ifnot;  ...  Endif;                        */
382     /*   top of stack:       TRUE        FALSE                               */
383     /*                                                                       */
384     /*   This is used to detect "two Ifnots in same If" errors.              */
385     /* --------------------------------------------------------------------- */
386
387     case IFDEF_CODE:
388         flag = TRUE;
389         goto DefCondition;
390     case IFNDEF_CODE:
391         flag = FALSE;
392
393       DefCondition:
394         get_next_token();
395         if (token_type != SYMBOL_TT)
396             return ebf_error_recover("symbol name");
397
398         /* Special case: a symbol of the form "VN_nnnn" is considered
399            defined if the compiler version number is at least nnnn.
400            Compiler version numbers look like "1640" for Inform 6.40;
401            see RELEASE_NUMBER.
402            ("VN_nnnn" isn't a real symbol and can't be used in other
403            contexts.) */
404         if ((token_text[0] == 'V')
405             && (token_text[1] == 'N')
406             && (token_text[2] == '_')
407             && (strlen(token_text)==7))
408         {
409             char *endstr;
410             i = strtol(token_text+3, &endstr, 10);
411             if (*endstr == '\0') {
412                 /* All characters after the underscore were digits */
413                 if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
414                 goto HashIfCondition;
415             }
416         }
417
418         if (symbols[token_value].flags & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
419         else symbols[token_value].flags |= USED_SFLAG;
420         goto HashIfCondition;
421
422     case IFNOT_CODE:
423         if (ifdef_sp == 0)
424             error("'Ifnot' without matching 'If...'");
425         else
426         if (!(ifdef_stack[ifdef_sp-1]))
427             error("Second 'Ifnot' for the same 'If...' condition");
428         else
429         {   dont_enter_into_symbol_table = -2; n = 1;
430             directives.enabled = TRUE;
431             do
432             {
433                 release_token_texts();
434                 get_next_token();
435                 if (token_type == EOF_TT)
436                 {   error("End of file reached in code 'If...'d out");
437                     directives.enabled = FALSE;
438                     return TRUE;
439                 }
440                 if (token_type == DIRECTIVE_TT)
441                 {
442                     switch(token_value)
443                     {   case ENDIF_CODE:
444                             n--; break;
445                         case IFV3_CODE:
446                         case IFV5_CODE:
447                         case IFDEF_CODE:
448                         case IFNDEF_CODE:
449                         case IFTRUE_CODE:
450                         case IFFALSE_CODE:
451                             n++; break;
452                         case IFNOT_CODE:
453                             if (n == 1)
454                             {   error(
455                               "Second 'Ifnot' for the same 'If...' condition");
456                                 break;
457                             }
458                     }
459                 }
460             } while (n > 0);
461             ifdef_sp--; 
462             dont_enter_into_symbol_table = FALSE;
463             directives.enabled = FALSE;
464         }
465         break;
466
467     case IFV3_CODE:
468         flag = FALSE;
469         if (!glulx_mode && version_number <= 3) flag = TRUE;
470         goto HashIfCondition;
471
472     case IFV5_CODE:
473         flag = TRUE;
474         if (!glulx_mode && version_number <= 3) flag = FALSE;
475         goto HashIfCondition;
476
477     case IFTRUE_CODE:
478         {   assembly_operand AO;
479             AO = parse_expression(CONSTANT_CONTEXT);
480             if (AO.marker != 0)
481             {   error("This condition can't be determined");
482                 flag = 0;
483             }
484             else flag = (AO.value != 0);
485         }
486         goto HashIfCondition;
487
488     case IFFALSE_CODE:
489         {   assembly_operand AO;
490             AO = parse_expression(CONSTANT_CONTEXT);
491             if (AO.marker != 0)
492             {   error("This condition can't be determined");
493                 flag = 1;
494             }
495             else flag = (AO.value == 0);
496         }
497         goto HashIfCondition;
498
499     HashIfCondition:
500         get_next_token();
501         if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
502             return ebf_error_recover("semicolon after 'If...' condition");
503
504         if (ifdef_sp >= MAX_IFDEF_STACK) {
505             error("'If' directives nested too deeply");
506             panic_mode_error_recovery(); return FALSE;
507         }
508         
509         if (flag)
510         {   ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
511         else
512         {   dont_enter_into_symbol_table = -2; n = 1;
513             directives.enabled = TRUE;
514             do
515             {
516                 release_token_texts();
517                 get_next_token();
518                 if (token_type == EOF_TT)
519                 {   error("End of file reached in code 'If...'d out");
520                     directives.enabled = FALSE;
521                     return TRUE;
522                 }
523                 if (token_type == DIRECTIVE_TT)
524                 {
525                     switch(token_value)
526                     {   case ENDIF_CODE:
527                             n--; break;
528                         case IFV3_CODE:
529                         case IFV5_CODE:
530                         case IFDEF_CODE:
531                         case IFNDEF_CODE:
532                         case IFTRUE_CODE:
533                         case IFFALSE_CODE:
534                             n++; break;
535                         case IFNOT_CODE:
536                             if (n == 1)
537                             {   ifdef_stack[ifdef_sp++] = FALSE;
538                                 n--; break;
539                             }
540                     }
541                 }
542             } while (n > 0);
543             directives.enabled = FALSE;
544             dont_enter_into_symbol_table = FALSE;
545         }
546         break;
547
548     /* --------------------------------------------------------------------- */
549     /*   Import global <varname> [, ...]                                     */
550     /* --------------------------------------------------------------------- */
551
552     case IMPORT_CODE:
553         error("The 'Import' directive is no longer supported.");
554         break;
555
556     /* --------------------------------------------------------------------- */
557     /*   Include "[>]filename"                                               */
558     /*                                                                       */
559     /* The ">" character means to load the file from the same directory as   */
560     /* the current file, instead of relying on the include path.             */
561     /* --------------------------------------------------------------------- */
562
563     case INCLUDE_CODE:
564         get_next_token();
565         if (token_type != DQ_TT)
566             return ebf_error_recover("filename in double-quotes");
567
568         {   char *name = token_text;
569
570             get_next_token();
571             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
572                 ebf_curtoken_error("semicolon ';' after Include filename");
573
574             if (strcmp(name, "language__") == 0)
575                  load_sourcefile(Language_Name, 0);
576             else if (name[0] == '>')
577                  load_sourcefile(name+1, 1);
578             else load_sourcefile(name, 0);
579             return FALSE;
580         }
581
582     /* --------------------------------------------------------------------- */
583     /*   Link "filename"                                                     */
584     /* --------------------------------------------------------------------- */
585
586     case LINK_CODE:
587         get_next_token();
588         error("The 'Link' directive is no longer supported.");
589         break;
590
591     /* --------------------------------------------------------------------- */
592     /*   Lowstring constantname "text of string"                             */
593     /* --------------------------------------------------------------------- */
594     /* Unlike most constant creations, these do not require backpatching:    */
595     /* the low strings always occupy a table at a fixed offset in the        */
596     /* Z-machine (after the abbreviations table has finished, at 0x100).     */
597     /* --------------------------------------------------------------------- */
598
599     case LOWSTRING_CODE:
600         if (glulx_mode) {
601             error("The LowString directive has no meaning in Glulx.");
602             panic_mode_error_recovery(); return FALSE;
603         }
604         get_next_token(); i = token_value;
605         if (token_type != SYMBOL_TT)
606             return ebf_error_recover("new low string name");
607         if (!(symbols[i].flags & UNKNOWN_SFLAG))
608             return ebf_symbol_error_recover("new low string name", typename(symbols[i].type), symbols[i].line);
609
610         get_next_token();
611         if (token_type != DQ_TT)
612             return ebf_error_recover("literal string in double-quotes");
613
614         assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T);
615         break;
616
617     /* --------------------------------------------------------------------- */
618     /*   Message | "information"                                             */
619     /*           | error "error message"                                     */
620     /*           | fatalerror "fatal error message"                          */
621     /*           | warning "warning message"                                 */
622     /* --------------------------------------------------------------------- */
623
624     case MESSAGE_CODE:
625         directive_keywords.enabled = TRUE;
626         get_next_token();
627         directive_keywords.enabled = FALSE;
628         if (token_type == DQ_TT)
629         {   int i;
630             if (hash_printed_since_newline) printf("\n");
631             for (i=0; token_text[i]!=0; i++)
632             {   if (token_text[i] == '^') printf("\n");
633                 else
634                 if (token_text[i] == '~') printf("\"");
635                 else printf("%c", token_text[i]);
636             }
637             printf("\n");
638             break;
639         }
640         if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
641         {   get_next_token();
642             if (token_type != DQ_TT)
643             {   return ebf_error_recover("error message in double-quotes");
644             }
645             error(token_text); break;
646         }
647         if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
648         {   get_next_token();
649             if (token_type != DQ_TT)
650             {   return ebf_error_recover("fatal error message in double-quotes");
651             }
652             fatalerror(token_text); break;
653         }
654         if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
655         {   get_next_token();
656             if (token_type != DQ_TT)
657             {   return ebf_error_recover("warning message in double-quotes");
658             }
659             warning(token_text); break;
660         }
661         return ebf_error_recover("a message in double-quotes, 'error', 'fatalerror' or 'warning'");
662         break;
663
664     /* --------------------------------------------------------------------- */
665     /*   Nearby objname "short name" ...                                     */
666     /* --------------------------------------------------------------------- */
667
668     case NEARBY_CODE:
669         make_object(TRUE, NULL, -1, -1, -1);
670         return FALSE;                                     /* See "objects.c" */
671
672     /* --------------------------------------------------------------------- */
673     /*   Object objname "short name" ...                                     */
674     /* --------------------------------------------------------------------- */
675
676     case OBJECT_CODE:
677         make_object(FALSE, NULL, -1, -1, -1);
678         return FALSE;                                     /* See "objects.c" */
679
680     /* --------------------------------------------------------------------- */
681     /*   Origsource <file>                                                   */
682     /*   Origsource <file> <line>                                            */
683     /*   Origsource <file> <line> <char>                                     */
684     /*   Origsource                                                          */
685     /*                                                                       */
686     /*   The first three forms declare that all following lines are derived  */
687     /*   from the named Inform 7 source file (with an optional line number   */
688     /*   and character number). This will be reported in error messages and  */
689     /*   in debug output. The declaration holds through the next Origsource  */
690     /*   directive (but does not apply to included files).                   */
691     /*                                                                       */
692     /*   The fourth form, with no arguments, clears the declaration.         */
693     /*                                                                       */
694     /*   Unlike the Include directive, Origsource does not open the named    */
695     /*   file or even verify that it exists. The filename is treated as an   */
696     /*   opaque string.                                                      */
697     /* --------------------------------------------------------------------- */
698
699     case ORIGSOURCE_CODE:
700         {
701             char *origsource_file = NULL;
702             int32 origsource_line = 0;
703             int32 origsource_char = 0;
704
705             /* Parse some optional tokens followed by a mandatory semicolon. */
706
707             get_next_token();
708             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
709                 if (token_type != DQ_TT) {
710                     return ebf_error_recover("a file name in double-quotes");
711                 }
712                 origsource_file = token_text;
713
714                 get_next_token();
715                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) {
716                     if (token_type != NUMBER_TT) {
717                         return ebf_error_recover("a file line number");
718                     }
719                     origsource_line = token_value;
720                     if (origsource_line < 0)
721                         origsource_line = 0;
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                         }
728                         origsource_char = token_value;
729                         if (origsource_char < 0)
730                             origsource_char = 0;
731                         
732                         get_next_token();
733                     }
734                 }
735             }
736
737             put_token_back();
738
739             set_origsource_location(origsource_file, origsource_line, origsource_char);
740         }
741         break;
742
743     /* --------------------------------------------------------------------- */
744     /*   Property [long] [additive] name                                     */
745     /*   Property [long] [additive] name alias oldname                       */
746     /*   Property [long] [additive] name defaultvalue                        */
747     /*   Property [long] individual name                                     */
748     /* --------------------------------------------------------------------- */
749
750     case PROPERTY_CODE: make_property(); break;           /* See "objects.c" */
751
752     /* --------------------------------------------------------------------- */
753     /*   Release <number>                                                    */
754     /* --------------------------------------------------------------------- */
755
756     case RELEASE_CODE:
757         {   assembly_operand AO;
758             AO = parse_expression(CONSTANT_CONTEXT);
759             if (AO.marker != 0)
760                 error("A definite value must be given as release number");
761             else
762                 release_number = AO.value;
763         }
764         break;
765
766     /* --------------------------------------------------------------------- */
767     /*   Replace routine [routinename]                                       */
768     /* --------------------------------------------------------------------- */
769
770     case REPLACE_CODE:
771         /* You can also replace system functions normally implemented in     */
772         /* the "hardware" of the Z-machine, like "random()":                 */
773
774         system_functions.enabled = TRUE;
775         directives.enabled = FALSE;
776         directive_keywords.enabled = FALSE;
777
778         /* Don't count the upcoming symbol as a top-level reference
779            *to* the function. */
780         df_dont_note_global_symbols = TRUE;
781         get_next_token();
782         df_dont_note_global_symbols = FALSE;
783         if (token_type == SYSFUN_TT)
784         {   if (system_function_usage[token_value] == 1)
785                 error("You can't 'Replace' a system function already used");
786             else system_function_usage[token_value] = 2;
787             get_next_token();
788             if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
789             {
790                 error("You can't give a 'Replace'd system function a new name");
791                 panic_mode_error_recovery(); return FALSE;
792             }
793             return FALSE;
794         }
795
796         if (token_type != SYMBOL_TT)
797             return ebf_error_recover("name of routine to replace");
798         if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
799             return ebf_error_recover("name of routine not yet defined");
800
801         symbols[token_value].flags |= REPLACE_SFLAG;
802
803         /* If a second symbol is provided, it will refer to the
804            original (replaced) definition of the routine. */
805         i = token_value;
806
807         system_functions.enabled = FALSE;
808         df_dont_note_global_symbols = TRUE;
809         get_next_token();
810         df_dont_note_global_symbols = FALSE;
811         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
812         {   return FALSE;
813         }
814
815         if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG))
816             return ebf_error_recover("semicolon ';' or new routine name");
817
818         /* Define the original-form symbol as a zero constant. Its
819            value will be overwritten later, when we define the
820            replacement. */
821         assign_symbol(token_value, 0, CONSTANT_T);
822         add_symbol_replacement_mapping(i, token_value);
823
824         break;
825
826     /* --------------------------------------------------------------------- */
827     /*   Serial "yymmdd"                                                     */
828     /* --------------------------------------------------------------------- */
829
830     case SERIAL_CODE:
831         get_next_token();
832         if ((token_type != DQ_TT) || (strlen(token_text)!=6))
833         {   error("The serial number must be a 6-digit date in double-quotes");
834             panic_mode_error_recovery(); return FALSE;
835         }
836         for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
837         {   error("The serial number must be a 6-digit date in double-quotes");
838             panic_mode_error_recovery(); return FALSE;
839         }
840         strcpy(serial_code_buffer, token_text);
841         serial_code_given_in_program = TRUE;
842         break;
843
844     /* --------------------------------------------------------------------- */
845     /*   Statusline score/time                                               */
846     /* --------------------------------------------------------------------- */
847
848     case STATUSLINE_CODE:
849         directive_keywords.enabled = TRUE;
850         get_next_token();
851         directive_keywords.enabled = FALSE;
852         if ((token_type != DIR_KEYWORD_TT)
853             || ((token_value != SCORE_DK) && (token_value != TIME_DK)))
854             return ebf_error_recover("'score' or 'time' after 'statusline'");
855         if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
856         else statusline_flag = TIME_STYLE;
857         break;
858
859     /* --------------------------------------------------------------------- */
860     /*   Stub routinename number-of-locals                                   */
861     /* --------------------------------------------------------------------- */
862
863     case STUB_CODE:
864         /* The upcoming symbol is a definition; don't count it as a
865            top-level reference *to* the stub function. */
866         df_dont_note_global_symbols = TRUE;
867         get_next_token();
868         df_dont_note_global_symbols = FALSE;
869         if (token_type != SYMBOL_TT)
870             return ebf_error_recover("routine name to stub");
871
872         i = token_value; flag = FALSE;
873
874         if (symbols[i].flags & UNKNOWN_SFLAG)
875         {   symbols[i].flags |= STUB_SFLAG;
876             flag = TRUE;
877         }
878
879         get_next_token(); k = token_value;
880         if (token_type != NUMBER_TT)
881             return ebf_error_recover("number of local variables");
882         if ((k>4) || (k<0))
883         {   error("Must specify 0 to 4 local variables for 'Stub' routine");
884             k = 0;
885         }
886
887         if (flag)
888         {
889             /*  Give these parameter-receiving local variables names
890                 for the benefit of the debugging information file,
891                 and for assembly tracing to look sensible.
892                 (We don't set local_variable.keywords because we're not
893                 going to be parsing any code.)                               */
894
895             clear_local_variables();
896             if (k >= 1) add_local_variable("dummy1");
897             if (k >= 2) add_local_variable("dummy2");
898             if (k >= 3) add_local_variable("dummy3");
899             if (k >= 4) add_local_variable("dummy4");
900
901             assign_symbol(i,
902                 assemble_routine_header(FALSE, symbols[i].name, FALSE, i),
903                 ROUTINE_T);
904
905             /*  Ensure the return value of a stubbed routine is false,
906                 since this is necessary to make the library work properly    */
907
908             if (!glulx_mode)
909                 assemblez_0(rfalse_zc);
910             else
911                 assembleg_1(return_gc, zero_operand);
912
913             /*  Inhibit "local variable unused" warnings  */
914
915             for (i=1; i<=k; i++) variables[i].usage = 1;
916             sequence_point_follows = FALSE;
917             assemble_routine_end(FALSE, get_token_locations());
918         }
919         break;
920
921     /* --------------------------------------------------------------------- */
922     /*   Switches switchblock                                                */
923     /* (this directive is ignored if the -i switch was set at command line)  */
924     /* --------------------------------------------------------------------- */
925
926     case SWITCHES_CODE:
927         dont_enter_into_symbol_table = TRUE;
928         get_next_token();
929         dont_enter_into_symbol_table = FALSE;
930         if (token_type != UQ_TT)
931             return ebf_error_recover("string of switches");
932         if (!ignore_switches_switch)
933         {
934             if (constant_made_yet) {
935                 error("A 'Switches' directive must must come before the first constant definition");
936                 break;
937             }
938             if (no_routines > 1)
939             {
940                 /* The built-in Main__ routine is number zero. */
941                 error("A 'Switches' directive must come before the first routine definition.");
942                 break;
943             }
944             obsolete_warning("the Switches directive is deprecated and may produce incorrect results. Use command-line arguments or header comments.");
945             switches(token_text, 0);                       /* see "inform.c" */
946         }
947         break;
948
949     /* --------------------------------------------------------------------- */
950     /*   System_file                                                         */
951     /*                                                                       */
952     /* Some files are declared as "system files": this information is used   */
953     /* by Inform only to skip the definition of a routine X if the designer  */
954     /* has indicated his intention to Replace X.                             */
955     /* --------------------------------------------------------------------- */
956
957     case SYSTEM_CODE:
958         declare_systemfile(); break;                        /* see "files.c" */
959
960     /* --------------------------------------------------------------------- */
961     /*   Trace dictionary   [on/NUM]                                         */
962     /*         objects      [on/NUM]                                         */
963     /*         symbols      [on/NUM]                                         */
964     /*         verbs        [on/NUM]                                         */
965     /*                      [on/off/NUM]      {same as "assembly"}           */
966     /*         assembly     [on/off/NUM]                                     */
967     /*         expressions  [on/off/NUM]                                     */
968     /*         lines        [on/off/NUM]      {not supported}                */
969     /*         tokens       [on/off/NUM]                                     */
970     /*         linker       [on/off/NUM]      {not supported}                */
971     /*                                                                       */
972     /* The first four trace commands immediately display a compiler table.   */
973     /* The rest set or clear an ongoing trace.                               */
974     /* --------------------------------------------------------------------- */
975
976     case TRACE_CODE:
977         directives.enabled = FALSE;
978         trace_keywords.enabled = TRUE;
979         get_next_token();
980         trace_keywords.enabled = FALSE;
981         directives.enabled = TRUE;
982         
983         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
984             /* "Trace;" */
985             put_token_back();
986             i = ASSEMBLY_TK;
987             trace_level = &asm_trace_level;
988             j = 1;
989             goto HandleTraceKeyword;
990         }
991         if (token_type == NUMBER_TT) {
992             /* "Trace NUM;" */
993             i = ASSEMBLY_TK;
994             trace_level = &asm_trace_level;
995             j = token_value;
996             goto HandleTraceKeyword;
997         }
998
999         /* Anything else must be "Trace KEYWORD..." Remember that
1000            'on' and 'off' are trace keywords. */
1001         
1002         if (token_type != TRACE_KEYWORD_TT)
1003             return ebf_error_recover("debugging keyword");
1004
1005         trace_keywords.enabled = TRUE;
1006
1007         /* Note that "Trace verbs" doesn't affect list_verbs_setting.
1008            It shows the grammar at this point in the code. Setting
1009            list_verbs_setting shows the grammar at the end of 
1010            compilation.
1011            Same goes for "Trace dictionary" and list_dict_setting, etc. */
1012         
1013         i = token_value;
1014
1015         switch(i)
1016         {
1017         case ASSEMBLY_TK:
1018             trace_level = &asm_trace_level;  break;
1019         case EXPRESSIONS_TK:
1020             trace_level = &expr_trace_level; break;
1021         case TOKENS_TK:
1022             trace_level = &tokens_trace_level; break;
1023         case DICTIONARY_TK:
1024         case SYMBOLS_TK:
1025         case OBJECTS_TK:
1026         case VERBS_TK:
1027             /* show a table rather than changing any trace level */
1028             trace_level = NULL; break;
1029         case LINES_TK:
1030             /* never implememented */
1031             trace_level = NULL; break;
1032         case LINKER_TK:
1033             /* no longer implememented */
1034             trace_level = NULL; break;
1035         default:
1036             /* default to "Trace assembly" */
1037             put_token_back();
1038             trace_level = &asm_trace_level; break;
1039         }
1040         
1041         j = 1;
1042         get_next_token();
1043         if ((token_type == SEP_TT) &&
1044             (token_value == SEMICOLON_SEP))
1045         {   put_token_back();
1046         }
1047         else if (token_type == NUMBER_TT)
1048         {   j = token_value;
1049         }
1050         else if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
1051         {   j = 1;
1052         }
1053         else if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
1054         {   j = 0;
1055         }
1056         else
1057         {   put_token_back();
1058         }
1059
1060         trace_keywords.enabled = FALSE;
1061
1062         HandleTraceKeyword:
1063
1064         if (i == LINES_TK || i == LINKER_TK) {
1065             warning_named("Trace option is not supported:", trace_keywords.keywords[i]);
1066             break;
1067         }
1068         
1069         if (trace_level == NULL && j == 0) {
1070             warning_named("Trace directive to display table at 'off' level has no effect: table", trace_keywords.keywords[i]);
1071             break;
1072         }
1073         
1074         switch(i)
1075         {   case DICTIONARY_TK: show_dictionary(j);  break;
1076             case OBJECTS_TK:    list_object_tree();  break;
1077             case SYMBOLS_TK:    list_symbols(j);     break;
1078             case VERBS_TK:      list_verb_table();   break;
1079             default:
1080                 if (trace_level)
1081                     *trace_level = j;
1082                 break;
1083         }
1084         break;
1085
1086     /* --------------------------------------------------------------------- */
1087     /*   Undef symbol                                                        */
1088     /* --------------------------------------------------------------------- */
1089
1090     case UNDEF_CODE:
1091         get_next_token();
1092         if (token_type != SYMBOL_TT)
1093             return ebf_error_recover("symbol name");
1094
1095         if (symbols[token_value].flags & UNKNOWN_SFLAG)
1096         {   break; /* undef'ing an undefined constant is okay */
1097         }
1098
1099         if (symbols[token_value].type != CONSTANT_T)
1100         {   error_named("Cannot Undef a symbol which is not a defined constant:", symbols[token_value].name);
1101             break;
1102         }
1103
1104         if (debugfile_switch)
1105         {   write_debug_undef(token_value);
1106         }
1107         /* We remove it from the symbol table. But previous uses of the symbol
1108            were valid, so we don't set neverused true. We also mark it
1109            USED so that it can't trigger "symbol not used" warnings. */
1110         end_symbol_scope(token_value, FALSE);
1111         symbols[token_value].flags |= USED_SFLAG;
1112         break;
1113
1114     /* --------------------------------------------------------------------- */
1115     /*   Verb ...                                                            */
1116     /* --------------------------------------------------------------------- */
1117
1118     case VERB_CODE: make_verb(); return FALSE;             /* see "tables.c" */
1119
1120     /* --------------------------------------------------------------------- */
1121     /*   Version <number>                                                    */
1122     /* --------------------------------------------------------------------- */
1123
1124     case VERSION_CODE:
1125
1126         {   assembly_operand AO;
1127             AO = parse_expression(CONSTANT_CONTEXT);
1128             /* If a version has already been set on the command line,
1129                that overrides this. */
1130             if (version_set_switch)
1131             {
1132               warning("The Version directive was overridden by a command-line argument.");
1133               break;
1134             }
1135
1136             if (AO.marker != 0)
1137             {
1138               error("A definite value must be given as version number.");
1139               break;
1140             }
1141             else if (no_routines > 1)
1142             {
1143               /* The built-in Main__ routine is number zero. */
1144               error("A 'Version' directive must come before the first routine definition.");
1145               break;
1146             }
1147             else if (glulx_mode) 
1148             {
1149               warning("The Version directive does not work in Glulx. Use \
1150 -vX.Y.Z instead, as either a command-line argument or a header comment.");
1151               break;
1152             }
1153             else
1154             {
1155                 int debtok;
1156                 i = AO.value;
1157                 if ((i<3) || (i>8))
1158                 {   error("The version number must be in the range 3 to 8");
1159                     break;
1160                 }
1161                 obsolete_warning("the Version directive is deprecated and may produce incorrect results. Use -vN instead, as either a command-line argument or a header comment.");
1162                 select_version(i);
1163                 /* We must now do a small dance to reset the DICT_ENTRY_BYTES
1164                    constant, which was defined at startup based on the Z-code
1165                    version.
1166                    The calculation here is repeated from select_target(). */
1167                 DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0);
1168                 debtok = get_symbol_index("DICT_ENTRY_BYTES");
1169                 if (debtok >= 0 && !(symbols[debtok].flags & UNKNOWN_SFLAG))
1170                 {
1171                     if (!(symbols[debtok].flags & REDEFINABLE_SFLAG))
1172                     {
1173                         warning("The DICT_ENTRY_BYTES symbol is not marked redefinable");
1174                     }
1175                     /* Redefine the symbol... */
1176                     assign_symbol(debtok, DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
1177                 }
1178             }
1179         }
1180         break;                                             /* see "inform.c" */
1181
1182     /* --------------------------------------------------------------------- */
1183     /*   Zcharacter table <num> ...                                          */
1184     /*   Zcharacter table + <num> ...                                        */
1185     /*   Zcharacter <string> <string> <string>                               */
1186     /*   Zcharacter <char>                                                   */
1187     /* --------------------------------------------------------------------- */
1188
1189     case ZCHARACTER_CODE:
1190
1191         if (glulx_mode) {
1192             error("The Zcharacter directive has no meaning in Glulx.");
1193             panic_mode_error_recovery(); return FALSE;
1194         }
1195
1196         directive_keywords.enabled = TRUE;
1197         get_next_token();
1198         directive_keywords.enabled = FALSE;
1199
1200         switch(token_type)
1201         {   case DQ_TT:
1202                 new_alphabet(token_text, 0);
1203                 get_next_token();
1204                 if (token_type != DQ_TT)
1205                     return ebf_error_recover("double-quoted alphabet string");
1206                 new_alphabet(token_text, 1);
1207                 get_next_token();
1208                 if (token_type != DQ_TT)
1209                     return ebf_error_recover("double-quoted alphabet string");
1210                 new_alphabet(token_text, 2);
1211             break;
1212
1213             case SQ_TT:
1214                 map_new_zchar(text_to_unicode(token_text));
1215                 if (token_text[textual_form_length] != 0)
1216                     return ebf_error_recover("single character value");
1217             break;
1218
1219             case DIR_KEYWORD_TT:
1220             switch(token_value)
1221             {   case TABLE_DK:
1222                 {   int plus_flag = FALSE;
1223                     get_next_token();
1224                     if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
1225                     {   plus_flag = TRUE;
1226                         get_next_token();
1227                     }
1228                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1229                     {   switch(token_type)
1230                         {   case NUMBER_TT:
1231                                 new_zscii_character(token_value, plus_flag);
1232                                 plus_flag = TRUE; break;
1233                             case SQ_TT:
1234                                 new_zscii_character(text_to_unicode(token_text),
1235                                     plus_flag);
1236                                 if (token_text[textual_form_length] != 0)
1237                                     return ebf_error_recover("single character value");
1238                                 plus_flag = TRUE;
1239                                 break;
1240                             default:
1241                                 return ebf_error_recover("character or Unicode number");
1242                         }
1243                         get_next_token();
1244                     }
1245                     if (plus_flag) new_zscii_finished();
1246                     put_token_back();
1247                 }
1248                     break;
1249                 case TERMINATING_DK:
1250                     get_next_token();
1251                     while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
1252                     {   switch(token_type)
1253                         {   case NUMBER_TT:
1254                                 terminating_characters[no_termcs++]
1255                                     = token_value;
1256                                 break;
1257                             default:
1258                                 return ebf_error_recover("ZSCII number");
1259                         }
1260                         get_next_token();
1261                     }
1262                     put_token_back();
1263                     break;
1264                 default:
1265                     return ebf_error_recover("'table', 'terminating', \
1266 a string or a constant");
1267             }
1268                 break;
1269             default:
1270                 return ebf_error_recover("three alphabet strings, \
1271 a 'table' or 'terminating' command or a single character");
1272         }
1273         break;
1274
1275     /* ===================================================================== */
1276
1277     }
1278
1279     /* We are now at the end of a syntactically valid directive. It
1280        should be terminated by a semicolon. */
1281
1282     get_next_token();
1283     if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1284     {   ebf_curtoken_error("';'");
1285         /* Put the non-semicolon back. We will continue parsing from
1286            that point, in hope that it's the start of a new directive.
1287            (This recovers cleanly from a missing semicolon at the end
1288            of a directive. It's not so clean if the directive *does*
1289            end with a semicolon, but there's extra garbage before it.) */
1290         put_token_back();
1291     }
1292     return FALSE;
1293 }
1294
1295 /* ========================================================================= */
1296 /*   Data structure management routines                                      */
1297 /* ------------------------------------------------------------------------- */
1298
1299 extern void init_directs_vars(void)
1300 {
1301 }
1302
1303 extern void directs_begin_pass(void)
1304 {   no_routines = 0;
1305     no_named_routines = 0;
1306     no_termcs = 0;
1307     constant_made_yet = FALSE;
1308     ifdef_sp = 0;
1309 }
1310
1311 extern void directs_allocate_arrays(void)
1312 {
1313 }
1314
1315 extern void directs_free_arrays(void)
1316 {
1317 }
1318
1319 /* ========================================================================= */