Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
263 dpurdie 1
/*
2
	CPP V5 -- directives
3
 
4
	source:  dir.c
5
	started: October 7, 1985
6
	version: May 31, 1988
7
 
8
	External routines defined in this file: do_pp
9
 
10
	Written by Edward K. Ream.
11
	This software is in the public domain.
12
 
13
	See the read.me file for disclaimer and other information.
14
*/
15
 
16
#include "cpp.h"
17
 
18
#define TRACE_LINE(name) TRACEP(name, printf("line %d\n", t_line))
19
 
20
static long	eval		(void);
21
static long 	eval1		(void);
22
static bool	gt_prec		(en_tokens, en_tokens);
23
static bool	isfnch		(int, en_tokens);
24
 
25
static void	pp_elif		(void);
26
static void	pp_else		(void);
27
static void	pp_endif	(void);
28
static void	pp_enum		(void);
29
static void	pp_error	(void);
30
static void	pp_if		(void);
31
static void	pp_ifdef	(bool);
32
static void	pp_incl		(void);
33
static void	pp_line		(void);
34
static void	pp_undef	(void);
35
static int	prec		(int);
36
 
37
static void	push_op		(en_tokens);
38
static en_tokens pop_op		(void);
39
static void	push_val	(long);
40
static long	pop_val		(void);
41
static void	skip_lines	(void);
42
 
43
/*
44
	Do one preprocessor directive.
45
*/
46
 
47
#define EQL(string) str_eq(t_symbol+1,string+1)
48
 
49
void
50
do_pp()
51
{
52
	TICK("do_pp");
53
 
54
	skip_ws(FALSE);
55
 
56
	/* Get the directive into t_symbol[]. */
57
	if (!isalpha(ch)) {
58
		goto not_alpha;
59
	}
60
	t_id(t_symbol, MAX_SYMBOL);
61
 
62
	/* 3/3/89: bug fix:  full white space allowed here. */
63
	skip_ws(FALSE);
64
 
65
	/* Skip simple white space after the directive. */
66
	/* -----
67
	while (ch == ' ' || ch == '\t') {
68
		sysnext();
69
	}
70
	----- */
71
 
72
	switch(t_symbol [0]) {
73
 
74
	case 'd':
75
		if (t_length == 6 && EQL("define")) {
76
			pp_def();
77
			return;
78
		}
79
		goto not_pp;
80
 
81
	case 'e':
82
		if (t_length == 4) {
83
			if (EQL("else")) {
84
				pp_else();
85
				return;
86
			}
87
			else if (EQL("elif")) {
88
				pp_elif();
89
				return;
90
			}
91
		}
92
#ifdef HAS_PP_ENUM
93
		else if (t_length == 4 && EQL("enum")) {
94
			pp_enum();
95
			return;
96
		}
97
#endif
98
		else if (t_length == 5 && EQL("endif")) {
99
			pp_endif();
100
			return;
101
		}
102
		else if (t_length == 5 && EQL("error")) {
103
			pp_error();
104
			return;
105
		}
106
		goto not_pp;
107
 
108
	case 'i':
109
		switch(t_length) {
110
		case 2:	if (EQL("if")) {
111
				pp_if();
112
				return;
113
			}
114
			goto not_pp;
115
		case 5:	if (EQL("ifdef")) {
116
				pp_ifdef(TRUE);
117
				return;
118
			}
119
			goto not_pp;
120
		case 6:	if (EQL("ifndef")) {
121
				pp_ifdef(FALSE);
122
				return;
123
			}
124
			goto not_pp;
125
		case 7:	if (EQL("include")) {
126
				pp_incl();
127
				return;
128
			}
129
			goto not_pp;
130
		}
131
		goto not_pp;
132
 
133
	case 'l':
134
		if (t_length == 4 && EQL("line")) {
135
			pp_line();
136
			return;
137
		}
138
		goto not_pp;
139
 
140
	case 'p':
141
		if (t_length == 6 && EQL("pragma")) {
142
			/* Do NOTHING!! */
143
			skip_pp();
144
			return;
145
		}
146
		goto not_pp;
147
 
148
	case 'u':
149
		if (t_length == 5 && EQL("undef")) {
150
			pp_undef();
151
			return;
152
		}
153
		goto not_pp;
154
 
155
	default:
156
		goto not_pp;
157
	}
158
 
159
not_alpha:
160
	/*
161
		Be more permissive than the new C standard.
162
		Just skip the rest of the line.
163
	*/
164
	skip_pp();
165
	return;
166
 
167
not_pp:
168
	err2(t_symbol, " is not a valid preprocessor directive.");
169
	skip_pp();
170
}
171
 
