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
(flag_signed_char
== 0
348 ||
((c
>> (CHAR_TYPE_SIZE
- 1)) & 1) == 0)
349 yylval.integer.value
= c
& ((1 << CHAR_TYPE_SIZE
) - 1);
351 yylval.integer.value
= c | ~
((1 << CHAR_TYPE_SIZE
) - 1);
354 yylval.integer.unsignedp
= 0;
357 yyerror ("invalid character constant in #if");
363 /* some of these chars are invalid in constant expressions;
364 maybe do something about them later */
394 yyerror ("double quoted strings not allowed in #if expressions");
400 c
= tokstart
[namelen
], is_idchar
(c
) || c
== '.';
403 return parse_number
(namelen
);
406 if
(!is_idstart
(c
)) {
407 yyerror ("invalid token in expression");
411 /* It is a name. See how long it is. */
414 is_idchar
(tokstart
[namelen
]);
423 /* Parse a C escape sequence. STRING_PTR points to a variable
424 containing a pointer to the string to parse. That pointer
425 is updated past the characters we use. The value of the
426 escape sequence is returned.
428 A negative value means the sequence \ newline was seen,
429 which is supposed to be equivalent to nothing at all.
431 If \ is followed by a null character, we return a negative
432 value and leave the string pointer pointing at the null character.
434 If \ is followed by 000, we return 0 and leave the string pointer
435 after the zeros. A value of 0 does not mean end of string. */
438 parse_escape
(string_ptr
)
439 const char **string_ptr
;
441 int c
= *(*string_ptr
)++;
453 return TARGET_NEWLINE
;
466 c
= *(*string_ptr
)++;
468 c
= parse_escape
(string_ptr
);
471 return
(c
& 0200) |
(c
& 037);
486 c
= *(*string_ptr
)++;
487 if
(c
>= '0' && c
<= '7')
488 i
= (i
<< 3) + c
- '0';
495 if
((i
& ~
((1 << CHAR_TYPE_SIZE
) - 1)) != 0)
497 i
&= (1 << CHAR_TYPE_SIZE
) - 1;
498 warning
("octal character constant does not fit in a byte");
507 c
= *(*string_ptr
)++;
509 i
= (i
<< 4) + hex_value
(c
);
516 if
((i
& ~
((1 << BITS_PER_UNIT
) - 1)) != 0)
518 i
&= (1 << BITS_PER_UNIT
) - 1;
519 warning
("hex character constant does not fit in a byte");
532 error ("%s", _
(msgid
));
533 longjmp
(parse_return_error
, 1);
536 /* This page contains the entry point to this file. */
538 /* Parse STRING as an expression, and complain if this fails
539 to use up all of the contents of STRING. */
540 /* We do not support C comments. They should be removed before
541 this function is called. */
544 parse_c_expression
(string)
549 if
(lexptr
== 0 ||
*lexptr
== 0) {
550 error ("empty #if expression");
551 return
0; /* don't include the #if group */
554 /* if there is some sort of scanning error, just return 0 and assume
555 the parsing routine has printed an error message somewhere.
556 there is surely a better thing to do than this. */
557 if
(setjmp
(parse_return_error
))
561 return
0; /* actually this is never reached
562 the way things stand. */
564 error ("Junk after end of expression.");
566 return expression_value
; /* set by yyparse () */