Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997, 1998
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
#include "config.h"
32
#include <limits.h>
33
#include "system.h"
34
#include "version.h"
35
#include "c_types.h"
36
#include "error.h"
37
#include "catalog.h"
38
#include "basetype.h"
39
#include "buffer.h"
40
#include "capsule.h"
41
#include "compile.h"
42
#include "constant.h"
43
#include "debug.h"
44
#include "declare.h"
45
#include "exception.h"
46
#include "file.h"
47
#include "dump.h"
48
#include "hash.h"
49
#include "initialise.h"
50
#include "instance.h"
51
#include "inttype.h"
52
#include "lex.h"
53
#include "literal.h"
54
#include "load.h"
55
#include "macro.h"
56
#include "namespace.h"
57
#include "operator.h"
58
#include "option.h"
59
#include "overload.h"
60
#include "parse.h"
61
#include "predict.h"
62
#include "preproc.h"
63
#include "printf.h"
64
#include "redeclare.h"
65
#include "statement.h"
66
#include "syntax.h"
67
#include "table.h"
68
#include "template.h"
69
#include "tok.h"
70
#include "tokdef.h"
71
#include "typeid.h"
72
#include "unmangle.h"
73
#include "ustring.h"
74
#include "variable.h"
75
#include "xalloc.h"
76
 
77
 
78
/*
79
    DEFAULT MACHINE OPTION
80
 
81
    This macro is used to determine the machine dependent options to
82
    be used.
83
*/
84
 
85
#ifndef FS_MACHINE
86
#ifdef FS_DOS
87
#define FS_MACHINE		"dos"
88
#else
89
#define FS_MACHINE		"unix"
90
#endif
91
#endif
92
 
93
 
94
/*
95
    COMMAND-LINE FLAGS
96
 
97
    These flags may be set by command-line options to indicate various
98
    actions to the compiler.
99
*/
100
 
101
static int builtin_asserts = 1 ;
102
static int builtin_macros = 1 ;
103
static int check_level = 0 ;
104
static int complete_program = 0 ;
105
static int have_startup = 0 ;
106
static int spec_linker = 0 ;
107
static int started_scope = 0 ;
108
static int output_last = 1 ;
109
static int unmangle_names = 0 ;
110
static int quit_immediately = 0 ;
111
static string dump_name = NULL ;
112
static string dump_opt = NULL ;
113
static string spec_name = NULL ;
114
static string table_name = NULL ;
115
 
116
 
117
/*
118
    TABLE OF COMMAND-LINE ARGUMENTS
119
 
120
    This table describes all the command-line options.  Each is given by
121
    an option letter, followed by a flag indicating whether the option can
122
    be split into two components, and a description of the second option
123
    component.
124
*/
125
 
126
typedef struct {
127
    char opt ;
128
    char space ;
129
    CONST char *arg ;
130
    CONST char *desc ;
131
} PROGRAM_ARG ;
132
 
