Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
263 dpurdie 1
/*
2
	CPP V5 -- Main routine
3
 
4
	source:  cpp.c
5
	started: October 7, 1985
6
	version: see below
7
 
8
	Written by Edward K. Ream.
9
	This software is in the public domain.
10
 
11
	See the read.me file for disclaimer and other information.
12
*/
13
 
14
#include "cpp.h"
15
 
16
#define SIGNON "CPP V5.3b:    August 4, 1989 Built(" __DATE__ ")"
17
#ifdef SHERLOCK
18
#define USAGE1 "usage: cpp [options] in [out|-E] ++/--routine\n\n"
19
#else
20
#define USAGE1 "usage: cpp [options] in [out]\n\n"
21
#endif
22
 
23
#define USAGE2	"-c           keep all comments and white space\n"
24
#define USAGE3  "-d id=value  #define id value\n"
25
#define USAGE4  "-n           comments DO nest\n"
26
#define USAGE5  "-s <path>    set search path for #include's\n"
27
#define USAGE6  "-u id        #undef id\n"
28
#define USAGE7  "-x           disallow single-line comments\n"
29
#define USAGE8  "-e           output to standard output\n"
30
 
31
main(argc, argv)
32
int argc;
33
char **argv;
34
{
35
	char *in = NULL, *out = NULL;
36
	char *arg;
37
	char *def;
38
	char *p1, *p;
39
	char path_buf[200];
40
 
41
	/* These two calls MUST come before any others. */
42
	SL_INIT();
43
	SL_PARSE(argc, argv, "++", "--");
44
 
45
	/* The call to mst_init() MUST be placed here so we can define
46
	   macros using the -d option.
47
 
48
	   The call to mst2_init() must FOLLOW the gathering of
49
	   command line arguments so that the __line__ and __file__
50
	   macros may be disabled using the -u option.
51
	*/
52
	mst_init();
53
 
54
	/* Allow user to abort. */
55
	syscsts();
56
 
57
	TICKB("main");
58
 
59
	/* Set search path from the INCLUDE environment variable. */
60
	arg = getenv("INCLUDE");
61
	if (arg != 0) {
62
		strcpy(path_buf, arg);
63
		arg = path_buf;
64
		for (p = &path_buf[0]; ;) {
65
			if (*p != ';' && *p != '\0') {
66
				p++;
67
				continue;
68
			}
69
			if (*p == ';') {
70
				*p = '\0';
71
				p++;
72
			}
73
			if (n_paths >= MAX_PATHS) {
74
				printf("too many default path names.\n");
75
				exit(BAD_EXIT);
76
			}
77
			else {
78
				p1 = str_mcat(arg, "\\");
79
				TRACEP("main",
80
					printf("default path: %s\n", arg));
81
				paths [n_paths++] = p1;
82
			}
83
			if (*p == '\0') {
84
				break;
85
			}
86
			else {
87
				arg = p;
88
			}
89
		}
90
	}
91
 
92
	/* Make first test for correct command line. */
93
	if (argc < 3) {
94
                printf("%s\n", SIGNON);
95
		printf("%s%s%s%s", USAGE1, USAGE2,  USAGE3,  USAGE4);
96
		printf("%s%s%s%s", USAGE5, USAGE6, USAGE7, USAGE8);
97
		exit(BAD_EXIT);
98
	}
99
 
100
	/* Process all the arguments on the command line. */
101
	argc--;
102
	argv++;
103
	while (argc-- > 0) {
104
		arg = *argv++;
105
 
106
		if (str_eq(arg, "-c") || str_eq(arg, "-C")) {
107
			/* Keep comments in output. */
108
			com_flag = TRUE;
109
		}
110
 
111
		else if(str_eq(arg, "-d") || str_eq(arg, "-D")) {
112
			/* Define a variable. */
113
			if (argc--) {
114
				arg = *argv++;
115
				/* Scan for an optional equal sign. */
116
                arg_d:;		for (def = arg;	*def; def++) {
117
					if (*def == '=') {
118
						*def = '\0';
119
						def++;
120
						break;
121
					}
122
				}
123
				mst_enter(arg, def, -1);
124
			}
125
			else {
126
				printf("Trailing -d\n");
127
				exit(BAD_EXIT);
128
			}
129
		}
130
                else if (arg[0] == '-' &&
131
                              (arg[1] == 'd' || arg[1] == 'D')) {
132
                        arg += 2;               /* remove -d|D */
133
                        goto arg_d;             /* process argument */
134
		}
135
 
136
                else if (str_eq(arg, "-n") || str_eq(arg, "-N")) {
137
			/* Disallow nested comments. */
138
			nest_flag = FALSE;
139
		}
140
 
141
		else if (str_eq(arg, "-s") || str_eq(arg, "-S")) {
142
			/* Define a path. */
143
			if (argc--) {
144
				arg = *argv++;
145
		arg_s:;		if (n_paths >= MAX_PATHS) {
146
					printf("too many path names.\n");
147
					exit(BAD_EXIT);
148
				}
149
				else {
150
					p1 = str_mcat(arg, "\\");
151
					paths [n_paths++] = p1;
152
				}
153
			}
154
			else {
155
				printf("Trailing -s.\n");
156
				exit(BAD_EXIT);
157
			}
158
		}
159
                else if (arg[0] == '-' &&
160
                              (arg[1] == 's' || arg[1] == 'S')) {
161
                        arg += 2;               /* remove -s|S */
162
                        goto arg_s;             /* process argument */
163
		}
164
 
165
                else if (str_eq(arg, "-u") || str_eq(arg, "-U")) {
166
			/* Suppress the initial definition of a variable. */
167
			if (argc--) {
168
				arg = *argv++;
169
		arg_u:;		mst_unarg(arg);
170
			}
171
			else {
172
				printf("Trailing -u.\n");
173
				exit(BAD_EXIT);
174
			}
175
		}
176
                else if (arg[0] == '-' &&
177
                              (arg[1] == 'u' || arg[1] == 'U')) {
178
                        arg += 2;               /* remove -u|U */
179
                        goto arg_u;             /* process argument */
180
		}
181
 
182
		else if (str_eq(arg, "-x") || str_eq(arg, "-X")) {
183
			/* 8/1/89 Disable single-line comments. */
184
			slc_flag = FALSE;
185
		}
186
 
187
 
188
		else if (str_eq(arg, "-e") || str_eq(arg, "-E")) {
189
                        /* 22/04/02, standard output */
190
		        out = "--";             /* stdout */
191
		}
192
 
193
		else if (in == NULL) {
194
			in = arg;
195
		}
196
 
197
		else if (out == NULL) {
198
			out = arg;
199
		}
200
		else {
201
			printf("Extra file argument: %s\n", arg);
202
			exit(BAD_EXIT);
203
		}
204
	}
205
 
206
	/* Make sure that both file arguments were provided. */
207
	if (in == NULL) {
208
		printf("Missing input, output file arguments.\n");
209
		exit(BAD_EXIT);
210
	}
211
	else if (out == NULL) {
212
		printf("Missing output file argument.\n");
213
		exit(BAD_EXIT);
214
	}
215
	else if (str_eq(in, out)) {
216
		fatal("Can not copy input file to output file.");
217
	}
218
 
219
	/*
220
		Open the output file.
221
 
222
		This should be done BEFORE opening the input file because
223
		opening the input file will cause a character to be written
224
		to the output file.
225
	*/
226
	if (syscreat(out) == FALSE) {
227
		printf("Can not open %s\n", out);
228
		exit(BAD_EXIT);
229
	}
230
 
231
	/* Open the input file. */
232
	if (sysopen(in) == FALSE) {
233
		printf("Can not open %s\n", in);
234
		sysabort();
235
	}
236
 
237
	/*
238
		Initialize the predefined macros (__line__ and __file__) here
239
		so that they can be suppressed with the -u command line option.
240
	*/
241
	mst2_init();
242
 
243
	/* Start off at a new line. */
244
	begin_line(TRUE);
245
 
246
	/* Copy the program to the output file. */
247
	copy_file();
248
 
249
	/* Close the output file. */
250
	sysoclose();
251
 
252
	TRACE("m_stat", m_stat());
253
	TRACE("dump", sl_dump());
254
 
255
	sysend();
256
 
257
	LEAVE("main");
258
	exit(0);
259
}
260
 
