1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 1986-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril 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 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 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 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 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 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 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