|
|
1.1 root 1: /* Parse C expressions for CCCP.
2: Copyright (C) 1987 Free Software Foundation.
3:
1.1.1.6 root 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 1, 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.
1.1 root 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: %{
1.1.1.3 root 27: #include "config.h"
1.1 root 28: #include <setjmp.h>
29: /* #define YYDEBUG 1 */
30:
1.1.1.4 root 31: int yylex ();
32: void yyerror ();
1.1 root 33: int expression_value;
34:
35: static jmp_buf parse_return_error;
36:
37: /* some external tables of character types */
38: extern unsigned char is_idstart[], is_idchar[];
39:
1.1.1.7 ! root 40: #ifndef CHAR_TYPE_SIZE
! 41: #define CHAR_TYPE_SIZE BITS_PER_UNIT
! 42: #endif
1.1 root 43: %}
44:
45: %union {
1.1.1.7 ! root 46: struct constant {long value; int unsignedp;} integer;
1.1 root 47: int voidval;
48: char *sval;
49: }
50:
1.1.1.7 ! root 51: %type <integer> exp exp1 start
! 52: %token <integer> INT CHAR
1.1 root 53: %token <sval> NAME
1.1.1.7 ! root 54: %token <integer> ERROR
1.1 root 55:
1.1.1.2 root 56: %right '?' ':'
1.1 root 57: %left ','
58: %left OR
59: %left AND
60: %left '|'
61: %left '^'
62: %left '&'
63: %left EQUAL NOTEQUAL
64: %left '<' '>' LEQ GEQ
65: %left LSH RSH
66: %left '+' '-'
67: %left '*' '/' '%'
68: %right UNARY
1.1.1.2 root 69:
70: /* %expect 40 */
1.1 root 71:
72: %%
73:
74: start : exp1
1.1.1.7 ! root 75: { expression_value = $1.value; }
1.1 root 76: ;
77:
78: /* Expressions, including the comma operator. */
79: exp1 : exp
80: | exp1 ',' exp
81: { $$ = $3; }
82: ;
83:
84: /* Expressions, not including the comma operator. */
85: exp : '-' exp %prec UNARY
1.1.1.7 ! root 86: { $$.value = - $2.value;
! 87: $$.unsignedp = $2.unsignedp; }
1.1 root 88: | '!' exp %prec UNARY
1.1.1.7 ! root 89: { $$.value = ! $2.value;
! 90: $$.unsignedp = 0; }
1.1 root 91: | '~' exp %prec UNARY
1.1.1.7 ! root 92: { $$.value = ~ $2.value;
! 93: $$.unsignedp = $2.unsignedp; }
1.1 root 94: | '(' exp1 ')'
95: { $$ = $2; }
96: ;
97:
98: /* Binary operators in order of decreasing precedence. */
99: exp : exp '*' exp
1.1.1.7 ! root 100: { $$.unsignedp = $1.unsignedp || $3.unsignedp;
! 101: if ($$.unsignedp)
! 102: $$.value = (unsigned) $1.value * $3.value;
! 103: else
! 104: $$.value = $1.value * $3.value; }
1.1 root 105: | exp '/' exp
1.1.1.7 ! root 106: { if ($3.value == 0)
1.1.1.5 root 107: {
108: error ("division by zero in #if");
1.1.1.7 ! root 109: $3.value = 1;
1.1.1.5 root 110: }
1.1.1.7 ! root 111: $$.unsignedp = $1.unsignedp || $3.unsignedp;
! 112: if ($$.unsignedp)
! 113: $$.value = (unsigned) $1.value / $3.value;
! 114: else
! 115: $$.value = $1.value / $3.value; }
1.1 root 116: | exp '%' exp
1.1.1.7 ! root 117: { if ($3.value == 0)
1.1.1.5 root 118: {
119: error ("division by zero in #if");
1.1.1.7 ! root 120: $3.value = 1;
1.1.1.5 root 121: }
1.1.1.7 ! root 122: $$.unsignedp = $1.unsignedp || $3.unsignedp;
! 123: if ($$.unsignedp)
! 124: $$.value = (unsigned) $1.value % $3.value;
! 125: else
! 126: $$.value = $1.value % $3.value; }
1.1 root 127: | exp '+' exp
1.1.1.7 ! root 128: { $$.value = $1.value + $3.value;
! 129: $$.unsignedp = $1.unsignedp || $3.unsignedp; }
1.1 root 130: | exp '-' exp
1.1.1.7 ! root 131: { $$.value = $1.value - $3.value;
! 132: $$.unsignedp = $1.unsignedp || $3.unsignedp; }
1.1 root 133: | exp LSH exp
1.1.1.7 ! root 134: { $$.unsignedp = $1.unsignedp;
! 135: if ($$.unsignedp)
! 136: $$.value = (unsigned) $1.value << $3.value;
! 137: else
! 138: $$.value = $1.value << $3.value; }
1.1 root 139: | exp RSH exp
1.1.1.7 ! root 140: { $$.unsignedp = $1.unsignedp;
! 141: if ($$.unsignedp)
! 142: $$.value = (unsigned) $1.value >> $3.value;
! 143: else
! 144: $$.value = $1.value >> $3.value; }
1.1 root 145: | exp EQUAL exp
1.1.1.7 ! root 146: { $$.value = ($1.value == $3.value);
! 147: $$.unsignedp = 0; }
1.1 root 148: | exp NOTEQUAL exp
1.1.1.7 ! root 149: { $$.value = ($1.value != $3.value);
! 150: $$.unsignedp = 0; }
1.1 root 151: | exp LEQ exp
1.1.1.7 ! root 152: { $$.unsignedp = 0;
! 153: if ($1.unsignedp || $3.unsignedp)
! 154: $$.value = (unsigned) $1.value <= $3.value;
! 155: else
! 156: $$.value = $1.value <= $3.value; }
1.1 root 157: | exp GEQ exp
1.1.1.7 ! root 158: { $$.unsignedp = 0;
! 159: if ($1.unsignedp || $3.unsignedp)
! 160: $$.value = (unsigned) $1.value >= $3.value;
! 161: else
! 162: $$.value = $1.value >= $3.value; }
1.1 root 163: | exp '<' exp
1.1.1.7 ! root 164: { $$.unsignedp = 0;
! 165: if ($1.unsignedp || $3.unsignedp)
! 166: $$.value = (unsigned) $1.value < $3.value;
! 167: else
! 168: $$.value = $1.value < $3.value; }
1.1 root 169: | exp '>' exp
1.1.1.7 ! root 170: { $$.unsignedp = 0;
! 171: if ($1.unsignedp || $3.unsignedp)
! 172: $$.value = (unsigned) $1.value > $3.value;
! 173: else
! 174: $$.value = $1.value > $3.value; }
1.1 root 175: | exp '&' exp
1.1.1.7 ! root 176: { $$.value = $1.value & $3.value;
! 177: $$.unsignedp = $1.unsignedp || $3.unsignedp; }
1.1 root 178: | exp '^' exp
1.1.1.7 ! root 179: { $$.value = $1.value ^ $3.value;
! 180: $$.unsignedp = $1.unsignedp || $3.unsignedp; }
1.1 root 181: | exp '|' exp
1.1.1.7 ! root 182: { $$.value = $1.value | $3.value;
! 183: $$.unsignedp = $1.unsignedp || $3.unsignedp; }
1.1 root 184: | exp AND exp
1.1.1.7 ! root 185: { $$.value = ($1.value && $3.value);
! 186: $$.unsignedp = 0; }
1.1 root 187: | exp OR exp
1.1.1.7 ! root 188: { $$.value = ($1.value || $3.value);
! 189: $$.unsignedp = 0; }
1.1 root 190: | exp '?' exp ':' exp
1.1.1.7 ! root 191: { $$.value = $1.value ? $3.value : $5.value;
! 192: $$.unsignedp = $3.unsignedp || $5.unsignedp; }
1.1 root 193: | INT
1.1.1.7 ! root 194: { $$ = yylval.integer; }
1.1 root 195: | CHAR
1.1.1.7 ! root 196: { $$ = yylval.integer; }
1.1 root 197: | NAME
1.1.1.7 ! root 198: { $$.value = 0;
! 199: $$.unsignedp = 0; }
1.1 root 200: ;
201: %%
202:
203: /* During parsing of a C expression, the pointer to the next character
204: is in this variable. */
205:
206: static char *lexptr;
207:
208: /* Take care of parsing a number (anything that starts with a digit).
209: Set yylval and return the token type; update lexptr.
210: LEN is the number of characters in it. */
211:
212: /* maybe needs to actually deal with floating point numbers */
213:
1.1.1.4 root 214: int
1.1 root 215: parse_number (olen)
216: int olen;
217: {
218: register char *p = lexptr;
219: register long n = 0;
220: register int c;
221: register int base = 10;
1.1.1.7 ! root 222: register int len = olen;
1.1 root 223:
224: for (c = 0; c < len; c++)
225: if (p[c] == '.') {
226: /* It's a float since it contains a point. */
227: yyerror ("floating point numbers not allowed in #if expressions");
228: return ERROR;
229: }
1.1.1.7 ! root 230:
! 231: yylval.integer.unsignedp = 0;
! 232:
1.1 root 233: if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
234: p += 2;
235: base = 16;
236: len -= 2;
237: }
238: else if (*p == '0')
239: base = 8;
1.1.1.7 ! root 240:
! 241: while (len > 0) {
1.1 root 242: c = *p++;
1.1.1.7 ! root 243: len--;
! 244: if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
! 245:
! 246: if (c >= '0' && c <= '9') {
! 247: n *= base;
1.1 root 248: n += c - '0';
1.1.1.7 ! root 249: } else if (base == 16 && c >= 'a' && c <= 'f') {
! 250: n *= base;
! 251: n += c - 'a' + 10;
! 252: } else {
! 253: /* `l' means long, and `u' means unsigned. */
! 254: while (1) {
! 255: if (c == 'l' || c == 'L')
! 256: ;
! 257: else if (c == 'u' || c == 'U')
! 258: yylval.integer.unsignedp = 1;
! 259: else
! 260: break;
! 261:
! 262: if (len == 0)
! 263: break;
! 264: c = *p++;
! 265: len--;
1.1 root 266: }
1.1.1.7 ! root 267: /* Don't look for any more digits after the suffixes. */
! 268: break;
1.1 root 269: }
270: }
271:
1.1.1.7 ! root 272: if (len != 0) {
! 273: yyerror ("Invalid number in #if expression");
! 274: return ERROR;
! 275: }
! 276:
! 277: /* If too big to be signed, consider it unsigned. */
! 278: if (n < 0)
! 279: yylval.integer.unsignedp = 1;
! 280:
1.1 root 281: lexptr = p;
1.1.1.7 ! root 282: yylval.integer.value = n;
1.1 root 283: return INT;
284: }
285:
286: struct token {
287: char *operator;
288: int token;
289: };
290:
1.1.1.7 ! root 291: #ifndef NULL
1.1 root 292: #define NULL 0
1.1.1.7 ! root 293: #endif
1.1 root 294:
295: static struct token tokentab2[] = {
296: {"&&", AND},
297: {"||", OR},
298: {"<<", LSH},
299: {">>", RSH},
300: {"==", EQUAL},
301: {"!=", NOTEQUAL},
302: {"<=", LEQ},
303: {">=", GEQ},
304: {NULL, ERROR}
305: };
306:
307: /* Read one token, getting characters through lexptr. */
308:
1.1.1.4 root 309: int
1.1 root 310: yylex ()
311: {
312: register int c;
313: register int namelen;
314: register char *tokstart;
315: register struct token *toktab;
316:
317: retry:
318:
319: tokstart = lexptr;
320: c = *tokstart;
321: /* See if it is a special token of length 2. */
322: for (toktab = tokentab2; toktab->operator != NULL; toktab++)
323: if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
324: lexptr += 2;
325: return toktab->token;
326: }
327:
328: switch (c) {
329: case 0:
330: return 0;
331:
332: case ' ':
333: case '\t':
334: case '\n':
335: lexptr++;
336: goto retry;
337:
338: case '\'':
339: lexptr++;
340: c = *lexptr++;
341: if (c == '\\')
342: c = parse_escape (&lexptr);
1.1.1.7 ! root 343:
! 344: /* Sign-extend the constant if chars are signed on target machine. */
! 345: {
! 346: if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
! 347: || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
! 348: yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
! 349: else
! 350: yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
! 351: }
! 352:
! 353: yylval.integer.unsignedp = 0;
1.1 root 354: c = *lexptr++;
355: if (c != '\'') {
356: yyerror ("Invalid character constant in #if");
357: return ERROR;
358: }
359:
360: return CHAR;
361:
362: /* some of these chars are invalid in constant expressions;
363: maybe do something about them later */
1.1.1.2 root 364: case '/':
1.1 root 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: case ']':
381: case '.':
382: case '?':
383: case ':':
384: case '=':
385: case '{':
386: case '}':
387: case ',':
388: lexptr++;
389: return c;
390:
391: case '"':
392: yyerror ("double quoted strings not allowed in #if expressions");
393: return ERROR;
394: }
395: if (c >= '0' && c <= '9') {
396: /* It's a number */
397: for (namelen = 0;
398: c = tokstart[namelen], is_idchar[c] || c == '.';
399: namelen++)
400: ;
401: return parse_number (namelen);
402: }
403:
404: if (!is_idstart[c]) {
405: yyerror ("Invalid token in expression");
406: return ERROR;
407: }
408:
409: /* It is a name. See how long it is. */
410:
411: for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++)
412: ;
413:
414: lexptr += namelen;
415: return NAME;
416: }
417:
418:
419: /* Parse a C escape sequence. STRING_PTR points to a variable
420: containing a pointer to the string to parse. That pointer
421: is updated past the characters we use. The value of the
422: escape sequence is returned.
423:
424: A negative value means the sequence \ newline was seen,
425: which is supposed to be equivalent to nothing at all.
426:
427: If \ is followed by a null character, we return a negative
428: value and leave the string pointer pointing at the null character.
429:
430: If \ is followed by 000, we return 0 and leave the string pointer
431: after the zeros. A value of 0 does not mean end of string. */
432:
1.1.1.4 root 433: int
1.1 root 434: parse_escape (string_ptr)
435: char **string_ptr;
436: {
437: register int c = *(*string_ptr)++;
438: switch (c)
439: {
440: case 'a':
1.1.1.7 ! root 441: return TARGET_BELL;
1.1 root 442: case 'b':
1.1.1.7 ! root 443: return TARGET_BS;
1.1 root 444: case 'e':
445: return 033;
446: case 'f':
1.1.1.7 ! root 447: return TARGET_FF;
1.1 root 448: case 'n':
1.1.1.7 ! root 449: return TARGET_NEWLINE;
1.1 root 450: case 'r':
1.1.1.7 ! root 451: return TARGET_CR;
1.1 root 452: case 't':
1.1.1.7 ! root 453: return TARGET_TAB;
1.1 root 454: case 'v':
1.1.1.7 ! root 455: return TARGET_VT;
1.1 root 456: case '\n':
457: return -2;
458: case 0:
459: (*string_ptr)--;
460: return 0;
461: case '^':
462: c = *(*string_ptr)++;
463: if (c == '\\')
464: c = parse_escape (string_ptr);
465: if (c == '?')
466: return 0177;
467: return (c & 0200) | (c & 037);
468:
469: case '0':
470: case '1':
471: case '2':
472: case '3':
473: case '4':
474: case '5':
475: case '6':
476: case '7':
477: {
478: register int i = c - '0';
479: register int count = 0;
480: while (++count < 3)
481: {
1.1.1.7 ! root 482: c = *(*string_ptr)++;
! 483: if (c >= '0' && c <= '7')
! 484: i = (i << 3) + c - '0';
! 485: else
1.1 root 486: {
1.1.1.7 ! root 487: (*string_ptr)--;
! 488: break;
1.1 root 489: }
1.1.1.7 ! root 490: }
! 491: if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
! 492: {
! 493: i &= (1 << CHAR_TYPE_SIZE) - 1;
! 494: warning ("octal character constant does not fit in a byte");
! 495: }
! 496: return i;
! 497: }
! 498: case 'x':
! 499: {
! 500: register int i = 0;
! 501: register int count = 0;
! 502: for (;;)
! 503: {
! 504: c = *(*string_ptr)++;
! 505: if (c >= '0' && c <= '9')
! 506: i = (i << 4) + c - '0';
! 507: else if (c >= 'a' && c <= 'f')
! 508: i = (i << 4) + c - 'a' + 10;
! 509: else if (c >= 'A' && c <= 'F')
! 510: i = (i << 4) + c - 'A' + 10;
1.1 root 511: else
512: {
513: (*string_ptr)--;
514: break;
515: }
516: }
1.1.1.7 ! root 517: if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
! 518: {
! 519: i &= (1 << BITS_PER_UNIT) - 1;
! 520: warning ("hex character constant does not fit in a byte");
! 521: }
1.1 root 522: return i;
523: }
524: default:
525: return c;
526: }
527: }
528:
1.1.1.4 root 529: void
1.1 root 530: yyerror (s)
531: char *s;
532: {
533: error (s);
534: longjmp (parse_return_error, 1);
535: }
536:
537: /* This page contains the entry point to this file. */
538:
539: /* Parse STRING as an expression, and complain if this fails
540: to use up all of the contents of STRING. */
1.1.1.2 root 541: /* We do not support C comments. They should be removed before
542: this function is called. */
543:
1.1 root 544: int
545: parse_c_expression (string)
546: char *string;
547: {
548: lexptr = string;
549:
550: if (lexptr == 0 || *lexptr == 0) {
551: error ("empty #if expression");
552: return 0; /* don't include the #if group */
553: }
554:
555: /* if there is some sort of scanning error, just return 0 and assume
556: the parsing routine has printed an error message somewhere.
557: there is surely a better thing to do than this. */
1.1.1.7 ! root 558: if (setjmp (parse_return_error))
1.1 root 559: return 0;
560:
561: if (yyparse ())
562: return 0; /* actually this is never reached
563: the way things stand. */
564: if (*lexptr)
565: error ("Junk after end of expression.");
566:
1.1.1.7 ! root 567: return expression_value; /* set by yyparse () */
1.1 root 568: }
569:
570: #ifdef TEST_EXP_READER
571: /* main program, for testing purposes. */
1.1.1.7 ! root 572: main ()
1.1 root 573: {
1.1.1.7 ! root 574: int n, c;
1.1 root 575: char buf[1024];
576: extern int yydebug;
577: /*
578: yydebug = 1;
579: */
580: initialize_random_junk ();
581:
582: for (;;) {
1.1.1.7 ! root 583: printf ("enter expression: ");
1.1 root 584: n = 0;
1.1.1.7 ! root 585: while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF)
1.1 root 586: n++;
1.1.1.7 ! root 587: if (buf[n] == EOF)
! 588: break;
1.1 root 589: buf[n] = '\0';
1.1.1.7 ! root 590: printf ("parser returned %d\n", parse_c_expression (buf));
1.1 root 591: }
592: }
593:
594: /* table to tell if char can be part of a C identifier. */
1.1.1.7 ! root 595: unsigned char is_idchar[256];
1.1 root 596: /* table to tell if char can be first char of a c identifier. */
1.1.1.7 ! root 597: unsigned char is_idstart[256];
! 598: /* table to tell if c is horizontal space. isspace () thinks that
1.1 root 599: newline is space; this is not a good idea for this program. */
600: char is_hor_space[256];
601:
602: /*
603: * initialize random junk in the hash table and maybe other places
604: */
1.1.1.7 ! root 605: initialize_random_junk ()
1.1 root 606: {
607: register int i;
608:
609: /*
610: * Set up is_idchar and is_idstart tables. These should be
1.1.1.7 ! root 611: * faster than saying (is_alpha (c) || c == '_'), etc.
1.1 root 612: * Must do set up these things before calling any routines tthat
613: * refer to them.
614: */
615: for (i = 'a'; i <= 'z'; i++) {
616: ++is_idchar[i - 'a' + 'A'];
617: ++is_idchar[i];
618: ++is_idstart[i - 'a' + 'A'];
619: ++is_idstart[i];
620: }
621: for (i = '0'; i <= '9'; i++)
622: ++is_idchar[i];
623: ++is_idchar['_'];
624: ++is_idstart['_'];
1.1.1.2 root 625: #ifdef DOLLARS_IN_IDENTIFIERS
626: ++is_idchar['$'];
627: ++is_idstart['$'];
628: #endif
1.1 root 629:
630: /* horizontal space table */
631: ++is_hor_space[' '];
632: ++is_hor_space['\t'];
633: }
634:
635: error (msg)
636: {
1.1.1.7 ! root 637: printf ("error: %s\n", msg);
! 638: }
! 639:
! 640: warning (msg)
! 641: {
! 642: printf ("warning: %s\n", msg);
! 643: }
! 644:
! 645: struct hashnode *
! 646: lookup (name, len, hash)
! 647: char *name;
! 648: int len;
! 649: int hash;
! 650: {
! 651: return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1);
1.1 root 652: }
653: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.