~ubuntu-branches/ubuntu/vivid/inform/vivid

« back to all changes in this revision

Viewing changes to inform-6.31.1/src/syntax.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-05-26 22:09:44 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526220944-ba7phz0d1k4vo7wx
Tags: 6.31.1+dfsg-1
* Remove a considerable number of files from the package
  due to unacceptable licensing terms.
* Repair library symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ------------------------------------------------------------------------- */
 
2
/*   "syntax" : Syntax analyser and compiler                                 */
 
3
/*                                                                           */
 
4
/*   Part of Inform 6.31                                                     */
 
5
/*   copyright (c) Graham Nelson 1993 - 2006                                 */
 
6
/*                                                                           */
 
7
/* ------------------------------------------------------------------------- */
 
8
 
 
9
#include "header.h"
 
10
 
 
11
static char *lexical_source;
 
12
 
 
13
int no_syntax_lines;                                  /*  Syntax line count  */
 
14
 
 
15
static void begin_syntax_line(int statement_mode)
 
16
{   no_syntax_lines++;
 
17
    next_token_begins_syntax_line = TRUE;
 
18
 
 
19
    clear_expression_space();
 
20
    if (statement_mode)
 
21
    {   statements.enabled = TRUE;
 
22
        conditions.enabled = TRUE;
 
23
        local_variables.enabled = TRUE;
 
24
        system_functions.enabled = TRUE;
 
25
 
 
26
        misc_keywords.enabled = FALSE;
 
27
        directive_keywords.enabled = FALSE;
 
28
        directives.enabled = FALSE;
 
29
        segment_markers.enabled = FALSE;
 
30
        opcode_names.enabled = FALSE;
 
31
    }
 
32
    else
 
33
    {   directives.enabled = TRUE;
 
34
        segment_markers.enabled = TRUE;
 
35
 
 
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;
 
43
    }
 
44
 
 
45
    sequence_point_follows = TRUE;
 
46
 
 
47
    if (debugfile_switch)
 
48
    {   get_next_token();
 
49
        debug_line_ref = token_line_ref;
 
50
        put_token_back();
 
51
    }
 
52
}
 
53
 
 
54
extern void panic_mode_error_recovery(void)
 
55
{
 
56
    while ((token_type != EOF_TT)
 
57
           && ((token_type != SEP_TT)||(token_value != SEMICOLON_SEP)))
 
58
 
 
59
        get_next_token();
 
60
}
 
61
 
 
62
extern void parse_program(char *source)
 
63
{
 
64
    lexical_source = source;
 
65
    while (parse_directive(FALSE)) ;
 
66
}
 
67
 
 
68
extern int parse_directive(int internal_flag)
 
69
{
 
70
    /*  Internal_flag is FALSE if the directive is encountered normally,
 
71
        TRUE if encountered with a # prefix inside a routine.
 
72
 
 
73
        Returns: TRUE if program continues, FALSE if end of file reached.    */
 
74
 
 
75
    int routine_symbol;
 
76
 
 
77
    begin_syntax_line(FALSE);
 
78
    get_next_token();
 
79
 
 
80
    if (token_type == EOF_TT) return(FALSE);
 
81
 
 
82
    if ((token_type == SEP_TT) && (token_value == HASH_SEP))
 
83
        get_next_token();
 
84
 
 
85
    if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
 
86
    {   if (internal_flag)
 
87
        {   error("It is illegal to nest routines using '#['");
 
88
            return(TRUE);
 
89
        }
 
90
 
 
91
        directives.enabled = FALSE;
 
92
        directive_keywords.enabled = FALSE;
 
93
        segment_markers.enabled = FALSE;
 
94
 
 
95
        get_next_token();
 
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);
 
100
            return(FALSE);
 
101
        }
 
102
 
 
103
        routine_symbol = token_value;
 
104
 
 
105
        if ((sflags[routine_symbol] & REPLACE_SFLAG) && (is_systemfile()))
 
