1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
19 ***********************************************************************/
25 * preprocessor expression evaluation support
32 #define lex(c) ((((c)=peektoken)>=0?(peektoken=(-1)):((c)=pplex())),(c))
33 #define unlex(c) (peektoken=(c))
35 static int peektoken
; /* expression lookahead token */
36 static char* errmsg
; /* subexpr() error message */
39 * exists predicate evaluation
43 exists(int op
, char* pred
, register char* args
)
49 char file
[MAXTOKEN
+ 1];
51 state
= (pp
.state
& ~DISABLE
);
55 pp
.state
|= HEADER
|PASSEOF
;
65 error(1, "%s: \"...\" or <...> argument expected", pred
);
71 if ((c
= pplex()) == ',')
73 while ((c
= pplex()) == T_STRING
)
75 if (pathaccess(pp
.path
, pp
.token
, file
, NiL
, 0))
77 pathcanon(pp
.path
, 0);
78 message((-2, "%s: %s found", pred
, pp
.path
));
82 if ((c
= pplex()) != ',') break;
84 if (c
) error(1, "%s: \"...\" arguments expected", pred
);
85 strcpy(pp
.path
, file
);
86 message((-2, "%s: %s not found", pred
, file
));
89 else c
= ppsearch(file
, type
, SEARCH_EXISTS
) >= 0;
93 register struct ppfile
* fp
;
96 c
= fp
->flags
|| fp
->guard
== INC_IGNORE
;
105 * strcmp/match predicate evaluation
109 compare(char* pred
, char* args
, int match
)
115 char tmp
[MAXTOKEN
+ 1];
117 state
= (pp
.state
& ~DISABLE
);
125 if (pplex() != ',' || !pplex())
128 c
= strcmp(tmp
, pp
.token
);
129 else if ((c
= regcomp(&re
, pp
.token
, REG_AUGMENTED
|REG_LENIENT
|REG_NULL
)) || (c
= regexec(&re
, tmp
, NiL
, 0, 0)) && c
!= REG_NOMATCH
)
136 if ((pp
.state
& PASSEOF
) && pplex())
142 error(2, "%s: 2 arguments expected", pred
);
149 * #if predicate parse and evaluation
156 register struct pplist
* p
;
157 register struct ppsymbol
* sym
;
161 static char pred
[MAXID
+ 1];
164 * first gather the args
167 index
= (int)hashref(pp
.strtab
, pp
.token
);
168 if (warn
&& peekchr() != '(') switch (index
)
180 if (pp
.macref
) pprefmac(pp
.token
, REF_IF
);
183 strcpy(pred
, pp
.token
);
186 pp
.state
&= ~DISABLE
;
196 if (index
&& !(pp
.state
& STRICT
))
197 error(1, "%s: predicate argument expected", pred
);
198 if (pp
.macref
) pprefmac(pred
, REF_IF
);
207 debug((-6, "pred=%s args=%s", pred
, args
));
208 if ((pp
.state
& STRICT
) && !(pp
.mode
& HOSTED
)) switch (index
)
214 error(1, "%s(%s): non-standard predicate test", pred
, args
);
220 if (type
!= T_ID
) error(1, "%s: identifier argument expected", pred
);
221 else if ((sym
= pprefmac(args
, REF_IF
)) && sym
->macro
) return 1;
222 else if (args
[0] == '_' && args
[1] == '_' && !strncmp(args
, "__STDPP__", 9))
224 if (pp
.hosted
== 1 && pp
.in
->prev
->type
== IN_FILE
)
227 pp
.flags
|= PP_hosted
;
229 return *(args
+ 9) ? (int)hashref(pp
.strtab
, args
+ 9) : 1;
234 return exists(index
, pred
, args
);
237 return compare(pred
, args
, index
== X_MATCH
);
239 if (type
!= T_ID
) error(1, "%s: identifier argument expected", pred
);
240 else if (((sym
= pprefmac(args
, REF_IF
)) || (sym
= ppsymref(pp
.symtab
, args
))) && (sym
->flags
& SYM_NOTICED
)) return 1;
243 return ppoption(args
);
245 error(2, "%s invalid in #%s expressions", pred
, dirname(IF
));
248 if (warn
&& !(pp
.mode
& HOSTED
) && (sym
= ppsymref(pp
.symtab
, pred
)) && (sym
->flags
& SYM_PREDICATE
))
249 error(1, "use #%s(%s) to disambiguate", pred
, args
);
250 if (p
= (struct pplist
*)hashget(pp
.prdtab
, pred
))
252 if (!*args
) return 1;
255 if (streq(p
->value
, args
)) return 1;
265 * evaluate a long integer subexpression with precedence
266 * taken from the library routine streval()
267 * may be called recursively
269 * NOTE: all operands are evaluated as both the parse
270 * and evaluation are done on the fly
274 subexpr(register int precedence
, int* pun
)
279 register int operand
= 1;
288 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "more tokens expected";
291 n
= -subexpr(13, &un
);
294 n
= subexpr(13, &un
);
297 n
= !subexpr(13, &un
);
300 n
= ~subexpr(13, &un
);
319 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "too many )'s";
328 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "closing ) expected";
334 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "operator expected";
341 if (precedence
> 1) goto done
;
345 if (!n
) n
= subexpr(2, &un
);
361 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= ": expected for ? operator";
370 else n
= subexpr(2, &un
);
377 xn
= (c
== T_ANDAND
) ? 4 : 3;
378 if (precedence
>= xn
) goto done
;
379 if ((n
!= 0) == (c
== T_ANDAND
)) n
= subexpr(xn
, &un
) != 0;
390 if (precedence
> 4) goto done
;
391 n
|= subexpr(5, &un
);
394 if (precedence
> 5) goto done
;
395 n
^= subexpr(6, &un
);
398 if (precedence
> 6) goto done
;
399 n
&= subexpr(7, &un
);
403 if (precedence
> 7) goto done
;
404 n
= (n
== subexpr(8, &un
)) == (c
== T_EQ
);
411 if (precedence
> 8) goto done
;
419 n
= n
< (unsigned long)x
;
422 n
= (unsigned long)n
< x
;
425 n
= (unsigned long)n
< (unsigned long)x
;
436 n
= n
<= (unsigned long)x
;
439 n
= (unsigned long)n
<= x
;
442 n
= (unsigned long)n
<= (unsigned long)x
;
453 n
= n
>= (unsigned long)x
;
456 n
= (unsigned long)n
>= x
;
459 n
= (unsigned long)n
>= (unsigned long)x
;
470 n
= n
> (unsigned long)x
;
473 n
= (unsigned long)n
> x
;
476 n
= (unsigned long)n
> (unsigned long)x
;
488 if (precedence
> 9) goto done
;
489 x
= subexpr(10, &un
);
490 if (c
== T_LSHIFT
) n
<<= x
;
496 if (precedence
> 10) goto done
;
497 x
= subexpr(11, &un
);
498 if (c
== '+') n
+= x
;
504 if (precedence
> 11) goto done
;
505 x
= subexpr(12, &un
);
506 if (c
== '*') n
*= x
;
509 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "divide by zero";
512 else if (c
== '/') n
/= x
;
518 pp
.state
&= ~DISABLE
;
521 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "# must precede a predicate identifier";
530 c
= *(pp
.toknxt
- 1);
531 *(pp
.toknxt
- 1) = 0;
532 n
= chrtoi(pp
.token
+ 1);
533 *(pp
.toknxt
- 1) = c
;
534 if (n
& ~((1<<CHAR_BIT
)-1))
536 if (!(pp
.mode
& HOSTED
))
537 error(1, "'%s': multi-character character constants are not portable", pp
.token
);
547 case T_HEXADECIMAL_U
:
548 case T_HEXADECIMAL_UL
:
556 case T_HEXADECIMAL_L
:
557 n
= strtoul(pp
.token
, NiL
, 0);
558 if ((unsigned long)n
> LONG_MAX
) un
|= 01;
561 n
= chrtoi(pp
.token
);
564 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "invalid token";
567 if (errmsg
) return 0;
568 if (!operand
) goto nooperand
;
575 if (!errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "operand expected";
583 * preprocessor expression evaluator using modified streval(3)
584 * *pun!=0 if result is unsigned
594 ppstate
= (pp
.state
& (CONDITIONAL
|DISABLE
|NOSPACE
|STRIP
));
595 pp
.state
&= ~(DISABLE
|STRIP
);
596 pp
.state
|= CONDITIONAL
|NOSPACE
;
597 opeektoken
= peektoken
;
601 if (peektoken
== ':' && !errmsg
&& !(pp
.mode
& INACTIVE
)) errmsg
= "invalid use of :";
604 error(2, "%s in expression", errmsg
);
608 peektoken
= opeektoken
;
609 pp
.state
&= ~(CONDITIONAL
|NOSPACE
);
611 if (*pun
) debug((-4, "ppexpr() = %luU", n
));
612 else debug((-4, "ppexpr() = %ld", n
));
617 * return non-zero if option s is set
623 switch ((int)hashget(pp
.strtab
, s
))
626 return pp
.mode
& ALLMULTIPLE
;
628 return pp
.mode
& BUILTIN
;
630 return pp
.mode
& CATLITERAL
;
631 case X_COMPATIBILITY
:
632 return pp
.state
& COMPATIBILITY
;
634 return -error_info
.trace
;
636 return pp
.option
& ELSEIF
;
638 return pp
.option
& FINAL
;
640 return pp
.mode
& HOSTED
;
642 return pp
.flags
& PP_hosted
;
644 return pp
.option
& INITIAL
;
646 return pp
.option
& KEYARGS
;
648 return pp
.flags
& PP_linebase
;
650 return pp
.flags
& PP_linefile
;
652 return pp
.flags
& PP_linetype
;
654 return pp
.option
& PLUSCOMMENT
;
656 return pp
.option
& PLUSPLUS
;
658 return pp
.option
& PLUSSPLICE
;
660 return pp
.option
& PRAGMAEXPAND
;
662 return pp
.option
& PREDEFINED
;
664 return pp
.option
& PREFIX
;
666 return pp
.option
& PROTOTYPED
;
668 return pp
.mode
& READONLY
;
670 return pp
.option
& REGUARD
;
672 return pp
.state
& SPACEOUT
;
674 return pp
.option
& SPLICECAT
;
676 return pp
.option
& SPLICESPACE
;
678 return pp
.state
& STRICT
;
680 return pp
.option
& STRINGSPAN
;
682 return pp
.option
& STRINGSPLIT
;
686 return !(pp
.state
& NOTEXT
);
688 return pp
.state
& TRANSITION
;
692 return pp
.state
& WARN
;
694 if (pp
.state
& WARN
) error(1, "%s: unknown option name", s
);