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 */
31 int yylex PARAMS ((void));
32 void yyerror PARAMS ((const char *msgid));
33 extern void error PARAMS ((const char *msgid, ...));
34 extern void warning PARAMS ((const char *msgid, ...));
35 extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
37 int parse_number PARAMS ((int));
38 int parse_escape PARAMS ((char **));
39 int parse_c_expression PARAMS ((char *));
42 static jmp_buf parse_return_error;
44 /* some external tables of character types */
45 extern unsigned char is_idstart[], is_idchar[];
47 #ifndef CHAR_TYPE_SIZE
48 #define CHAR_TYPE_SIZE BITS_PER_UNIT
53 struct constant {long value; int unsignedp;} integer;
58 %type <integer> exp exp1 start
59 %token <integer> INT CHAR
61 %token <integer> ERROR
82 { expression_value = $1.value; }
85 /* Expressions, including the comma operator. */
91 /* Expressions, not including the comma operator. */
92 exp : '-' exp %prec UNARY
93 { $$.value = - $2.value;
94 $$.unsignedp = $2.unsignedp; }
96 { $$.value = ! $2.value;
100 | '~' exp %prec UNARY
101 { $$.value = ~ $2.value;
102 $$.unsignedp = $2.unsignedp; }
107 /* Binary operators in order of decreasing precedence. */
109 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
111 $$.value = (unsigned) $1.value * $3.value;
113 $$.value = $1.value * $3.value; }
117 error ("division by zero in #if");
120 $$.unsignedp = $1.unsignedp || $3.unsignedp;
122 $$.value = (unsigned) $1.value / $3.value;
124 $$.value = $1.value / $3.value; }
128 error ("division by zero in #if");
131 $$.unsignedp = $1.unsignedp || $3.unsignedp;
133 $$.value = (unsigned) $1.value % $3.value;
135 $$.value = $1.value % $3.value; }
137 { $$.value = $1.value + $3.value;
138 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
140 { $$.value = $1.value - $3.value;
141 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
143 { $$.unsignedp = $1.unsignedp;
145 $$.value = (unsigned) $1.value << $3.value;
147 $$.value = $1.value << $3.value; }
149 { $$.unsignedp = $1.unsignedp;
151 $$.value = (unsigned) $1.value >> $3.value;
153 $$.value = $1.value >> $3.value; }
155 { $$.value = ($1.value == $3.value);
158 { $$.value = ($1.value != $3.value);
162 if ($1.unsignedp || $3.unsignedp)
164 (unsigned) $1.value <= (unsigned) $3.value;
166 $$.value = $1.value <= $3.value; }
169 if ($1.unsignedp || $3.unsignedp)
171 (unsigned) $1.value >= (unsigned) $3.value;
173 $$.value = $1.value >= $3.value; }
176 if ($1.unsignedp || $3.unsignedp)
178 (unsigned) $1.value < (unsigned) $3.value;
180 $$.value = $1.value < $3.value; }
183 if ($1.unsignedp || $3.unsignedp)
185 (unsigned) $1.value > (unsigned) $3.value;
187 $$.value = $1.value > $3.value; }
189 { $$.value = $1.value & $3.value;
190 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
192 { $$.value = $1.value ^ $3.value;
193 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
195 { $$.value = $1.value | $3.value;
196 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
198 { $$.value = ($1.value && $3.value);
201 { $$.value = ($1.value || $3.value);
203 | exp '?' exp ':' exp
204 { $$.value = $1.value ? $3.value : $5.value;
205 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
207 { $$ = yylval.integer; }
209 { $$ = yylval.integer; }
216 /* During parsing of a C expression, the pointer to the next character
217 is in this variable. */
221 /* Take care of parsing a number (anything that starts with a digit).
222 Set yylval and return the token type; update lexptr.
223 LEN is the number of characters in it. */
225 /* maybe needs to actually deal with floating point numbers */
231 register char *p = lexptr;
234 register int base = 10;
235 register int len = olen;
237 for (c = 0; c < len; c++)
239 /* It's a float since it contains a point. */
240 yyerror ("floating point numbers not allowed in #if expressions");
244 yylval.integer.unsignedp = 0;
246 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
257 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
259 if (c >= '0' && c <= '9') {
262 } else if (base == 16 && c >= 'a' && c <= 'f') {
266 /* `l' means long, and `u' means unsigned. */
268 if (c == 'l' || c == 'L')
270 else if (c == 'u' || c == 'U')
271 yylval.integer.unsignedp = 1;
280 /* Don't look for any more digits after the suffixes. */
286 yyerror ("Invalid number in #if expression");
290 /* If too big to be signed, consider it unsigned. */
292 yylval.integer.unsignedp = 1;
295 yylval.integer.value = n;
300 const char *operator;
308 static struct token tokentab2[] = {
320 /* Read one token, getting characters through lexptr. */
326 register int namelen;
327 register char *tokstart;
328 register struct token *toktab;
334 /* See if it is a special token of length 2. */
335 for (toktab = tokentab2; toktab->operator != NULL; toktab++)
336 if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
338 return toktab->token;
356 c = parse_escape (&lexptr);
358 /* Sign-extend the constant if chars are signed on target machine. */
360 if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
361 sizeof ("__CHAR_UNSIGNED__")-1, -1)
362 || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
363 yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
365 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
368 yylval.integer.unsignedp = 0;
371 yyerror ("Invalid character constant in #if");
377 /* some of these chars are invalid in constant expressions;
378 maybe do something about them later */
407 yyerror ("double quoted strings not allowed in #if expressions");
410 if (c >= '0' && c <= '9') {
413 c = tokstart[namelen], is_idchar[c] || c == '.';
416 return parse_number (namelen);
419 if (!is_idstart[c]) {
420 yyerror ("Invalid token in expression");
424 /* It is a name. See how long it is. */
427 is_idchar[(int)(unsigned char)tokstart[namelen]];
436 /* Parse a C escape sequence. STRING_PTR points to a variable
437 containing a pointer to the string to parse. That pointer
438 is updated past the characters we use. The value of the
439 escape sequence is returned.
441 A negative value means the sequence \ newline was seen,
442 which is supposed to be equivalent to nothing at all.
444 If \ is followed by a null character, we return a negative
445 value and leave the string pointer pointing at the null character.
447 If \ is followed by 000, we return 0 and leave the string pointer
448 after the zeros. A value of 0 does not mean end of string. */
451 parse_escape (string_ptr)
454 register int c = *(*string_ptr)++;
466 return TARGET_NEWLINE;
479 c = *(*string_ptr)++;
481 c = parse_escape (string_ptr);
484 return (c & 0200) | (c & 037);
495 register int i = c - '0';
496 register int count = 0;
499 c = *(*string_ptr)++;
500 if (c >= '0' && c <= '7')
501 i = (i << 3) + c - '0';
508 if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
510 i &= (1 << CHAR_TYPE_SIZE) - 1;
511 warning ("octal character constant does not fit in a byte");
520 c = *(*string_ptr)++;
521 if (c >= '0' && c <= '9')
522 i = (i << 4) + c - '0';
523 else if (c >= 'a' && c <= 'f')
524 i = (i << 4) + c - 'a' + 10;
525 else if (c >= 'A' && c <= 'F')
526 i = (i << 4) + c - 'A' + 10;
533 if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
535 i &= (1 << BITS_PER_UNIT) - 1;
536 warning ("hex character constant does not fit in a byte");
550 longjmp (parse_return_error, 1);
553 /* This page contains the entry point to this file. */
555 /* Parse STRING as an expression, and complain if this fails
556 to use up all of the contents of STRING. */
557 /* We do not support C comments. They should be removed before
558 this function is called. */
561 parse_c_expression (string)
566 if (lexptr == 0 || *lexptr == 0) {
567 error ("empty #if expression");
568 return 0; /* don't include the #if group */
571 /* if there is some sort of scanning error, just return 0 and assume
572 the parsing routine has printed an error message somewhere.
573 there is surely a better thing to do than this. */
574 if (setjmp (parse_return_error))
578 return 0; /* actually this is never reached
579 the way things stand. */
581 error ("Junk after end of expression.");
583 return expression_value; /* set by yyparse () */