1
/* ------------------------------------------------------------------------- */
2
/* "directs" : Directives (# commands) */
4
/* Part of Inform 6.30 */
5
/* copyright (c) Graham Nelson 1993 - 2004 */
7
/* ------------------------------------------------------------------------- */
11
int no_routines, /* Number of routines compiled so far */
12
no_named_routines, /* Number not embedded in objects */
13
no_locals, /* Number of locals in current routine */
14
no_termcs; /* Number of terminating characters */
15
int terminating_characters[32];
17
int32 routine_starts_line; /* Source code line on which the current
18
routine starts. (Useful for reporting
19
"unused variable" warnings on the start
20
line rather than the end line.) */
22
static int constant_made_yet; /* Have any constants been defined yet? */
24
static int ifdef_stack[32], ifdef_sp;
26
/* ------------------------------------------------------------------------- */
28
extern int parse_given_directive(void)
29
{ int *trace_level; int32 i, j, k, n, flag;
34
/* --------------------------------------------------------------------- */
35
/* Abbreviate "string1" ["string2" ...] */
36
/* --------------------------------------------------------------------- */
42
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
45
/* Glulx doesn't have a 64-abbrev limit */
46
if (!glulx_mode && MAX_ABBREVS==64)
47
{ if (no_abbreviations==64)
48
error("All 64 abbreviations already declared");
51
{ if (no_abbreviations==MAX_ABBREVS)
52
memoryerror("MAX_ABBREVS", MAX_ABBREVS);
55
if (abbrevs_lookup_table_made)
56
{ error("All abbreviations must be declared together");
59
if (token_type != DQ_TT)
60
ebf_error("abbreviation string", token_text);
62
if (strlen(token_text)<2)
63
{ error_named("It's not worth abbreviating", token_text);
66
make_abbreviation(token_text);
69
/* --------------------------------------------------------------------- */
70
/* Array arrayname array... */
71
/* --------------------------------------------------------------------- */
73
case ARRAY_CODE: make_global(TRUE, FALSE); break; /* See "tables.c" */
75
/* --------------------------------------------------------------------- */
76
/* Attribute newname [alias oldname] */
77
/* --------------------------------------------------------------------- */
80
make_attribute(); break; /* See "objects.c" */
82
/* --------------------------------------------------------------------- */
83
/* Class classname ... */
84
/* --------------------------------------------------------------------- */
86
case CLASS_CODE: make_class(NULL); return FALSE; /* See "tables.c" */
88
/* --------------------------------------------------------------------- */
89
/* Constant newname [[=] value] [, ...] */
90
/* --------------------------------------------------------------------- */
93
constant_made_yet=TRUE;
96
get_next_token(); i = token_value;
98
if ((token_type != SYMBOL_TT)
99
|| (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))))
100
{ ebf_error("new constant name", token_text);
101
panic_mode_error_recovery(); break;
104
assign_symbol(i, 0, CONSTANT_T);
108
if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
109
goto ParseConstantSpec;
111
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
114
if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
117
{ assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
119
{ assign_marked_symbol(i, AO.marker, AO.value,
121
sflags[i] |= CHANGE_SFLAG;
122
if (i == grammar_version_symbol)
124
"Grammar__Version must be given an explicit constant value");
127
{ assign_symbol(i, AO.value, CONSTANT_T);
128
if (i == grammar_version_symbol)
129
{ if ((grammar_version_number != AO.value)
130
&& (no_fake_actions > 0))
132
"Once a fake action has been defined it is too late to \
133
change the grammar version. (If you are using the library, move any \
134
Fake_Action directives to a point after the inclusion of \"Parser\".)");
135
grammar_version_number = AO.value;
140
if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
141
goto ParseConstantSpec;
145
/* --------------------------------------------------------------------- */
146
/* Default constantname integer */
147
/* --------------------------------------------------------------------- */
151
{ error("'Default' cannot be used in -M (Module) mode");
156
if (token_type != SYMBOL_TT)
157
{ ebf_error("name", token_text);
158
panic_mode_error_recovery(); break;
162
if (sflags[token_value] & UNKNOWN_SFLAG)
164
sflags[i] |= DEFCON_SFLAG;
168
if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
171
{ assembly_operand AO;
172
AO = parse_expression(CONSTANT_CONTEXT);
174
{ if (AO.marker != 0)
175
{ assign_marked_symbol(i, AO.marker, AO.value,
177
sflags[i] |= CHANGE_SFLAG;
179
else assign_symbol(i, AO.value, CONSTANT_T);
185
/* --------------------------------------------------------------------- */
186
/* Dictionary constantname "word" */
187
/* --------------------------------------------------------------------- */
189
case DICTIONARY_CODE:
190
obsolete_warning("use 'word' as a constant dictionary address");
191
goto ParseConstantSpec;
193
/* --------------------------------------------------------------------- */
195
/* --------------------------------------------------------------------- */
197
case END_CODE: return(TRUE);
200
if (ifdef_sp == 0) error("'Endif' without matching 'If...'");
204
/* --------------------------------------------------------------------- */
206
/* --------------------------------------------------------------------- */
208
case EXTEND_CODE: extend_verb(); return FALSE; /* see "tables.c" */
210
/* --------------------------------------------------------------------- */
211
/* Fake_Action name */
212
/* --------------------------------------------------------------------- */
214
case FAKE_ACTION_CODE:
215
make_fake_action(); break; /* see "tables.c" */
217
/* --------------------------------------------------------------------- */
218
/* Global variable [= value / array...] */
219
/* --------------------------------------------------------------------- */
221
case GLOBAL_CODE: make_global(FALSE, FALSE); break; /* See "tables.c" */
223
/* --------------------------------------------------------------------- */
226
/* Note that each time Inform tests an If... condition, it stacks the */
227
/* result (TRUE or FALSE) on ifdef_stack: thus, the top of this stack */
228
/* reveals what clause of the current If... is being compiled: */
230
/* If...; ... Ifnot; ... Endif; */
231
/* top of stack: TRUE FALSE */
233
/* This is used to detect "two Ifnots in same If" errors. */
234
/* --------------------------------------------------------------------- */
244
if (token_type != SYMBOL_TT)
245
{ ebf_error("symbol name", token_text);
249
if ((token_text[0] == 'V')
250
&& (token_text[1] == 'N')
251
&& (token_text[2] == '_')
252
&& (strlen(token_text)==7))
253
{ i = atoi(token_text+3);
254
if (VNUMBER < i) flag = (flag)?FALSE:TRUE;
255
goto HashIfCondition;
258
if (sflags[token_value] & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE;
259
else sflags[token_value] |= USED_SFLAG;
260
goto HashIfCondition;
264
error("'Ifnot' without matching 'If...'");
266
if (!(ifdef_stack[ifdef_sp-1]))
267
error("Second 'Ifnot' for the same 'If...' condition");
269
{ dont_enter_into_symbol_table = -2; n = 1;
270
directives.enabled = TRUE;
273
if (token_type == EOF_TT)
274
{ error("End of file reached in code 'If...'d out");
275
directives.enabled = FALSE;
278
if (token_type == DIRECTIVE_TT)
279
{ switch(token_value)
292
"Second 'Ifnot' for the same 'If...' condition");
299
dont_enter_into_symbol_table = FALSE;
300
directives.enabled = FALSE;
305
flag = FALSE; if (version_number == 3) flag = TRUE;
306
goto HashIfCondition;
309
flag = TRUE; if (version_number == 3) flag = FALSE;
310
goto HashIfCondition;
313
{ assembly_operand AO;
314
AO = parse_expression(CONSTANT_CONTEXT);
315
if (module_switch && (AO.marker != 0))
316
{ error("This condition can't be determined");
319
else flag = (AO.value != 0);
321
goto HashIfCondition;
324
{ assembly_operand AO;
325
AO = parse_expression(CONSTANT_CONTEXT);
326
if (module_switch && (AO.marker != 0))
327
{ error("This condition can't be determined");
330
else flag = (AO.value == 0);
332
goto HashIfCondition;
336
if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
337
{ ebf_error("semicolon after 'If...' condition", token_text);
342
{ ifdef_stack[ifdef_sp++] = TRUE; return FALSE; }
344
{ dont_enter_into_symbol_table = -2; n = 1;
345
directives.enabled = TRUE;
348
if (token_type == EOF_TT)
349
{ error("End of file reached in code 'If...'d out");
350
directives.enabled = FALSE;
353
if (token_type == DIRECTIVE_TT)
367
{ ifdef_stack[ifdef_sp++] = FALSE;
373
directives.enabled = FALSE;
374
dont_enter_into_symbol_table = FALSE;
378
/* --------------------------------------------------------------------- */
379
/* Import global <varname> [, ...] */
381
/* (Further imported goods may be allowed later.) */
382
/* --------------------------------------------------------------------- */
386
{ error("'Import' can only be used in -M (Module) mode");
389
directives.enabled = TRUE;
392
if ((token_type == DIRECTIVE_TT) && (token_value == GLOBAL_CODE))
393
make_global(FALSE, TRUE);
394
else error_named("'Import' cannot import things of this type:",
397
} while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
399
directives.enabled = FALSE;
402
/* --------------------------------------------------------------------- */
403
/* Include "[>]filename" */
404
/* --------------------------------------------------------------------- */
408
if (token_type != DQ_TT)
409
{ ebf_error("filename in double-quotes", token_text);
410
panic_mode_error_recovery(); return FALSE;
413
{ char *name = token_text;
416
if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
417
ebf_error("semicolon ';' after Include filename", token_text);
419
if (strcmp(name, "language__") == 0)
420
load_sourcefile(Language_Name, 0);
421
else if (name[0] == '>')
422
load_sourcefile(name+1, 1);
423
else load_sourcefile(name, 0);
427
/* --------------------------------------------------------------------- */
428
/* Link "filename" */
429
/* --------------------------------------------------------------------- */
433
if (token_type != DQ_TT)
434
{ ebf_error("filename in double-quotes", token_text);
435
panic_mode_error_recovery(); return FALSE;
437
link_module(token_text); /* See "linker.c" */
440
/* --------------------------------------------------------------------- */
441
/* Lowstring constantname "text of string" */
442
/* --------------------------------------------------------------------- */
443
/* Unlike most constant creations, these do not require backpatching: */
444
/* the low strings always occupy a table at a fixed offset in the */
445
/* Z-machine (after the abbreviations table has finished, at 0x100). */
446
/* --------------------------------------------------------------------- */
450
{ error("'LowString' cannot be used in -M (Module) mode"); break;
452
get_next_token(); i = token_value;
453
if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
454
{ ebf_error("new low string name", token_text);
455
panic_mode_error_recovery(); return FALSE;
459
if (token_type != DQ_TT)
460
{ ebf_error("literal string in double-quotes", token_text);
461
panic_mode_error_recovery(); return FALSE;
464
assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T);
467
/* --------------------------------------------------------------------- */
468
/* Message | "information" */
469
/* | error "error message" */
470
/* | fatalerror "fatal error message" */
471
/* | warning "warning message" */
472
/* --------------------------------------------------------------------- */
475
directive_keywords.enabled = TRUE;
477
directive_keywords.enabled = FALSE;
478
if (token_type == DQ_TT)
480
if (hash_printed_since_newline) printf("\n");
481
for (i=0; token_text[i]!=0; i++)
482
{ if (token_text[i] == '^') printf("\n");
484
if (token_text[i] == '~') printf("\"");
485
else printf("%c", token_text[i]);
490
if ((token_type == DIR_KEYWORD_TT) && (token_value == ERROR_DK))
492
if (token_type != DQ_TT)
493
{ ebf_error("error message in double-quotes", token_text);
495
error(token_text); break;
497
if ((token_type == DIR_KEYWORD_TT) && (token_value == FATALERROR_DK))
499
if (token_type != DQ_TT)
500
{ ebf_error("fatal error message in double-quotes", token_text);
502
fatalerror(token_text); break;
504
if ((token_type == DIR_KEYWORD_TT) && (token_value == WARNING_DK))
506
if (token_type != DQ_TT)
507
{ ebf_error("warning message in double-quotes", token_text);
509
warning(token_text); break;
511
ebf_error("a message in double-quotes, 'error', 'fatalerror' or 'warning'",
515
/* --------------------------------------------------------------------- */
516
/* Nearby objname "short name" ... */
517
/* --------------------------------------------------------------------- */
519
case NEARBY_CODE: make_object(TRUE, NULL, -1, -1, -1);
520
return FALSE; /* See "objects.c" */
522
/* --------------------------------------------------------------------- */
523
/* Object objname "short name" ... */
524
/* --------------------------------------------------------------------- */
526
case OBJECT_CODE: make_object(FALSE, NULL, -1, -1, -1);
527
return FALSE; /* See "objects.c" */
529
/* --------------------------------------------------------------------- */
530
/* Property [long] [additive] name [alias oldname] */
531
/* --------------------------------------------------------------------- */
533
case PROPERTY_CODE: make_property(); break; /* See "objects.c" */
535
/* --------------------------------------------------------------------- */
536
/* Release <number> */
537
/* --------------------------------------------------------------------- */
540
{ assembly_operand AO;
541
AO = parse_expression(CONSTANT_CONTEXT);
542
if (module_switch && (AO.marker != 0))
543
error("A definite value must be given as release number");
545
release_number = AO.value;
549
/* --------------------------------------------------------------------- */
550
/* Replace routine */
551
/* --------------------------------------------------------------------- */
554
/* You can also replace system functions normally implemented in */
555
/* the "hardware" of the Z-machine, like "random()": */
557
system_functions.enabled = TRUE;
558
directives.enabled = FALSE;
559
directive_keywords.enabled = FALSE;
562
if (token_type == SYSFUN_TT)
563
{ if (system_function_usage[token_value] == 1)
564
error("You can't 'Replace' a system function already used");
565
else system_function_usage[token_value] = 2;
569
if (token_type != SYMBOL_TT)
570
{ ebf_error("name of routine to replace", token_text);
574
if (!(sflags[token_value] & UNKNOWN_SFLAG))
575
{ ebf_error("name of routine not yet defined", token_text);
578
sflags[token_value] |= REPLACE_SFLAG;
582
/* --------------------------------------------------------------------- */
583
/* Serial "yymmdd" */
584
/* --------------------------------------------------------------------- */
588
if ((token_type != DQ_TT) || (strlen(token_text)!=6))
589
{ error("The serial number must be a 6-digit date in double-quotes");
592
for (i=0; i<6; i++) if (isdigit(token_text[i])==0)
593
{ error("The serial number must be a 6-digit date in double-quotes");
596
strcpy(serial_code_buffer, token_text);
597
serial_code_given_in_program = TRUE;
600
/* --------------------------------------------------------------------- */
601
/* Statusline score/time */
602
/* --------------------------------------------------------------------- */
604
case STATUSLINE_CODE:
606
warning("This does not set the final game's statusline");
608
directive_keywords.enabled = TRUE;
610
directive_keywords.enabled = FALSE;
611
if ((token_type != DIR_KEYWORD_TT)
612
|| ((token_value != SCORE_DK) && (token_value != TIME_DK)))
613
{ ebf_error("'score' or 'time' after 'statusline'", token_text);
616
if (token_value == SCORE_DK) statusline_flag = SCORE_STYLE;
617
else statusline_flag = TIME_STYLE;
620
/* --------------------------------------------------------------------- */
621
/* Stub routinename number-of-locals */
622
/* --------------------------------------------------------------------- */
627
if (token_type != SYMBOL_TT)
628
{ ebf_error("routine name to stub", token_text);
629
panic_mode_error_recovery(); return FALSE;
632
i = token_value; flag = FALSE;
634
if (sflags[i] & UNKNOWN_SFLAG)
635
{ sflags[i] |= STUB_SFLAG;
639
get_next_token(); k = token_value;
640
if (token_type != NUMBER_TT)
641
{ ebf_error("number of local variables", token_text);
645
{ error("Must specify 0 to 4 local variables for 'Stub' routine");
651
/* Give these parameter-receiving local variables names
652
for the benefit of the debugging information file,
653
and for assembly tracing to look sensible. */
655
local_variable_texts[0] = "dummy1";
656
local_variable_texts[1] = "dummy2";
657
local_variable_texts[2] = "dummy3";
658
local_variable_texts[3] = "dummy4";
661
assemble_routine_header(k, FALSE, (char *) symbs[i],
662
&token_line_ref, FALSE, i),
665
/* Ensure the return value of a stubbed routine is false,
666
since this is necessary to make the library work properly */
669
assemblez_0(rfalse_zc);
671
assembleg_1(return_gc, zero_operand);
673
/* Inhibit "local variable unused" warnings */
675
for (i=1; i<=k; i++) variable_usage[i] = 1;
676
sequence_point_follows = FALSE;
677
assemble_routine_end(FALSE, &token_line_ref);
681
/* --------------------------------------------------------------------- */
682
/* Switches switchblock */
683
/* (this directive is ignored if the -i switch was set at command line) */
684
/* --------------------------------------------------------------------- */
687
dont_enter_into_symbol_table = TRUE;
689
dont_enter_into_symbol_table = FALSE;
690
if (token_type != DQ_TT)
691
{ ebf_error("string of switches", token_text);
694
if (!ignore_switches_switch)
695
{ if (constant_made_yet)
696
error("A 'Switches' directive must must come before \
697
the first constant definition");
698
switches(token_text, 0); /* see "inform.c" */
702
/* --------------------------------------------------------------------- */
705
/* Some files are declared as "system files": this information is used */
706
/* by Inform only to skip the definition of a routine X if the designer */
707
/* has indicated his intention to Replace X. */
708
/* --------------------------------------------------------------------- */
711
declare_systemfile(); break; /* see "files.c" */
713
/* --------------------------------------------------------------------- */
714
/* Trace dictionary */
719
/* assembly [on/off] */
720
/* expressions [on/off] */
722
/* --------------------------------------------------------------------- */
725
directives.enabled = FALSE;
726
trace_keywords.enabled = TRUE;
728
trace_keywords.enabled = FALSE;
729
directives.enabled = TRUE;
730
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
731
{ asm_trace_level = 1; return FALSE; }
733
if (token_type != TRACE_KEYWORD_TT)
734
{ ebf_error("debugging keyword", token_text);
735
panic_mode_error_recovery(); return FALSE;
738
trace_keywords.enabled = TRUE;
740
i = token_value; j = 0;
742
{ case DICTIONARY_TK: break;
743
case OBJECTS_TK: break;
744
case VERBS_TK: break;
748
trace_level = &asm_trace_level; break;
750
trace_level = &expr_trace_level; break;
752
trace_level = &line_trace_level; break;
754
trace_level = &tokens_trace_level; break;
756
trace_level = &linker_trace_level; break;
758
trace_level = NULL; break;
761
trace_level = &asm_trace_level; break;
765
if ((token_type == SEP_TT) &&
766
(token_value == SEMICOLON_SEP))
767
{ put_token_back(); break;
769
if (token_type == NUMBER_TT)
770
{ j = token_value; break; }
771
if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK))
773
if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK))
775
put_token_back(); break;
779
{ case DICTIONARY_TK: show_dictionary(); break;
780
case OBJECTS_TK: list_object_tree(); break;
781
case SYMBOLS_TK: list_symbols(j); break;
782
case VERBS_TK: list_verb_table(); break;
787
trace_keywords.enabled = FALSE;
790
/* --------------------------------------------------------------------- */
792
/* --------------------------------------------------------------------- */
794
case VERB_CODE: make_verb(); return FALSE; /* see "tables.c" */
796
/* --------------------------------------------------------------------- */
797
/* Version <number> */
798
/* --------------------------------------------------------------------- */
802
/* Ignore this if a version has already been set on the command line */
803
if (version_set_switch) break;
805
{ assembly_operand AO;
806
AO = parse_expression(CONSTANT_CONTEXT);
807
if (module_switch && (AO.marker != 0))
808
error("A definite value must be given as version number");
812
{ error("The version number must be in the range 3 to 8");
818
break; /* see "inform.c" */
820
/* --------------------------------------------------------------------- */
821
/* Zcharacter table <num> ... */
822
/* Zcharacter table + <num> ... */
823
/* Zcharacter <string> <string> <string> */
824
/* Zcharacter <char> */
825
/* --------------------------------------------------------------------- */
827
case ZCHARACTER_CODE:
830
error("Glulx Inform does not handle Unicode yet.");
834
directive_keywords.enabled = TRUE;
836
directive_keywords.enabled = FALSE;
840
new_alphabet(token_text, 0);
842
if (token_type != DQ_TT)
843
ebf_error("double-quoted alphabet string", token_text);
844
else new_alphabet(token_text, 1);
846
if (token_type != DQ_TT)
847
ebf_error("double-quoted alphabet string", token_text);
848
else new_alphabet(token_text, 2);
852
map_new_zchar(text_to_unicode(token_text));
853
if (token_text[textual_form_length] != 0)
854
ebf_error("single character value", token_text);
860
{ int plus_flag = FALSE;
862
if ((token_type == SEP_TT) && (token_value == PLUS_SEP))
866
while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
869
new_zscii_character(token_value, plus_flag);
870
plus_flag = TRUE; break;
872
new_zscii_character(text_to_unicode(token_text),
874
if (token_text[textual_form_length] != 0)
875
ebf_error("single character value",
880
ebf_error("character or Unicode number",
885
if (plus_flag) new_zscii_finished();
891
while ((token_type!=SEP_TT) || (token_value!=SEMICOLON_SEP))
894
terminating_characters[no_termcs++]
898
ebf_error("ZSCII number", token_text); break;
905
ebf_error("'table', 'terminating', a string or a constant",
910
ebf_error("three alphabet strings, a 'table' or 'terminating' \
911
command or a single character", token_text);
916
/* ===================================================================== */
920
if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
921
{ ebf_error("';'", token_text);
927
/* ========================================================================= */
928
/* Data structure management routines */
929
/* ------------------------------------------------------------------------- */
931
extern void init_directs_vars(void)
935
extern void directs_begin_pass(void)
937
no_named_routines = 0;
940
constant_made_yet = FALSE;
944
extern void directs_allocate_arrays(void)
948
extern void directs_free_arrays(void)
952
/* ========================================================================= */