1 /* Parse C expressions for CCCP.
2 Copyright (C) 1987, 2000 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 */
30 int yylex PARAMS ((void));
31 void yyerror PARAMS ((const char *msgid));
32 extern void error PARAMS ((const char *msgid, ...));
33 extern void warning PARAMS ((const char *msgid, ...));
34 extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
36 int parse_number PARAMS ((int));
37 int parse_escape PARAMS ((char **));
38 int parse_c_expression PARAMS ((char *));
41 static jmp_buf parse_return_error;
43 /* some external tables of character types */
44 extern unsigned char is_idstart[], is_idchar[];
49 struct constant {long value; int unsignedp;} integer;
54 %type <integer> exp exp1 start
55 %token <integer> INT CHAR
57 %token <integer> ERROR
78 { expression_value = $1.value; }
81 /* Expressions, including the comma operator. */
87 /* Expressions, not including the comma operator. */
88 exp : '-' exp %prec UNARY
89 { $$.value = - $2.value;
90 $$.unsignedp = $2.unsignedp; }
92 { $$.value = ! $2.value;
97 { $$.value = ~ $2.value;
98 $$.unsignedp = $2.unsignedp; }
103 /* Binary operators in order of decreasing precedence. */
105 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
107 $$.value = (unsigned) $1.value * $3.value;
109 $$.value = $1.value * $3.value; }
113 error ("division by zero in #if");
116 $$.unsignedp = $1.unsignedp || $3.unsignedp;
118 $$.value = (unsigned) $1.value / $3.value;
120 $$.value = $1.value / $3.value; }
124 error ("division by zero in #if");
127 $$.unsignedp = $1.unsignedp || $3.unsignedp;
129 $$.value = (unsigned) $1.value % $3.value;
131 $$.value = $1.value % $3.value; }
133 { $$.value = $1.value + $3.value;
134 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
136 { $$.value = $1.value - $3.value;
137 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
139 { $$.unsignedp = $1.unsignedp;
141 $$.value = (unsigned) $1.value << $3.value;
143 $$.value = $1.value << $3.value; }
145 { $$.unsignedp = $1.unsignedp;
147 $$.value = (unsigned) $1.value >> $3.value;
149 $$.value = $1.value >> $3.value; }
151 { $$.value = ($1.value == $3.value);
154 { $$.value = ($1.value != $3.value);
158 if ($1.unsignedp || $3.unsignedp)
160 (unsigned) $1.value <= (unsigned) $3.value;
162 $$.value = $1.value <= $3.value; }
165 if ($1.unsignedp || $3.unsignedp)
167 (unsigned) $1.value >= (unsigned) $3.value;
169 $$.value = $1.value >= $3.value; }
172 if ($1.unsignedp || $3.unsignedp)
174 (unsigned) $1.value < (unsigned) $3.value;
176 $$.value = $1.value < $3.value; }
179 if ($1.unsignedp || $3.unsignedp)
181 (unsigned) $1.value > (unsigned) $3.value;
183 $$.value = $1.value > $3.value; }
185 { $$.value = $1.value & $3.value;
186 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
188 { $$.value = $1.value ^ $3.value;
189 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
191 { $$.value = $1.value | $3.value;
192 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
194 { $$.value = ($1.value && $3.value);
197 { $$.value = ($1.value || $3.value);
199 | exp '?' exp ':' exp
200 { $$.value = $1.value ? $3.value : $5.value;
201 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
203 { $$ = yylval.integer; }
205 { $$ = yylval.integer; }
212 /* During parsing of a C expression, the pointer to the next character
213 is in this variable. */
217 /* Take care of parsing a number (anything that starts with a digit).
218 Set yylval and return the token type; update lexptr.
219 LEN is the number of characters in it. */
221 /* maybe needs to actually deal with floating point numbers */
227 register char *p = lexptr;
230 register int base = 10;
231 register int len = olen;
233 for (c = 0; c < len; c++)
235 /* It's a float since it contains a point. */
236 yyerror ("floating point numbers not allowed in #if expressions");
240 yylval.integer.unsignedp = 0;
242 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
253 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
255 if (c >= '0' && c <= '9') {
258 } else if (base == 16 && c >= 'a' && c <= 'f') {
262 /* `l' means long, and `u' means unsigned. */
264 if (c == 'l' || c == 'L')
266 else if (c == 'u' || c == 'U')
267 yylval.integer.unsignedp = 1;
276 /* Don't look for any more digits after the suffixes. */
282 yyerror ("Invalid number in #if expression");
286 /* If too big to be signed, consider it unsigned. */
288 yylval.integer.unsignedp = 1;
291 yylval.integer.value = n;
296 const char *operator;
304 static struct token tokentab2[] = {
316 /* Read one token, getting characters through lexptr. */
322 register int namelen;
323 register char *tokstart;
324 register struct token *toktab;
330 /* See if it is a special token of length 2. */
331 for (toktab = tokentab2; toktab->operator != NULL; toktab++)
332 if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
334 return toktab->token;
352 c = parse_escape (&lexptr);
354 /* Sign-extend the constant if chars are signed on target machine. */
356 if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
357 sizeof ("__CHAR_UNSIGNED__")-1, -1)
358 || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
359 yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
361 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
364 yylval.integer.unsignedp = 0;
367 yyerror ("Invalid character constant in #if");
373 /* some of these chars are invalid in constant expressions;
374 maybe do something about them later */
403 yyerror ("double quoted strings not allowed in #if expressions");
406 if (c >= '0' && c <= '9') {
409 c = tokstart[namelen], is_idchar[c] || c == '.';
412 return parse_number (namelen);
415 if (!is_idstart[c]) {
416 yyerror ("Invalid token in expression");
420 /* It is a name. See how long it is. */
423 is_idchar[(int)(unsigned char)tokstart[namelen]];
432 /* Parse a C escape sequence. STRING_PTR points to a variable
433 containing a pointer to the string to parse. That pointer
434 is updated past the characters we use. The value of the
435 escape sequence is returned.
437 A negative value means the sequence \ newline was seen,
438 which is supposed to be equivalent to nothing at all.
440 If \ is followed by a null character, we return a negative
441 value and leave the string pointer pointing at the null character.
443 If \ is followed by 000, we return 0 and leave the string pointer
444 after the zeros. A value of 0 does not mean end of string. */
447 parse_escape (string_ptr)
450 register int c = *(*string_ptr)++;
462 return TARGET_NEWLINE;
475 c = *(*string_ptr)++;
477 c = parse_escape (string_ptr);
480 return (c & 0200) | (c & 037);
491 register int i = c - '0';
492 register int count = 0;
495 c = *(*string_ptr)++;
496 if (c >= '0' && c <= '7')
497 i = (i << 3) + c - '0';
504 if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
506 i &= (1 << CHAR_TYPE_SIZE) - 1;
507 warning ("octal character constant does not fit in a byte");
516 c = *(*string_ptr)++;
517 if (c >= '0' && c <= '9')
518 i = (i << 4) + c - '0';
519 else if (c >= 'a' && c <= 'f')
520 i = (i << 4) + c - 'a' + 10;
521 else if (c >= 'A' && c <= 'F')
522 i = (i << 4) + c - 'A' + 10;
529 if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
531 i &= (1 << BITS_PER_UNIT) - 1;
532 warning ("hex character constant does not fit in a byte");
546 longjmp (parse_return_error, 1);
549 /* This page contains the entry point to this file. */
551 /* Parse STRING as an expression, and complain if this fails
552 to use up all of the contents of STRING. */
553 /* We do not support C comments. They should be removed before
554 this function is called. */
557 parse_c_expression (string)
562 if (lexptr == 0 || *lexptr == 0) {
563 error ("empty #if expression");
564 return 0; /* don't include the #if group */
567 /* if there is some sort of scanning error, just return 0 and assume
568 the parsing routine has printed an error message somewhere.
569 there is surely a better thing to do than this. */
570 if (setjmp (parse_return_error))
574 return 0; /* actually this is never reached
575 the way things stand. */
577 error ("Junk after end of expression.");
579 return expression_value; /* set by yyparse () */