261
/*
262
	Copy the input file to the output file.
263
*/
264
 
265
void
266
copy_file()
267
{
268
	int	i;
269
	bool	old_mflag;
270
	char	id_buf[MAX_SYMBOL];
271
 
272
	TICKB("copy_file");
273
 
274
	t_symbol[0] = '\0';
275
	t_subtype = 0;
276
 
277
	/*
278
		We branch to the 'rescan' label whenever a construct is seen
279
		that does not result directly in a token being returned, i.e.,
280
		for macros, PP directives and whitespace.
281
	*/
282
 
283
loop:
284
	TRACEP("copy_file_loop", printf("ch: %s\n", pr_ch(ch)));
285
 
286
	if (isid1(ch)) {
287
		old_mflag = m_flag;
288
		t_id(&t_symbol[0], MAX_SYMBOL);
289
		if (!outer_expand(&t_symbol[0], old_mflag)) {
290
			syssput(&t_symbol[0]);
291
		}
292
		goto loop;
293
	}
294
 
295
	switch (ch) {
296
 
297
	case ' ':
298
	case '\t':
299
		syscput(ch);
300
		sysnext();
301
		goto loop;
302
 
303
	case '\n':
304
 
305
                /* Allow user to abort here. */
306
		syscsts();
307
 
308
		sysnlput();
309
		sysnext();
310
		bump_line();
311
		begin_line(TRUE);
312
		goto loop;
313
 
314
#if (REMOVED)
315
	case '#':
316
                error("Unexpected # ignored.");
317
		sysnext();
318
		goto loop;
319
#endif
320
 
321
	case '/':
322
		/* comment or / or /= or // */
323
		sysnext();
324
		if (ch == '*') {
325
			sysnext();
326
			if (com_flag) {
327
				syscput('/');
328
				syscput('*');
329
				copy_comment();
330
			}
331
			else {
332
				skip_comment();
333
			}
334
		}
335
		else if (slc_flag && ch == '/') {
336
			/* 8/1/89 C++ style single-line comment. */
337
			skip_past();
338
			goto loop;
339
		}
340
		else {
341
			syscput('/');
342
		}
343
		goto loop;
344
 
345
	case '\'':
346
		t_string(&t_symbol[0], MAX_SYMBOL, TRUE);
347
		syssput(&t_symbol[0]);
348
		goto loop;
349
 
350
	case '"':
351
		/* Do concatenation of string literals here. */
352
		TRACE("nocat",
353
			t_string(&t_symbol[0], MAX_SYMBOL, TRUE);
354
			syssput(&t_symbol[0]);
355
			goto loop;
356
		);
357
 
358
		/*
359
			Note that a macro may expand into several strings,
360
			so that we have to be careful not to stop searching
361
			for more strings to concatenate too soon.
362
		*/
363
 
364
		t_symbol[0] = '"';
365
		for(i = 1;;) {
366
			if (ch == ' ' || ch == '\t') {
367
				sysnext();
368
			}
369
			else if (ch == '"') {
370
				t_string(&t_symbol[i], MAX_SYMBOL-i, FALSE);
371
				i = strlen(&t_symbol[0]);
372
			}
373
			else if (isid1(ch)) {
374
				old_mflag = m_flag;
375
				t_id(&id_buf[0], MAX_SYMBOL);
376
				if (!outer_expand(&id_buf[0], old_mflag)) {
377
					/* Not a macro. */
378
					syssput(&id_buf[0]);
379
					goto loop;
380
				}
381
			}
382
			else {
383
				break;
384
			}
385
		}
386
		t_symbol[i++] = '"';
387
		t_symbol[i]   = '\0';
388
		syssput(&t_symbol[0]);
389
		goto loop;
390
 
391
	/*
392
		We must be VERY careful about exactly when we switch from one
393
		input file to the next.  This is the place. 
394
	*/
395
 
396
	case END_FILE:
397
 
398
		/* Switch input streams. */
399
		sysiclose();
400
		if (t_inlevel == -1) {
401
			RETURN_VOID("copy_file");
402
		}
403
		else {
404
			begin_line(TRUE);
405
			goto loop;
406
		}
407
 
408
	default:
409
		/* Be permissive. */
410
		syscput(ch);
411
		sysnext();
412
		goto loop;
413
	}
414
}
415
 