106
        {   dont_enter_into_symbol_table = TRUE;
 
107
            do
 
108
            {   get_next_token();
 
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;
 
114
        }
 
115
        else
 
116
        {   assign_symbol(routine_symbol,
 
117
                parse_routine(lexical_source, FALSE,
 
118
                    (char *) symbs[routine_symbol], FALSE, routine_symbol),
 
119
                ROUTINE_T);
 
120
            slines[routine_symbol] = routine_starts_line;
 
121
        }
 
122
        get_next_token();
 
123
        if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
 
124
        {   ebf_error("';' after ']'", token_text);
 
125
            put_token_back();
 
126
        }
 
127
        return TRUE;
 
128
    }
 
129
 
 
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]);
 
133
        return TRUE;
 
134
    }
 
135
 
 
136
    if (token_type != DIRECTIVE_TT)
 
137
    {   ebf_error("directive, '[' or class name", token_text);
 
138
        panic_mode_error_recovery();
 
139
        return TRUE;
 
140
    }
 
141
 
 
142
    return !(parse_given_directive());
 
143
}
 
144
 
 
145
static int switch_sign(void)
 
146
{
 
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;
 
150
    return 0;
 
151
}
 
152
 
 
153
static assembly_operand spec_stack[32];
 
154
static int spec_type[32];
 
155
 
 
156
static void compile_alternatives_z(assembly_operand switch_value, int n,
 
157
    int stack_level, int label, int flag)
 
158
{   switch(n)
 
159
    {   case 1:
 
160
            assemblez_2_branch(je_zc, switch_value,
 
161
                spec_stack[stack_level],
 
162
                label, flag); return;
 
163
        case 2:
 
164
            assemblez_3_branch(je_zc, switch_value,
 
165
                spec_stack[stack_level], spec_stack[stack_level+1],
 
166
                label, flag); return;
 
167
        case 3:
 
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;
 
172
    }
 
173
}
 
174
 
 
175
static void compile_alternatives_g(assembly_operand switch_value, int n,
 
176
    int stack_level, int label, int flag)
 
177
{   
 
178
    int the_zc = (flag) ? jeq_gc : jne_gc;
 
179
 
 
180
    if (n == 1) {
 
181
      assembleg_2_branch(the_zc, switch_value,
 
182
        spec_stack[stack_level],
 
183
        label); 
 
184
    }
 
185
    else {
 
186
      error("*** Cannot generate multi-equality tests in Glulx ***");
 
187
    }
 
188
}
 
189
 
 
190
static void compile_alternatives(assembly_operand switch_value, int n,
 
191
    int stack_level, int label, int flag)
 
192
{
 
193
  if (!glulx_mode)
 
194
    compile_alternatives_z(switch_value, n, stack_level, label, flag);
 
195
  else
 
196
    compile_alternatives_g(switch_value, n, stack_level, label, flag);
 
197
}
 
198
 
 
199
static void parse_switch_spec(assembly_operand switch_value, int label,
 
200
    int action_switch)
 
201
{
 
202
    int i, j, label_after = -1, spec_sp = 0;
 
203
    int max_equality_args = ((!glulx_mode) ? 3 : 1);
 
204
 
 
205
    sequence_point_follows = FALSE;
 
206
 
 
207
    do
 
208
    {   if (spec_sp == 32)
 
209
        {   error("At most 32 values can be given in a single 'switch' case");
 
210
            panic_mode_error_recovery();
 
211
            return;
 
212
        }
 
213
 
 
214
        if (action_switch)
 
215
        {   get_next_token();
 
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);
 
221
 
 
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);
 
225
            }
 
226
        }
 
227
        else
 
228
            spec_stack[spec_sp] =
 
229
      code_generate(parse_expression(CONSTANT_CONTEXT), CONSTANT_CONTEXT, -1);
 
230
 
 
231
        misc_keywords.enabled = TRUE;
 
232
        get_next_token();
 
233
        misc_keywords.enabled = FALSE;
 
234
 
 
235
        spec_type[spec_sp++] = switch_sign();
 
236
        switch(spec_type[spec_sp-1])
 
