1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*34f9b3eeSRoland Mainz * Copyright (c) 1986-2009 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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 {
75da2e3ebdSchin if (pathaccess(pp.path, pp.token, file, NiL, 0))
76da2e3ebdSchin {
77da2e3ebdSchin pathcanon(pp.path, 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)
130da2e3ebdSchin regfatal(&re, 3, 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