|
|
1.1 ! root 1: /* Parse C expressions for CCCP. ! 2: Copyright (C) 1986 Free Software Foundation. ! 3: ! 4: NO WARRANTY ! 5: ! 6: BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY ! 7: NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT ! 8: WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, ! 9: RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" ! 10: WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, ! 11: BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ! 12: FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY ! 13: AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE ! 14: DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR ! 15: CORRECTION. ! 16: ! 17: IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. ! 18: STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY ! 19: WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE ! 20: LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR ! 21: OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE ! 22: USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR ! 23: DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR ! 24: A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS ! 25: PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH ! 26: DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. ! 27: ! 28: GENERAL PUBLIC LICENSE TO COPY ! 29: ! 30: 1. You may copy and distribute verbatim copies of this source file ! 31: as you receive it, in any medium, provided that you conspicuously ! 32: and appropriately publish on each copy a valid copyright notice ! 33: "Copyright (C) 1986 Free Software Foundation"; and include ! 34: following the copyright notice a verbatim copy of the above disclaimer ! 35: of warranty and of this License. ! 36: ! 37: 2. You may modify your copy or copies of this source file or ! 38: any portion of it, and copy and distribute such modifications under ! 39: the terms of Paragraph 1 above, provided that you also do the following: ! 40: ! 41: a) cause the modified files to carry prominent notices stating ! 42: that you changed the files and the date of any change; and ! 43: ! 44: b) cause the whole of any work that you distribute or publish, ! 45: that in whole or in part contains or is a derivative of this ! 46: program or any part thereof, to be licensed at no charge to all ! 47: third parties on terms identical to those contained in this ! 48: License Agreement (except that you may choose to grant more extensive ! 49: warranty protection to some or all third parties, at your option). ! 50: ! 51: c) You may charge a distribution fee for the physical act of ! 52: transferring a copy, and you may at your option offer warranty ! 53: protection in exchange for a fee. ! 54: ! 55: Mere aggregation of another unrelated program with this program (or its ! 56: derivative) on a volume of a storage or distribution medium does not bring ! 57: the other program under the scope of these terms. ! 58: ! 59: 3. You may copy and distribute this program (or a portion or derivative ! 60: of it, under Paragraph 2) in object code or executable form under the terms ! 61: of Paragraphs 1 and 2 above provided that you also do one of the following: ! 62: ! 63: a) accompany it with the complete corresponding machine-readable ! 64: source code, which must be distributed under the terms of ! 65: Paragraphs 1 and 2 above; or, ! 66: ! 67: b) accompany it with a written offer, valid for at least three ! 68: years, to give any third party free (except for a nominal ! 69: shipping charge) a complete machine-readable copy of the ! 70: corresponding source code, to be distributed under the terms of ! 71: Paragraphs 1 and 2 above; or, ! 72: ! 73: c) accompany it with the information you received as to where the ! 74: corresponding source code may be obtained. (This alternative is ! 75: allowed only for noncommercial distribution and only if you ! 76: received the program in object code or executable form alone.) ! 77: ! 78: For an executable file, complete source code means all the source code for ! 79: all modules it contains; but, as a special exception, it need not include ! 80: source code for modules which are standard libraries that accompany the ! 81: operating system on which the executable file runs. ! 82: ! 83: 4. You may not copy, sublicense, distribute or transfer this program ! 84: except as expressly provided under this License Agreement. Any attempt ! 85: otherwise to copy, sublicense, distribute or transfer this program is void and ! 86: your rights to use the program under this License agreement shall be ! 87: automatically terminated. However, parties who have received computer ! 88: software programs from you with this License Agreement will not have ! 89: their licenses terminated so long as such parties remain in full compliance. ! 90: ! 91: In other words, you are welcome to use, share and improve this program. ! 92: You are forbidden to forbid anyone else to use, share and improve ! 93: what you give them. Help stamp out software-hoarding! ! 94: ! 95: Adapted from expread.y of GDB by Paul Rubin, July 1986. ! 96: ! 97: /* Parse a C expression from text in a string */ ! 98: ! 99: %{ ! 100: #include <setjmp.h> ! 101: /* #define YYDEBUG 1 */ ! 102: ! 103: static int yylex (); ! 104: static yyerror (); ! 105: int expression_value; ! 106: ! 107: static jmp_buf parse_return_error; ! 108: ! 109: /* some external tables of character types */ ! 110: extern unsigned char is_idstart[], is_idchar[]; ! 111: ! 112: %} ! 113: ! 114: %union { ! 115: long lval; ! 116: int voidval; ! 117: char *sval; ! 118: } ! 119: ! 120: %type <lval> exp exp1 start ! 121: %token <lval> INT CHAR ! 122: %token <sval> NAME ! 123: %token <lval> ERROR ! 124: ! 125: %left ',' ! 126: %left OR ! 127: %left AND ! 128: %left '|' ! 129: %left '^' ! 130: %left '&' ! 131: %left EQUAL NOTEQUAL ! 132: %left '<' '>' LEQ GEQ ! 133: %left LSH RSH ! 134: %left '+' '-' ! 135: %left '*' '/' '%' ! 136: %right UNARY ! 137: ! 138: %% ! 139: ! 140: start : exp1 ! 141: { expression_value = $1; } ! 142: ; ! 143: ! 144: /* Expressions, including the comma operator. */ ! 145: exp1 : exp ! 146: | exp1 ',' exp ! 147: { $$ = $3; } ! 148: ; ! 149: ! 150: /* Expressions, not including the comma operator. */ ! 151: exp : '-' exp %prec UNARY ! 152: { $$ = - $2; } ! 153: | '!' exp %prec UNARY ! 154: { $$ = ! $2; } ! 155: | '~' exp %prec UNARY ! 156: { $$ = ~ $2; } ! 157: | '(' exp1 ')' ! 158: { $$ = $2; } ! 159: ; ! 160: ! 161: /* Binary operators in order of decreasing precedence. */ ! 162: exp : exp '*' exp ! 163: { $$ = $1 * $3; } ! 164: | exp '/' exp ! 165: { $$ = $1 / $3; } ! 166: | exp '%' exp ! 167: { $$ = $1 % $3; } ! 168: | exp '+' exp ! 169: { $$ = $1 + $3; } ! 170: | exp '-' exp ! 171: { $$ = $1 - $3; } ! 172: | exp LSH exp ! 173: { $$ = $1 << $3; } ! 174: | exp RSH exp ! 175: { $$ = $1 >> $3; } ! 176: | exp EQUAL exp ! 177: { $$ = ($1 == $3); } ! 178: | exp NOTEQUAL exp ! 179: { $$ = ($1 != $3); } ! 180: | exp LEQ exp ! 181: { $$ = ($1 <= $3); } ! 182: | exp GEQ exp ! 183: { $$ = ($1 >= $3); } ! 184: | exp '<' exp ! 185: { $$ = ($1 < $3); } ! 186: | exp '>' exp ! 187: { $$ = ($1 > $3); } ! 188: | exp '&' exp ! 189: { $$ = ($1 & $3); } ! 190: | exp '^' exp ! 191: { $$ = ($1 ^ $3); } ! 192: | exp '|' exp ! 193: { $$ = ($1 | $3); } ! 194: | exp AND exp ! 195: { $$ = ($1 && $3); } ! 196: | exp OR exp ! 197: { $$ = ($1 || $3); } ! 198: | exp '?' exp ':' exp ! 199: { $$ = $1 ? $3 : $5; } ! 200: | INT ! 201: { $$ = yylval.lval; } ! 202: | CHAR ! 203: { $$ = yylval.lval; } ! 204: | NAME ! 205: { $$ = 0; } ! 206: ; ! 207: %% ! 208: ! 209: /* During parsing of a C expression, the pointer to the next character ! 210: is in this variable. */ ! 211: ! 212: static char *lexptr; ! 213: ! 214: /* Take care of parsing a number (anything that starts with a digit). ! 215: Set yylval and return the token type; update lexptr. ! 216: LEN is the number of characters in it. */ ! 217: ! 218: /* maybe needs to actually deal with floating point numbers */ ! 219: ! 220: static int ! 221: parse_number (olen) ! 222: int olen; ! 223: { ! 224: register char *p = lexptr; ! 225: register long n = 0; ! 226: register int c; ! 227: register int base = 10; ! 228: register len = olen; ! 229: char *err_copy; ! 230: ! 231: extern double atof (); ! 232: ! 233: for (c = 0; c < len; c++) ! 234: if (p[c] == '.') { ! 235: /* It's a float since it contains a point. */ ! 236: yyerror ("floating point numbers not allowed in #if expressions"); ! 237: return ERROR; ! 238: ! 239: /* **************** ! 240: yylval.dval = atof (p); ! 241: lexptr += len; ! 242: return FLOAT; ! 243: **************** */ ! 244: } ! 245: ! 246: if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { ! 247: p += 2; ! 248: base = 16; ! 249: len -= 2; ! 250: } ! 251: else if (*p == '0') ! 252: base = 8; ! 253: ! 254: while (len-- > 0) { ! 255: c = *p++; ! 256: n *= base; ! 257: if (c >= '0' && c <= '9') ! 258: n += c - '0'; ! 259: else { ! 260: if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; ! 261: if (base == 16 && c >= 'a' && c <= 'f') ! 262: n += c - 'a' + 10; ! 263: else if (len == 0 && c == 'l') ! 264: ; ! 265: else { ! 266: yyerror ("Invalid number in #if expression"); ! 267: return ERROR; ! 268: } ! 269: } ! 270: } ! 271: ! 272: lexptr = p; ! 273: yylval.lval = n; ! 274: return INT; ! 275: } ! 276: ! 277: struct token { ! 278: char *operator; ! 279: int token; ! 280: }; ! 281: ! 282: #define NULL 0 ! 283: ! 284: static struct token tokentab2[] = { ! 285: {"&&", AND}, ! 286: {"||", OR}, ! 287: {"<<", LSH}, ! 288: {">>", RSH}, ! 289: {"==", EQUAL}, ! 290: {"!=", NOTEQUAL}, ! 291: {"<=", LEQ}, ! 292: {">=", GEQ}, ! 293: {NULL, ERROR} ! 294: }; ! 295: ! 296: /* Read one token, getting characters through lexptr. */ ! 297: ! 298: static int ! 299: yylex () ! 300: { ! 301: register int c; ! 302: register int namelen; ! 303: register char *tokstart; ! 304: register struct token *toktab; ! 305: ! 306: retry: ! 307: ! 308: tokstart = lexptr; ! 309: c = *tokstart; ! 310: /* See if it is a special token of length 2. */ ! 311: for (toktab = tokentab2; toktab->operator != NULL; toktab++) ! 312: if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { ! 313: lexptr += 2; ! 314: return toktab->token; ! 315: } ! 316: ! 317: switch (c) { ! 318: case 0: ! 319: return 0; ! 320: ! 321: case ' ': ! 322: case '\t': ! 323: case '\n': ! 324: lexptr++; ! 325: goto retry; ! 326: ! 327: case '\'': ! 328: lexptr++; ! 329: c = *lexptr++; ! 330: if (c == '\\') ! 331: c = parse_escape (&lexptr); ! 332: yylval.lval = c; ! 333: c = *lexptr++; ! 334: if (c != '\'') { ! 335: yyerror ("Invalid character constant in #if"); ! 336: return ERROR; ! 337: } ! 338: ! 339: return CHAR; ! 340: ! 341: case '/': /* possible comment */ ! 342: if (*lexptr != '*') ! 343: return c; ! 344: for (;;) { ! 345: while (*lexptr != '\0') { ! 346: if (*lexptr++ == '*' && *lexptr == '/') { ! 347: lexptr++; ! 348: goto retry; ! 349: } ! 350: } ! 351: } ! 352: ! 353: /* some of these chars are invalid in constant expressions; ! 354: maybe do something about them later */ ! 355: case '+': ! 356: case '-': ! 357: case '*': ! 358: case '%': ! 359: case '|': ! 360: case '&': ! 361: case '^': ! 362: case '~': ! 363: case '!': ! 364: case '@': ! 365: case '<': ! 366: case '>': ! 367: case '(': ! 368: case ')': ! 369: case '[': ! 370: case ']': ! 371: case '.': ! 372: case '?': ! 373: case ':': ! 374: case '=': ! 375: case '{': ! 376: case '}': ! 377: case ',': ! 378: lexptr++; ! 379: return c; ! 380: ! 381: case '"': ! 382: yyerror ("double quoted strings not allowed in #if expressions"); ! 383: return ERROR; ! 384: } ! 385: if (c >= '0' && c <= '9') { ! 386: /* It's a number */ ! 387: for (namelen = 0; ! 388: c = tokstart[namelen], is_idchar[c] || c == '.'; ! 389: namelen++) ! 390: ; ! 391: return parse_number (namelen); ! 392: } ! 393: ! 394: if (!is_idstart[c]) { ! 395: yyerror ("Invalid token in expression"); ! 396: return ERROR; ! 397: } ! 398: ! 399: /* It is a name. See how long it is. */ ! 400: ! 401: for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) ! 402: ; ! 403: ! 404: lexptr += namelen; ! 405: return NAME; ! 406: } ! 407: ! 408: ! 409: /* Parse a C escape sequence. STRING_PTR points to a variable ! 410: containing a pointer to the string to parse. That pointer ! 411: is updated past the characters we use. The value of the ! 412: escape sequence is returned. ! 413: ! 414: A negative value means the sequence \ newline was seen, ! 415: which is supposed to be equivalent to nothing at all. ! 416: ! 417: If \ is followed by a null character, we return a negative ! 418: value and leave the string pointer pointing at the null character. ! 419: ! 420: If \ is followed by 000, we return 0 and leave the string pointer ! 421: after the zeros. A value of 0 does not mean end of string. */ ! 422: ! 423: static int ! 424: parse_escape (string_ptr) ! 425: char **string_ptr; ! 426: { ! 427: register int c = *(*string_ptr)++; ! 428: switch (c) ! 429: { ! 430: case 'a': ! 431: return '\a'; ! 432: case 'b': ! 433: return '\b'; ! 434: case 'e': ! 435: return 033; ! 436: case 'f': ! 437: return '\f'; ! 438: case 'n': ! 439: return '\n'; ! 440: case 'r': ! 441: return '\r'; ! 442: case 't': ! 443: return '\t'; ! 444: case 'v': ! 445: return '\v'; ! 446: case '\n': ! 447: return -2; ! 448: case 0: ! 449: (*string_ptr)--; ! 450: return 0; ! 451: case '^': ! 452: c = *(*string_ptr)++; ! 453: if (c == '\\') ! 454: c = parse_escape (string_ptr); ! 455: if (c == '?') ! 456: return 0177; ! 457: return (c & 0200) | (c & 037); ! 458: ! 459: case '0': ! 460: case '1': ! 461: case '2': ! 462: case '3': ! 463: case '4': ! 464: case '5': ! 465: case '6': ! 466: case '7': ! 467: { ! 468: register int i = c - '0'; ! 469: register int count = 0; ! 470: while (++count < 3) ! 471: { ! 472: if ((c = *(*string_ptr)++) >= '0' && c <= '7') ! 473: { ! 474: i *= 8; ! 475: i += c - '0'; ! 476: } ! 477: else ! 478: { ! 479: (*string_ptr)--; ! 480: break; ! 481: } ! 482: } ! 483: return i; ! 484: } ! 485: default: ! 486: return c; ! 487: } ! 488: } ! 489: ! 490: static ! 491: yyerror (s) ! 492: char *s; ! 493: { ! 494: error (s); ! 495: longjmp (parse_return_error, 1); ! 496: } ! 497: ! 498: /* This page contains the entry point to this file. */ ! 499: ! 500: /* Parse STRING as an expression, and complain if this fails ! 501: to use up all of the contents of STRING. */ ! 502: int ! 503: parse_c_expression (string) ! 504: char *string; ! 505: { ! 506: lexptr = string; ! 507: ! 508: if (lexptr == 0 || *lexptr == 0) { ! 509: error ("empty #if expression"); ! 510: return 0; /* don't include the #if group */ ! 511: } ! 512: ! 513: /* if there is some sort of scanning error, just return 0 and assume ! 514: the parsing routine has printed an error message somewhere. ! 515: there is surely a better thing to do than this. */ ! 516: if (setjmp(parse_return_error)) ! 517: return 0; ! 518: ! 519: if (yyparse ()) ! 520: return 0; /* actually this is never reached ! 521: the way things stand. */ ! 522: if (*lexptr) ! 523: error ("Junk after end of expression."); ! 524: ! 525: return expression_value; /* set by yyparse() */ ! 526: } ! 527: ! 528: #ifdef TEST_EXP_READER ! 529: /* main program, for testing purposes. */ ! 530: main() ! 531: { ! 532: int n; ! 533: char buf[1024]; ! 534: extern int yydebug; ! 535: /* ! 536: yydebug = 1; ! 537: */ ! 538: initialize_random_junk (); ! 539: ! 540: for (;;) { ! 541: printf("enter expression: "); ! 542: n = 0; ! 543: while ((buf[n] = getchar()) != '\n') ! 544: n++; ! 545: buf[n] = '\0'; ! 546: printf("parser returned %d\n", parse_c_expression(buf)); ! 547: } ! 548: } ! 549: ! 550: /* table to tell if char can be part of a C identifier. */ ! 551: char is_idchar[256]; ! 552: /* table to tell if char can be first char of a c identifier. */ ! 553: char is_idstart[256]; ! 554: /* table to tell if c is horizontal space. isspace() thinks that ! 555: newline is space; this is not a good idea for this program. */ ! 556: char is_hor_space[256]; ! 557: ! 558: /* ! 559: * initialize random junk in the hash table and maybe other places ! 560: */ ! 561: initialize_random_junk() ! 562: { ! 563: register int i; ! 564: ! 565: /* ! 566: * Set up is_idchar and is_idstart tables. These should be ! 567: * faster than saying (is_alpha(c) || c == '_'), etc. ! 568: * Must do set up these things before calling any routines tthat ! 569: * refer to them. ! 570: */ ! 571: for (i = 'a'; i <= 'z'; i++) { ! 572: ++is_idchar[i - 'a' + 'A']; ! 573: ++is_idchar[i]; ! 574: ++is_idstart[i - 'a' + 'A']; ! 575: ++is_idstart[i]; ! 576: } ! 577: for (i = '0'; i <= '9'; i++) ! 578: ++is_idchar[i]; ! 579: ++is_idchar['_']; ! 580: ++is_idstart['_']; ! 581: ! 582: /* horizontal space table */ ! 583: ++is_hor_space[' ']; ! 584: ++is_hor_space['\t']; ! 585: } ! 586: ! 587: error (msg) ! 588: { ! 589: printf("error: %s\n", msg); ! 590: } ! 591: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.