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