133
static PROGRAM_ARG prog_args [] = {
134
    { 'A', 1, "<pre>(<tok>)", "assert a predicate" },
135
    { 'D', 1, "<mac>=<def>", "define a macro" },
136
    { 'E', 0, NULL, "preprocess input file only" },
137
    { 'F', 1, "<file>", "read list of options from file" },
138
    { 'H', 0, NULL, "report file inclusions" },
139
    { 'I', 1, "<dir>", "specify an include directory" },
140
    { 'M', 1, "<mach>", "machine dependent options" },
141
    { 'N', 1, "<name>:<dir>", "specify a named include directory" },
142
    { 'O', 0, NULL, "optimise output capsule" },
143
    { 'R', 0, NULL, "reverse order of files" },
144
    { 'S', 0, NULL, "spec file linker action" },
145
    { 'U', 1, "<mac>", "undefine a macro" },
146
    { 'V', 0, NULL, "enable verbose mode" },
147
    { 'W', 1, "<opt>", "enable warnings option" },
148
    { 'X', 0, NULL, "disable exception handling" },
149
    { 'Z', 1, "<number>", "set maximum number of errors" },
150
    { 'a', 0, NULL, "apply complete program checks" },
151
    { 'c', 0, NULL, "disable TDF output" },
152
    { 'd', 1, "<opt>=<file>", "dump symbol table" },
153
    { 'e', 1, "<file>", "add an end-up file" },
154
    { 'f', 1, "<file>", "add a start-up file" },
155
    { 'g', 0, "<level>", "enable diagnostics mode" },
156
    { 'h', 0, NULL, "print this help page" },
157
    { 'j', 1, "<opts>", "set TDF output options" },
158
    { 'm', 1, "<opts>", "set error printing options" },
159
    { 'n', 1, "<file>", "specify portability table" },
160
    { 'o', 1, "<output>", "specify output file" },
161
    { 'q', 0, NULL, "quit immediately" },
162
    { 'r', 1, "<file>", "specify error marker" },
163
    { 's', 1, "<file>", "specify spec output file" },
164
    { 't', 0, NULL, "output TDF token declarations" },
165
    { 'u', 0, NULL, "unmangle identifier names" },
166
    { 'v', 0, NULL, "print version number" },
167
    { 'w', 0, NULL, "disable all warnings" },
168
#ifdef DEBUG
169
    { 'x', 1, "<debug>", "debugging options" },
170
#endif
171
    { 'z', 0, NULL, "ignore compilation errors" },
172
    { '?', 0, NULL, "print this help page" },
173
    { '-', 0, NULL, "specify end of options" }
174
} ;
175
 
176
#define no_prog_args	array_size ( prog_args )
177
 
178
 
179
/*
180
    PRINT PROGRAM USAGE
181
 
182
    This routine prints the program usage to the file f.
183
*/
184
 
185
static void report_usage
186
    PROTO_N ( ( f ) )
187
    PROTO_T ( FILE *f )
188
{
189
    int i ;
190
    fprintf_v ( f, "Usage: %s [options] [input] [output]\n", progname ) ;
191
    for ( i = 0 ; i < no_prog_args ; i++ ) {
192
	char opt = prog_args [i].opt ;
193
	CONST char *arg = prog_args [i].arg ;
194
	CONST char *desc = prog_args [i].desc ;
195
	if ( arg == NULL ) arg = "\t" ;
196
	if ( desc == NULL ) desc = "(not documented)" ;
197
	fprintf_v ( f, " -%c%s\t%s\n", opt, arg, desc ) ;
198
    }
199
    fputc_v ( '\n', f ) ;
200
    return ;
201
}
202
 
203
 
204
/*
205
    SET MACHINE DEPENDENT FLAGS
206
 
207
    This routine sets the machine dependent options for the machine
208
    described by mach.  The routine returns false for an unknown machine
209
    descriptor.
210
*/
211
 
212
static int set_machine
213
    PROTO_N ( ( mach ) )
214
    PROTO_T ( CONST char *mach )
215
{
216
    if ( streq ( mach, "dos" ) ) {
217
	allow_dos_newline = 1 ;
218
	good_fseek = 0 ;
219
	binary_mode = 1 ;
220
	file_sep = '\\' ;
221
	drive_sep = ':' ;
222
	return ( 1 ) ;
223
    }
224
    if ( streq ( mach, "unix" ) ) {
225
	allow_dos_newline = 0 ;
226
	good_fseek = 1 ;
227
	binary_mode = 0 ;
228
	file_sep = '/' ;
229
	drive_sep = 0 ;
230
	return ( 1 ) ;
231
    }
232
    return ( 0 ) ;
233
}
234
 
235
 
236
/*
237
    PRE-SET A COMPILE-TIME OPTION
238
 
239
    This routine pre-sets the value of option A to be B.
240
*/
241
 
242
#define preset( A, B )\
243
    OPT_CATALOG [A].def [0] = ( B ) ;\
244
    OPT_CATALOG [A].def [1] = ( B )
245
 
246
 
247
/*
248
    READ AN ARGUMENT FROM A FILE
249
 
250
    This routine reads a command-line argument from the file f into the
251
    buffer s of length n, returning the result.
252
*/
253
 
254
static char *read_arg
255
    PROTO_N ( ( f, s, n ) )
