1 /* Parse C expressions for CCCP.
2 Copyright (C) 1987 Free Software Foundation.
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
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.
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.
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!
22 Adapted from expread.y of GDB by Paul Rubin, July 1986.
24 /* Parse a C expression from text in a string */
32 int yylex PARAMS ((void));
33 void yyerror PARAMS ((const char *msgid));
34 extern void error PARAMS ((const char *msgid, ...));
35 extern void warning PARAMS ((const char *msgid, ...));
36 extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
38 int parse_number PARAMS ((int));
39 int parse_escape PARAMS ((char **));
40 int parse_c_expression PARAMS ((char *));
43 static jmp_buf parse_return_error;
45 /* some external tables of character types */
46 extern unsigned char is_idstart[], is_idchar[];
51 struct constant {long value; int unsignedp;} integer;
56 %type <integer> exp exp1 start
57 %token <integer> INT CHAR
59 %token <integer> ERROR
80 { expression_value = $1.value; }
83 /* Expressions, including the comma operator. */
89 /* Expressions, not including the comma operator. */
90 exp : '-' exp %prec UNARY
91 { $$.value = - $2.value;
92 $$.unsignedp = $2.unsignedp; }
94 { $$.value = ! $2.value;
99 { $$.value = ~ $2.value;
100 $$.unsignedp = $2.unsignedp; }
105 /* Binary operators in order of decreasing precedence. */
107 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
109 $$.value = (unsigned) $1.value * $3.value;
111 $$.value = $1.value * $3.value; }
115 error ("division by zero in #if");
118 $$.unsignedp = $1.unsignedp || $3.unsignedp;
120 $$.value = (unsigned) $1.value / $3.value;
122 $$.value = $1.value / $3.value; }
126 error ("division by zero in #if");
129 $$.unsignedp = $1.unsignedp || $3.unsignedp;
131 $$.value = (unsigned) $1.value % $3.value;
133 $$.value = $1.value % $3.value; }
135 { $$.value = $1.value + $3.value;
136 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
138 { $$.value = $1.value - $3.value;
139 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
141 { $$.unsignedp = $1.unsignedp;
143 $$.value = (unsigned) $1.value << $3.value;
145 $$.value = $1.value << $3.value; }
147 { $$.unsignedp = $1.unsignedp;
149 $$.value = (unsigned) $1.value >> $3.value;
151 $$.value = $1.value >> $3.value; }
153 { $$.value = ($1.value == $3.value);
156 { $$.value = ($1.value != $3.value);
160 if ($1.unsignedp || $3.unsignedp)
162 (unsigned) $1.value <= (unsigned) $3.value;
164 $$.value = $1.value <= $3.value; }
167 if ($1.unsignedp || $3.unsignedp)
169 (unsigned) $1.value >= (unsigned) $3.value;
171 $$.value = $1.value >= $3.value; }
174 if ($1.unsignedp || $3.unsignedp)
176 (unsigned) $1.value < (unsigned) $3.value;
178 $$.value = $1.value < $3.value; }
181 if ($1.unsignedp || $3.unsignedp)
183 (unsigned) $1.value > (unsigned) $3.value;
185 $$.value = $1.value > $3.value; }
187 { $$.value = $1.value & $3.value;
188 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
190 { $$.value = $1.value ^ $3.value;
191 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
193 { $$.value = $1.value | $3.value;
194 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
196 { $$.value = ($1.value && $3.value);
199 { $$.value = ($1.value || $3.value);
201 | exp '?' exp ':' exp
202 { $$.value = $1.value ? $3.value : $5.value;
203 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
205 { $$ = yylval.integer; }
207 { $$ = yylval.integer; }
214 /* During parsing of a C expression, the pointer to the next character
215 is in this variable. */
219 /* Take care of parsing a number (anything that starts with a digit).
220 Set yylval and return the token type; update lexptr.
221 LEN is the number of characters in it. */
223 /* maybe needs to actually deal with floating point numbers */
229 register char *p = lexptr;
232 register int base = 10;
233 register int len = olen;
235 for (c = 0; c < len; c++)
237 /* It's a float since it contains a point. */
238 yyerror ("floating point numbers not allowed in #if expressions");
242 yylval.integer.unsignedp = 0;
244 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
255 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
257 if (c >= '0' && c <= '9') {
260 } else if (base == 16 && c >= 'a' && c <= 'f') {
264 /* `l' means long, and `u' means unsigned. */
266 if (c == 'l' || c == 'L')
268 else if (c == 'u' || c == 'U')
269 yylval.integer.unsignedp = 1;
278 /* Don't look for any more digits after the suffixes. */
284 yyerror ("Invalid number in #if expression");
288 /* If too big to be signed, consider it unsigned. */
290 yylval.integer.unsignedp = 1;
293 yylval.integer.value = n;
298 const char *operator;
306 static struct token tokentab2[] = {
318 /* Read one token, getting characters through lexptr. */
324 register int namelen;
325 register char *tokstart;
326 register struct token *toktab;
332 /* See if it is a special token of length 2. */
333 for (toktab = tokentab2; toktab->operator != NULL; toktab++)
334 if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
336 return toktab->token;
354 c = parse_escape (&lexptr);
356 /* Sign-extend the constant if chars are signed on target machine. */
358 if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
359 sizeof ("__CHAR_UNSIGNED__")-1, -1)
360 || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
361 yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
363 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
366 yylval.integer.unsignedp = 0;
369 yyerror ("Invalid character constant in #if");
375 /* some of these chars are invalid in constant expressions;
376 maybe do something about them later */
405 yyerror ("double quoted strings not allowed in #if expressions");
408 if (c >= '0' && c <= '9') {
411 c = tokstart[namelen], is_idchar[c] || c == '.';
414 return parse_number (namelen);
417 if (!is_idstart[c]) {
418 yyerror ("Invalid token in expression");
422 /* It is a name. See how long it is. */
425 is_idchar[(int)(unsigned char)tokstart[namelen]];
434 /* Parse a C escape sequence. STRING_PTR points to a variable
435 containing a pointer to the string to parse. That pointer
436 is updated past the characters we use. The value of the
437 escape sequence is returned.
439 A negative value means the sequence \ newline was seen,
440 which is supposed to be equivalent to nothing at all.
442 If \ is followed by a null character, we return a negative
443 value and leave the string pointer pointing at the null character.
445 If \ is followed by 000, we return 0 and leave the string pointer
446 after the zeros. A value of 0 does not mean end of string. */
449 parse_escape (string_ptr)
452 register int c = *(*string_ptr)++;
464 return TARGET_NEWLINE;
477 c = *(*string_ptr)++;
479 c = parse_escape (string_ptr);
482 return (c & 0200) | (c & 037);
493 register int i = c - '0';
494 register int count = 0;
497 c = *(*string_ptr)++;
498 if (c >= '0' && c <= '7')
499 i = (i << 3) + c - '0';
506 if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
508 i &= (1 << CHAR_TYPE_SIZE) - 1;
509 warning ("octal character constant does not fit in a byte");
518 c = *(*string_ptr)++;
519 if (c >= '0' && c <= '9')
520 i = (i << 4) + c - '0';
521 else if (c >= 'a' && c <= 'f')
522 i = (i << 4) + c - 'a' + 10;
523 else if (c >= 'A' && c <= 'F')
524 i = (i << 4) + c - 'A' + 10;
531 if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
533 i &= (1 << BITS_PER_UNIT) - 1;
534 warning ("hex character constant does not fit in a byte");
548 longjmp (parse_return_error, 1);
551 /* This page contains the entry point to this file. */
553 /* Parse STRING as an expression, and complain if this fails
554 to use up all of the contents of STRING. */
555 /* We do not support C comments. They should be removed before
556 this function is called. */
559 parse_c_expression (string)
564 if (lexptr == 0 || *lexptr == 0) {
565 error ("empty #if expression");
566 return 0; /* don't include the #if group */
569 /* if there is some sort of scanning error, just return 0 and assume
570 the parsing routine has printed an error message somewhere.
571 there is surely a better thing to do than this. */
572 if (setjmp (parse_return_error))
576 return 0; /* actually this is never reached
577 the way things stand. */
579 error ("Junk after end of expression.");
581 return expression_value; /* set by yyparse () */