1
/* ------------------------------------------------------------------------- */
2
/* "syntax" : Syntax analyser and compiler */
4
/* Part of Inform 6.31 */
5
/* copyright (c) Graham Nelson 1993 - 2006 */
7
/* ------------------------------------------------------------------------- */
11
static char *lexical_source;
13
int no_syntax_lines; /* Syntax line count */
15
static void begin_syntax_line(int statement_mode)
17
next_token_begins_syntax_line = TRUE;
19
clear_expression_space();
21
{ statements.enabled = TRUE;
22
conditions.enabled = TRUE;
23
local_variables.enabled = TRUE;
24
system_functions.enabled = TRUE;
26
misc_keywords.enabled = FALSE;
27
directive_keywords.enabled = FALSE;
28
directives.enabled = FALSE;
29
segment_markers.enabled = FALSE;
30
opcode_names.enabled = FALSE;
33
{ directives.enabled = TRUE;
34
segment_markers.enabled = TRUE;
36
statements.enabled = FALSE;
37
misc_keywords.enabled = FALSE;
38
directive_keywords.enabled = FALSE;
39
local_variables.enabled = FALSE;
40
system_functions.enabled = FALSE;
41
conditions.enabled = FALSE;
42
opcode_names.enabled = FALSE;
45
sequence_point_follows = TRUE;
49
debug_line_ref = token_line_ref;
54
extern void panic_mode_error_recovery(void)
56
while ((token_type != EOF_TT)
57
&& ((token_type != SEP_TT)||(token_value != SEMICOLON_SEP)))
62
extern void parse_program(char *source)
64
lexical_source = source;
65
while (parse_directive(FALSE)) ;
68
extern int parse_directive(int internal_flag)
70
/* Internal_flag is FALSE if the directive is encountered normally,
71
TRUE if encountered with a # prefix inside a routine.
73
Returns: TRUE if program continues, FALSE if end of file reached. */
77
begin_syntax_line(FALSE);
80
if (token_type == EOF_TT) return(FALSE);
82
if ((token_type == SEP_TT) && (token_value == HASH_SEP))
85
if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
87
{ error("It is illegal to nest routines using '#['");
91
directives.enabled = FALSE;
92
directive_keywords.enabled = FALSE;
93
segment_markers.enabled = FALSE;
96
if ((token_type != SYMBOL_TT)
97
|| ((!(sflags[token_value] & UNKNOWN_SFLAG))
98
&& (!(sflags[token_value] & REPLACE_SFLAG))))
99
{ ebf_error("routine name", token_text);
103
routine_symbol = token_value;
105
if ((sflags[routine_symbol] & REPLACE_SFLAG) && (is_systemfile()))
106
{ dont_enter_into_symbol_table = TRUE;
109
} while (!((token_type == EOF_TT)
110
|| ((token_type==SEP_TT)
111
&& (token_value==CLOSE_SQUARE_SEP))));
112
dont_enter_into_symbol_table = FALSE;
113
if (token_type == EOF_TT) return FALSE;
116
{ assign_symbol(routine_symbol,
117
parse_routine(lexical_source, FALSE,
118
(char *) symbs[routine_symbol], FALSE, routine_symbol),
120
slines[routine_symbol] = routine_starts_line;
123
if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
124
{ ebf_error("';' after ']'", token_text);
130
if ((token_type == SYMBOL_TT) && (stypes[token_value] == CLASS_T))
131
{ sflags[token_value] |= USED_SFLAG;
132
make_object(FALSE, NULL, -1, -1, svals[token_value]);
136
if (token_type != DIRECTIVE_TT)
137
{ ebf_error("directive, '[' or class name", token_text);
138
panic_mode_error_recovery();
142
return !(parse_given_directive());
145
static int switch_sign(void)
147
if ((token_type == SEP_TT)&&(token_value == COLON_SEP)) return 1;
148
if ((token_type == SEP_TT)&&(token_value == COMMA_SEP)) return 2;
149
if ((token_type==MISC_KEYWORD_TT)&&(token_value==TO_MK)) return 3;
153
static assembly_operand spec_stack[32];
154
static int spec_type[32];
156
static void compile_alternatives_z(assembly_operand switch_value, int n,
157
int stack_level, int label, int flag)
160
assemblez_2_branch(je_zc, switch_value,
161
spec_stack[stack_level],
162
label, flag); return;
164
assemblez_3_branch(je_zc, switch_value,
165
spec_stack[stack_level], spec_stack[stack_level+1],
166
label, flag); return;
168
assemblez_4_branch(je_zc, switch_value,
169
spec_stack[stack_level], spec_stack[stack_level+1],
170
spec_stack[stack_level+2],
171
label, flag); return;
175
static void compile_alternatives_g(assembly_operand switch_value, int n,
176
int stack_level, int label, int flag)
178
int the_zc = (flag) ? jeq_gc : jne_gc;
181
assembleg_2_branch(the_zc, switch_value,
182
spec_stack[stack_level],
186
error("*** Cannot generate multi-equality tests in Glulx ***");
190
static void compile_alternatives(assembly_operand switch_value, int n,
191
int stack_level, int label, int flag)
194
compile_alternatives_z(switch_value, n, stack_level, label, flag);
196
compile_alternatives_g(switch_value, n, stack_level, label, flag);
199
static void parse_switch_spec(assembly_operand switch_value, int label,
202
int i, j, label_after = -1, spec_sp = 0;
203
int max_equality_args = ((!glulx_mode) ? 3 : 1);
205
sequence_point_follows = FALSE;
209
{ error("At most 32 values can be given in a single 'switch' case");
210
panic_mode_error_recovery();
216
spec_stack[spec_sp].type =
217
((!glulx_mode) ? LONG_CONSTANT_OT : CONSTANT_OT);
218
spec_stack[spec_sp].value = 0;
219
spec_stack[spec_sp].marker = 0;
220
spec_stack[spec_sp] = action_of_name(token_text);
222
if (spec_stack[spec_sp].value == -1)
223
{ spec_stack[spec_sp].value = 0;
224
ebf_error("action (or fake action) name", token_text);
228
spec_stack[spec_sp] =
229
code_generate(parse_expression(CONSTANT_CONTEXT), CONSTANT_CONTEXT, -1);
231
misc_keywords.enabled = TRUE;
233
misc_keywords.enabled = FALSE;
235
spec_type[spec_sp++] = switch_sign();
236
switch(spec_type[spec_sp-1])
239
ebf_error("',' or ':'", token_text);
240
else ebf_error("',', ':' or 'to'", token_text);
241
panic_mode_error_recovery();
243
case 1: goto GenSpecCode;
244
case 3: if (label_after == -1) label_after = next_label++;
250
if ((spec_sp > max_equality_args) && (label_after == -1))
251
label_after = next_label++;
253
if (label_after == -1)
254
{ compile_alternatives(switch_value, spec_sp, 0, label, FALSE); return;
257
for (i=0; i<spec_sp;)
259
j=i; while ((j<spec_sp) && (spec_type[j] != 3)) j++;
262
{ if (j-i > max_equality_args) j=i+max_equality_args;
265
compile_alternatives(switch_value, j-i, i, label, FALSE);
267
compile_alternatives(switch_value, j-i, i, label_after, TRUE);
274
if (i == spec_sp - 2)
275
{ assemblez_2_branch(jl_zc, switch_value, spec_stack[i],
277
assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1],
281
{ assemblez_2_branch(jl_zc, switch_value, spec_stack[i],
283
assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1],
285
assemble_label_no(next_label++);
289
if (i == spec_sp - 2)
290
{ assembleg_2_branch(jlt_gc, switch_value, spec_stack[i],
292
assembleg_2_branch(jgt_gc, switch_value, spec_stack[i+1],
296
{ assembleg_2_branch(jlt_gc, switch_value, spec_stack[i],
298
assembleg_2_branch(jle_gc, switch_value, spec_stack[i+1],
300
assemble_label_no(next_label++);
307
assemble_label_no(label_after);
310
extern int32 parse_routine(char *source, int embedded_flag, char *name,
311
int veneer_flag, int r_symbol)
312
{ int32 packed_address; int i; int debug_flag = FALSE;
313
int switch_clause_made = FALSE, default_clause_made = FALSE,
315
dbgl start_line_ref = token_line_ref;
317
/* (switch_label needs no initialisation here, but it prevents some
318
compilers from issuing warnings) */
320
if ((source != lexical_source) || (veneer_flag))
321
{ lexical_source = source;
322
restart_lexer(lexical_source, name);
327
for (i=0;i<MAX_LOCAL_VARIABLES-1;i++) local_variables.keywords[i] = "";
330
{ statements.enabled = TRUE;
331
dont_enter_into_symbol_table = TRUE;
333
dont_enter_into_symbol_table = FALSE;
334
if ((token_type == SEP_TT) && (token_value == TIMES_SEP)
335
&& (no_locals == 0) && (!debug_flag))
336
{ debug_flag = TRUE; continue;
339
if (token_type != DQ_TT)
340
{ if ((token_type == SEP_TT)
341
&& (token_value == SEMICOLON_SEP)) break;
342
ebf_error("local variable name or ';'", token_text);
343
panic_mode_error_recovery();
347
if (no_locals == MAX_LOCAL_VARIABLES-1)
348
{ error_numbered("Too many local variables for a routine; max is",
349
MAX_LOCAL_VARIABLES-1);
350
panic_mode_error_recovery();
354
for (i=0;i<no_locals;i++)
355
if (strcmpcis(token_text, local_variables.keywords[i])==0)
356
error_named("Local variable defined twice:", token_text);
357
local_variables.keywords[no_locals++] = token_text;
360
construct_local_variable_tables();
362
if ((trace_fns_setting==3)
363
|| ((trace_fns_setting==2) && (veneer_mode==FALSE))
364
|| ((trace_fns_setting==1) && (is_systemfile()==FALSE)))
366
if ((embedded_flag == FALSE) && (veneer_mode == FALSE) && debug_flag)
367
sflags[r_symbol] |= STAR_SFLAG;
369
packed_address = assemble_routine_header(no_locals, debug_flag,
370
name, &start_line_ref, embedded_flag, r_symbol);
373
{ begin_syntax_line(TRUE);
377
if (token_type == EOF_TT)
378
{ ebf_error("']'", token_text);
380
assemble_routine_end(embedded_flag, &token_line_ref);
384
if ((token_type == SEP_TT)
385
&& (token_value == CLOSE_SQUARE_SEP))
386
{ if (switch_clause_made && (!default_clause_made))
387
assemble_label_no(switch_label);
388
directives.enabled = TRUE;
389
sequence_point_follows = TRUE;
390
assemble_routine_end(embedded_flag, &token_line_ref);
394
if ((token_type == STATEMENT_TT) && (token_value == SDEFAULT_CODE))
395
{ if (default_clause_made)
396
error("Multiple 'default' clauses defined in same 'switch'");
397
default_clause_made = TRUE;
399
if (switch_clause_made)
400
{ if (!execution_never_reaches_here)
401
{ sequence_point_follows = FALSE;
403
assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc);
405
assembleg_1(return_gc,
406
((embedded_flag)?zero_operand:one_operand));
408
assemble_label_no(switch_label);
410
switch_clause_made = TRUE;
413
if ((token_type == SEP_TT) &&
414
(token_value == COLON_SEP)) continue;
415
ebf_error("':' after 'default'", token_text);
416
panic_mode_error_recovery();
420
/* Only check for the form of a case switch if the initial token
421
isn't double-quoted text, as that would mean it was a print_ret
422
statement: this is a mild ambiguity in the grammar.
423
Action statements also cannot be cases. */
425
if ((token_type != DQ_TT) && (token_type != SEP_TT))
427
if (switch_sign() > 0)
428
{ assembly_operand AO;
429
if (default_clause_made)
430
error("'default' must be the last 'switch' case");
432
if (switch_clause_made)
433
{ if (!execution_never_reaches_here)
434
{ sequence_point_follows = FALSE;
436
assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc);
438
assembleg_1(return_gc,
439
((embedded_flag)?zero_operand:one_operand));
441
assemble_label_no(switch_label);
444
switch_label = next_label++;
445
switch_clause_made = TRUE;
446
put_token_back(); put_token_back();
449
AO.type = VARIABLE_OT; AO.value = 249; AO.marker = 0;
452
AO.type = GLOBALVAR_OT;
453
AO.value = MAX_LOCAL_VARIABLES+6; /* sw__var */
456
parse_switch_spec(AO, switch_label, TRUE);
461
{ put_token_back(); put_token_back(); get_next_token();
462
sequence_point_follows = TRUE;
466
parse_statement(-1, -1);
470
return packed_address;
473
extern void parse_code_block(int break_label, int continue_label,
475
{ int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label,
478
begin_syntax_line(TRUE);
481
if (token_type == SEP_TT && token_value == OPEN_BRACE_SEP)
483
{ begin_syntax_line(TRUE);
485
if (token_type == SEP_TT && token_value == CLOSE_BRACE_SEP)
486
{ if (switch_clause_made && (!default_clause_made))
487
assemble_label_no(switch_label);
490
if (token_type == EOF_TT)
491
{ ebf_error("'}'", token_text); return; }
493
if (switch_rule != 0)
495
/* Within a 'switch' block */
497
if ((token_type==STATEMENT_TT)&&(token_value==SDEFAULT_CODE))
498
{ if (default_clause_made)
499
error("Multiple 'default' clauses defined in same 'switch'");
500
default_clause_made = TRUE;
502
if (switch_clause_made)
503
{ if (!execution_never_reaches_here)
504
{ sequence_point_follows = FALSE;
505
assemble_jump(break_label);
507
assemble_label_no(switch_label);
509
switch_clause_made = TRUE;
512
if ((token_type == SEP_TT) &&
513
(token_value == COLON_SEP)) continue;
514
ebf_error("':' after 'default'", token_text);
515
panic_mode_error_recovery();
519
/* Decide: is this an ordinary statement, or the start
522
if (token_type == DQ_TT) goto NotASwitchCase;
525
= ((token_type == SEP_TT)&&(token_value == MINUS_SEP));
526
if (unary_minus_flag) get_next_token();
528
/* Now read the token _after_ any possible constant:
529
if that's a 'to', ',' or ':' then we have a case */
531
misc_keywords.enabled = TRUE;
533
misc_keywords.enabled = FALSE;
535
if (switch_sign() > 0)
536
{ assembly_operand AO;
538
if (default_clause_made)
539
error("'default' must be the last 'switch' case");
541
if (switch_clause_made)
542
{ if (!execution_never_reaches_here)
543
{ sequence_point_follows = FALSE;
544
assemble_jump(break_label);
546
assemble_label_no(switch_label);
549
switch_label = next_label++;
550
switch_clause_made = TRUE;
551
put_token_back(); put_token_back();
552
if (unary_minus_flag) put_token_back();
555
parse_switch_spec(AO, switch_label, FALSE);
559
{ put_token_back(); put_token_back();
560
if (unary_minus_flag) put_token_back();
565
if ((switch_rule != 0) && (!switch_clause_made))
566
ebf_error("switch value", token_text);
569
sequence_point_follows = TRUE;
570
parse_statement(break_label, continue_label);
575
if (switch_rule != 0)
576
ebf_error("braced code block after 'switch'", token_text);
578
parse_statement(break_label, continue_label);
582
/* ========================================================================= */
583
/* Data structure management routines */
584
/* ------------------------------------------------------------------------- */
586
extern void init_syntax_vars(void)
590
extern void syntax_begin_pass(void)
591
{ no_syntax_lines = 0;
594
extern void syntax_allocate_arrays(void)
598
extern void syntax_free_arrays(void)
602
/* ========================================================================= */