237
        {   case 0:
 
238
                if (action_switch)
 
239
                    ebf_error("',' or ':'", token_text);
 
240
                else ebf_error("',', ':' or 'to'", token_text);
 
241
                panic_mode_error_recovery();
 
242
                return;
 
243
            case 1: goto GenSpecCode;
 
244
            case 3: if (label_after == -1) label_after = next_label++;
 
245
        }
 
246
     } while(TRUE);
 
247
 
 
248
     GenSpecCode:
 
249
 
 
250
     if ((spec_sp > max_equality_args) && (label_after == -1))
 
251
         label_after = next_label++;
 
252
 
 
253
     if (label_after == -1)
 
254
     {   compile_alternatives(switch_value, spec_sp, 0, label, FALSE); return;
 
255
     }
 
256
 
 
257
     for (i=0; i<spec_sp;)
 
258
     {
 
259
         j=i; while ((j<spec_sp) && (spec_type[j] != 3)) j++;
 
260
 
 
261
         if (j > i)
 
262
         {   if (j-i > max_equality_args) j=i+max_equality_args;
 
263
 
 
264
             if (j == spec_sp)
 
265
                 compile_alternatives(switch_value, j-i, i, label, FALSE);
 
266
             else
 
267
                 compile_alternatives(switch_value, j-i, i, label_after, TRUE);
 
268
 
 
269
             i=j;
 
270
         }
 
271
         else
 
272
         {   
 
273
           if (!glulx_mode) {
 
274
             if (i == spec_sp - 2)
 
275
             {   assemblez_2_branch(jl_zc, switch_value, spec_stack[i],
 
276
                     label, TRUE);
 
277
                 assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1],
 
278
                     label, TRUE);
 
279
             }
 
280
             else
 
281
             {   assemblez_2_branch(jl_zc, switch_value, spec_stack[i],
 
282
                     next_label, TRUE);
 
283
                 assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1],
 
284
                     label_after, FALSE);
 
285
                 assemble_label_no(next_label++);
 
286
             }
 
287
           }
 
288
           else {
 
289
             if (i == spec_sp - 2)
 
290
             {   assembleg_2_branch(jlt_gc, switch_value, spec_stack[i],
 
291
                     label);
 
292
                 assembleg_2_branch(jgt_gc, switch_value, spec_stack[i+1],
 
293
                     label);
 
294
             }
 
295
             else
 
296
             {   assembleg_2_branch(jlt_gc, switch_value, spec_stack[i],
 
297
                     next_label);
 
298
                 assembleg_2_branch(jle_gc, switch_value, spec_stack[i+1],
 
299
                     label_after);
 
300
                 assemble_label_no(next_label++);
 
301
             }
 
302
           }
 
303
           i = i+2;
 
304
         }
 
305
     }
 
306
 
 
307
     assemble_label_no(label_after);
 
308
}
 
309
 
 
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,
 
314
        switch_label = 0;
 
315
    dbgl start_line_ref = token_line_ref;
 
316
 
 
317
    /*  (switch_label needs no initialisation here, but it prevents some
 
318
        compilers from issuing warnings)   */
 
319
 
 
320
    if ((source != lexical_source) || (veneer_flag))
 
321
    {   lexical_source = source;
 
322
        restart_lexer(lexical_source, name);
 
323
    }
 
324
 
 
325
    no_locals = 0;
 
326
 
 
327
    for (i=0;i<MAX_LOCAL_VARIABLES-1;i++) local_variables.keywords[i] = "";
 
328
 
 
329
    do
 
330
    {   statements.enabled = TRUE;
 
331
        dont_enter_into_symbol_table = TRUE;
 
332
        get_next_token();
 
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;
 
337
        }
 
338
 
 
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();
 
344
            break;
 
345
        }
 
346
 
 
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();
 
351
            break;
 
352
        }
 
353
 
 
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;
 
358
    } while(TRUE);
 
359
 
 
360
    construct_local_variable_tables();
 