172
#undef EQL
173
 
174
/*
175
	Handle the #error directive.
176
	Produce a diagnostic message.
177
*/
178
static char	err_msg[] = "#error:  ";
179
 
180
static void
181
pp_error()
182
{
183
	char	message[MAX_SYMBOL];
184
	int	i;
185
 
186
	strcpy(message, err_msg);
187
	for (i = strlen(message); i < MAX_SYMBOL; i++) {
188
		if (ch == '\n' || ch == END_FILE) {
189
			break;
190
		}
191
		else {
192
			message[i] = ch;
193
			sysnext();
194
		}
195
	}
196
	message[i] = '\0';
197
	fatal(message);
198
}
199
 
200
 
201
/*
202
	Evaluate a constant expression to either true or false.
203
	A constant expression consists of:
204
 
205
	1. integer constants or character constants
206
	2. the unary - + and ~ operators
207
	3. the binary + - * / & | ^ << >> == != < > <= >= oprators
208
	4. the ternary ? : operator
209
	5. the ( and ) groupers.
210
 
211
	Identifiers are expanded if they are defined, otherwise they
212
	are taken to have a value of zero. All arithmetic is integer and
213
	ints are expanded to long.
214
*/
215
 
216
#define MAX_EVAL_VAL 100
217
#define MAX_EVAL_OP 50
218
 
219
static	long 		val_stack[MAX_EVAL_VAL];
220
static	int		val_ptr = 0;
221
static	en_tokens	op_stack[MAX_EVAL_OP];
222
static	int		op_ptr = 0;
223
static long result;
224
static bool paren_seen;
225
static bool error_seen;
226
 
227
static long
228
eval()
229
{
230
	TRACETOK("eval");
231
 
232
	error_seen = FALSE;
233
	get_token(TRUE);
234
	result = eval1();
235
 
236
	RETURN_LONG("eval", result);
237
}
238
 
239
static char	* junk;
240
static int	junki;
241
 
