|
|
1.1 ! root 1: /* Parse C expressions for CCCP. ! 2: Copyright (C) 1987, 1992 Free Software Foundation. ! 3: ! 4: This program is free software; you can redistribute it and/or modify it ! 5: under the terms of the GNU General Public License as published by the ! 6: Free Software Foundation; either version 2, or (at your option) any ! 7: later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 12: GNU General Public License for more details. ! 13: ! 14: You should have received a copy of the GNU General Public License ! 15: along with this program; if not, write to the Free Software ! 16: Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: ! 18: In other words, you are welcome to use, share and improve this program. ! 19: You are forbidden to forbid anyone else to use, share and improve ! 20: what you give them. Help stamp out software-hoarding! ! 21: ! 22: Adapted from expread.y of GDB by Paul Rubin, July 1986. ! 23: ! 24: /* Parse a C expression from text in a string */ ! 25: ! 26: %{ ! 27: #include "config.h" ! 28: #include <setjmp.h> ! 29: /* #define YYDEBUG 1 */ ! 30: ! 31: #ifdef MULTIBYTE_CHARS ! 32: #include <stdlib.h> ! 33: #include <locale.h> ! 34: #endif ! 35: ! 36: typedef unsigned char U_CHAR; ! 37: ! 38: /* This is used for communicating lists of keywords with cccp.c. */ ! 39: struct arglist { ! 40: struct arglist *next; ! 41: U_CHAR *name; ! 42: int length; ! 43: int argno; ! 44: }; ! 45: ! 46: int yylex (); ! 47: void yyerror (); ! 48: int expression_value; ! 49: ! 50: static jmp_buf parse_return_error; ! 51: ! 52: /* Nonzero means count most punctuation as part of a name. */ ! 53: static int keyword_parsing = 0; ! 54: ! 55: /* some external tables of character types */ ! 56: extern unsigned char is_idstart[], is_idchar[], is_hor_space[]; ! 57: ! 58: /* Flag for -pedantic. */ ! 59: extern int pedantic; ! 60: ! 61: /* Flag for -traditional. */ ! 62: extern int traditional; ! 63: ! 64: #ifndef CHAR_TYPE_SIZE ! 65: #define CHAR_TYPE_SIZE BITS_PER_UNIT ! 66: #endif ! 67: ! 68: #ifndef INT_TYPE_SIZE ! 69: #define INT_TYPE_SIZE BITS_PER_WORD ! 70: #endif ! 71: ! 72: #ifndef LONG_TYPE_SIZE ! 73: #define LONG_TYPE_SIZE BITS_PER_WORD ! 74: #endif ! 75: ! 76: #ifndef WCHAR_TYPE_SIZE ! 77: #define WCHAR_TYPE_SIZE INT_TYPE_SIZE ! 78: #endif ! 79: %} ! 80: ! 81: %union { ! 82: struct constant {long value; int unsignedp;} integer; ! 83: struct name {U_CHAR *address; int length;} name; ! 84: struct arglist *keywords; ! 85: int voidval; ! 86: char *sval; ! 87: } ! 88: ! 89: %type <integer> exp exp1 start ! 90: %type <keywords> keywords ! 91: %token <integer> INT CHAR ! 92: %token <name> NAME ! 93: %token <integer> ERROR ! 94: ! 95: %right '?' ':' ! 96: %left ',' ! 97: %left OR ! 98: %left AND ! 99: %left '|' ! 100: %left '^' ! 101: %left '&' ! 102: %left EQUAL NOTEQUAL ! 103: %left '<' '>' LEQ GEQ ! 104: %left LSH RSH ! 105: %left '+' '-' ! 106: %left '*' '/' '%' ! 107: %right UNARY ! 108: ! 109: /* %expect 40 */ ! 110: ! 111: %% ! 112: ! 113: start : exp1 ! 114: { expression_value = $1.value; } ! 115: ; ! 116: ! 117: /* Expressions, including the comma operator. */ ! 118: exp1 : exp ! 119: | exp1 ',' exp ! 120: { if (pedantic) ! 121: pedwarn ("comma operator in operand of `#if'"); ! 122: $$ = $3; } ! 123: ; ! 124: ! 125: /* Expressions, not including the comma operator. */ ! 126: exp : '-' exp %prec UNARY ! 127: { $$.value = - $2.value; ! 128: $$.unsignedp = $2.unsignedp; } ! 129: | '!' exp %prec UNARY ! 130: { $$.value = ! $2.value; ! 131: $$.unsignedp = 0; } ! 132: | '+' exp %prec UNARY ! 133: { $$ = $2; } ! 134: | '~' exp %prec UNARY ! 135: { $$.value = ~ $2.value; ! 136: $$.unsignedp = $2.unsignedp; } ! 137: | '#' NAME ! 138: { $$.value = check_assertion ($2.address, $2.length, ! 139: 0, 0); ! 140: $$.unsignedp = 0; } ! 141: | '#' NAME ! 142: { keyword_parsing = 1; } ! 143: '(' keywords ')' ! 144: { $$.value = check_assertion ($2.address, $2.length, ! 145: 1, $5); ! 146: keyword_parsing = 0; ! 147: $$.unsignedp = 0; } ! 148: | '(' exp1 ')' ! 149: { $$ = $2; } ! 150: ; ! 151: ! 152: /* Binary operators in order of decreasing precedence. */ ! 153: exp : exp '*' exp ! 154: { $$.unsignedp = $1.unsignedp || $3.unsignedp; ! 155: if ($$.unsignedp) ! 156: $$.value = (unsigned) $1.value * $3.value; ! 157: else ! 158: $$.value = $1.value * $3.value; } ! 159: | exp '/' exp ! 160: { if ($3.value == 0) ! 161: { ! 162: error ("division by zero in #if"); ! 163: $3.value = 1; ! 164: } ! 165: $$.unsignedp = $1.unsignedp || $3.unsignedp; ! 166: if ($$.unsignedp) ! 167: $$.value = (unsigned) $1.value / $3.value; ! 168: else ! 169: $$.value = $1.value / $3.value; } ! 170: | exp '%' exp ! 171: { if ($3.value == 0) ! 172: { ! 173: error ("division by zero in #if"); ! 174: $3.value = 1; ! 175: } ! 176: $$.unsignedp = $1.unsignedp || $3.unsignedp; ! 177: if ($$.unsignedp) ! 178: $$.value = (unsigned) $1.value % $3.value; ! 179: else ! 180: $$.value = $1.value % $3.value; } ! 181: | exp '+' exp ! 182: { $$.value = $1.value + $3.value; ! 183: $$.unsignedp = $1.unsignedp || $3.unsignedp; } ! 184: | exp '-' exp ! 185: { $$.value = $1.value - $3.value; ! 186: $$.unsignedp = $1.unsignedp || $3.unsignedp; } ! 187: | exp LSH exp ! 188: { $$.unsignedp = $1.unsignedp; ! 189: if ($$.unsignedp) ! 190: $$.value = (unsigned) $1.value << $3.value; ! 191: else ! 192: $$.value = $1.value << $3.value; } ! 193: | exp RSH exp ! 194: { $$.unsignedp = $1.unsignedp; ! 195: if ($$.unsignedp) ! 196: $$.value = (unsigned) $1.value >> $3.value; ! 197: else ! 198: $$.value = $1.value >> $3.value; } ! 199: | exp EQUAL exp ! 200: { $$.value = ($1.value == $3.value); ! 201: $$.unsignedp = 0; } ! 202: | exp NOTEQUAL exp ! 203: { $$.value = ($1.value != $3.value); ! 204: $$.unsignedp = 0; } ! 205: | exp LEQ exp ! 206: { $$.unsignedp = 0; ! 207: if ($1.unsignedp || $3.unsignedp) ! 208: $$.value = (unsigned) $1.value <= $3.value; ! 209: else ! 210: $$.value = $1.value <= $3.value; } ! 211: | exp GEQ exp ! 212: { $$.unsignedp = 0; ! 213: if ($1.unsignedp || $3.unsignedp) ! 214: $$.value = (unsigned) $1.value >= $3.value; ! 215: else ! 216: $$.value = $1.value >= $3.value; } ! 217: | exp '<' exp ! 218: { $$.unsignedp = 0; ! 219: if ($1.unsignedp || $3.unsignedp) ! 220: $$.value = (unsigned) $1.value < $3.value; ! 221: else ! 222: $$.value = $1.value < $3.value; } ! 223: | exp '>' exp ! 224: { $$.unsignedp = 0; ! 225: if ($1.unsignedp || $3.unsignedp) ! 226: $$.value = (unsigned) $1.value > $3.value; ! 227: else ! 228: $$.value = $1.value > $3.value; } ! 229: | exp '&' exp ! 230: { $$.value = $1.value & $3.value; ! 231: $$.unsignedp = $1.unsignedp || $3.unsignedp; } ! 232: | exp '^' exp ! 233: { $$.value = $1.value ^ $3.value; ! 234: $$.unsignedp = $1.unsignedp || $3.unsignedp; } ! 235: | exp '|' exp ! 236: { $$.value = $1.value | $3.value; ! 237: $$.unsignedp = $1.unsignedp || $3.unsignedp; } ! 238: | exp AND exp ! 239: { $$.value = ($1.value && $3.value); ! 240: $$.unsignedp = 0; } ! 241: | exp OR exp ! 242: { $$.value = ($1.value || $3.value); ! 243: $$.unsignedp = 0; } ! 244: | exp '?' exp ':' exp ! 245: { $$.value = $1.value ? $3.value : $5.value; ! 246: $$.unsignedp = $3.unsignedp || $5.unsignedp; } ! 247: | INT ! 248: { $$ = yylval.integer; } ! 249: | CHAR ! 250: { $$ = yylval.integer; } ! 251: | NAME ! 252: { $$.value = 0; ! 253: $$.unsignedp = 0; } ! 254: ; ! 255: ! 256: keywords : ! 257: { $$ = 0; } ! 258: | '(' keywords ')' keywords ! 259: { struct arglist *temp; ! 260: $$ = (struct arglist *) xmalloc (sizeof (struct arglist)); ! 261: $$->next = $2; ! 262: $$->name = (U_CHAR *) "("; ! 263: $$->length = 1; ! 264: temp = $$; ! 265: while (temp != 0 && temp->next != 0) ! 266: temp = temp->next; ! 267: temp->next = (struct arglist *) xmalloc (sizeof (struct arglist)); ! 268: temp->next->next = $4; ! 269: temp->next->name = (U_CHAR *) ")"; ! 270: temp->next->length = 1; } ! 271: | NAME keywords ! 272: { $$ = (struct arglist *) xmalloc (sizeof (struct arglist)); ! 273: $$->name = $1.address; ! 274: $$->length = $1.length; ! 275: $$->next = $2; } ! 276: ; ! 277: %% ! 278: ! 279: /* During parsing of a C expression, the pointer to the next character ! 280: is in this variable. */ ! 281: ! 282: static char *lexptr; ! 283: ! 284: /* Take care of parsing a number (anything that starts with a digit). ! 285: Set yylval and return the token type; update lexptr. ! 286: LEN is the number of characters in it. */ ! 287: ! 288: /* maybe needs to actually deal with floating point numbers */ ! 289: ! 290: int ! 291: parse_number (olen) ! 292: int olen; ! 293: { ! 294: register char *p = lexptr; ! 295: register long n = 0; ! 296: register int c; ! 297: register int base = 10; ! 298: register int len = olen; ! 299: ! 300: for (c = 0; c < len; c++) ! 301: if (p[c] == '.') { ! 302: /* It's a float since it contains a point. */ ! 303: yyerror ("floating point numbers not allowed in #if expressions"); ! 304: return ERROR; ! 305: } ! 306: ! 307: yylval.integer.unsignedp = 0; ! 308: ! 309: if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { ! 310: p += 2; ! 311: base = 16; ! 312: len -= 2; ! 313: } ! 314: else if (*p == '0') ! 315: base = 8; ! 316: ! 317: while (len > 0) { ! 318: c = *p++; ! 319: len--; ! 320: if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; ! 321: ! 322: if (c >= '0' && c <= '9') { ! 323: n *= base; ! 324: n += c - '0'; ! 325: } else if (base == 16 && c >= 'a' && c <= 'f') { ! 326: n *= base; ! 327: n += c - 'a' + 10; ! 328: } else { ! 329: /* `l' means long, and `u' means unsigned. */ ! 330: while (1) { ! 331: if (c == 'l' || c == 'L') ! 332: ; ! 333: else if (c == 'u' || c == 'U') ! 334: yylval.integer.unsignedp = 1; ! 335: else ! 336: break; ! 337: ! 338: if (len == 0) ! 339: break; ! 340: c = *p++; ! 341: len--; ! 342: } ! 343: /* Don't look for any more digits after the suffixes. */ ! 344: break; ! 345: } ! 346: } ! 347: ! 348: if (len != 0) { ! 349: yyerror ("Invalid number in #if expression"); ! 350: return ERROR; ! 351: } ! 352: ! 353: /* If too big to be signed, consider it unsigned. */ ! 354: if (n < 0) ! 355: yylval.integer.unsignedp = 1; ! 356: ! 357: lexptr = p; ! 358: yylval.integer.value = n; ! 359: return INT; ! 360: } ! 361: ! 362: struct token { ! 363: char *operator; ! 364: int token; ! 365: }; ! 366: ! 367: #ifndef NULL ! 368: #define NULL 0 ! 369: #endif ! 370: ! 371: static struct token tokentab2[] = { ! 372: {"&&", AND}, ! 373: {"||", OR}, ! 374: {"<<", LSH}, ! 375: {">>", RSH}, ! 376: {"==", EQUAL}, ! 377: {"!=", NOTEQUAL}, ! 378: {"<=", LEQ}, ! 379: {">=", GEQ}, ! 380: {"++", ERROR}, ! 381: {"--", ERROR}, ! 382: {NULL, ERROR} ! 383: }; ! 384: ! 385: /* Read one token, getting characters through lexptr. */ ! 386: ! 387: int ! 388: yylex () ! 389: { ! 390: register int c; ! 391: register int namelen; ! 392: register char *tokstart; ! 393: register struct token *toktab; ! 394: int wide_flag; ! 395: ! 396: retry: ! 397: ! 398: tokstart = lexptr; ! 399: c = *tokstart; ! 400: /* See if it is a special token of length 2. */ ! 401: if (! keyword_parsing) ! 402: for (toktab = tokentab2; toktab->operator != NULL; toktab++) ! 403: if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { ! 404: lexptr += 2; ! 405: if (toktab->token == ERROR) ! 406: { ! 407: char *buf = (char *) alloca (40); ! 408: sprintf (buf, "`%s' not allowed in operand of `#if'", toktab->operator); ! 409: yyerror (buf); ! 410: } ! 411: return toktab->token; ! 412: } ! 413: ! 414: switch (c) { ! 415: case 0: ! 416: return 0; ! 417: ! 418: case ' ': ! 419: case '\t': ! 420: case '\r': ! 421: case '\n': ! 422: lexptr++; ! 423: goto retry; ! 424: ! 425: case 'L': ! 426: /* Capital L may start a wide-string or wide-character constant. */ ! 427: if (lexptr[1] == '\'') ! 428: { ! 429: lexptr++; ! 430: wide_flag = 1; ! 431: goto char_constant; ! 432: } ! 433: if (lexptr[1] == '"') ! 434: { ! 435: lexptr++; ! 436: wide_flag = 1; ! 437: goto string_constant; ! 438: } ! 439: break; ! 440: ! 441: case '\'': ! 442: wide_flag = 0; ! 443: char_constant: ! 444: lexptr++; ! 445: if (keyword_parsing) { ! 446: char *start_ptr = lexptr - 1; ! 447: while (1) { ! 448: c = *lexptr++; ! 449: if (c == '\\') ! 450: c = parse_escape (&lexptr); ! 451: else if (c == '\'') ! 452: break; ! 453: } ! 454: yylval.name.address = (U_CHAR *) tokstart; ! 455: yylval.name.length = lexptr - start_ptr; ! 456: return NAME; ! 457: } ! 458: ! 459: /* This code for reading a character constant ! 460: handles multicharacter constants and wide characters. ! 461: It is mostly copied from c-lex.c. */ ! 462: { ! 463: register int result = 0; ! 464: register num_chars = 0; ! 465: unsigned width = CHAR_TYPE_SIZE; ! 466: int max_chars; ! 467: char *token_buffer; ! 468: ! 469: if (wide_flag) ! 470: { ! 471: width = WCHAR_TYPE_SIZE; ! 472: #ifdef MULTIBYTE_CHARS ! 473: max_chars = MB_CUR_MAX; ! 474: #else ! 475: max_chars = 1; ! 476: #endif ! 477: } ! 478: else ! 479: max_chars = LONG_TYPE_SIZE / width; ! 480: ! 481: token_buffer = (char *) alloca (max_chars + 1); ! 482: ! 483: while (1) ! 484: { ! 485: c = *lexptr++; ! 486: ! 487: if (c == '\'' || c == EOF) ! 488: break; ! 489: ! 490: if (c == '\\') ! 491: { ! 492: c = parse_escape (&lexptr); ! 493: if (width < HOST_BITS_PER_INT ! 494: && (unsigned) c >= (1 << width)) ! 495: pedwarn ("escape sequence out of range for character"); ! 496: } ! 497: ! 498: num_chars++; ! 499: ! 500: /* Merge character into result; ignore excess chars. */ ! 501: if (num_chars < max_chars + 1) ! 502: { ! 503: if (width < HOST_BITS_PER_INT) ! 504: result = (result << width) | (c & ((1 << width) - 1)); ! 505: else ! 506: result = c; ! 507: token_buffer[num_chars - 1] = c; ! 508: } ! 509: } ! 510: ! 511: token_buffer[num_chars] = 0; ! 512: ! 513: if (c != '\'') ! 514: error ("malformatted character constant"); ! 515: else if (num_chars == 0) ! 516: error ("empty character constant"); ! 517: else if (num_chars > max_chars) ! 518: { ! 519: num_chars = max_chars; ! 520: error ("character constant too long"); ! 521: } ! 522: else if (num_chars != 1 && ! traditional) ! 523: warning ("multi-character character constant"); ! 524: ! 525: /* If char type is signed, sign-extend the constant. */ ! 526: if (! wide_flag) ! 527: { ! 528: int num_bits = num_chars * width; ! 529: ! 530: if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1) ! 531: || ((result >> (num_bits - 1)) & 1) == 0) ! 532: yylval.integer.value ! 533: = result & ((unsigned) ~0 >> (HOST_BITS_PER_INT - num_bits)); ! 534: else ! 535: yylval.integer.value ! 536: = result | ~((unsigned) ~0 >> (HOST_BITS_PER_INT - num_bits)); ! 537: } ! 538: else ! 539: { ! 540: #ifdef MULTIBYTE_CHARS ! 541: /* Set the initial shift state and convert the next sequence. */ ! 542: result = 0; ! 543: /* In all locales L'\0' is zero and mbtowc will return zero, ! 544: so don't use it. */ ! 545: if (num_chars > 1 ! 546: || (num_chars == 1 && token_buffer[0] != '\0')) ! 547: { ! 548: wchar_t wc; ! 549: (void) mbtowc (NULL, NULL, 0); ! 550: if (mbtowc (& wc, token_buffer, num_chars) == num_chars) ! 551: result = wc; ! 552: else ! 553: warning ("Ignoring invalid multibyte character"); ! 554: } ! 555: #endif ! 556: yylval.integer.value = result; ! 557: } ! 558: } ! 559: ! 560: /* This is always a signed type. */ ! 561: yylval.integer.unsignedp = 0; ! 562: ! 563: return CHAR; ! 564: ! 565: /* some of these chars are invalid in constant expressions; ! 566: maybe do something about them later */ ! 567: case '/': ! 568: case '+': ! 569: case '-': ! 570: case '*': ! 571: case '%': ! 572: case '|': ! 573: case '&': ! 574: case '^': ! 575: case '~': ! 576: case '!': ! 577: case '@': ! 578: case '<': ! 579: case '>': ! 580: case '[': ! 581: case ']': ! 582: case '.': ! 583: case '?': ! 584: case ':': ! 585: case '=': ! 586: case '{': ! 587: case '}': ! 588: case ',': ! 589: case '#': ! 590: if (keyword_parsing) ! 591: break; ! 592: case '(': ! 593: case ')': ! 594: lexptr++; ! 595: return c; ! 596: ! 597: case '"': ! 598: string_constant: ! 599: if (keyword_parsing) { ! 600: char *start_ptr = lexptr; ! 601: lexptr++; ! 602: while (1) { ! 603: c = *lexptr++; ! 604: if (c == '\\') ! 605: c = parse_escape (&lexptr); ! 606: else if (c == '"') ! 607: break; ! 608: } ! 609: yylval.name.address = (U_CHAR *) tokstart; ! 610: yylval.name.length = lexptr - start_ptr; ! 611: return NAME; ! 612: } ! 613: yyerror ("string constants not allowed in #if expressions"); ! 614: return ERROR; ! 615: } ! 616: ! 617: if (c >= '0' && c <= '9' && !keyword_parsing) { ! 618: /* It's a number */ ! 619: for (namelen = 0; ! 620: c = tokstart[namelen], is_idchar[c] || c == '.'; ! 621: namelen++) ! 622: ; ! 623: return parse_number (namelen); ! 624: } ! 625: ! 626: /* It is a name. See how long it is. */ ! 627: ! 628: if (keyword_parsing) { ! 629: for (namelen = 0;; namelen++) { ! 630: if (is_hor_space[tokstart[namelen]]) ! 631: break; ! 632: if (tokstart[namelen] == '(' || tokstart[namelen] == ')') ! 633: break; ! 634: if (tokstart[namelen] == '"' || tokstart[namelen] == '\'') ! 635: break; ! 636: } ! 637: } else { ! 638: if (!is_idstart[c]) { ! 639: yyerror ("Invalid token in expression"); ! 640: return ERROR; ! 641: } ! 642: ! 643: for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) ! 644: ; ! 645: } ! 646: ! 647: lexptr += namelen; ! 648: yylval.name.address = (U_CHAR *) tokstart; ! 649: yylval.name.length = namelen; ! 650: return NAME; ! 651: } ! 652: ! 653: ! 654: /* Parse a C escape sequence. STRING_PTR points to a variable ! 655: containing a pointer to the string to parse. That pointer ! 656: is updated past the characters we use. The value of the ! 657: escape sequence is returned. ! 658: ! 659: A negative value means the sequence \ newline was seen, ! 660: which is supposed to be equivalent to nothing at all. ! 661: ! 662: If \ is followed by a null character, we return a negative ! 663: value and leave the string pointer pointing at the null character. ! 664: ! 665: If \ is followed by 000, we return 0 and leave the string pointer ! 666: after the zeros. A value of 0 does not mean end of string. */ ! 667: ! 668: int ! 669: parse_escape (string_ptr) ! 670: char **string_ptr; ! 671: { ! 672: register int c = *(*string_ptr)++; ! 673: switch (c) ! 674: { ! 675: case 'a': ! 676: return TARGET_BELL; ! 677: case 'b': ! 678: return TARGET_BS; ! 679: case 'e': ! 680: return 033; ! 681: case 'f': ! 682: return TARGET_FF; ! 683: case 'n': ! 684: return TARGET_NEWLINE; ! 685: case 'r': ! 686: return TARGET_CR; ! 687: case 't': ! 688: return TARGET_TAB; ! 689: case 'v': ! 690: return TARGET_VT; ! 691: case '\n': ! 692: return -2; ! 693: case 0: ! 694: (*string_ptr)--; ! 695: return 0; ! 696: case '^': ! 697: c = *(*string_ptr)++; ! 698: if (c == '\\') ! 699: c = parse_escape (string_ptr); ! 700: if (c == '?') ! 701: return 0177; ! 702: return (c & 0200) | (c & 037); ! 703: ! 704: case '0': ! 705: case '1': ! 706: case '2': ! 707: case '3': ! 708: case '4': ! 709: case '5': ! 710: case '6': ! 711: case '7': ! 712: { ! 713: register int i = c - '0'; ! 714: register int count = 0; ! 715: while (++count < 3) ! 716: { ! 717: c = *(*string_ptr)++; ! 718: if (c >= '0' && c <= '7') ! 719: i = (i << 3) + c - '0'; ! 720: else ! 721: { ! 722: (*string_ptr)--; ! 723: break; ! 724: } ! 725: } ! 726: if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0) ! 727: { ! 728: i &= (1 << CHAR_TYPE_SIZE) - 1; ! 729: warning ("octal character constant does not fit in a byte"); ! 730: } ! 731: return i; ! 732: } ! 733: case 'x': ! 734: { ! 735: register int i = 0; ! 736: for (;;) ! 737: { ! 738: c = *(*string_ptr)++; ! 739: if (c >= '0' && c <= '9') ! 740: i = (i << 4) + c - '0'; ! 741: else if (c >= 'a' && c <= 'f') ! 742: i = (i << 4) + c - 'a' + 10; ! 743: else if (c >= 'A' && c <= 'F') ! 744: i = (i << 4) + c - 'A' + 10; ! 745: else ! 746: { ! 747: (*string_ptr)--; ! 748: break; ! 749: } ! 750: } ! 751: if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0) ! 752: { ! 753: i &= (1 << BITS_PER_UNIT) - 1; ! 754: warning ("hex character constant does not fit in a byte"); ! 755: } ! 756: return i; ! 757: } ! 758: default: ! 759: return c; ! 760: } ! 761: } ! 762: ! 763: void ! 764: yyerror (s) ! 765: char *s; ! 766: { ! 767: error (s); ! 768: longjmp (parse_return_error, 1); ! 769: } ! 770: ! 771: /* This page contains the entry point to this file. */ ! 772: ! 773: /* Parse STRING as an expression, and complain if this fails ! 774: to use up all of the contents of STRING. */ ! 775: /* We do not support C comments. They should be removed before ! 776: this function is called. */ ! 777: ! 778: int ! 779: parse_c_expression (string) ! 780: char *string; ! 781: { ! 782: lexptr = string; ! 783: ! 784: if (lexptr == 0 || *lexptr == 0) { ! 785: error ("empty #if expression"); ! 786: return 0; /* don't include the #if group */ ! 787: } ! 788: ! 789: /* if there is some sort of scanning error, just return 0 and assume ! 790: the parsing routine has printed an error message somewhere. ! 791: there is surely a better thing to do than this. */ ! 792: if (setjmp (parse_return_error)) ! 793: return 0; ! 794: ! 795: if (yyparse ()) ! 796: return 0; /* actually this is never reached ! 797: the way things stand. */ ! 798: if (*lexptr) ! 799: error ("Junk after end of expression."); ! 800: ! 801: return expression_value; /* set by yyparse () */ ! 802: } ! 803: ! 804: #ifdef TEST_EXP_READER ! 805: extern int yydebug; ! 806: ! 807: /* Main program for testing purposes. */ ! 808: int ! 809: main () ! 810: { ! 811: int n, c; ! 812: char buf[1024]; ! 813: ! 814: /* ! 815: yydebug = 1; ! 816: */ ! 817: initialize_random_junk (); ! 818: ! 819: for (;;) { ! 820: printf ("enter expression: "); ! 821: n = 0; ! 822: while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF) ! 823: n++; ! 824: if (buf[n] == EOF) ! 825: break; ! 826: buf[n] = '\0'; ! 827: printf ("parser returned %d\n", parse_c_expression (buf)); ! 828: } ! 829: ! 830: return 0; ! 831: } ! 832: ! 833: /* table to tell if char can be part of a C identifier. */ ! 834: unsigned char is_idchar[256]; ! 835: /* table to tell if char can be first char of a c identifier. */ ! 836: unsigned char is_idstart[256]; ! 837: /* table to tell if c is horizontal space. isspace () thinks that ! 838: newline is space; this is not a good idea for this program. */ ! 839: char is_hor_space[256]; ! 840: ! 841: /* ! 842: * initialize random junk in the hash table and maybe other places ! 843: */ ! 844: initialize_random_junk () ! 845: { ! 846: register int i; ! 847: ! 848: /* ! 849: * Set up is_idchar and is_idstart tables. These should be ! 850: * faster than saying (is_alpha (c) || c == '_'), etc. ! 851: * Must do set up these things before calling any routines tthat ! 852: * refer to them. ! 853: */ ! 854: for (i = 'a'; i <= 'z'; i++) { ! 855: ++is_idchar[i - 'a' + 'A']; ! 856: ++is_idchar[i]; ! 857: ++is_idstart[i - 'a' + 'A']; ! 858: ++is_idstart[i]; ! 859: } ! 860: for (i = '0'; i <= '9'; i++) ! 861: ++is_idchar[i]; ! 862: ++is_idchar['_']; ! 863: ++is_idstart['_']; ! 864: #if DOLLARS_IN_IDENTIFIERS ! 865: ++is_idchar['$']; ! 866: ++is_idstart['$']; ! 867: #endif ! 868: ! 869: /* horizontal space table */ ! 870: ++is_hor_space[' ']; ! 871: ++is_hor_space['\t']; ! 872: } ! 873: ! 874: error (msg) ! 875: { ! 876: printf ("error: %s\n", msg); ! 877: } ! 878: ! 879: warning (msg) ! 880: { ! 881: printf ("warning: %s\n", msg); ! 882: } ! 883: ! 884: struct hashnode * ! 885: lookup (name, len, hash) ! 886: char *name; ! 887: int len; ! 888: int hash; ! 889: { ! 890: return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1); ! 891: } ! 892: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.