361
 
 
362
    if ((trace_fns_setting==3)
 
363
        || ((trace_fns_setting==2) && (veneer_mode==FALSE))
 
364
        || ((trace_fns_setting==1) && (is_systemfile()==FALSE)))
 
365
        debug_flag = TRUE;
 
366
    if ((embedded_flag == FALSE) && (veneer_mode == FALSE) && debug_flag)
 
367
        sflags[r_symbol] |= STAR_SFLAG;
 
368
 
 
369
    packed_address = assemble_routine_header(no_locals, debug_flag,
 
370
        name, &start_line_ref, embedded_flag, r_symbol);
 
371
 
 
372
    do
 
373
    {   begin_syntax_line(TRUE);
 
374
 
 
375
        get_next_token();
 
376
 
 
377
        if (token_type == EOF_TT)
 
378
        {   ebf_error("']'", token_text);
 
379
            put_token_back();
 
380
            assemble_routine_end(embedded_flag, &token_line_ref);
 
381
            break;
 
382
        }
 
383
 
 
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);
 
391
            break;
 
392
        }
 
393
 
 
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;
 
398
 
 
399
            if (switch_clause_made)
 
400
            {   if (!execution_never_reaches_here)
 
401
                {   sequence_point_follows = FALSE;
 
402
                    if (!glulx_mode)
 
403
                        assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc);
 
404
                    else
 
405
                        assembleg_1(return_gc, 
 
406
                            ((embedded_flag)?zero_operand:one_operand));
 
407
                }
 
408
                assemble_label_no(switch_label);
 
409
            }
 
410
            switch_clause_made = TRUE;
 
411
 
 
412
            get_next_token();
 
413
            if ((token_type == SEP_TT) &&
 
414
                (token_value == COLON_SEP)) continue;
 
415
            ebf_error("':' after 'default'", token_text);
 
416
            panic_mode_error_recovery();
 
417
            continue;
 
418
        }
 
419
 
 
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. */
 
424
 
 
425
        if ((token_type != DQ_TT) && (token_type != SEP_TT))
 
426
        {   get_next_token();
 
427
            if (switch_sign() > 0)
 
428
            {   assembly_operand AO;
 
429
                if (default_clause_made)
 
430
                    error("'default' must be the last 'switch' case");
 
431
 
 
432
                if (switch_clause_made)
 
433
                {   if (!execution_never_reaches_here)
 
434
                    {   sequence_point_follows = FALSE;
 
435
                        if (!glulx_mode)
 
436
                            assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc);
 
437
                        else
 
438
                            assembleg_1(return_gc, 
 
439
                                ((embedded_flag)?zero_operand:one_operand));
 
440
                    }
 
441
                    assemble_label_no(switch_label);
 
442
                }
 
443
 
 
444
                switch_label = next_label++;
 
445
                switch_clause_made = TRUE;
 
446
                put_token_back(); put_token_back();
 
447
 
 
448
                if (!glulx_mode) {
 
449
                    AO.type = VARIABLE_OT; AO.value = 249; AO.marker = 0;
 
450
                }
 
451
                else {
 
452
                    AO.type = GLOBALVAR_OT;
 
453
                    AO.value = MAX_LOCAL_VARIABLES+6; /* sw__var */
 
454
                    AO.marker = 0;
 
455
                }
 
456
                parse_switch_spec(AO, switch_label, TRUE);
 
457
 
 
458
                continue;
 
459
            }
 
460
            else
 
461
            {   put_token_back(); put_token_back(); get_next_token();
 
462
                sequence_point_follows = TRUE;
 
463
            }
 
464
        }
 
465
 
 
466
        parse_statement(-1, -1);
 
467
 
 
468
    } while (TRUE);
 
469
 
 
470
    return packed_address;
 
471
}
 
472
 
 
473
extern void parse_code_block(int break_label, int continue_label,
 
474
    int switch_rule)
 