256
    PROTO_T ( FILE *f X char *s X int n )
257
{
258
    char *p = fgets ( s, n, f ) ;
259
    if ( p ) {
260
	char c = *p ;
261
	if ( c == '#' || c == '\n' ) {
262
	    /* Ignore empty lines and comments */
263
	    p = read_arg ( f, s, n ) ;
264
	} else {
265
	    /* Remove terminal newline */
266
	    char *q = strrchr ( p, '\n' ) ;
267
	    if ( q ) *q = 0 ;
268
	}
269
    }
270
    return ( p ) ;
271
}
272
 
273
 
274
/*
275
    PROCESS A LIST OF ARGUMENTS
276
 
277
    This routine is called by main to process the command-line arguments
278
    given by argc and argv.  It returns a list of strings giving the
279
    input and output files.
280
*/
281
 
282
static LIST ( string ) process_args
283
    PROTO_N ( ( argc, argv ) )
284
    PROTO_T ( int argc X char **argv )
285
{
286
    char opt = 0 ;
287
    FILE *f = NULL ;
288
    char buff [1000] ;
289
    int allow_opt = 1 ;
290
    string output = NULL ;
291
    LIST ( string ) files = NULL_list ( string ) ;
292
 
293
    /* Set development default options */
294
#ifdef DEBUG
295
    output_tokdec = 1 ;
296
#endif
297
 
298
    /* Scan through the arguments */
299
    for ( ; ; ) {
300
	char *arg = NULL ;
301
	if ( f != NULL ) {
302
	    /* Get next option from file */
303
	    arg = read_arg ( f, buff, ( int ) sizeof ( buff ) ) ;
304
	    if ( arg == NULL ) {
305
		/* End of file reached */
306
		fclose_v ( f ) ;
307
		f = NULL ;
308
	    }
309
	}
310
	if ( arg == NULL && argc ) {
311
	    /* Get next option from array */
312
	    arg = *( argv++ ) ;
313
	    argc-- ;
314
	}
315
	if ( arg == NULL ) {
316
	    /* No more options */
317
	    break ;
318
	}
319
	if ( opt == 0 ) {
320
	    /* Find option letter */
321
	    if ( arg [0] == '-' && allow_opt ) {
322
		opt = arg [1] ;
323
		if ( opt ) arg += 2 ;
324
	    }
325
	}
326
	if ( opt == 0 ) {
327
	    /* Input or output file 'arg' */
328
	    string uarg = xustrcpy ( ustrlit ( arg ) ) ;
329
	    CONS_string ( uarg, files, files ) ;
330
 
331
	} else {
332
	    /* Command-line options */
333
	    int i ;
334
	    int known = 0 ;
335
	    char next_opt = 0 ;
336
 
337
	    /* Search through options */
338
	    for ( i = 0 ; i < no_prog_args ; i++ ) {
339
		if ( opt == prog_args [i].opt ) {
340
		    if ( prog_args [i].arg ) {
341
			/* Complex options */
342
			if ( arg [0] == 0 && prog_args [i].space ) {
343
			    next_opt = opt ;
344
			    known = 1 ;
345
			} else {
346
			    known = 2 ;
347
			}
348
		    } else {
349
			/* Simple options */
350
			if ( arg [0] == 0 ) {
351
			    known = 2 ;
352
			    break ;
353
			}
354
		    }
355
		}
356
	    }
357
 
358
	    /* Deal with complete options */
359
	    if ( known == 2 ) {
360
		string uarg = ustrlit ( arg ) ;
361
		switch ( opt ) {
362
 
363
		    case 'A' : {
364
			/* Assertion */
365
			BUFFER *bf = &internal_buff ;
366
			if ( streq ( arg, "-" ) ) {
367
			    builtin_asserts = 0 ;
368
			    break ;
369
			}
370
			bfprintf ( bf, "#assert %x\n", arg ) ;
371
			preset ( OPT_ppdir_assert, OPTION_ALLOW ) ;
372
			preset ( OPT_ppdir_unassert, OPTION_ALLOW ) ;
373
			preset ( OPT_ppdir_assert_ignore, OPTION_OFF ) ;
374
			preset ( OPT_ppdir_unassert_ignore, OPTION_OFF ) ;
375
			have_startup = 1 ;
376
			break ;
377
		    }
378
 
379
		    case 'D' : {
380
			/* Macro definition */
381
			char c ;
382
			CONST char *def = "1" ;
383
			BUFFER *bf = &internal_buff ;
384
			bfprintf ( bf, "#define " ) ;
385
			while ( c = *( arg++ ), c != 0 ) {
386
			    if ( c == '=' ) {
387
				def = arg ;
388
				break ;
389
			    }
390
			    bfputc ( bf, ( int ) c ) ;
391
			}
392
			bfprintf ( bf, " %x\n", def ) ;
393
			have_startup = 1 ;
394
			break ;
395
		    }
396
 
397
		    case 'E' : {
398
			/* Preprocessor option */
399
			preproc_only = 1 ;
400
			break ;
401
		    }
402
 
403
		    case 'F' : {
404
			/* Open option file */
405
			if ( f != NULL ) {
406
			    CONST char *err = "Nested option files" ;
407
			    error ( ERROR_WARNING, err ) ;
408
			    break ;
409
			}
410
			f = fopen ( arg, "r" ) ;
411
			if ( f == NULL ) {
412
			    CONST char *err = "Can't open option file '%s'" ;
413
			    error ( ERROR_WARNING, err, arg ) ;
414
			}
415
			break ;
416
		    }
417
 
418
		    case 'H' : {
419
			/* Inclusion reporting option */
420
			preset ( OPT_include_verbose, OPTION_WARN ) ;
421
			break ;
422
		    }
423
 
424
		    case 'I' : {
425
			/* Include file search directory */
426
			uarg = xustrcpy ( uarg ) ;
427
			add_directory ( uarg, NULL_string ) ;
428
			break ;
429
		    }
430
 
431
		    case 'M' : {
432
			/* Machine dependent options */
433
			known = set_machine ( arg ) ;
434
			break ;
435
		    }
436
 
437
		    case 'N' : {
438
			/* Named include file search directory */
439
			string dir ;
440
			uarg = xustrcpy ( uarg ) ;
441
			dir = ustrchr ( uarg, ':' ) ;
442
			if ( dir == NULL ) {
443
			    CONST char *err = "Bad '-%c' option" ;
444
			    error ( ERROR_WARNING, err, opt ) ;
445
			    add_directory ( uarg, NULL_string ) ;
446
			} else {
447
			    *dir = 0 ;
448
			    add_directory ( dir + 1, uarg ) ;
449
			}
450
			break ;
451
		    }
452
 
453
		    case 'O' : {
454
			/* Optimisation mode */
455
			output_inline = 1 ;
456
			output_unused = 0 ;
457
			break ;
458
		    }
459
 
460
		    case 'R' : {
461
			/* Reverse order of files */
462
			output_last = 0 ;
463
			break ;
464
		    }
465
 
466
		    case 'S' : {
467
			/* Spec linker option */
468
			spec_linker = 1 ;
469
			break ;
470
		    }
471
 
472
		    case 'U' : {
473
			/* Macro undefinition */
474
			BUFFER *bf = &internal_buff ;
475
			if ( streq ( arg, "-" ) ) {
476
			    builtin_macros = 0 ;
477
			    break ;
478
			}
479
			bfprintf ( bf, "#undef %x\n", arg ) ;
480
			have_startup = 1 ;
481
			break ;
482
		    }
483
 
484
		    case 'V' : {
485
			/* Switch on verbose mode */
486
			verbose = 1 ;
487
			break ;
488
		    }
489
 
490
		    case 'W' : {
491
			/* Switch on checks */
492
			char c ;
493
			CONST char *sev = "warning" ;
494
			BUFFER *bf = &internal_buff ;
495
			if ( streq ( arg, "all" ) ) {
496
			    check_level = 1 ;
497
			    break ;
498
			}
499
			if ( !started_scope ) {
500
			    bfprintf ( bf, "#pragma TenDRA begin\n" ) ;
501
			    started_scope = 1 ;
502
			}
503
			bfprintf ( bf, "#pragma TenDRA option \"" ) ;
504
			while ( c = *( arg++ ), c != 0 ) {
505
			    if ( c == '=' ) {
506
				sev = arg ;
507
				break ;
508
			    }
509
			    bfputc ( bf, ( int ) c ) ;
510
			}
511
			bfprintf ( bf, "\" %x\n", sev ) ;
512
			have_startup = 1 ;
513
			break ;
514
		    }
515
 
516
		    case 'X' : {
517
			/* Disable exception handling */
518
			output_except = 0 ;
519
			break ;
520
		    }
521
 
522
		    case 'Z' : {
523
			/* Set maximum number of errors */
524
			BUFFER *bf = &internal_buff ;
525
			if ( !started_scope ) {
526
			    bfprintf ( bf, "#pragma TenDRA begin\n" ) ;
527
			    started_scope = 1 ;
528
			}
529
			bfprintf ( bf, "#pragma TenDRA set error limit" ) ;
530
			bfprintf ( bf, " %x\n", uarg ) ;
531
			have_startup = 1 ;
532
			break ;
533
		    }
534
 
535
		    case 'a' : {
536
			/* Complete program checks */
537
			complete_program = 1 ;
538
			break ;
539
		    }
540
 
541
		    case 'c' : {
542
			/* Disable TDF output */
543
			output_capsule = 0 ;
544
			break ;
545
		    }
546
 
547
		    case 'd' : {
548
			/* Dump file */
549
			string dump ;
550
			uarg = xustrcpy ( uarg ) ;
551
			dump = ustrchr ( uarg, '=' ) ;
552
			if ( dump == NULL ) {
553
			    CONST char *err = "Bad '-%c' option" ;
554
			    error ( ERROR_WARNING, err, opt ) ;
555
			    break ;
556
			}
557
			if ( dump_name ) {
558
			    CONST char *err = "Multiple dump files" ;
559
			    error ( ERROR_WARNING, err ) ;
560
			}
561
			dump_opt = uarg ;
562
			dump_name = dump + 1 ;
563
			break ;
564
		    }
565
 
566
		    case 'e' : {
567
			/* End-up file */
568
			LIST ( string ) p ;
569
			uarg = xustrcpy ( uarg ) ;
570
			CONS_string ( uarg, NULL_list ( string ), p ) ;
571
			endup_files = APPEND_list ( endup_files, p ) ;
572
			have_startup = 1 ;
573
			break ;
574
		    }
575
 
576
		    case 'f' : {
577
			/* Start-up file */
578
			LIST ( string ) p ;
579
			uarg = xustrcpy ( uarg ) ;
580
			CONS_string ( uarg, NULL_list ( string ), p ) ;
581
			startup_files = APPEND_list ( startup_files, p ) ;
582
			have_startup = 1 ;
583
			break ;
584
		    }
585
 
586
		    case 'g' : {
587
			/* Diagnostics mode */
588
			if ( uarg [0] == 0 ) {
589
			    output_diag = DIAG_VERSION ;
590
			} else if ( uarg [1] == 0 ) {
591
			    switch ( uarg [0] ) {
592
				case '0' : output_diag = 0 ; break ;
593
				case '1' : output_diag = 1 ; break ;
594
				case '2' : output_diag = 2 ; break ;
595
				default : known = 0 ; break ;
596
			    }
597
			} else {
598
			    known = 0 ;
599
			}
600
			break ;
601
		    }
602
 
603
		    case 'h' :
604
		    case '?' : {
605
			/* Help option */
606
			report_usage ( error_file ) ;
607
			break ;
608
		    }
609
 
610
		    case 'j' : {
611
			/* Output options */
612
			output_option ( uarg ) ;
613
			break ;
614
		    }
615
 
616
		    case 'm' : {
617
			/* Error options */
618
			error_option ( uarg ) ;
619
			break ;
620
		    }
621
 
622
		    case 'n' : {
623
			/* Portability table */
624
			if ( table_name ) {
625
			    CONST char *err = "Multiple portability tables" ;
626
			    error ( ERROR_WARNING, err ) ;
627
			}
628
			table_name = xustrcpy ( uarg ) ;
629
			break ;
630
		    }
631
 
632
		    case 'o' : {
633
			/* Output file */
634
			if ( output ) {
635
			    CONST char *err = "Multiple output files" ;
636
			    error ( ERROR_WARNING, err ) ;
637
			}
638
			output = xustrcpy ( uarg ) ;
639
			break ;
640
		    }
641
 
642
		    case 'q' : {
643
			/* Quit immediately */
644
			quit_immediately = 1 ;
645
			break ;
646
		    }
647
 
648
		    case 'r' : {
649
			/* Error marker file */
650
			output_name [ OUTPUT_ERROR ] = xustrcpy ( uarg ) ;
651
			break ;
652
		    }
653
 
654
		    case 's' : {
655
			/* Spec output file */
656
			if ( spec_name ) {
657
			    CONST char *err = "Multiple spec output files" ;
658
			    error ( ERROR_WARNING, err ) ;
659
			}
660
			spec_name = xustrcpy ( uarg ) ;
661
			break ;
662
		    }
663
 
664
		    case 't' : {
665
			/* Output TDF token declarations */
666
			output_tokdec = 1 ;
667
			break ;
668
		    }
669
 
670
		    case 'u' : {
671
			/* Unmangle an identifier name */
672
			unmangle_names = 1 ;
673
			break ;
674
		    }
675
 
676
		    case 'v' : {
677
			/* Print version number */
678
			string v = report_version ( 1 ) ;
679
			fprintf_v ( error_file, "%s\n\n", strlit ( v ) ) ;
680
			break ;
681
		    }
682
 
683
		    case 'w' : {
684
			/* Suppress all warnings */
685
			preset ( OPT_warning, OPTION_OFF ) ;
686
			check_level = 0 ;
687
			break ;
688
		    }
689
 
690
		    case 'z' : {
691
			/* Ignore compilation errors */
692
			preset ( OPT_error, OPTION_WARN ) ;
693
			max_errors = ULONG_MAX ;
694
			break ;
695
		    }
696
 
697
		    case '-' : {
698
			/* Last option */
699
			allow_opt = 0 ;
700
			break ;
701
		    }
702
 
703
#ifdef DEBUG
704
		    case 'x' : {
705
			/* Debug options */
706
			debug_option ( arg ) ;
707
			quit_immediately = 1 ;
708
			break ;
709
		    }
710
#endif
711
		}
712
	    }
713
 
714
	    /* Deal with unknown options */
715
	    if ( known == 0 ) {
716
		CONST char *err = "Unknown option, '-%c%s'" ;
717
		error ( ERROR_WARNING, err, opt, arg ) ;
718
	    }
719
	    opt = next_opt ;
720
	}
721
    }
722
    if ( opt ) {
723
	CONST char *err = "Incomplete option, '-%c'" ;
724
	error ( ERROR_WARNING, err, opt ) ;
725
    }
726
 
727
    /* Examine list of files */
728
    if ( IS_NULL_list ( files ) ) {
729
	CONS_string ( NULL, NULL_list ( string ), files ) ;
730
    }
731
    if ( output || IS_NULL_list ( TAIL_list ( files ) ) ) {
732
	CONS_string ( output, files, files ) ;
733
	output_last = 1 ;
734
    }
735
    files = REVERSE_list ( files ) ;
736
    return ( files ) ;
737
}
738
 
