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