416
/*
417
	Return the next preprocessor token.
418
	This should be called only in contexts where output is NOT required.
419
*/
420
 
421
#ifdef SHERLOCK
422
char bug_s1 [] = "get_token";
423
char bug_s2 [] = "returns token %d, %s\n";
424
#endif
425
 
426
/* CAUTION: evaluate value only once! */
427
#define T_RETURN(value)\
428
	token = value;\
429
	TRACEPN(bug_s1, printf(bug_s2, token, pr_tok()));\
430
	return;
431
 
432
void
433
get_token(expand_flag)
434
bool expand_flag;
435
{
436
	int i;
437
	bool	old_mflag;
438
	unsigned char mesgbuf [40];
439
	unsigned char cbuf [2];
440
 
441
	TRACEP("get_token", printf("(%s) line %d\n",
442
		pr_bool(expand_flag), t_line));
443
 
444
	t_symbol[0] = '\0';
445
	t_subtype = 0;
446
 
447
	/*
448
		We branch to the 'rescan' label whenever a construct is seen
449
		that does not result directly in a token being returned, i.e.,
450
		for macros, PP directives and whitespace.
451
	*/
452
rescan:
453
 
454
	/* Special case for "wide" characters and strings. */
455
	if (ch == 'L') {
456
		sysnext();
457
		if (isid2(ch)) {
458
			syspushback(ch);
459
			ch = 'L';
460
		}
461
	}
462
 
463
	if (isid1(ch)) {
464
		old_mflag = m_flag;
465
		t_id(&t_symbol[0], MAX_SYMBOL);
466
		if (expand_flag && outer_expand(&t_symbol[0], old_mflag)) {
467
			goto rescan;
468
		}
469
		else {
470
			T_RETURN(ID_TOK);
471
		}
472
	}
473
 
474
	TICK("get_token1");
475
 
476
	switch (ch) {
477
 
478
	case ' ':
479
	case '\t':
480
		sysnext();
481
		goto rescan;
482
 
483
	case '\n':
484
	case END_FILE:
485
 
486
		TRACEPN("get_token", printf("con_flag: NULL_TOK\n"));
487
		T_RETURN(NULL_TOK);
488
 
489
	case '#':
490
                error("Unexpected # ignored.");
491
		sysnext();
492
		goto rescan;
493
 
494
	case '0': case '1': case '2': case '3': case '4':
495
	case '5': case '6': case '7': case '8': case '9':
496
 
497
		T_RETURN(t_number(FALSE));
498
 
499
	case '.':
500
		sysnext();
501
		if (ch >= '0' && ch <= '9') {
502
			T_RETURN(t_number(TRUE));
503
		}
504
		else if (ch == '.') {
505
			sysnext();
506
			if (ch == '.') {
507
				sysnext();
508
				T_RETURN(DOTS3);
509
			}
510
		}
511
		else {
512
			T_RETURN(DOT_TOK);
513
		}
514
 
515
	case '"':
516
		t_string(&t_symbol[0], MAX_SYMBOL, FALSE);
517
		T_RETURN(STRING_TOK);
518
 
519
	case '\'':
520
		t_string(&t_symbol[0], MAX_SYMBOL, FALSE);
521
		t_value = (long) char_val(&t_symbol[0]);
522
		T_RETURN(CHAR_TOK);
523
 
524
 
525
	case '=':	/* = or == */
526
 
527
		sysnext();
528
		if (ch == '=') {
529
			sysnext();
530
			T_RETURN(EQUAL_TOK);
531
		}
532
		else {
533
			T_RETURN(ASSN_TOK);
534
		}
535
 
536
 
537
	case '+':	/* + or ++ or += */
538
 
539
		sysnext();
540
		if (ch == '+') {
541
			sysnext();
542
			T_RETURN(INC_TOK);
543
		}
544
		else if (ch == '=') {
545
			sysnext();
546
			T_RETURN(PLUS_ASSN_TOK);
547
		}
548
		else {
549
			T_RETURN(PLUS_TOK);
550
		}
551
 
552
 
553
	case '-':	/* - or -- or -> */
554
 
555
		sysnext();
556
		if (ch == '=') {
557
			sysnext();
558
			T_RETURN(MINUS_ASSN_TOK);
559
		}
560
		else if (ch == '-') {
561
			sysnext();
562
			T_RETURN(DEC_TOK);
563
		}
564
		else if (ch == '>') {
565
			sysnext();
566
			T_RETURN(ARROW_TOK);
567
		}
568
		else {
569
			T_RETURN(MINUS_TOK);
570
		}
571
 
572
 
573
	case '*':	/* * or *= */
574
 
575
		sysnext();
576
		if (ch == '=') {
577
			sysnext();
578
			T_RETURN(STAR_ASSN_TOK);
579
		}
580
		else {
581
			T_RETURN(STAR_TOK);
582
		}
583
 
584
 
585
	case '/':	/* comment or / or /= */
586
 
587
		sysnext();
588
		if (ch == '*') {
589
			sysnext();
590
			skip_comment();
591
			goto rescan;
592
		}
593
		else if (ch == '=') {
594
			sysnext();
595
			T_RETURN(DIV_ASSN_TOK);
596
		}
597
		else {
598
			T_RETURN(DIV_TOK);
599
		}
600
 
601
 
602
	case '%':	/* % or %= */
603
 
604
		sysnext();
605
		if (ch == '=') {
606
			sysnext();
607
			T_RETURN(MOD_ASSN_TOK);
608
		}
609
		else {
610
			T_RETURN(MOD_TOK);
611
		}
612
 
613
 
614
	case '>':	/* > or >= or >> or >>= */
615
 
616
		sysnext();
617
		if (ch == '>') {
618
			sysnext();
619
			if (ch == '=') {
620
				sysnext();
621
				T_RETURN(RSHIFT_ASSN_TOK);
622
			}
623
			else {
624
				T_RETURN(RSHIFT_TOK);
625
			}
626
		}
627
		else if (ch == '=') {
628
			sysnext();
629
			T_RETURN(GE_TOK);
630
		}
631
		else {
632
			T_RETURN(GT_TOK);
633
		}
634
 
635
 
636
	case '<':	/* < or or <= or << or <<= */
637
 
638
		sysnext();
639
		if (ch == '<') {
640
			sysnext();
641
			if (ch == '=') {
642
				sysnext();
643
				T_RETURN(LSHIFT_ASSN_TOK);
644
			}
645
			else {
646
				T_RETURN(LSHIFT_TOK);
647
			}
648
		}
649
		else if (ch == '=') {
650
			sysnext();
651
			T_RETURN(LE_TOK);
652
		}
653
		else {
654
			T_RETURN(LT_TOK);
655
		}
656
 
657
 
658
	case '!':	/* ! or != */
659
 
660
		sysnext();
661
		if (ch == '=') {
662
			sysnext();
663
			T_RETURN(NE_TOK);
664
		}
665
		else {
666
			T_RETURN(NOT_TOK);
667
		}
668
 
669
 
670
	case '|':	/* | or |= or || */
671
 
672
		sysnext();
673
		if (ch == '=') {
674
			sysnext();
675
			T_RETURN(OR_ASSN_TOK);
676
		}
677
		else if (ch == '|') {
678
			sysnext();
679
			T_RETURN(LOR_TOK);
680
		}
681
		else {
682
			T_RETURN(OR_TOK);
683
		}
684
 
685
 
686
	case '&':	/* & or &= or && */
687
 
688
		sysnext();
689
		if (ch == '=') {
690
			sysnext();
691
			T_RETURN(AND_ASSN_TOK);
692
		}
693
		else if (ch == '&') {
694
			sysnext();
695
			T_RETURN(LAND_TOK);
696
		}
697
		else {
698
			T_RETURN(AND_TOK);
699
		}
700
 
701
 
702
	case '^':	/* ^ or ^= */
703
 
704
		sysnext();
705
		if (ch == '=') {
706
			sysnext();
707
			T_RETURN(XOR_ASSN_TOK);
708
		}
709
		else {
710
			T_RETURN(XOR_TOK);
711
		}
712
 
713
 
714
	case '?':	sysnext();	T_RETURN(QUESTION_TOK);
715
	case ':':	sysnext();	T_RETURN(COLON_TOK);
716
 
717
	case '~':	sysnext();	T_RETURN(TILDE_TOK);
718
	case ',':	sysnext();	T_RETURN(COMMA_TOK);
719
	case '(':	sysnext();	T_RETURN(LPAREN_TOK);
720
	case ')':	sysnext();	T_RETURN(RPAREN_TOK);
721
	case '[':	sysnext();	T_RETURN(LBRACK_TOK);
722
	case ']':	sysnext();	T_RETURN(RBRACK_TOK);
723
	case '{':	sysnext();	T_RETURN(LCURLY_TOK);
724
	case '}':	sysnext();	T_RETURN(RCURLY_TOK);
725
	case ';':	sysnext();	T_RETURN(SEMICOLON_TOK);
726
 
727
	default:
728
 
729
		strcpy(mesgbuf, "Character error: ");
730
		cbuf [0] = ch;
731
		cbuf [1] = '\0';
732
		strcat(mesgbuf, cbuf);
733
		error(mesgbuf);
734
		sysnext();
735
		goto rescan;
736
	}
737
}
738
 
739
#undef T_RETURN
740
 
741
/*
742
	Do beginning of line processing.
743
	Look for preprocessor directives only if flag is TRUE.
744
*/
745
void
746
begin_line(flag)
747
bool flag;
748
{
749
	TRACEPB("begin_line", printf("t_line: %d\n", t_line));
750
 
751
	for (;;) {
752
		if (com_flag) {
753
			copy_ws(TRUE);
754
		}
755
		else {
756
			skip_ws(TRUE);
757
		}
758
 
759
		/* PP directives are not allowed as the result of macro expansion. */
760
		if (flag && ch == '#' && !m_flag) {
761
			sysnext();
762
			do_pp();
763
		}
764
		else {
765
			break;
766
		}
767
	}
768
 
769
	RETURN_VOID("begin_line");
770
}
771
 
772
/*
773
	Bump the line number of the current file.
774
*/
775
void
776
bump_line()
777
{
778
	t_line++;
779
	TRACEP("bump_line", printf("t_line = %d\n", t_line));
780
}