242
static long
243
eval1()
244
{
245
	register en_tokens op, op2;
246
	register long val1, val2, val3;
247
	int op_1ptr;
248
 
249
	TRACETOK("eval1");
250
 
251
	op_1ptr  = op_ptr;
252
 
253
	/* State S1: unary +, unary -, !, ~, constant or id is expected here. */
254
 
255
s1:
256
	TRACEPN("v_eval1", printf("at state 1\n"));
257
 
258
	while (is(PLUS_TOK) || is(MINUS_TOK) || is(TILDE_TOK) || is(NOT_TOK)) {
259
		if (is(PLUS_TOK)) {
260
			push_op(UPLUS_TOK);
261
		}
262
		else if (is(MINUS_TOK)) {
263
			push_op(UMINUS_TOK);
264
		}
265
		else if (is(NOT_TOK)) {
266
			push_op(NOT_TOK);
267
		}
268
		else {
269
			push_op(TILDE_TOK);
270
		}
271
		get_token(TRUE);
272
	}
273
 
274
	/* We expect a constant or identifier here. */
275
	if (is(INT_TOK) || is(LONG_TOK) || is(CHAR_TOK)) {
276
		push_val((long) t_value);
277
		get_token(TRUE);
278
	}
279
	else if (is(ID_TOK)) {
280
		/* Special case defined id and defined(id). */
281
		if (str_eq(t_symbol, "defined")) {
282
 
283
			/* Do not macro expand an id here! */
284
			get_token(FALSE);
285
			if (!is(ID_TOK) && !is(LPAREN_TOK)) {
286
				error("Id or '(' expected after 'defined'.");
287
				goto bad_expr;
288
			}
289
			paren_seen = is(LPAREN_TOK);
290
			if (paren_seen) {
291
				get_token(FALSE);
292
				if (!is(ID_TOK)) {
293
					error("Id expected after '('.");
294
					goto bad_expr;
295
				}
296
			}
297
			if(mst_lookup(t_symbol, &junk, &junki)) {
298
				push_val(1L);
299
			}
300
			else {
301
				push_val(0L);
302
			}
303
			get_token(TRUE);
304
			if (paren_seen) {
305
				if (is(RPAREN_TOK)) {
306
					get_token(TRUE);
307
				}
308
				else {
309
					error("')' expected.");
310
					goto bad_expr;
311
				}
312
			}
313
		}
314
		else {
315
			/* The identifier must be undefined, so it gets 0. */
316
			push_val(0L);
317
			get_token(TRUE);
318
		}
319
	}
320
	else if (is(LPAREN_TOK)) {
321
		get_token(TRUE);
322
 
323
		/* Evaluate the expression recursively. */		
324
		result = eval1();
325
		if (is(RPAREN_TOK)) {
326
			get_token(TRUE);
327
			push_val(result);
328
		}
329
		else {
330
			error("')' expected.");
331
			goto bad_expr;
332
		}
333
	}		
334
	else {
335
		error("Integer constant or parenthesized expression expected.");
336
		goto bad_expr;
337
	}
338
 
339
	/* Perform all unary ops and enter state S2. */
340
	TRACEPN("v_eval1", printf("at state 1A\n"));
341
	while (op_ptr > op_1ptr) {
342
		switch (op = pop_op()) {
343
		case UPLUS_TOK:	 break;
344
		case UMINUS_TOK: push_val(-pop_val());		break;
345
		case NOT_TOK:	 push_val((long)(!pop_val()));	break;
346
		case TILDE_TOK:	 push_val(~pop_val());		break;
347
		default:	 push_op(op);			goto s2;
348
		}
349
	}
350
 
351
	/* State S2: binary op or end_of_expression expected here. */
352
 
353
s2:
354
	TRACEPN("v_eval1", printf("at state 2\n"));
355
 
356
	/*
357
		Perform binary operators until the operator stack is
358
		empty or until token operator has a higher precedence
359
		than the operator on the top of the operator stack.
360
	*/
361
 
362
	while (op_ptr > op_1ptr && gt_prec(op_stack[op_ptr - 1], token)) {
363
 
364
		val2 = pop_val();
365
		val1 = pop_val();
366
		op   = pop_op();
367
 
368
		switch (op) {
369
		case PLUS_TOK:		push_val(val1 + val2);	break;
370
		case MINUS_TOK:		push_val(val1 - val2);	break;
371
		case STAR_TOK:		push_val(val1 * val2);	break;
372
		case DIV_TOK:		push_val((long)(val2?(val1/val2):0));
373
					break;
374
		case MOD_TOK:		push_val(val1 % val2);	break;
375
		case AND_TOK:		push_val(val1 & val2);	break;
376
		case OR_TOK:		push_val(val1 | val2);	break;
377
		case XOR_TOK:		push_val(val1 ^ val2);	break;
378
		case LSHIFT_TOK:	push_val(val1 << val2);	break;
379
		case RSHIFT_TOK:	push_val(val1 >> val2);	break;
380
		case EQUAL_TOK:		push_val((long)(val1 == val2));	break;
381
		case NE_TOK:		push_val((long)(val1 != val2));	break;
382
		case LT_TOK:		push_val((long)(val1 <  val2));	break;
383
		case GT_TOK:		push_val((long)(val1 >  val2));	break;
384
		case LE_TOK:		push_val((long)(val1 <= val2));	break;
385
		case GE_TOK:		push_val((long)(val1 >= val2));	break;
386
		case LAND_TOK:		push_val((long)(val1 && val2)); break;
387
		case LOR_TOK:		push_val((long)(val1 || val2)); break;
388
 
389
		case COLON_TOK:		op2 = pop_op();
390
					if (op2 != QUESTION_TOK) {
391
						goto bad_expr;
392
					}
393
					val3 = pop_val();		
394
					push_val(val3 ? val1 : val2);
395
					break;
396
 
397
		default:		goto bad_expr;
398
		}
399
	}
400
 
401
	/* Enter state S1 or return on end-of-expression. */
402
	if (is(NULL_TOK) || is(RPAREN_TOK)) {
403
		val1 = pop_val();
404
		RETURN_LONG("eval1", val1);
405
	}
406
	else if (is(ERR_TOK)) {
407
		goto bad_expr;
408
	}
409
	else {
410
		push_op(token);
411
		get_token(TRUE);
412
		goto s1;
413
	}
414
 
415
bad_expr:
416
	if (!error_seen) {
417
		error("Bad constant expression--zero assumed.");
418
	}
419
	error_seen = TRUE;
420
	RETURN_LONG("eval1", 0L);
421
}
422
 
423
 
