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