1 /* Parse C expressions for CCCP.
2 Copyright (C) 1987, 2000, 2001 Free Software Foundation.
3 Adapted from expread.y of GDB by Paul Rubin, July 1986.
4 Adapted to ANSI C, Richard Stallman, Jan 1987
5 Dusted off, polished, and adapted for use as traditional
6 preprocessor only, Zack Weinberg, Jul 2000
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 /* Parse a C expression from text in a string */
31 static int yylex PARAMS ((void));
32 static void yyerror PARAMS ((const char *msgid)) ATTRIBUTE_NORETURN;
34 static int parse_number PARAMS ((int));
35 static int parse_escape PARAMS ((const char **));
37 static int expression_value;
38 static jmp_buf parse_return_error;
40 /* During parsing of a C expression, the pointer to the next
41 character is in this variable. */
43 static const char *lexptr;
47 struct constant {long value; int unsignedp;} integer;
52 %type <integer> exp exp1 start
53 %token <integer> INT CHAR
55 %token <integer> ERROR
76 { expression_value = $1.value; }
79 /* Expressions, including the comma operator. */
85 /* Expressions, not including the comma operator. */
86 exp : '-' exp %prec UNARY
87 { $$.value = - $2.value;
88 $$.unsignedp = $2.unsignedp; }
90 { $$.value = ! $2.value;
95 { $$.value = ~ $2.value;
96 $$.unsignedp = $2.unsignedp; }
101 /* Binary operators in order of decreasing precedence. */
103 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
105 $$.value = (unsigned) $1.value * $3.value;
107 $$.value = $1.value * $3.value; }
111 error ("division by zero in #if");
114 $$.unsignedp = $1.unsignedp || $3.unsignedp;
116 $$.value = (unsigned) $1.value / $3.value;
118 $$.value = $1.value / $3.value; }
122 error ("division by zero in #if");
125 $$.unsignedp = $1.unsignedp || $3.unsignedp;
127 $$.value = (unsigned) $1.value % $3.value;
129 $$.value = $1.value % $3.value; }
131 { $$.value = $1.value + $3.value;
132 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
134 { $$.value = $1.value - $3.value;
135 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
137 { $$.unsignedp = $1.unsignedp;
139 $$.value = (unsigned) $1.value << $3.value;
141 $$.value = $1.value << $3.value; }
143 { $$.unsignedp = $1.unsignedp;
145 $$.value = (unsigned) $1.value >> $3.value;
147 $$.value = $1.value >> $3.value; }
149 { $$.value = ($1.value == $3.value);
152 { $$.value = ($1.value != $3.value);
156 if ($1.unsignedp || $3.unsignedp)
158 (unsigned) $1.value <= (unsigned) $3.value;
160 $$.value = $1.value <= $3.value; }
163 if ($1.unsignedp || $3.unsignedp)
165 (unsigned) $1.value >= (unsigned) $3.value;
167 $$.value = $1.value >= $3.value; }
170 if ($1.unsignedp || $3.unsignedp)
172 (unsigned) $1.value < (unsigned) $3.value;
174 $$.value = $1.value < $3.value; }
177 if ($1.unsignedp || $3.unsignedp)
179 (unsigned) $1.value > (unsigned) $3.value;
181 $$.value = $1.value > $3.value; }
183 { $$.value = $1.value & $3.value;
184 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
186 { $$.value = $1.value ^ $3.value;
187 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
189 { $$.value = $1.value | $3.value;
190 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
192 { $$.value = ($1.value && $3.value);
195 { $$.value = ($1.value || $3.value);
197 | exp '?' exp ':' exp
198 { $$.value = $1.value ? $3.value : $5.value;
199 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
201 { $$ = yylval.integer; }
203 { $$ = yylval.integer; }
208 test_assertion ((unsigned char **) &lexptr); }
212 /* Take care of parsing a number (anything that starts with a digit).
213 Set yylval and return the token type; update lexptr.
214 LEN is the number of characters in it. */
216 /* maybe needs to actually deal with floating point numbers */
222 const char *p = lexptr;
228 for (c = 0; c < len; c++)
230 /* It's a float since it contains a point. */
231 yyerror ("floating point numbers not allowed in #if expressions");
235 /* Traditionally, all numbers are signed. However, we make it
236 unsigned if requested with a suffix. */
237 yylval.integer.unsignedp = 0;
239 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
254 || (base == 16 && ISXDIGIT (c))) {
255 n = (n * base) + hex_value (c);
257 /* `l' means long, and `u' means unsigned. */
259 if (c == 'l' || c == 'L')
261 else if (c == 'u' || c == 'U')
262 yylval.integer.unsignedp = 1;
271 /* Don't look for any more digits after the suffixes. */
277 yyerror ("invalid number in #if expression");
282 yylval.integer.value = n;
287 const char *const operator;
295 static const struct token tokentab2[] = {
307 /* Read one token, getting characters through lexptr. */
314 const char *tokstart;
315 const struct token *toktab;
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]) {
325 return toktab->token;
343 c = parse_escape (&lexptr);
345 /* Sign-extend the constant if chars are signed on target machine. */
347 if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
348 sizeof ("__CHAR_UNSIGNED__")-1, -1)
349 || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
350 yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
352 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
355 yylval.integer.unsignedp = 0;
358 yyerror ("invalid character constant in #if");
364 /* some of these chars are invalid in constant expressions;
365 maybe do something about them later */
395 yyerror ("double quoted strings not allowed in #if expressions");
401 c = tokstart[namelen], is_idchar (c) || c == '.';
404 return parse_number (namelen);
407 if (!is_idstart (c)) {
408 yyerror ("invalid token in expression");
412 /* It is a name. See how long it is. */
415 is_idchar (tokstart[namelen]);
424 /* Parse a C escape sequence. STRING_PTR points to a variable
425 containing a pointer to the string to parse. That pointer
426 is updated past the characters we use. The value of the
427 escape sequence is returned.
429 A negative value means the sequence \ newline was seen,
430 which is supposed to be equivalent to nothing at all.
432 If \ is followed by a null character, we return a negative
433 value and leave the string pointer pointing at the null character.
435 If \ is followed by 000, we return 0 and leave the string pointer
436 after the zeros. A value of 0 does not mean end of string. */
439 parse_escape (string_ptr)
440 const char **string_ptr;
442 int c = *(*string_ptr)++;
454 return TARGET_NEWLINE;
467 c = *(*string_ptr)++;
469 c = parse_escape (string_ptr);
472 return (c & 0200) | (c & 037);
487 c = *(*string_ptr)++;
488 if (c >= '0' && c <= '7')
489 i = (i << 3) + c - '0';
496 if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
498 i &= (1 << CHAR_TYPE_SIZE) - 1;
499 warning ("octal character constant does not fit in a byte");
508 c = *(*string_ptr)++;
510 i = (i << 4) + hex_value (c);
517 if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
519 i &= (1 << BITS_PER_UNIT) - 1;
520 warning ("hex character constant does not fit in a byte");
533 error ("%s", _(msgid));
534 longjmp (parse_return_error, 1);
537 /* This page contains the entry point to this file. */
539 /* Parse STRING as an expression, and complain if this fails
540 to use up all of the contents of STRING. */
541 /* We do not support C comments. They should be removed before
542 this function is called. */
545 parse_c_expression (string)
550 if (lexptr == 0 || *lexptr == 0) {
551 error ("empty #if expression");
552 return 0; /* don't include the #if group */
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. */
558 if (setjmp (parse_return_error))
562 return 0; /* actually this is never reached
563 the way things stand. */
565 error ("Junk after end of expression.");
567 return expression_value; /* set by yyparse () */