424
/*
425
	Return TRUE if a reduction is possible with op1 on the operator stack 
426
	and op2 as the new operator.  
427
 
428
	Always return TRUE if op2 delimits the expression, otherwise
429
	return TRUE if op1 has higher precedence than op2, otherwise
430
	return TRUE if they associate left to right.
431
 
432
	This code reflects the table on page 49 of K & R.
433
*/
434
 
435
static bool
436
gt_prec(op1, op2)
437
register en_tokens op1;
438
register en_tokens op2;
439
{
440
	register int prec1, prec2;
441
 
442
	TRACEP("gt_prec", printf("(%s, %s)\n",
443
		pr_op(op1), pr_op(op2)));
444
 
445
	if (op2 == RPAREN_TOK || op2 == NULL_TOK) {
446
		return TRUE;
447
	}
448
	else if (op2 == ERR_TOK) {
449
		/* Abort immediately. */
450
		return FALSE;
451
	}
452
 
453
	prec1 = prec((int)op1);
454
	prec2 = prec((int)op2);
455
 
456
	if (prec1 != prec2) {
457
		/* Associativity doesn't matter. */
458
		return prec1 > prec2;
459
	}
460
	else if (prec1 == 14 || prec1 == 3 || prec1 == 2) {
461
		/* Associate right to left. */
462
		return FALSE;
463
	}
464
	else {
465
		/* Associate left to right. */
466
		return TRUE;
467
	}
468
}
469
 
470
 
471
/*
472
	Return TRUE if c is legal in a file name.
473
	Assume that the delim character is not legal.
474
*/
475
static bool
476
isfnch(c, delim)
477
int	  c;
478
en_tokens delim;
479
{
480
	TICK("isfnch");
481
 
482
	switch (c) {
483
	case '*':
484
	case '?':
485
	case '\n':
486
	case ' ':
487
	case '\t':
488
	case END_FILE:
489
				return FALSE;
490
 
491
	default:		return (c != (int)delim);
492
	}
493
}
494
 
495
 
496
/*
497
	Return the precedence of an operator.
498
 
499
	This code reflects the table on page 49 of K & R.
500
*/
501
 
502
static int
503
prec(operator)
504
int operator;
505
{
506
	TRACEP("prec", printf("(%s)\n", pr_op(operator)));
507
 
508
	switch (operator) {
509
	case TILDE_TOK:		return 14;
510
	case STAR_TOK:
511
	case DIV_TOK:
512
	case MOD_TOK:		return 13;
513
	case PLUS_TOK:
514
	case MINUS_TOK:		return 12;
515
	case LSHIFT_TOK:
516
	case RSHIFT_TOK:	return 11;
517
	case LT_TOK:
518
	case LE_TOK:
519
	case GT_TOK:
520
	case GE_TOK:		return 10;
521
	case EQUAL_TOK:
522
	case NE_TOK:		return 9;
523
	case XOR_TOK:		return 7;
524
	case OR_TOK:		return 6;
525
	case COLON_TOK:
526
	case QUESTION_TOK:	return 3;
527
	default:		return -1;
528
	}
529
}
530
 
531
 
532
/*
533
	Routines to push and pop the operator and operand stacks.
534
*/
535
static void
536
push_op(op)
537
en_tokens op;
538
{
539
	TRACEP("push_op", printf("(%s), op_ptr = %d\n",
540
		pr_op(op), op_ptr));
541
 
542
	if (op_ptr < MAX_EVAL_OP) {
543
		op_stack[op_ptr++] = op;
544
	}
545
	else {
546
		fatal("Operator stack overflow.");
547
	}
548
}
549
 
550
static en_tokens
551
pop_op()
552
{
553
	TRACEP("pop_op", printf("op_ptr = %d\n", op_ptr));
554
 
555
	if (op_ptr > 0) {
556
 
557
		TRACEP("pop_op", printf("returns: %s\n",
558
			pr_op(op_stack[op_ptr - 1])));
559
 
560
		return op_stack [--op_ptr];
561
	}
562
	else {
563
		syserr("Operator stack underflow.");
564
		return NULL_TOK;
565
	}
566
}
567
 
568
static void
569
push_val(val)
570
long val;
571
{
572
	TRACEP("push_val", printf("(%ld), val_ptr = %d\n", val, val_ptr));
573
 
574
	if (val_ptr < MAX_EVAL_VAL) {
575
		val_stack [val_ptr++] = val;
576
	}
577
	else {
578
		fatal("Value stack overflow.");
579
	}
580
}
581
 