475
{   int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label,
 
476
        unary_minus_flag;
 
477
 
 
478
    begin_syntax_line(TRUE);
 
479
    get_next_token();
 
480
 
 
481
    if (token_type == SEP_TT && token_value == OPEN_BRACE_SEP)
 
482
    {   do
 
483
        {   begin_syntax_line(TRUE);
 
484
            get_next_token();
 
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);
 
488
                return;
 
489
            }
 
490
            if (token_type == EOF_TT)
 
491
            {   ebf_error("'}'", token_text); return; }
 
492
 
 
493
            if (switch_rule != 0)
 
494
            {
 
495
                /*  Within a 'switch' block  */
 
496
 
 
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;
 
501
 
 
502
                    if (switch_clause_made)
 
503
                    {   if (!execution_never_reaches_here)
 
504
                        {   sequence_point_follows = FALSE;
 
505
                            assemble_jump(break_label);
 
506
                        }
 
507
                        assemble_label_no(switch_label);
 
508
                    }
 
509
                    switch_clause_made = TRUE;
 
510
 
 
511
                    get_next_token();
 
512
                    if ((token_type == SEP_TT) &&
 
513
                        (token_value == COLON_SEP)) continue;
 
514
                    ebf_error("':' after 'default'", token_text);
 
515
                    panic_mode_error_recovery();
 
516
                    continue;
 
517
                }
 
518
 
 
519
                /*  Decide: is this an ordinary statement, or the start
 
520
                    of a new case?  */
 
521
 
 
522
                if (token_type == DQ_TT) goto NotASwitchCase;
 
523
 
 
524
                unary_minus_flag
 
525
                    = ((token_type == SEP_TT)&&(token_value == MINUS_SEP));
 
526
                if (unary_minus_flag) get_next_token();
 
527
 
 
528
                /*  Now read the token _after_ any possible constant:
 
529
                    if that's a 'to', ',' or ':' then we have a case  */
 
530
 
 
531
                misc_keywords.enabled = TRUE;
 
532
                get_next_token();
 
533
                misc_keywords.enabled = FALSE;
 
534
 
 
535
                if (switch_sign() > 0)
 
536
                {   assembly_operand AO;
 
537
 
 
538
                    if (default_clause_made)
 
539
                        error("'default' must be the last 'switch' case");
 
540
 
 
541
                    if (switch_clause_made)
 
542
                    {   if (!execution_never_reaches_here)
 
543
                        {   sequence_point_follows = FALSE;
 
544
                            assemble_jump(break_label);
 
545
                        }
 
546
                        assemble_label_no(switch_label);
 
547
                    }
 
548
 
 
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();
 
553
 
 
554
                    AO = temp_var1;
 
555
                    parse_switch_spec(AO, switch_label, FALSE);
 
556
                    continue;
 
557
                }
 
558
                else
 
559
                {   put_token_back(); put_token_back();
 
560
                    if (unary_minus_flag) put_token_back();
 
561
                    get_next_token();
 
562
                }
 
563
            }
 
564
 
 
565
            if ((switch_rule != 0) && (!switch_clause_made))
 
566
                ebf_error("switch value", token_text);
 
567
 
 
568
            NotASwitchCase:
 
569
            sequence_point_follows = TRUE;
 
570
            parse_statement(break_label, continue_label);
 
571
        }
 
572
        while(TRUE);
 
573
    }
 
574
 
 
575
    if (switch_rule != 0)
 
576
        ebf_error("braced code block after 'switch'", token_text);
 
577
 
 
578
    parse_statement(break_label, continue_label);
 
579
    return;
 
580
}
 
581
 
 
582
/* ========================================================================= */
 
583
/*   Data structure management routines                                      */
 
584
/* ------------------------------------------------------------------------- */
 
585
 
 
586
extern void init_syntax_vars(void)
 
587
{
 
588
}
 
589
 
 
590
extern void syntax_begin_pass(void)
 
591
{   no_syntax_lines = 0;
 
592
}
 
593
 
 
594
extern void syntax_allocate_arrays(void)
 
595
{
 
596
}
 
597
 
 
598
extern void syntax_free_arrays(void)
 
599
{
 
600
}
 
601
 
 
602
/* ========================================================================= */