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