582
static long
583
pop_val()
584
{
585
	TRACEP("pop_val", printf("val_ptr = %d\n", val_ptr));
586
 
587
	if (val_ptr > 0) {
588
 
589
		TRACEP("pop_val", printf("returns %ld\n",
590
			val_stack [val_ptr - 1]));
591
 
592
		return val_stack [--val_ptr];
593
	}
594
	else {
595
		syserr("Value stack underflow.");
596
		return 0L;
597
	}
598
}
599
 
600
/*
601
	Handle the #elif directive when lines are NOT being skipped.
602
	The skip_lines() routines handles #elif when lines ARE being skipped.
603
*/
604
static void
605
pp_elif()
606
{
607
	TRACE_LINE("pp_elif");
608
 
609
	if (t_iflevel == 0) {
610
		error("#elif ignored--no matching #if.");
611
		skip_pp();
612
		return;
613
	}
614
 
615
	/* Skip lines if the constant expression evaluates to zero. */
616
	if (eval() == 0L) {
617
		/* Skip until #else or #endif. */
618
		skip_lines();
619
	}
620
}
621
 
622
 
623
/*
624
	Handle the #else directive when lines are NOT being skipped.
625
	The skip_lines() routine handles #else when lines ARE being skipped.	
626
*/
627
static void
628
pp_else()
629
{
630
	TRACE_LINE("pp_else");
631
 
632
	if (t_iflevel == 0) {
633
		error("#else ignored--no matching #if.");
634
		skip_pp();
635
	}
636
	else if (t_ifstack [t_iflevel - 1] == TRUE) {
637
		error("Duplicate #else ignored.");
638
		skip_pp();
639
	}
640
	else {
641
		t_ifstack [t_iflevel - 1] = TRUE;
642
		skip_lines();
643
	}
644
}
645
 
646
 
647
/*
648
	Handle the #endif directive when lines are NOT being skipped.
649
	The skip_lines() routine handles #endif when lines ARE being skipped.
650
*/
651
static void
652
pp_endif()
653
{
654
	TRACE_LINE("pp_endif");
655
 
656
	if (t_iflevel == 0) {
657
		error("#endif ignored--no matching #if.");
658
		skip_pp();
659
	}
660
	else {
661
		t_iflevel--;
662
		skip_pp();
663
	}
664
}
665
 
666
/*
667
	Handle the #if directive when lines are NOT being skipped.
668
	The skip_lines() routine handles #if when lines ARE being skipped.
669
*/
670
static void
671
pp_if()
672
{
673
	TRACE_LINE("pp_if");
674
 
675
	/* Indicate that no #else has been seen. */
676
	if (t_iflevel >= MAX_IF) {
677
		error("#if ignored--nested too deeply.");
678
		skip_pp();
679
		return;
680
	}
681
	t_ifstack [t_iflevel++] = FALSE;
682
 
683
	/* Skip lines if the constant expression evaluates to zero. */
684
	if (eval() == 0L) {
685
		/* Skip until #else or #endif. */
686
		skip_lines();
687
	}
688
}
689
 
690
/*
691
	Handle the #ifdef and #ifndef directives when lines are NOT being 
692
	skipped.
693
	The skip_lines() routine handles #if when lines ARE being skipped.
694
 
695
		flag == TRUE:	#ifdef
696
		flag == FALSE:	#ifndef
697
*/
698
static void
699
pp_ifdef(flag)
700
bool flag;
701
{
702
	bool result;
703
	char *text;
704
	int nargs;
705
 
706
	TRACE_LINE("pp_ifdef");
707
 
708
	if(t_iflevel > MAX_IF) {
709
		error("#ifdef or #ifndef ignored--nested too deeply.");
710
		skip_pp();
711
		return;
712
	}
713
 
714
	if (!isid1(ch)) {
715
		error("#ifdef or #ifndef ignored--identifier expected.");
716
		skip_pp();
717
		return;
718
	}
719
 
720
	/* Get id into t_symbol[]. */
721
	t_id(t_symbol, MAX_SYMBOL);
722
	skip_pp();
723
 
724
	/* Indicate that no #else has been seen. */
725
	t_ifstack [t_iflevel++] = FALSE;
726
 
727
	/* Skip lines if required. */
728
	result = mst_lookup(t_symbol, &text, &nargs);
729
	if ((flag && result == FALSE) || (!flag && result == TRUE)) {
730
		/* Skip until #else or #endif. */
731
		skip_lines();
732
	}
733
}
734
 
