1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * Glenn Fowler
23*4887Schin  * AT&T Research
24*4887Schin  *
25*4887Schin  * preprocessor expression evaluation support
26*4887Schin  */
27*4887Schin 
28*4887Schin #include "pplib.h"
29*4887Schin 
30*4887Schin #include <regex.h>
31*4887Schin 
32*4887Schin #define lex(c)		((((c)=peektoken)>=0?(peektoken=(-1)):((c)=pplex())),(c))
33*4887Schin #define unlex(c)	(peektoken=(c))
34*4887Schin 
35*4887Schin static int		peektoken;	/* expression lookahead token	*/
36*4887Schin static char*		errmsg;		/* subexpr() error message	*/
37*4887Schin 
38*4887Schin /*
39*4887Schin  * exists predicate evaluation
40*4887Schin  */
41*4887Schin 
42*4887Schin static int
43*4887Schin exists(int op, char* pred, register char* args)
44*4887Schin {
45*4887Schin 	register int	c;
46*4887Schin 	register int	type;
47*4887Schin 	char*		pptoken;
48*4887Schin 	long		state;
49*4887Schin 	char		file[MAXTOKEN + 1];
50*4887Schin 
51*4887Schin 	state = (pp.state & ~DISABLE);
52*4887Schin 	PUSH_STRING(args);
53*4887Schin 	pptoken = pp.token;
54*4887Schin 	pp.token = file;
55*4887Schin 	pp.state |= HEADER|PASSEOF;
56*4887Schin 	type = pplex();
57*4887Schin 	pp.state &= ~HEADER;
58*4887Schin 	pp.token = pptoken;
59*4887Schin 	switch (type)
60*4887Schin 	{
61*4887Schin 	case T_STRING:
62*4887Schin 	case T_HEADER:
63*4887Schin 		break;
64*4887Schin 	default:
65*4887Schin 		error(1, "%s: \"...\" or <...> argument expected", pred);
66*4887Schin 		c = 0;
67*4887Schin 		goto done;
68*4887Schin 	}
69*4887Schin 	if (op == X_EXISTS)
70*4887Schin 	{
71*4887Schin 		if ((c = pplex()) == ',')
72*4887Schin 		{
73*4887Schin 			while ((c = pplex()) == T_STRING)
74*4887Schin 			{
75*4887Schin 				if (pathaccess(pp.path, pp.token, file, NiL, 0))
76*4887Schin 				{
77*4887Schin 					pathcanon(pp.path, 0);
78*4887Schin 					message((-2, "%s: %s found", pred, pp.path));
79*4887Schin 					c = 1;
80*4887Schin 					goto done;
81*4887Schin 				}
82*4887Schin 				if ((c = pplex()) != ',') break;
83*4887Schin 			}
84*4887Schin 			if (c) error(1, "%s: \"...\" arguments expected", pred);
85*4887Schin 			strcpy(pp.path, file);
86*4887Schin 			message((-2, "%s: %s not found", pred, file));
87*4887Schin 			c = 0;
88*4887Schin 		}
89*4887Schin 		else c = ppsearch(file, type, SEARCH_EXISTS) >= 0;
90*4887Schin 	}
91*4887Schin 	else
92*4887Schin 	{
93*4887Schin 		register struct ppfile*	fp;
94*4887Schin 
95*4887Schin 		fp = ppsetfile(file);
96*4887Schin 		c = fp->flags || fp->guard == INC_IGNORE;
97*4887Schin 	}
98*4887Schin  done:
99*4887Schin 	while (pplex());
100*4887Schin 	pp.state = state;
101*4887Schin 	return c;
102*4887Schin }
103*4887Schin 
104*4887Schin /*
105*4887Schin  * strcmp/match predicate evaluation
106*4887Schin  */
107*4887Schin 
108*4887Schin static int
109*4887Schin compare(char* pred, char* args, int match)
110*4887Schin {
111*4887Schin 	register int	c;
112*4887Schin 	char*		pptoken;
113*4887Schin 	long		state;
114*4887Schin 	regex_t		re;
115*4887Schin 	char		tmp[MAXTOKEN + 1];
116*4887Schin 
117*4887Schin 	state = (pp.state & ~DISABLE);
118*4887Schin 	PUSH_STRING(args);
119*4887Schin 	pp.state |= PASSEOF;
120*4887Schin 	pptoken = pp.token;
121*4887Schin 	pp.token = tmp;
122*4887Schin 	if (!pplex())
123*4887Schin 		goto bad;
124*4887Schin 	pp.token = pptoken;
125*4887Schin 	if (pplex() != ',' || !pplex())
126*4887Schin 		goto bad;
127*4887Schin 	if (!match)
128*4887Schin 		c = strcmp(tmp, pp.token);
129*4887Schin 	else if ((c = regcomp(&re, pp.token, REG_AUGMENTED|REG_LENIENT|REG_NULL)) || (c = regexec(&re, tmp, NiL, 0, 0)) && c != REG_NOMATCH)
130*4887Schin 		regfatal(&re, 3, c);
131*4887Schin 	else
132*4887Schin 	{
133*4887Schin 		c = !c;
134*4887Schin 		regfree(&re);
135*4887Schin 	}
136*4887Schin 	if ((pp.state & PASSEOF) && pplex())
137*4887Schin 		goto bad;
138*4887Schin 	pp.state = state;
139*4887Schin 	return c;
140*4887Schin  bad:
141*4887Schin 	pp.token = pptoken;
142*4887Schin 	error(2, "%s: 2 arguments expected", pred);
143*4887Schin 	while (pplex());
144*4887Schin 	pp.state = state;
145*4887Schin 	return 0;
146*4887Schin }
147*4887Schin 
148*4887Schin /*
149*4887Schin  * #if predicate parse and evaluation
150*4887Schin  */
151*4887Schin 
152*4887Schin static int
153*4887Schin predicate(int warn)
154*4887Schin {
155*4887Schin 	register char*			args;
156*4887Schin 	register struct pplist*		p;
157*4887Schin 	register struct ppsymbol*	sym;
158*4887Schin 	register int			type;
159*4887Schin 	int				index;
160*4887Schin 
161*4887Schin 	static char			pred[MAXID + 1];
162*4887Schin 
163*4887Schin 	/*
164*4887Schin 	 * first gather the args
165*4887Schin 	 */
166*4887Schin 
167*4887Schin 	index = (int)hashref(pp.strtab, pp.token);
168*4887Schin 	if (warn && peekchr() != '(') switch (index)
169*4887Schin 	{
170*4887Schin 	case X_DEFINED:
171*4887Schin 	case X_EXISTS:
172*4887Schin 	case X_INCLUDED:
173*4887Schin 	case X_MATCH:
174*4887Schin 	case X_NOTICED:
175*4887Schin 	case X_OPTION:
176*4887Schin 	case X_SIZEOF:
177*4887Schin 	case X_STRCMP:
178*4887Schin 		break;
179*4887Schin 	default:
180*4887Schin 		if (pp.macref) pprefmac(pp.token, REF_IF);
181*4887Schin 		return 0;
182*4887Schin 	}
183*4887Schin 	strcpy(pred, pp.token);
184*4887Schin 	pp.state |= DISABLE;
185*4887Schin 	type = pppredargs();
186*4887Schin 	pp.state &= ~DISABLE;
187*4887Schin 	switch (type)
188*4887Schin 	{
189*4887Schin 	case T_ID:
190*4887Schin 	case T_STRING:
191*4887Schin 		break;
192*4887Schin 	default:
193*4887Schin 		unlex(type);
194*4887Schin 		/*FALLTHROUGH*/
195*4887Schin 	case 0:
196*4887Schin 		if (index && !(pp.state & STRICT))
197*4887Schin 			error(1, "%s: predicate argument expected", pred);
198*4887Schin 		if (pp.macref) pprefmac(pred, REF_IF);
199*4887Schin 		return 0;
200*4887Schin 	}
201*4887Schin 	args = pp.args;
202*4887Schin 
203*4887Schin 	/*
204*4887Schin 	 * now evaluate
205*4887Schin 	 */
206*4887Schin 
207*4887Schin 	debug((-6, "pred=%s args=%s", pred, args));
208*4887Schin 	if ((pp.state & STRICT) && !(pp.mode & HOSTED)) switch (index)
209*4887Schin 	{
210*4887Schin 	case X_DEFINED:
211*4887Schin 	case X_SIZEOF:
212*4887Schin 		break;
213*4887Schin 	default:
214*4887Schin 		error(1, "%s(%s): non-standard predicate test", pred, args);
215*4887Schin 		return 0;
216*4887Schin 	}
217*4887Schin 	switch (index)
218*4887Schin 	{
219*4887Schin 	case X_DEFINED:
220*4887Schin 		if (type != T_ID) error(1, "%s: identifier argument expected", pred);
221*4887Schin 		else if ((sym = pprefmac(args, REF_IF)) && sym->macro) return 1;
222*4887Schin 		else if (args[0] == '_' && args[1] == '_' && !strncmp(args, "__STDPP__", 9))
223*4887Schin 		{
224*4887Schin 			if (pp.hosted == 1 && pp.in->prev->type == IN_FILE)
225*4887Schin 			{
226*4887Schin 				pp.mode |= HOSTED;
227*4887Schin 				pp.flags |= PP_hosted;
228*4887Schin 			}
229*4887Schin 			return *(args + 9) ? (int)hashref(pp.strtab, args + 9) : 1;
230*4887Schin 		}
231*4887Schin 		break;
232*4887Schin 	case X_EXISTS:
233*4887Schin 	case X_INCLUDED:
234*4887Schin 		return exists(index, pred, args);
235*4887Schin 	case X_MATCH:
236*4887Schin 	case X_STRCMP:
237*4887Schin 		return compare(pred, args, index == X_MATCH);
238*4887Schin 	case X_NOTICED:
239*4887Schin 		if (type != T_ID) error(1, "%s: identifier argument expected", pred);
240*4887Schin 		else if (((sym = pprefmac(args, REF_IF)) || (sym = ppsymref(pp.symtab, args))) && (sym->flags & SYM_NOTICED)) return 1;
241*4887Schin 		break;
242*4887Schin 	case X_OPTION:
243*4887Schin 		return ppoption(args);
244*4887Schin 	case X_SIZEOF:
245*4887Schin 		error(2, "%s invalid in #%s expressions", pred, dirname(IF));
246*4887Schin 		break;
247*4887Schin 	default:
248*4887Schin 		if (warn && !(pp.mode & HOSTED) && (sym = ppsymref(pp.symtab, pred)) && (sym->flags & SYM_PREDICATE))
249*4887Schin 			error(1, "use #%s(%s) to disambiguate", pred, args);
250*4887Schin 		if (p = (struct pplist*)hashget(pp.prdtab, pred))
251*4887Schin 		{
252*4887Schin 			if (!*args) return 1;
253*4887Schin 			while (p)
254*4887Schin 			{
255*4887Schin 				if (streq(p->value, args)) return 1;
256*4887Schin 				p = p->next;
257*4887Schin 			}
258*4887Schin 		}
259*4887Schin 		break;
260*4887Schin 	}
261*4887Schin 	return 0;
262*4887Schin }
263*4887Schin 
264*4887Schin /*
265*4887Schin  * evaluate a long integer subexpression with precedence
266*4887Schin  * taken from the library routine streval()
267*4887Schin  * may be called recursively
268*4887Schin  *
269*4887Schin  * NOTE: all operands are evaluated as both the parse
270*4887Schin  *	 and evaluation are done on the fly
271*4887Schin  */
272*4887Schin 
273*4887Schin static long
274*4887Schin subexpr(register int precedence, int* pun)
275*4887Schin {
276*4887Schin 	register int		c;
277*4887Schin 	register long		n;
278*4887Schin 	register long		x;
279*4887Schin 	register int		operand = 1;
280*4887Schin 	int			un = 0;
281*4887Schin 	int			xn;
282*4887Schin 
283*4887Schin 	switch (lex(c))
284*4887Schin 	{
285*4887Schin 	case 0:
286*4887Schin 	case '\n':
287*4887Schin 		unlex(c);
288*4887Schin 		if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "more tokens expected";
289*4887Schin 		return 0;
290*4887Schin 	case '-':
291*4887Schin 		n = -subexpr(13, &un);
292*4887Schin 		break;
293*4887Schin 	case '+':
294*4887Schin 		n = subexpr(13, &un);
295*4887Schin 		break;
296*4887Schin 	case '!':
297*4887Schin 		n = !subexpr(13, &un);
298*4887Schin 		break;
299*4887Schin 	case '~':
300*4887Schin 		n = ~subexpr(13, &un);
301*4887Schin 		break;
302*4887Schin 	default:
303*4887Schin 		unlex(c);
304*4887Schin 		n = 0;
305*4887Schin 		operand = 0;
306*4887Schin 		break;
307*4887Schin 	}
308*4887Schin 	un <<= 1;
309*4887Schin 	for (;;)
310*4887Schin 	{
311*4887Schin 		switch (lex(c))
312*4887Schin 		{
313*4887Schin 		case 0:
314*4887Schin 		case '\n':
315*4887Schin 			goto done;
316*4887Schin 		case ')':
317*4887Schin 			if (!precedence)
318*4887Schin 			{
319*4887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "too many )'s";
320*4887Schin 				return 0;
321*4887Schin 			}
322*4887Schin 			goto done;
323*4887Schin 		case '(':
324*4887Schin 			n = subexpr(1, &un);
325*4887Schin 			if (lex(c) != ')')
326*4887Schin 			{
327*4887Schin 				unlex(c);
328*4887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "closing ) expected";
329*4887Schin 				return 0;
330*4887Schin 			}
331*4887Schin 		gotoperand:
332*4887Schin 			if (operand)
333*4887Schin 			{
334*4887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operator expected";
335*4887Schin 				return 0;
336*4887Schin 			}
337*4887Schin 			operand = 1;
338*4887Schin 			un <<= 1;
339*4887Schin 			continue;
340*4887Schin 		case '?':
341*4887Schin 			if (precedence > 1) goto done;
342*4887Schin 			un = 0;
343*4887Schin 			if (lex(c) == ':')
344*4887Schin 			{
345*4887Schin 				if (!n) n = subexpr(2, &un);
346*4887Schin 				else
347*4887Schin 				{
348*4887Schin 					x = pp.mode;
349*4887Schin 					pp.mode |= INACTIVE;
350*4887Schin 					subexpr(2, &xn);
351*4887Schin 					pp.mode = x;
352*4887Schin 				}
353*4887Schin 			}
354*4887Schin 			else
355*4887Schin 			{
356*4887Schin 				unlex(c);
357*4887Schin 				x = subexpr(2, &xn);
358*4887Schin 				if (lex(c) != ':')
359*4887Schin 				{
360*4887Schin 					unlex(c);
361*4887Schin 					if (!errmsg && !(pp.mode & INACTIVE)) errmsg = ": expected for ? operator";
362*4887Schin 					return 0;
363*4887Schin 				}
364*4887Schin 				if (n)
365*4887Schin 				{
366*4887Schin 					n = x;
367*4887Schin 					un = xn;
368*4887Schin 					subexpr(2, &xn);
369*4887Schin 				}
370*4887Schin 				else n = subexpr(2, &un);
371*4887Schin 			}
372*4887Schin 			break;
373*4887Schin 		case ':':
374*4887Schin 			goto done;
375*4887Schin 		case T_ANDAND:
376*4887Schin 		case T_OROR:
377*4887Schin 			xn = (c == T_ANDAND) ? 4 : 3;
378*4887Schin 			if (precedence >= xn) goto done;
379*4887Schin 			if ((n != 0) == (c == T_ANDAND)) n = subexpr(xn, &un) != 0;
380*4887Schin 			else
381*4887Schin 			{
382*4887Schin 				x = pp.mode;
383*4887Schin 				pp.mode |= INACTIVE;
384*4887Schin 				subexpr(xn, &un);
385*4887Schin 				pp.mode = x;
386*4887Schin 			}
387*4887Schin 			un = 0;
388*4887Schin 			break;
389*4887Schin 		case '|':
390*4887Schin 			if (precedence > 4) goto done;
391*4887Schin 			n |= subexpr(5, &un);
392*4887Schin 			break;
393*4887Schin 		case '^':
394*4887Schin 			if (precedence > 5) goto done;
395*4887Schin 			n ^= subexpr(6, &un);
396*4887Schin 			break;
397*4887Schin 		case '&':
398*4887Schin 			if (precedence > 6) goto done;
399*4887Schin 			n &= subexpr(7, &un);
400*4887Schin 			break;
401*4887Schin 		case T_EQ:
402*4887Schin 		case T_NE:
403*4887Schin 			if (precedence > 7) goto done;
404*4887Schin 			n = (n == subexpr(8, &un)) == (c == T_EQ);
405*4887Schin 			un = 0;
406*4887Schin 			break;
407*4887Schin 		case '<':
408*4887Schin 		case T_LE:
409*4887Schin 		case T_GE:
410*4887Schin 		case '>':
411*4887Schin 			if (precedence > 8) goto done;
412*4887Schin 			x = subexpr(9, &un);
413*4887Schin 			switch (c)
414*4887Schin 			{
415*4887Schin 			case '<':
416*4887Schin 				switch (un)
417*4887Schin 				{
418*4887Schin 				case 01:
419*4887Schin 					n = n < (unsigned long)x;
420*4887Schin 					break;
421*4887Schin 				case 02:
422*4887Schin 					n = (unsigned long)n < x;
423*4887Schin 					break;
424*4887Schin 				case 03:
425*4887Schin 					n = (unsigned long)n < (unsigned long)x;
426*4887Schin 					break;
427*4887Schin 				default:
428*4887Schin 					n = n < x;
429*4887Schin 					break;
430*4887Schin 				}
431*4887Schin 				break;
432*4887Schin 			case T_LE:
433*4887Schin 				switch (un)
434*4887Schin 				{
435*4887Schin 				case 01:
436*4887Schin 					n = n <= (unsigned long)x;
437*4887Schin 					break;
438*4887Schin 				case 02:
439*4887Schin 					n = (unsigned long)n <= x;
440*4887Schin 					break;
441*4887Schin 				case 03:
442*4887Schin 					n = (unsigned long)n <= (unsigned long)x;
443*4887Schin 					break;
444*4887Schin 				default:
445*4887Schin 					n = n <= x;
446*4887Schin 					break;
447*4887Schin 				}
448*4887Schin 				break;
449*4887Schin 			case T_GE:
450*4887Schin 				switch (un)
451*4887Schin 				{
452*4887Schin 				case 01:
453*4887Schin 					n = n >= (unsigned long)x;
454*4887Schin 					break;
455*4887Schin 				case 02:
456*4887Schin 					n = (unsigned long)n >= x;
457*4887Schin 					break;
458*4887Schin 				case 03:
459*4887Schin 					n = (unsigned long)n >= (unsigned long)x;
460*4887Schin 					break;
461*4887Schin 				default:
462*4887Schin 					n = n >= x;
463*4887Schin 					break;
464*4887Schin 				}
465*4887Schin 				break;
466*4887Schin 			case '>':
467*4887Schin 				switch (un)
468*4887Schin 				{
469*4887Schin 				case 01:
470*4887Schin 					n = n > (unsigned long)x;
471*4887Schin 					break;
472*4887Schin 				case 02:
473*4887Schin 					n = (unsigned long)n > x;
474*4887Schin 					break;
475*4887Schin 				case 03:
476*4887Schin 					n = (unsigned long)n > (unsigned long)x;
477*4887Schin 					break;
478*4887Schin 				default:
479*4887Schin 					n = n > x;
480*4887Schin 					break;
481*4887Schin 				}
482*4887Schin 				break;
483*4887Schin 			}
484*4887Schin 			un = 0;
485*4887Schin 			break;
486*4887Schin 		case T_LSHIFT:
487*4887Schin 		case T_RSHIFT:
488*4887Schin 			if (precedence > 9) goto done;
489*4887Schin 			x = subexpr(10, &un);
490*4887Schin 			if (c == T_LSHIFT) n <<= x;
491*4887Schin 			else n >>= x;
492*4887Schin 			un >>= 1;
493*4887Schin 			break;
494*4887Schin 		case '+':
495*4887Schin 		case '-':
496*4887Schin 			if (precedence > 10) goto done;
497*4887Schin 			x = subexpr(11, &un);
498*4887Schin 			if (c == '+') n += x;
499*4887Schin 			else n -= x;
500*4887Schin 			break;
501*4887Schin 		case '*':
502*4887Schin 		case '/':
503*4887Schin 		case '%':
504*4887Schin 			if (precedence > 11) goto done;
505*4887Schin 			x = subexpr(12, &un);
506*4887Schin 			if (c == '*') n *= x;
507*4887Schin 			else if (x == 0)
508*4887Schin 			{
509*4887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "divide by zero";
510*4887Schin 				return 0;
511*4887Schin 			}
512*4887Schin 			else if (c == '/') n /= x;
513*4887Schin 			else n %= x;
514*4887Schin 			break;
515*4887Schin 		case '#':
516*4887Schin 			pp.state |= DISABLE;
517*4887Schin 			c = pplex();
518*4887Schin 			pp.state &= ~DISABLE;
519*4887Schin 			if (c != T_ID)
520*4887Schin 			{
521*4887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "# must precede a predicate identifier";
522*4887Schin 				return 0;
523*4887Schin 			}
524*4887Schin 			n = predicate(0);
525*4887Schin 			goto gotoperand;
526*4887Schin 		case T_ID:
527*4887Schin 			n = predicate(1);
528*4887Schin 			goto gotoperand;
529*4887Schin 		case T_CHARCONST:
530*4887Schin 			c = *(pp.toknxt - 1);
531*4887Schin 			*(pp.toknxt - 1) = 0;
532*4887Schin 			n = chrtoi(pp.token + 1);
533*4887Schin 			*(pp.toknxt - 1) = c;
534*4887Schin 			if (n & ~((1<<CHAR_BIT)-1))
535*4887Schin 			{
536*4887Schin 				if (!(pp.mode & HOSTED))
537*4887Schin 					error(1, "'%s': multi-character character constants are not portable", pp.token);
538*4887Schin 			}
539*4887Schin #if CHAR_MIN < 0
540*4887Schin 			else n = (char)n;
541*4887Schin #endif
542*4887Schin 			goto gotoperand;
543*4887Schin 		case T_DECIMAL_U:
544*4887Schin 		case T_DECIMAL_UL:
545*4887Schin 		case T_OCTAL_U:
546*4887Schin 		case T_OCTAL_UL:
547*4887Schin 		case T_HEXADECIMAL_U:
548*4887Schin 		case T_HEXADECIMAL_UL:
549*4887Schin 			un |= 01;
550*4887Schin 			/*FALLTHROUGH*/
551*4887Schin 		case T_DECIMAL:
552*4887Schin 		case T_DECIMAL_L:
553*4887Schin 		case T_OCTAL:
554*4887Schin 		case T_OCTAL_L:
555*4887Schin 		case T_HEXADECIMAL:
556*4887Schin 		case T_HEXADECIMAL_L:
557*4887Schin 			n = strtoul(pp.token, NiL, 0);
558*4887Schin 			if ((unsigned long)n > LONG_MAX) un |= 01;
559*4887Schin 			goto gotoperand;
560*4887Schin 		case T_WCHARCONST:
561*4887Schin 			n = chrtoi(pp.token);
562*4887Schin 			goto gotoperand;
563*4887Schin 		default:
564*4887Schin 			if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid token";
565*4887Schin 			return 0;
566*4887Schin 		}
567*4887Schin 		if (errmsg) return 0;
568*4887Schin 		if (!operand) goto nooperand;
569*4887Schin 	}
570*4887Schin  done:
571*4887Schin 	unlex(c);
572*4887Schin 	if (!operand)
573*4887Schin 	{
574*4887Schin 	nooperand:
575*4887Schin 		if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operand expected";
576*4887Schin 		return 0;
577*4887Schin 	}
578*4887Schin 	if (un) *pun |= 01;
579*4887Schin 	return n;
580*4887Schin }
581*4887Schin 
582*4887Schin /*
583*4887Schin  * preprocessor expression evaluator using modified streval(3)
584*4887Schin  * *pun!=0 if result is unsigned
585*4887Schin  */
586*4887Schin 
587*4887Schin long
588*4887Schin ppexpr(int* pun)
589*4887Schin {
590*4887Schin 	long	n;
591*4887Schin 	int	opeektoken;
592*4887Schin 	long	ppstate;
593*4887Schin 
594*4887Schin 	ppstate = (pp.state & (CONDITIONAL|DISABLE|NOSPACE|STRIP));
595*4887Schin 	pp.state &= ~(DISABLE|STRIP);
596*4887Schin 	pp.state |= CONDITIONAL|NOSPACE;
597*4887Schin 	opeektoken = peektoken;
598*4887Schin 	peektoken = -1;
599*4887Schin 	*pun = 0;
600*4887Schin 	n = subexpr(0, pun);
601*4887Schin 	if (peektoken == ':' && !errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid use of :";
602*4887Schin 	if (errmsg)
603*4887Schin 	{
604*4887Schin 		error(2, "%s in expression", errmsg);
605*4887Schin 		errmsg = 0;
606*4887Schin 		n = 0;
607*4887Schin 	}
608*4887Schin 	peektoken = opeektoken;
609*4887Schin 	pp.state &= ~(CONDITIONAL|NOSPACE);
610*4887Schin 	pp.state |= ppstate;
611*4887Schin 	if (*pun) debug((-4, "ppexpr() = %luU", n));
612*4887Schin 	else debug((-4, "ppexpr() = %ld", n));
613*4887Schin 	return n;
614*4887Schin }
615*4887Schin 
616*4887Schin /*
617*4887Schin  * return non-zero if option s is set
618*4887Schin  */
619*4887Schin 
620*4887Schin int
621*4887Schin ppoption(char* s)
622*4887Schin {
623*4887Schin 	switch ((int)hashget(pp.strtab, s))
624*4887Schin 	{
625*4887Schin 	case X_ALLMULTIPLE:
626*4887Schin 		return pp.mode & ALLMULTIPLE;
627*4887Schin 	case X_BUILTIN:
628*4887Schin 		return pp.mode & BUILTIN;
629*4887Schin 	case X_CATLITERAL:
630*4887Schin 		return pp.mode & CATLITERAL;
631*4887Schin 	case X_COMPATIBILITY:
632*4887Schin 		return pp.state & COMPATIBILITY;
633*4887Schin 	case X_DEBUG:
634*4887Schin 		return -error_info.trace;
635*4887Schin 	case X_ELSEIF:
636*4887Schin 		return pp.option & ELSEIF;
637*4887Schin 	case X_FINAL:
638*4887Schin 		return pp.option & FINAL;
639*4887Schin 	case X_HOSTDIR:
640*4887Schin 		return pp.mode & HOSTED;
641*4887Schin 	case X_HOSTED:
642*4887Schin 		return pp.flags & PP_hosted;
643*4887Schin 	case X_INITIAL:
644*4887Schin 		return pp.option & INITIAL;
645*4887Schin 	case X_KEYARGS:
646*4887Schin 		return pp.option & KEYARGS;
647*4887Schin 	case X_LINEBASE:
648*4887Schin 		return pp.flags & PP_linebase;
649*4887Schin 	case X_LINEFILE:
650*4887Schin 		return pp.flags & PP_linefile;
651*4887Schin 	case X_LINETYPE:
652*4887Schin 		return pp.flags & PP_linetype;
653*4887Schin 	case X_PLUSCOMMENT:
654*4887Schin 		return pp.option & PLUSCOMMENT;
655*4887Schin 	case X_PLUSPLUS:
656*4887Schin 		return pp.option & PLUSPLUS;
657*4887Schin 	case X_PLUSSPLICE:
658*4887Schin 		return pp.option & PLUSSPLICE;
659*4887Schin 	case X_PRAGMAEXPAND:
660*4887Schin 		return pp.option & PRAGMAEXPAND;
661*4887Schin 	case X_PREDEFINED:
662*4887Schin 		return pp.option & PREDEFINED;
663*4887Schin 	case X_PREFIX:
664*4887Schin 		return pp.option & PREFIX;
665*4887Schin 	case X_PROTOTYPED:
666*4887Schin 		return pp.option & PROTOTYPED;
667*4887Schin 	case X_READONLY:
668*4887Schin 		return pp.mode & READONLY;
669*4887Schin 	case X_REGUARD:
670*4887Schin 		return pp.option & REGUARD;
671*4887Schin 	case X_SPACEOUT:
672*4887Schin 		return pp.state & SPACEOUT;
673*4887Schin 	case X_SPLICECAT:
674*4887Schin 		return pp.option & SPLICECAT;
675*4887Schin 	case X_SPLICESPACE:
676*4887Schin 		return pp.option & SPLICESPACE;
677*4887Schin 	case X_STRICT:
678*4887Schin 		return pp.state & STRICT;
679*4887Schin 	case X_STRINGSPAN:
680*4887Schin 		return pp.option & STRINGSPAN;
681*4887Schin 	case X_STRINGSPLIT:
682*4887Schin 		return pp.option & STRINGSPLIT;
683*4887Schin 	case X_TEST:
684*4887Schin 		return pp.test;
685*4887Schin 	case X_TEXT:
686*4887Schin 		return !(pp.state & NOTEXT);
687*4887Schin 	case X_TRANSITION:
688*4887Schin 		return pp.state & TRANSITION;
689*4887Schin 	case X_TRUNCATE:
690*4887Schin 		return pp.truncate;
691*4887Schin 	case X_WARN:
692*4887Schin 		return pp.state & WARN;
693*4887Schin 	default:
694*4887Schin 		if (pp.state & WARN) error(1, "%s: unknown option name", s);
695*4887Schin 		return 0;
696*4887Schin 	}
697*4887Schin }
698