739
 
740
/*
741
    INITIALISE FILE LOCATIONS
742
 
743
    This routine initialises the standard file locations.
744
*/
745
 
746
static void init_loc
747
    PROTO_Z ()
748
{
749
    IGNORE set_crt_loc ( ustrlit ( "<builtin-in>" ), 1 ) ;
750
    builtin_loc = crt_loc ;
751
    IGNORE set_crt_loc ( ustrlit ( "<command-line>" ), 1 ) ;
752
    preproc_loc = crt_loc ;
753
    decl_loc = crt_loc ;
754
    stmt_loc = crt_loc ;
755
    return ;
756
}
757
 
758
 
759
/*
760
    PERFORM LANGUAGE DEPENDENT INITIALISATION
761
 
762
    This routine performs any language dependent initialisation not
763
    covered in the main initialisation routines.  Note that the default
764
    language is C++.
765
*/
766
 
767
static void init_lang
768
    PROTO_N ( ( c ) )
769
    PROTO_T ( int c )
770
{
771
    if ( c ) {
772
	crt_linkage = dspec_c ;
773
	set_std_namespace ( NULL_id ) ;
774
    }
775
    init_tok ( c ) ;
776
    return ;
777
}
778
 
779
 
780
/*
781
    CALL MAIN INITIALISATION ROUTINES
782
 
783
    This routine calls all the initialisation routines.
784
*/
785
 