735
 
736
/*
737
	Handle the #include directive.
738
*/
739
static void
740
pp_incl()
741
{
742
	bool	old_mflag;
743
	bool	err_flag;
744
	int	i;
745
	char	f_name [MAX_FILE_NAME];
746
	char	path_name [200];
747
	char	delim;
748
 
749
	TRACE_LINE("pp_incl");
750
 
751
	/* File name is OK. */
752
	err_flag = FALSE;
753
 
754
	/*
755
		Check for opening delimiter.
756
		Allow simple macro expansions here.
757
	*/
758
	if (isid1(ch)) {
759
		old_mflag = m_flag;
760
		t_id(&t_symbol[0], MAX_SYMBOL);
761
 
762
		/* We expect a proper macro here. */
763
		outer_expand(&t_symbol[0], old_mflag);
764
	}
765
 
766
	if (ch == '"') {
767
		delim = '"';
768
		sysnext();
769
	}
770
	else if (ch == '<') {
771
		delim = '>';
772
		sysnext();
773
	}
774
	else {
775
		err_flag = TRUE;
776
		delim = '\r';
777
	}
778
 
779
	/* Get file name into f_name[]. */
780
	for (i = 0; i < MAX_FILE_NAME-1 && isfnch(ch,(en_tokens)delim); i++) {
781
		f_name[i] = ch;
782
		sysnext();
783
	}
784
	f_name[i] = '\0';
785
 
786
	if (err_flag || ch != delim) {
787
		err3("#include ", f_name, " ignored--bad delimiter.");
788
		skip_pp();
789
		return;
790
	}
791
 
792
	/* Skip over the delimiter. */
793
	sysnext();
794
 
795
	/*
796
		We must skip the line here, because after
797
		sysopen() is called we would not be able to skip
798
		characters in the old level.
799
	*/
800
 
801
	skip_pp();
802
	if (ch == '\n') {
803
		sysnlput();
804
		sysnext();
805
	}
806
	bump_line();
807
 
808
	if (t_inlevel >= MAX_INCLUDE) {
809
		t_line--;
810
		err3("#include ", f_name, " ignored--nested too deeply.");
811
		t_line++;
812
		return;
813
	}
814
 
815
	/* Open the file. */
816
	if(sysopen(f_name) == FALSE) {
817
		for (i = 0; i < n_paths; i++) {
818
			strcpy(path_name, paths [i]);
819
			strcat(path_name, f_name);
820
 
821
			TRACEP("pp_incl", printf("attempting to open %s\n",
822
				path_name));
823
 
824
			if (sysopen(path_name) == TRUE) {
825
				return;
826
			}
827
		}
828
		t_line--;
829
		err3("#include ", f_name, " ignored--file not found.");
830
		t_line++;
831
	}
832
}
833
 
834
 
835
/*
836
	Set the line number and file name.
837
*/
838
static void
839
pp_line()
840
{
841
	bool	old_mflag;
842
	int	i;
843
 
844
	TRACE_LINE("pp_line");
845
 
846
	/* Allow macro expansion. */
847
	if (isid1(ch)) {
848
		old_mflag = m_flag;
849
		t_id(&t_symbol[0], MAX_SYMBOL);
850
 
851
		/* We expect a macro id here. */
852
		outer_expand(&t_symbol[0], old_mflag);
853
	}
854
 
855
	(void) t_number(FALSE);
856
	t_line = (int) t_value;
857
 
858
	/* See if an optional file name is present. */
859
	skip_ws(FALSE);
860
 
861
	/* Allow macro expansion. */
862
	if (isid1(ch)) {
863
		old_mflag = m_flag;
864
		t_id(&t_symbol[0], MAX_SYMBOL);
865
 
866
		/* We expect a macro id here. */
867
		outer_expand(&t_symbol[0], old_mflag);
868
	}
869
	if (ch == '\n' || ch == END_FILE) {
870
		return;
871
	}
872
 
873
	/* Copy line to t_file[]. */
874
	for(i = 0; i < MAX_FILE_NAME - 1; i++) {
875
		if (ch == END_FILE || ch == '\n') {
876
			break;
877
		}
878
		t_file[i] = ch;
879
		sysnext();
880
	}
881
	t_file [i] = '\0';
882
	skip_pp();
883
}
884
 
