xref: /onnv-gate/usr/src/lib/libpp/common/ppexpr.c (revision 10898)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1986-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * Glenn Fowler
234887Schin  * AT&T Research
244887Schin  *
254887Schin  * preprocessor expression evaluation support
264887Schin  */
274887Schin 
284887Schin #include "pplib.h"
294887Schin 
304887Schin #include <regex.h>
314887Schin 
324887Schin #define lex(c)		((((c)=peektoken)>=0?(peektoken=(-1)):((c)=pplex())),(c))
334887Schin #define unlex(c)	(peektoken=(c))
344887Schin 
354887Schin static int		peektoken;	/* expression lookahead token	*/
364887Schin static char*		errmsg;		/* subexpr() error message	*/
374887Schin 
384887Schin /*
394887Schin  * exists predicate evaluation
404887Schin  */
414887Schin 
424887Schin static int
434887Schin exists(int op, char* pred, register char* args)
444887Schin {
454887Schin 	register int	c;
464887Schin 	register int	type;
474887Schin 	char*		pptoken;
484887Schin 	long		state;
494887Schin 	char		file[MAXTOKEN + 1];
504887Schin 
514887Schin 	state = (pp.state & ~DISABLE);
524887Schin 	PUSH_STRING(args);
534887Schin 	pptoken = pp.token;
544887Schin 	pp.token = file;
554887Schin 	pp.state |= HEADER|PASSEOF;
564887Schin 	type = pplex();
574887Schin 	pp.state &= ~HEADER;
584887Schin 	pp.token = pptoken;
594887Schin 	switch (type)
604887Schin 	{
614887Schin 	case T_STRING:
624887Schin 	case T_HEADER:
634887Schin 		break;
644887Schin 	default:
654887Schin 		error(1, "%s: \"...\" or <...> argument expected", pred);
664887Schin 		c = 0;
674887Schin 		goto done;
684887Schin 	}
694887Schin 	if (op == X_EXISTS)
704887Schin 	{
714887Schin 		if ((c = pplex()) == ',')
724887Schin 		{
734887Schin 			while ((c = pplex()) == T_STRING)
744887Schin 			{
754887Schin 				if (pathaccess(pp.path, pp.token, file, NiL, 0))
764887Schin 				{
774887Schin 					pathcanon(pp.path, 0);
784887Schin 					message((-2, "%s: %s found", pred, pp.path));
794887Schin 					c = 1;
804887Schin 					goto done;
814887Schin 				}
824887Schin 				if ((c = pplex()) != ',') break;
834887Schin 			}
844887Schin 			if (c) error(1, "%s: \"...\" arguments expected", pred);
854887Schin 			strcpy(pp.path, file);
864887Schin 			message((-2, "%s: %s not found", pred, file));
874887Schin 			c = 0;
884887Schin 		}
894887Schin 		else c = ppsearch(file, type, SEARCH_EXISTS) >= 0;
904887Schin 	}
914887Schin 	else
924887Schin 	{
934887Schin 		register struct ppfile*	fp;
944887Schin 
954887Schin 		fp = ppsetfile(file);
964887Schin 		c = fp->flags || fp->guard == INC_IGNORE;
974887Schin 	}
984887Schin  done:
994887Schin 	while (pplex());
1004887Schin 	pp.state = state;
1014887Schin 	return c;
1024887Schin }
1034887Schin 
1044887Schin /*
1054887Schin  * strcmp/match predicate evaluation
1064887Schin  */
1074887Schin 
1084887Schin static int
1094887Schin compare(char* pred, char* args, int match)
1104887Schin {
1114887Schin 	register int	c;
1124887Schin 	char*		pptoken;
1134887Schin 	long		state;
1144887Schin 	regex_t		re;
1154887Schin 	char		tmp[MAXTOKEN + 1];
1164887Schin 
1174887Schin 	state = (pp.state & ~DISABLE);
1184887Schin 	PUSH_STRING(args);
1194887Schin 	pp.state |= PASSEOF;
1204887Schin 	pptoken = pp.token;
1214887Schin 	pp.token = tmp;
1224887Schin 	if (!pplex())
1234887Schin 		goto bad;
1244887Schin 	pp.token = pptoken;
1254887Schin 	if (pplex() != ',' || !pplex())
1264887Schin 		goto bad;
1274887Schin 	if (!match)
1284887Schin 		c = strcmp(tmp, pp.token);
1294887Schin 	else if ((c = regcomp(&re, pp.token, REG_AUGMENTED|REG_LENIENT|REG_NULL)) || (c = regexec(&re, tmp, NiL, 0, 0)) && c != REG_NOMATCH)
1304887Schin 		regfatal(&re, 3, c);
1314887Schin 	else
1324887Schin 	{
1334887Schin 		c = !c;
1344887Schin 		regfree(&re);
1354887Schin 	}
1364887Schin 	if ((pp.state & PASSEOF) && pplex())
1374887Schin 		goto bad;
1384887Schin 	pp.state = state;
1394887Schin 	return c;
1404887Schin  bad:
1414887Schin 	pp.token = pptoken;
1424887Schin 	error(2, "%s: 2 arguments expected", pred);
1434887Schin 	while (pplex());
1444887Schin 	pp.state = state;
1454887Schin 	return 0;
1464887Schin }
1474887Schin 
1484887Schin /*
1494887Schin  * #if predicate parse and evaluation
1504887Schin  */
1514887Schin 
1524887Schin static int
1534887Schin predicate(int warn)
1544887Schin {
1554887Schin 	register char*			args;
1564887Schin 	register struct pplist*		p;
1574887Schin 	register struct ppsymbol*	sym;
1584887Schin 	register int			type;
1594887Schin 	int				index;
1604887Schin 
1614887Schin 	static char			pred[MAXID + 1];
1624887Schin 
1634887Schin 	/*
1644887Schin 	 * first gather the args
1654887Schin 	 */
1664887Schin 
1674887Schin 	index = (int)hashref(pp.strtab, pp.token);
1684887Schin 	if (warn && peekchr() != '(') switch (index)
1694887Schin 	{
1704887Schin 	case X_DEFINED:
1714887Schin 	case X_EXISTS:
1724887Schin 	case X_INCLUDED:
1734887Schin 	case X_MATCH:
1744887Schin 	case X_NOTICED:
1754887Schin 	case X_OPTION:
1764887Schin 	case X_SIZEOF:
1774887Schin 	case X_STRCMP:
1784887Schin 		break;
1794887Schin 	default:
1804887Schin 		if (pp.macref) pprefmac(pp.token, REF_IF);
1814887Schin 		return 0;
1824887Schin 	}
1834887Schin 	strcpy(pred, pp.token);
1844887Schin 	pp.state |= DISABLE;
1854887Schin 	type = pppredargs();
1864887Schin 	pp.state &= ~DISABLE;
1874887Schin 	switch (type)
1884887Schin 	{
1894887Schin 	case T_ID:
1904887Schin 	case T_STRING:
1914887Schin 		break;
1924887Schin 	default:
1934887Schin 		unlex(type);
1944887Schin 		/*FALLTHROUGH*/
1954887Schin 	case 0:
1964887Schin 		if (index && !(pp.state & STRICT))
1974887Schin 			error(1, "%s: predicate argument expected", pred);
1984887Schin 		if (pp.macref) pprefmac(pred, REF_IF);
1994887Schin 		return 0;
2004887Schin 	}
2014887Schin 	args = pp.args;
2024887Schin 
2034887Schin 	/*
2044887Schin 	 * now evaluate
2054887Schin 	 */
2064887Schin 
2074887Schin 	debug((-6, "pred=%s args=%s", pred, args));
2084887Schin 	if ((pp.state & STRICT) && !(pp.mode & HOSTED)) switch (index)
2094887Schin 	{
2104887Schin 	case X_DEFINED:
2114887Schin 	case X_SIZEOF:
2124887Schin 		break;
2134887Schin 	default:
2144887Schin 		error(1, "%s(%s): non-standard predicate test", pred, args);
2154887Schin 		return 0;
2164887Schin 	}
2174887Schin 	switch (index)
2184887Schin 	{
2194887Schin 	case X_DEFINED:
2204887Schin 		if (type != T_ID) error(1, "%s: identifier argument expected", pred);
2214887Schin 		else if ((sym = pprefmac(args, REF_IF)) && sym->macro) return 1;
2224887Schin 		else if (args[0] == '_' && args[1] == '_' && !strncmp(args, "__STDPP__", 9))
2234887Schin 		{
2244887Schin 			if (pp.hosted == 1 && pp.in->prev->type == IN_FILE)
2254887Schin 			{
2264887Schin 				pp.mode |= HOSTED;
2274887Schin 				pp.flags |= PP_hosted;
2284887Schin 			}
2294887Schin 			return *(args + 9) ? (int)hashref(pp.strtab, args + 9) : 1;
2304887Schin 		}
2314887Schin 		break;
2324887Schin 	case X_EXISTS:
2334887Schin 	case X_INCLUDED:
2344887Schin 		return exists(index, pred, args);
2354887Schin 	case X_MATCH:
2364887Schin 	case X_STRCMP:
2374887Schin 		return compare(pred, args, index == X_MATCH);
2384887Schin 	case X_NOTICED:
2394887Schin 		if (type != T_ID) error(1, "%s: identifier argument expected", pred);
2404887Schin 		else if (((sym = pprefmac(args, REF_IF)) || (sym = ppsymref(pp.symtab, args))) && (sym->flags & SYM_NOTICED)) return 1;
2414887Schin 		break;
2424887Schin 	case X_OPTION:
2434887Schin 		return ppoption(args);
2444887Schin 	case X_SIZEOF:
2454887Schin 		error(2, "%s invalid in #%s expressions", pred, dirname(IF));
2464887Schin 		break;
2474887Schin 	default:
2484887Schin 		if (warn && !(pp.mode & HOSTED) && (sym = ppsymref(pp.symtab, pred)) && (sym->flags & SYM_PREDICATE))
2494887Schin 			error(1, "use #%s(%s) to disambiguate", pred, args);
2504887Schin 		if (p = (struct pplist*)hashget(pp.prdtab, pred))
2514887Schin 		{
2524887Schin 			if (!*args) return 1;
2534887Schin 			while (p)
2544887Schin 			{
2554887Schin 				if (streq(p->value, args)) return 1;
2564887Schin 				p = p->next;
2574887Schin 			}
2584887Schin 		}
2594887Schin 		break;
2604887Schin 	}
2614887Schin 	return 0;
2624887Schin }
2634887Schin 
2644887Schin /*
2654887Schin  * evaluate a long integer subexpression with precedence
2664887Schin  * taken from the library routine streval()
2674887Schin  * may be called recursively
2684887Schin  *
2694887Schin  * NOTE: all operands are evaluated as both the parse
2704887Schin  *	 and evaluation are done on the fly
2714887Schin  */
2724887Schin 
2734887Schin static long
2744887Schin subexpr(register int precedence, int* pun)
2754887Schin {
2764887Schin 	register int		c;
2774887Schin 	register long		n;
2784887Schin 	register long		x;
2794887Schin 	register int		operand = 1;
2804887Schin 	int			un = 0;
2814887Schin 	int			xn;
2824887Schin 
2834887Schin 	switch (lex(c))
2844887Schin 	{
2854887Schin 	case 0:
2864887Schin 	case '\n':
2874887Schin 		unlex(c);
2884887Schin 		if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "more tokens expected";
2894887Schin 		return 0;
2904887Schin 	case '-':
2914887Schin 		n = -subexpr(13, &un);
2924887Schin 		break;
2934887Schin 	case '+':
2944887Schin 		n = subexpr(13, &un);
2954887Schin 		break;
2964887Schin 	case '!':
2974887Schin 		n = !subexpr(13, &un);
2984887Schin 		break;
2994887Schin 	case '~':
3004887Schin 		n = ~subexpr(13, &un);
3014887Schin 		break;
3024887Schin 	default:
3034887Schin 		unlex(c);
3044887Schin 		n = 0;
3054887Schin 		operand = 0;
3064887Schin 		break;
3074887Schin 	}
3084887Schin 	un <<= 1;
3094887Schin 	for (;;)
3104887Schin 	{
3114887Schin 		switch (lex(c))
3124887Schin 		{
3134887Schin 		case 0:
3144887Schin 		case '\n':
3154887Schin 			goto done;
3164887Schin 		case ')':
3174887Schin 			if (!precedence)
3184887Schin 			{
3194887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "too many )'s";
3204887Schin 				return 0;
3214887Schin 			}
3224887Schin 			goto done;
3234887Schin 		case '(':
3244887Schin 			n = subexpr(1, &un);
3254887Schin 			if (lex(c) != ')')
3264887Schin 			{
3274887Schin 				unlex(c);
3284887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "closing ) expected";
3294887Schin 				return 0;
3304887Schin 			}
3314887Schin 		gotoperand:
3324887Schin 			if (operand)
3334887Schin 			{
3344887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operator expected";
3354887Schin 				return 0;
3364887Schin 			}
3374887Schin 			operand = 1;
3384887Schin 			un <<= 1;
3394887Schin 			continue;
3404887Schin 		case '?':
3414887Schin 			if (precedence > 1) goto done;
3424887Schin 			un = 0;
3434887Schin 			if (lex(c) == ':')
3444887Schin 			{
3454887Schin 				if (!n) n = subexpr(2, &un);
3464887Schin 				else
3474887Schin 				{
3484887Schin 					x = pp.mode;
3494887Schin 					pp.mode |= INACTIVE;
3504887Schin 					subexpr(2, &xn);
3514887Schin 					pp.mode = x;
3524887Schin 				}
3534887Schin 			}
3544887Schin 			else
3554887Schin 			{
3564887Schin 				unlex(c);
3574887Schin 				x = subexpr(2, &xn);
3584887Schin 				if (lex(c) != ':')
3594887Schin 				{
3604887Schin 					unlex(c);
3614887Schin 					if (!errmsg && !(pp.mode & INACTIVE)) errmsg = ": expected for ? operator";
3624887Schin 					return 0;
3634887Schin 				}
3644887Schin 				if (n)
3654887Schin 				{
3664887Schin 					n = x;
3674887Schin 					un = xn;
3684887Schin 					subexpr(2, &xn);
3694887Schin 				}
3704887Schin 				else n = subexpr(2, &un);
3714887Schin 			}
3724887Schin 			break;
3734887Schin 		case ':':
3744887Schin 			goto done;
3754887Schin 		case T_ANDAND:
3764887Schin 		case T_OROR:
3774887Schin 			xn = (c == T_ANDAND) ? 4 : 3;
3784887Schin 			if (precedence >= xn) goto done;
3794887Schin 			if ((n != 0) == (c == T_ANDAND)) n = subexpr(xn, &un) != 0;
3804887Schin 			else
3814887Schin 			{
3824887Schin 				x = pp.mode;
3834887Schin 				pp.mode |= INACTIVE;
3844887Schin 				subexpr(xn, &un);
3854887Schin 				pp.mode = x;
3864887Schin 			}
3874887Schin 			un = 0;
3884887Schin 			break;
3894887Schin 		case '|':
3904887Schin 			if (precedence > 4) goto done;
3914887Schin 			n |= subexpr(5, &un);
3924887Schin 			break;
3934887Schin 		case '^':
3944887Schin 			if (precedence > 5) goto done;
3954887Schin 			n ^= subexpr(6, &un);
3964887Schin 			break;
3974887Schin 		case '&':
3984887Schin 			if (precedence > 6) goto done;
3994887Schin 			n &= subexpr(7, &un);
4004887Schin 			break;
4014887Schin 		case T_EQ:
4024887Schin 		case T_NE:
4034887Schin 			if (precedence > 7) goto done;
4044887Schin 			n = (n == subexpr(8, &un)) == (c == T_EQ);
4054887Schin 			un = 0;
4064887Schin 			break;
4074887Schin 		case '<':
4084887Schin 		case T_LE:
4094887Schin 		case T_GE:
4104887Schin 		case '>':
4114887Schin 			if (precedence > 8) goto done;
4124887Schin 			x = subexpr(9, &un);
4134887Schin 			switch (c)
4144887Schin 			{
4154887Schin 			case '<':
4164887Schin 				switch (un)
4174887Schin 				{
4184887Schin 				case 01:
4194887Schin 					n = n < (unsigned long)x;
4204887Schin 					break;
4214887Schin 				case 02:
4224887Schin 					n = (unsigned long)n < x;
4234887Schin 					break;
4244887Schin 				case 03:
4254887Schin 					n = (unsigned long)n < (unsigned long)x;
4264887Schin 					break;
4274887Schin 				default:
4284887Schin 					n = n < x;
4294887Schin 					break;
4304887Schin 				}
4314887Schin 				break;
4324887Schin 			case T_LE:
4334887Schin 				switch (un)
4344887Schin 				{
4354887Schin 				case 01:
4364887Schin 					n = n <= (unsigned long)x;
4374887Schin 					break;
4384887Schin 				case 02:
4394887Schin 					n = (unsigned long)n <= x;
4404887Schin 					break;
4414887Schin 				case 03:
4424887Schin 					n = (unsigned long)n <= (unsigned long)x;
4434887Schin 					break;
4444887Schin 				default:
4454887Schin 					n = n <= x;
4464887Schin 					break;
4474887Schin 				}
4484887Schin 				break;
4494887Schin 			case T_GE:
4504887Schin 				switch (un)
4514887Schin 				{
4524887Schin 				case 01:
4534887Schin 					n = n >= (unsigned long)x;
4544887Schin 					break;
4554887Schin 				case 02:
4564887Schin 					n = (unsigned long)n >= x;
4574887Schin 					break;
4584887Schin 				case 03:
4594887Schin 					n = (unsigned long)n >= (unsigned long)x;
4604887Schin 					break;
4614887Schin 				default:
4624887Schin 					n = n >= x;
4634887Schin 					break;
4644887Schin 				}
4654887Schin 				break;
4664887Schin 			case '>':
4674887Schin 				switch (un)
4684887Schin 				{
4694887Schin 				case 01:
4704887Schin 					n = n > (unsigned long)x;
4714887Schin 					break;
4724887Schin 				case 02:
4734887Schin 					n = (unsigned long)n > x;
4744887Schin 					break;
4754887Schin 				case 03:
4764887Schin 					n = (unsigned long)n > (unsigned long)x;
4774887Schin 					break;
4784887Schin 				default:
4794887Schin 					n = n > x;
4804887Schin 					break;
4814887Schin 				}
4824887Schin 				break;
4834887Schin 			}
4844887Schin 			un = 0;
4854887Schin 			break;
4864887Schin 		case T_LSHIFT:
4874887Schin 		case T_RSHIFT:
4884887Schin 			if (precedence > 9) goto done;
4894887Schin 			x = subexpr(10, &un);
4904887Schin 			if (c == T_LSHIFT) n <<= x;
4914887Schin 			else n >>= x;
4924887Schin 			un >>= 1;
4934887Schin 			break;
4944887Schin 		case '+':
4954887Schin 		case '-':
4964887Schin 			if (precedence > 10) goto done;
4974887Schin 			x = subexpr(11, &un);
4984887Schin 			if (c == '+') n += x;
4994887Schin 			else n -= x;
5004887Schin 			break;
5014887Schin 		case '*':
5024887Schin 		case '/':
5034887Schin 		case '%':
5044887Schin 			if (precedence > 11) goto done;
5054887Schin 			x = subexpr(12, &un);
5064887Schin 			if (c == '*') n *= x;
5074887Schin 			else if (x == 0)
5084887Schin 			{
5094887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "divide by zero";
5104887Schin 				return 0;
5114887Schin 			}
5124887Schin 			else if (c == '/') n /= x;
5134887Schin 			else n %= x;
5144887Schin 			break;
5154887Schin 		case '#':
5164887Schin 			pp.state |= DISABLE;
5174887Schin 			c = pplex();
5184887Schin 			pp.state &= ~DISABLE;
5194887Schin 			if (c != T_ID)
5204887Schin 			{
5214887Schin 				if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "# must precede a predicate identifier";
5224887Schin 				return 0;
5234887Schin 			}
5244887Schin 			n = predicate(0);
5254887Schin 			goto gotoperand;
5264887Schin 		case T_ID:
5274887Schin 			n = predicate(1);
5284887Schin 			goto gotoperand;
5294887Schin 		case T_CHARCONST:
5304887Schin 			c = *(pp.toknxt - 1);
5314887Schin 			*(pp.toknxt - 1) = 0;
5324887Schin 			n = chrtoi(pp.token + 1);
5334887Schin 			*(pp.toknxt - 1) = c;
5344887Schin 			if (n & ~((1<<CHAR_BIT)-1))
5354887Schin 			{
5364887Schin 				if (!(pp.mode & HOSTED))
5374887Schin 					error(1, "'%s': multi-character character constants are not portable", pp.token);
5384887Schin 			}
5394887Schin #if CHAR_MIN < 0
5404887Schin 			else n = (char)n;
5414887Schin #endif
5424887Schin 			goto gotoperand;
5434887Schin 		case T_DECIMAL_U:
5444887Schin 		case T_DECIMAL_UL:
5454887Schin 		case T_OCTAL_U:
5464887Schin 		case T_OCTAL_UL:
5474887Schin 		case T_HEXADECIMAL_U:
5484887Schin 		case T_HEXADECIMAL_UL:
5494887Schin 			un |= 01;
5504887Schin 			/*FALLTHROUGH*/
5514887Schin 		case T_DECIMAL:
5524887Schin 		case T_DECIMAL_L:
5534887Schin 		case T_OCTAL:
5544887Schin 		case T_OCTAL_L:
5554887Schin 		case T_HEXADECIMAL:
5564887Schin 		case T_HEXADECIMAL_L:
5574887Schin 			n = strtoul(pp.token, NiL, 0);
5584887Schin 			if ((unsigned long)n > LONG_MAX) un |= 01;
5594887Schin 			goto gotoperand;
5604887Schin 		case T_WCHARCONST:
5614887Schin 			n = chrtoi(pp.token);
5624887Schin 			goto gotoperand;
5634887Schin 		default:
5644887Schin 			if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid token";
5654887Schin 			return 0;
5664887Schin 		}
5674887Schin 		if (errmsg) return 0;
5684887Schin 		if (!operand) goto nooperand;
5694887Schin 	}
5704887Schin  done:
5714887Schin 	unlex(c);
5724887Schin 	if (!operand)
5734887Schin 	{
5744887Schin 	nooperand:
5754887Schin 		if (!errmsg && !(pp.mode & INACTIVE)) errmsg = "operand expected";
5764887Schin 		return 0;
5774887Schin 	}
5784887Schin 	if (un) *pun |= 01;
5794887Schin 	return n;
5804887Schin }
5814887Schin 
5824887Schin /*
5834887Schin  * preprocessor expression evaluator using modified streval(3)
5844887Schin  * *pun!=0 if result is unsigned
5854887Schin  */
5864887Schin 
5874887Schin long
5884887Schin ppexpr(int* pun)
5894887Schin {
5904887Schin 	long	n;
5914887Schin 	int	opeektoken;
5924887Schin 	long	ppstate;
5934887Schin 
5944887Schin 	ppstate = (pp.state & (CONDITIONAL|DISABLE|NOSPACE|STRIP));
5954887Schin 	pp.state &= ~(DISABLE|STRIP);
5964887Schin 	pp.state |= CONDITIONAL|NOSPACE;
5974887Schin 	opeektoken = peektoken;
5984887Schin 	peektoken = -1;
5994887Schin 	*pun = 0;
6004887Schin 	n = subexpr(0, pun);
6014887Schin 	if (peektoken == ':' && !errmsg && !(pp.mode & INACTIVE)) errmsg = "invalid use of :";
6024887Schin 	if (errmsg)
6034887Schin 	{
6044887Schin 		error(2, "%s in expression", errmsg);
6054887Schin 		errmsg = 0;
6064887Schin 		n = 0;
6074887Schin 	}
6084887Schin 	peektoken = opeektoken;
6094887Schin 	pp.state &= ~(CONDITIONAL|NOSPACE);
6104887Schin 	pp.state |= ppstate;
6114887Schin 	if (*pun) debug((-4, "ppexpr() = %luU", n));
6124887Schin 	else debug((-4, "ppexpr() = %ld", n));
6134887Schin 	return n;
6144887Schin }
6154887Schin 
6164887Schin /*
6174887Schin  * return non-zero if option s is set
6184887Schin  */
6194887Schin 
6204887Schin int
6214887Schin ppoption(char* s)
6224887Schin {
6234887Schin 	switch ((int)hashget(pp.strtab, s))
6244887Schin 	{
6254887Schin 	case X_ALLMULTIPLE:
6264887Schin 		return pp.mode & ALLMULTIPLE;
6274887Schin 	case X_BUILTIN:
6284887Schin 		return pp.mode & BUILTIN;
6294887Schin 	case X_CATLITERAL:
6304887Schin 		return pp.mode & CATLITERAL;
6314887Schin 	case X_COMPATIBILITY:
6324887Schin 		return pp.state & COMPATIBILITY;
6334887Schin 	case X_DEBUG:
6344887Schin 		return -error_info.trace;
6354887Schin 	case X_ELSEIF:
6364887Schin 		return pp.option & ELSEIF;
6374887Schin 	case X_FINAL:
6384887Schin 		return pp.option & FINAL;
6394887Schin 	case X_HOSTDIR:
6404887Schin 		return pp.mode & HOSTED;
6414887Schin 	case X_HOSTED:
6424887Schin 		return pp.flags & PP_hosted;
6434887Schin 	case X_INITIAL:
6444887Schin 		return pp.option & INITIAL;
6454887Schin 	case X_KEYARGS:
6464887Schin 		return pp.option & KEYARGS;
6474887Schin 	case X_LINEBASE:
6484887Schin 		return pp.flags & PP_linebase;
6494887Schin 	case X_LINEFILE:
6504887Schin 		return pp.flags & PP_linefile;
6514887Schin 	case X_LINETYPE:
6524887Schin 		return pp.flags & PP_linetype;
6534887Schin 	case X_PLUSCOMMENT:
6544887Schin 		return pp.option & PLUSCOMMENT;
6554887Schin 	case X_PLUSPLUS:
6564887Schin 		return pp.option & PLUSPLUS;
6574887Schin 	case X_PLUSSPLICE:
6584887Schin 		return pp.option & PLUSSPLICE;
6594887Schin 	case X_PRAGMAEXPAND:
6604887Schin 		return pp.option & PRAGMAEXPAND;
6614887Schin 	case X_PREDEFINED:
6624887Schin 		return pp.option & PREDEFINED;
6634887Schin 	case X_PREFIX:
6644887Schin 		return pp.option & PREFIX;
6654887Schin 	case X_PROTOTYPED:
6664887Schin 		return pp.option & PROTOTYPED;
6674887Schin 	case X_READONLY:
6684887Schin 		return pp.mode & READONLY;
6694887Schin 	case X_REGUARD:
6704887Schin 		return pp.option & REGUARD;
6714887Schin 	case X_SPACEOUT:
6724887Schin 		return pp.state & SPACEOUT;
6734887Schin 	case X_SPLICECAT:
6744887Schin 		return pp.option & SPLICECAT;
6754887Schin 	case X_SPLICESPACE:
6764887Schin 		return pp.option & SPLICESPACE;
6774887Schin 	case X_STRICT:
6784887Schin 		return pp.state & STRICT;
6794887Schin 	case X_STRINGSPAN:
6804887Schin 		return pp.option & STRINGSPAN;
6814887Schin 	case X_STRINGSPLIT:
6824887Schin 		return pp.option & STRINGSPLIT;
6834887Schin 	case X_TEST:
6844887Schin 		return pp.test;
6854887Schin 	case X_TEXT:
6864887Schin 		return !(pp.state & NOTEXT);
6874887Schin 	case X_TRANSITION:
6884887Schin 		return pp.state & TRANSITION;
6894887Schin 	case X_TRUNCATE:
6904887Schin 		return pp.truncate;
6914887Schin 	case X_WARN:
6924887Schin 		return pp.state & WARN;
6934887Schin 	default:
6944887Schin 		if (pp.state & WARN) error(1, "%s: unknown option name", s);
6954887Schin 		return 0;
6964887Schin 	}
6974887Schin }
698