/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/config/mkdepend/ifparser.c
C | 549 lines | 391 code | 86 blank | 72 comment | 121 complexity | f30a8546e956a485428846402ca567af MD5 | raw file
1/* 2 * $Xorg: ifparser.c,v 1.3 2000/08/17 19:41:50 cpqbld Exp $ 3 * 4 * Copyright 1992 Network Computing Devices, Inc. 5 * 6 * Permission to use, copy, modify, and distribute this software and its 7 * documentation for any purpose and without fee is hereby granted, provided 8 * that the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Network Computing Devices may not be 11 * used in advertising or publicity pertaining to distribution of the software 12 * without specific, written prior permission. Network Computing Devices makes 13 * no representations about the suitability of this software for any purpose. 14 * It is provided ``as is'' without express or implied warranty. 15 * 16 * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 18 * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, 19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 20 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 21 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Author: Jim Fulton 25 * Network Computing Devices, Inc. 26 * 27 * Simple if statement processor 28 * 29 * This module can be used to evaluate string representations of C language 30 * if constructs. It accepts the following grammar: 31 * 32 * EXPRESSION := VALUE 33 * | VALUE BINOP EXPRESSION 34 * | VALUE '?' EXPRESSION ':' EXPRESSION 35 * 36 * VALUE := '(' EXPRESSION ')' 37 * | '!' VALUE 38 * | '-' VALUE 39 * | '+' VALUE 40 * | '~' VALUE 41 * | 'defined' '(' variable ')' 42 * | 'defined' variable 43 * | # variable '(' variable-list ')' 44 * | variable 45 * | number 46 * 47 * BINOP := '*' | '/' | '%' 48 * | '+' | '-' 49 * | '<<' | '>>' 50 * | '<' | '>' | '<=' | '>=' 51 * | '==' | '!=' 52 * | '&' | '^' | '|' 53 * | '&&' | '||' 54 * 55 * The normal C order of precedence is supported. 56 * 57 * 58 * External Entry Points: 59 * 60 * ParseIfExpression parse a string for #if 61 */ 62/* $XFree86: xc/config/makedepend/ifparser.c,v 3.11 2002/09/23 01:48:08 tsi Exp $ */ 63 64#include "ifparser.h" 65#include <ctype.h> 66#include <stdlib.h> 67#include <string.h> 68 69/**************************************************************************** 70 Internal Macros and Utilities for Parser 71 ****************************************************************************/ 72 73#define DO(val) if (!(val)) return NULL 74#define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff)) 75#define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++ 76#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_') 77 78 79static const char * 80parse_variable (IfParser *g, const char *cp, const char **varp) 81{ 82 SKIPSPACE (cp); 83 84 if (!isvarfirstletter (*cp)) 85 return CALLFUNC(g, handle_error) (g, cp, "variable name"); 86 87 *varp = cp; 88 /* EMPTY */ 89 for (cp++; isalnum(*cp) || *cp == '_'; cp++) ; 90 return cp; 91} 92 93 94static const char * 95parse_number (IfParser *g, const char *cp, long *valp) 96{ 97 long base = 10; 98 SKIPSPACE (cp); 99 100 if (!isdigit(*cp)) 101 return CALLFUNC(g, handle_error) (g, cp, "number"); 102 103 *valp = 0; 104 105 if (*cp == '0') { 106 cp++; 107 if ((*cp == 'x') || (*cp == 'X')) { 108 base = 16; 109 cp++; 110 } else { 111 base = 8; 112 } 113 } 114 115 /* Ignore overflows and assume ASCII, what source is usually written in */ 116 while (1) { 117 int increment = -1; 118 if (base == 8) { 119 if ((*cp >= '0') && (*cp <= '7')) 120 increment = *cp++ - '0'; 121 } else if (base == 16) { 122 if ((*cp >= '0') && (*cp <= '9')) 123 increment = *cp++ - '0'; 124 else if ((*cp >= 'A') && (*cp <= 'F')) 125 increment = *cp++ - ('A' - 10); 126 else if ((*cp >= 'a') && (*cp <= 'f')) 127 increment = *cp++ - ('a' - 10); 128 } else { /* Decimal */ 129 if ((*cp >= '0') && (*cp <= '9')) 130 increment = *cp++ - '0'; 131 } 132 if (increment < 0) 133 break; 134 *valp = (*valp * base) + increment; 135 } 136 137 /* Skip trailing qualifiers */ 138 while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++; 139 return cp; 140} 141 142static const char * 143parse_character (IfParser *g, const char *cp, long *valp) 144{ 145 char val; 146 147 SKIPSPACE (cp); 148 if (*cp == '\\') 149 switch (cp[1]) { 150 case 'n': val = '\n'; break; 151 case 't': val = '\t'; break; 152 case 'v': val = '\v'; break; 153 case 'b': val = '\b'; break; 154 case 'r': val = '\r'; break; 155 case 'f': val = '\f'; break; 156 case 'a': val = '\a'; break; 157 case '\\': val = '\\'; break; 158 case '?': val = '\?'; break; 159 case '\'': val = '\''; break; 160 case '\"': val = '\"'; break; 161 case 'x': val = (char) strtol (cp + 2, NULL, 16); break; 162 default: val = (char) strtol (cp + 1, NULL, 8); break; 163 } 164 else 165 val = *cp; 166 while (*cp != '\'') cp++; 167 *valp = (long) val; 168 return cp; 169} 170 171static const char * 172parse_value (IfParser *g, const char *cp, long *valp) 173{ 174 const char *var, *varend; 175 176 *valp = 0; 177 178 SKIPSPACE (cp); 179 if (!*cp) 180 return cp; 181 182 switch (*cp) { 183 case '(': 184 DO (cp = ParseIfExpression (g, cp + 1, valp)); 185 SKIPSPACE (cp); 186 if (*cp != ')') 187 return CALLFUNC(g, handle_error) (g, cp, ")"); 188 189 return cp + 1; /* skip the right paren */ 190 191 case '!': 192 DO (cp = parse_value (g, cp + 1, valp)); 193 *valp = !(*valp); 194 return cp; 195 196 case '-': 197 DO (cp = parse_value (g, cp + 1, valp)); 198 *valp = -(*valp); 199 return cp; 200 201 case '+': 202 DO (cp = parse_value (g, cp + 1, valp)); 203 return cp; 204 205 case '~': 206 DO (cp = parse_value (g, cp + 1, valp)); 207 *valp = ~(*valp); 208 return cp; 209 210 case '#': 211 DO (cp = parse_variable (g, cp + 1, &var)); 212 SKIPSPACE (cp); 213 if (*cp != '(') 214 return CALLFUNC(g, handle_error) (g, cp, "("); 215 do { 216 DO (cp = parse_variable (g, cp + 1, &var)); 217 SKIPSPACE (cp); 218 } while (*cp && *cp != ')'); 219 if (*cp != ')') 220 return CALLFUNC(g, handle_error) (g, cp, ")"); 221 *valp = 1; /* XXX */ 222 return cp + 1; 223 224 case '\'': 225 DO (cp = parse_character (g, cp + 1, valp)); 226 if (*cp != '\'') 227 return CALLFUNC(g, handle_error) (g, cp, "'"); 228 return cp + 1; 229 230 case 'd': 231 if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) { 232 int paren = 0; 233 int len; 234 235 cp += 7; 236 SKIPSPACE (cp); 237 if (*cp == '(') { 238 paren = 1; 239 cp++; 240 } 241 DO (cp = parse_variable (g, cp, &var)); 242 len = cp - var; 243 SKIPSPACE (cp); 244 if (paren && *cp != ')') 245 return CALLFUNC(g, handle_error) (g, cp, ")"); 246 *valp = (*(g->funcs.eval_defined)) (g, var, len); 247 return cp + paren; /* skip the right paren */ 248 } 249 /* fall out */ 250 } 251 252 if (isdigit(*cp)) { 253 DO (cp = parse_number (g, cp, valp)); 254 } else if (!isvarfirstletter(*cp)) 255 return CALLFUNC(g, handle_error) (g, cp, "variable or number"); 256 else { 257 DO (cp = parse_variable (g, cp, &var)); 258 varend = cp; 259 SKIPSPACE(cp); 260 if (*cp != '(') { 261 *valp = (*(g->funcs.eval_variable)) (g, var, varend - var); 262 } else { 263 do { 264 long dummy; 265 DO (cp = ParseIfExpression (g, cp + 1, &dummy)); 266 SKIPSPACE(cp); 267 if (*cp == ')') 268 break; 269 if (*cp != ',') 270 return CALLFUNC(g, handle_error) (g, cp, ","); 271 } while (1); 272 273 *valp = 1; /* XXX */ 274 cp++; 275 } 276 } 277 278 return cp; 279} 280 281 282 283static const char * 284parse_product (IfParser *g, const char *cp, long *valp) 285{ 286 long rightval; 287 288 DO (cp = parse_value (g, cp, valp)); 289 SKIPSPACE (cp); 290 291 switch (*cp) { 292 case '*': 293 DO (cp = parse_product (g, cp + 1, &rightval)); 294 *valp = (*valp * rightval); 295 break; 296 297 case '/': 298 DO (cp = parse_product (g, cp + 1, &rightval)); 299 *valp = (*valp / rightval); 300 break; 301 302 case '%': 303 DO (cp = parse_product (g, cp + 1, &rightval)); 304 *valp = (*valp % rightval); 305 break; 306 } 307 return cp; 308} 309 310 311static const char * 312parse_sum (IfParser *g, const char *cp, long *valp) 313{ 314 long rightval; 315 316 DO (cp = parse_product (g, cp, valp)); 317 SKIPSPACE (cp); 318 319 switch (*cp) { 320 case '+': 321 DO (cp = parse_sum (g, cp + 1, &rightval)); 322 *valp = (*valp + rightval); 323 break; 324 325 case '-': 326 DO (cp = parse_sum (g, cp + 1, &rightval)); 327 *valp = (*valp - rightval); 328 break; 329 } 330 return cp; 331} 332 333 334static const char * 335parse_shift (IfParser *g, const char *cp, long *valp) 336{ 337 long rightval; 338 339 DO (cp = parse_sum (g, cp, valp)); 340 SKIPSPACE (cp); 341 342 switch (*cp) { 343 case '<': 344 if (cp[1] == '<') { 345 DO (cp = parse_shift (g, cp + 2, &rightval)); 346 *valp = (*valp << rightval); 347 } 348 break; 349 350 case '>': 351 if (cp[1] == '>') { 352 DO (cp = parse_shift (g, cp + 2, &rightval)); 353 *valp = (*valp >> rightval); 354 } 355 break; 356 } 357 return cp; 358} 359 360 361static const char * 362parse_inequality (IfParser *g, const char *cp, long *valp) 363{ 364 long rightval; 365 366 DO (cp = parse_shift (g, cp, valp)); 367 SKIPSPACE (cp); 368 369 switch (*cp) { 370 case '<': 371 if (cp[1] == '=') { 372 DO (cp = parse_inequality (g, cp + 2, &rightval)); 373 *valp = (*valp <= rightval); 374 } else { 375 DO (cp = parse_inequality (g, cp + 1, &rightval)); 376 *valp = (*valp < rightval); 377 } 378 break; 379 380 case '>': 381 if (cp[1] == '=') { 382 DO (cp = parse_inequality (g, cp + 2, &rightval)); 383 *valp = (*valp >= rightval); 384 } else { 385 DO (cp = parse_inequality (g, cp + 1, &rightval)); 386 *valp = (*valp > rightval); 387 } 388 break; 389 } 390 return cp; 391} 392 393 394static const char * 395parse_equality (IfParser *g, const char *cp, long *valp) 396{ 397 long rightval; 398 399 DO (cp = parse_inequality (g, cp, valp)); 400 SKIPSPACE (cp); 401 402 switch (*cp) { 403 case '=': 404 if (cp[1] == '=') 405 cp++; 406 DO (cp = parse_equality (g, cp + 1, &rightval)); 407 *valp = (*valp == rightval); 408 break; 409 410 case '!': 411 if (cp[1] != '=') 412 break; 413 DO (cp = parse_equality (g, cp + 2, &rightval)); 414 *valp = (*valp != rightval); 415 break; 416 } 417 return cp; 418} 419 420 421static const char * 422parse_band (IfParser *g, const char *cp, long *valp) 423{ 424 long rightval; 425 426 DO (cp = parse_equality (g, cp, valp)); 427 SKIPSPACE (cp); 428 429 switch (*cp) { 430 case '&': 431 if (cp[1] != '&') { 432 DO (cp = parse_band (g, cp + 1, &rightval)); 433 *valp = (*valp & rightval); 434 } 435 break; 436 } 437 return cp; 438} 439 440 441static const char * 442parse_bxor (IfParser *g, const char *cp, long *valp) 443{ 444 long rightval; 445 446 DO (cp = parse_band (g, cp, valp)); 447 SKIPSPACE (cp); 448 449 switch (*cp) { 450 case '^': 451 DO (cp = parse_bxor (g, cp + 1, &rightval)); 452 *valp = (*valp ^ rightval); 453 break; 454 } 455 return cp; 456} 457 458 459static const char * 460parse_bor (IfParser *g, const char *cp, long *valp) 461{ 462 long rightval; 463 464 DO (cp = parse_bxor (g, cp, valp)); 465 SKIPSPACE (cp); 466 467 switch (*cp) { 468 case '|': 469 if (cp[1] != '|') { 470 DO (cp = parse_bor (g, cp + 1, &rightval)); 471 *valp = (*valp | rightval); 472 } 473 break; 474 } 475 return cp; 476} 477 478 479static const char * 480parse_land (IfParser *g, const char *cp, long *valp) 481{ 482 long rightval; 483 484 DO (cp = parse_bor (g, cp, valp)); 485 SKIPSPACE (cp); 486 487 switch (*cp) { 488 case '&': 489 if (cp[1] != '&') 490 return CALLFUNC(g, handle_error) (g, cp, "&&"); 491 DO (cp = parse_land (g, cp + 2, &rightval)); 492 *valp = (*valp && rightval); 493 break; 494 } 495 return cp; 496} 497 498 499static const char * 500parse_lor (IfParser *g, const char *cp, long *valp) 501{ 502 long rightval; 503 504 DO (cp = parse_land (g, cp, valp)); 505 SKIPSPACE (cp); 506 507 switch (*cp) { 508 case '|': 509 if (cp[1] != '|') 510 return CALLFUNC(g, handle_error) (g, cp, "||"); 511 DO (cp = parse_lor (g, cp + 2, &rightval)); 512 *valp = (*valp || rightval); 513 break; 514 } 515 return cp; 516} 517 518 519static const char * 520parse_cond(IfParser *g, const char *cp, long *valp) 521{ 522 long trueval, falseval; 523 524 DO (cp = parse_lor (g, cp, valp)); 525 SKIPSPACE (cp); 526 527 switch (*cp) { 528 case '?': 529 DO (cp = parse_cond (g, cp + 1, &trueval)); 530 SKIPSPACE (cp); 531 if (*cp != ':') 532 return CALLFUNC(g, handle_error) (g, cp, ":"); 533 DO (cp = parse_cond (g, cp + 1, &falseval)); 534 *valp = (*valp ? trueval : falseval); 535 break; 536 } 537 return cp; 538} 539 540 541/**************************************************************************** 542 External Entry Points 543 ****************************************************************************/ 544 545const char * 546ParseIfExpression (IfParser *g, const char *cp, long *valp) 547{ 548 return parse_cond (g, cp, valp); 549}