786
static void init_main
787
    PROTO_Z ()
788
{
789
    /* Set file locations */
790
    crt_loc = builtin_loc ;
791
    decl_loc = builtin_loc ;
792
    stmt_loc = builtin_loc ;
793
    preproc_loc = builtin_loc ;
794
 
795
    /* Initialise errors and options */
796
    init_hash () ;
797
    init_lang ( LANGUAGE_C ) ;
798
    init_catalog () ;
799
    init_option ( check_level ) ;
800
    if ( output_diag ) record_location = 1 ;
801
    init_dump ( dump_name, dump_opt ) ;
802
    if ( do_header ) dump_start ( &crt_loc, NIL ( INCL_DIR ) ) ;
803
 
804
    /* Initialise macros and keywords */
805
    init_char () ;
806
    init_constant () ;
807
    init_keywords () ;
808
    init_macros ( builtin_macros, builtin_asserts ) ;
809
 
810
    /* Read the portability table */
811
    read_table ( table_name ) ;
812
 
813
    /* Initialise types and namespaces */
814
    init_namespace () ;
815
    push_namespace ( global_namespace ) ;
816
    init_types () ;
817
    init_literal () ;
818
    init_exception () ;
819
    init_printf () ;
820
    init_initialise () ;
821
    init_token_args () ;
822
    init_templates () ;
823
    if ( do_header ) dump_end ( &crt_loc ) ;
824
    return ;
825
}
826
 