885
 
886
/*
887
	Undefine a previously #defined variable.
888
*/
889
static void
890
pp_undef()
891
{
892
	TRACE_LINE("pp_undef");
893
 
894
	/* Get the identifier into t_symbol[]. */
895
	if (!isid1(ch)) {
896
		error("#undef ignored--identifier expected.");
897
		skip_pp();
898
		return;
899
	}
900
	t_id(t_symbol, MAX_SYMBOL);
901
 
902
	/* Delete the identifier. Give no warning if it doesn't exist. */
903
	mst_delete(t_symbol);
904
	skip_pp();
905
}
906
 
907
 
908
/*
909
	Skip lines until a matching #else or #endif directive is found.
910
	Thus,  interior #ifdef, #ifndef, #if, #elif and  #else directives
911
	must be recognized and dealt with.
912
 
913
	A fine point:  This code skips lines without doing any parsing of the
914
	line.  The ONLY things this code looks for are lines which start with
915
	#ifdef, #ifndef, #if or #else.  One should not detect "unknown"
916
	preprocessor directives or other possible "errors," for the very good
917
	reason that one wants to use conditional compilation to exclude lines
918
	which might not even be written in the C language.
919
 
920
	Examples can be given where this action might be suspect.  Consider a
921
	string which is continued from one line to the next using the backslash
922
	newline convention.  If the continuation line starts with one of the
923
	four directives that this routine is looking for then either the lex or
924
	the person using the lex will become confused.  This is a minor hole in
925
	the C language, and it seems better to ignore the fine points and do
926
	what is sensible in most cases, namely skip entire lines as a unit.
927
 
928
	The routine skip_past() is used to do the skipping of exactly 1 line.
929
*/
930
 
931
#define EQL(string) str_eq(t_symbol,string)
932
static void
933
skip_lines()
934
{
935
	register int level = 0;		/* Inner nesting level */
936
 
937
	TRACE_LINE("skip_lines");
938
 
939
	/* Just in case. */
940
	if (t_iflevel <= 0) {
941
		syserr("skip_lines: Can't happen.");
942
	}
943
 
944
	/* Start a new line. */
945
loop:
946
 
947
	if (ch == END_FILE) {
948
		error("File ends inside range of #ifdef.");
949
		return;
950
	}
951
 
952
	/* Skip the line if it doesn't start with '#'. */
953
	if (ch != '#') {
954
		skip_past();
955
		goto loop;
956
	}
957
 
958
	/* Skip the line if '#' isn't followed by an id. */
959
	sysnext();
960
	skip_ws(FALSE);
961
 
962
	if (!isid1(ch)) {
963
		skip_past();
964
		goto loop;
965
	}
966
 
967
	/* Get the directive into t_symbol[]. */
968
	t_id(t_symbol, MAX_SYMBOL);
969
 
970
	if (EQL("ifdef") || EQL("ifndef") || EQL("if")) {
971
		level++;
972
	}
973
	else if (EQL("elif")) {
974
		if (level > 0) {
975
			/* This directive will itself be skipped. */
976
			skip_pp();
977
		}
978
		else if (eval() == 0L) {
979
			/* Call to eval will bump line number. */
980
			TRACEPN("skip_lines",
981
				printf("stopped by #elif at line %d\n",
982
					t_line - 1));
983
			return;
984
		}
985
	}
986
	else if (EQL("else")) {
987
		if (level > 0) {
988
			/* Skip this directive. */
989
			skip_pp();
990
		}
991
		else if (t_ifstack [t_iflevel - 1] == FALSE) {
992
			t_ifstack [t_iflevel - 1] = TRUE;
993
			skip_pp();
994
			TRACEPN("skip_lines",
995
				printf("stopped by #else at line %d\n",
996
					t_line));
997
			return;
998
		}
999
		else {
1000
			error("Extra #else ignored.");
1001
		}
1002
	}
1003
	else if (EQL("endif")) {
1004
		if (level > 0) {
1005
			level--;
1006
		}
1007
		else {
1008
			t_iflevel--;
1009
			skip_pp();
1010
			TRACEPN("skip_lines",
1011
				printf("stopped by #endif at line %d\n",
1012
					t_line));
1013
			return;
1014
		}
1015
	}
1016
	else {
1017
		skip_past();
1018
	}
1019
	goto loop;
1020
}
1021
 
1022
#undef EQL