827
 
828
/*
829
    CALL MAIN TERMINATION ROUTINES
830
 
831
    This routine frees any memory unneeded after the parsing routines.
832
*/
833
 
834
static void term_main
835
    PROTO_Z ()
836
{
837
    free_candidates ( &candidates ) ;
838
    free_buffer ( &field_buff ) ;
839
    free_buffer ( &token_buff ) ;
840
    term_macros () ;
841
    term_input () ;
842
    term_catalog () ;
843
    term_itypes () ;
844
    return ;
845
}
846
 
847
 
848
/*
849
    CALL MAIN FILE PROCESSING ROUTINES
850
 
851
    This routine calls the main routines for processing the given list
852
    of files.  This will have at least two elements, the last of which is
853
    the output file.
854
*/
855
 
856
static void process_files
857
    PROTO_N ( ( files ) )
858
    PROTO_T ( LIST ( string ) files )
859
{
860
    /* Find output file */
861
    int action ;
862
    unsigned len ;
863
    string output ;
864
    PARSE_STATE st ;
865
    unsigned max_len = 2 ;
866
    int mode = text_mode ;
867
    LIST ( string ) input ;
868
 
869
    /* Find output file */
870
    if ( output_last ) {
871
	LIST ( string ) end = END_list ( files ) ;
872
	output = DEREF_string ( HEAD_list ( end ) ) ;
873
	input = files ;
874
    } else {
875
	output = DEREF_string ( HEAD_list ( files ) ) ;
876
	input = TAIL_list ( files ) ;
877
    }
878
    output_name [ OUTPUT_TDF ] = output ;
879
    output_name [ OUTPUT_SPEC ] = spec_name ;
880
 
881
    /* Find processing action */
882
    save_state ( &st, 0 ) ;
883
    crt_state_depth = 0 ;
884
    if ( spec_linker ) {
885
	output_capsule = 0 ;	/* remove later */
886
	init_capsule () ;
887
	max_len = 0 ;
888
	action = 2 ;
889
    } else if ( preproc_only ) {
890
	output_name [ OUTPUT_PREPROC ] = output ;
891
	output_tdf = 0 ;
892
	output_capsule = 0 ;
893
	action = 1 ;
894
    } else {
895
	init_capsule () ;
896
	action = 0 ;
897
    }
898
 
899
    /* Check number of input files */
900
    len = LENGTH_list ( files ) ;
901
    if ( max_len && len > max_len ) {
902
	CONST char *err = "Too many arguments (should have %u)" ;
903
	error ( ERROR_WARNING, err, max_len ) ;
904
	len = max_len ;
905
    }
906
 
907
    /* Process start-up files in spec linker mode */
908
    if ( action == 2 ) {
909
	if ( have_startup ) {
910
	    IGNORE open_input ( mode ) ;
911
	    crt_loc = builtin_loc ;
912
	    input_name = NULL ;
913
	    input_file = NULL ;
914
	    process_file () ;
915
	    close_input () ;
916
	}
917
	mode = binary_mode ;
918
    }
919
 
920
    /* Scan through input files */
921
    while ( len >= 2 ) {
922
	/* Open input file */
923
	input_name = DEREF_string ( HEAD_list ( input ) ) ;
924
	if ( !open_input ( mode ) ) {
925
	    fail ( ERR_fail_input ( input_name ) ) ;
926
	    term_error ( 0 ) ;
927
	    return ;
928
	}
929
	init_diag () ;
930
 
931
	/* Process input file */
932
	switch ( action ) {
933
	    case 0 : {
934
		/* Parsing action */
935
		process_file () ;
936
		break ;
937
	    }
938
	    case 1 : {
939
		/* Preprocessing action */
940
		preprocess_file () ;
941
		break ;
942
	    }
943
	    case 2 : {
944
		/* Spec linker action */
945
		if ( read_spec () ) have_syntax_error = 1 ;
946
		no_declarations++ ;
947
		break ;
948
	    }
949
	}
950
 
951
	/* Close input file */
952
	clear_decl_blocks () ;
953
	close_input () ;
954
	input = TAIL_list ( input ) ;
955
	len-- ;
956
    }
957
 
958
    /* Write output file */
959
    if ( have_syntax_error ) {
960
	suppress_variable = 2 ;
961
	no_declarations++ ;
962
    }
963
    init_diag () ;
964
    preproc_loc = crt_loc ;
965
    restore_state ( &st ) ;
966
    if ( action == 1 ) {
967
	/* Preprocessing action */
968
	term_option () ;
969
    } else {
970
	/* Compilation actions */
971
	external_declaration ( NULL_exp, 0 ) ;
972
	clear_templates ( 2 ) ;
973
	term_main () ;
974
	IGNORE check_global ( complete_program ) ;
975
	term_option () ;
976
	compile_pending () ;
977
	write_capsule () ;
978
    }
979
    return ;
980
}
981
 
982
 
983
/*
984
    MAIN ROUTINE
985
 
986
    This is the main routine.  It processes the command-line options,
987
    calls the initialisation routines and calls the main processing
988
    routine.
989
*/
990
 
991
int main
992
    PROTO_N ( ( argc, argv ) )
993
    PROTO_T ( int argc X char **argv )
994
{
995
    LIST ( string ) files ;
996
    set_progname ( argv [0], PROG_VERSION ) ;
997
    IGNORE set_machine ( FS_MACHINE ) ;
998
    init_loc () ;
999
    files = process_args ( argc - 1, argv + 1 ) ;
1000
    builtin_startup () ;
1001
    if ( !quit_immediately ) {
1002
	/* Process files */
1003
	init_main () ;
1004
	if ( unmangle_names ) {
1005
	    unmangle_list ( files, stdout, 1 ) ;
1006
	} else {
1007
	    process_files ( files ) ;
1008
	    term_error ( 0 ) ;
1009
	}
1010
    }
1011
    return ( exit_status ) ;
1012
}