Avoid unnecessary dependencies on COND_EXEC insns.
[official-gcc.git] / gcc / tradcif.y
blob1cc7aa8dbcfe082778f55b48dc584eb97a56f55e
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
11 later version.
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 */
25 #include "config.h"
26 #include "system.h"
27 #include "defaults.h"
28 #include "tradcpp.h"
29 #include <setjmp.h>
31 static int yylex PARAMS ((void));
32 static void yyerror PARAMS ((const char *msgid));
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;
46 %union {
47 struct constant {long value; int unsignedp;} integer;
48 int voidval;
49 char *sval;
52 %type <integer> exp exp1 start
53 %token <integer> INT CHAR
54 %token <sval> NAME
55 %token <integer> ERROR
57 %right '?' ':'
58 %left ','
59 %left OR
60 %left AND
61 %left '|'
62 %left '^'
63 %left '&'
64 %left EQUAL NOTEQUAL
65 %left '<' '>' LEQ GEQ
66 %left LSH RSH
67 %left '+' '-'
68 %left '*' '/' '%'
69 %right UNARY
71 /* %expect 40 */
75 start : exp1
76 { expression_value = $1.value; }
79 /* Expressions, including the comma operator. */
80 exp1 : exp
81 | exp1 ',' exp
82 { $$ = $3; }
85 /* Expressions, not including the comma operator. */
86 exp : '-' exp %prec UNARY
87 { $$.value = - $2.value;
88 $$.unsignedp = $2.unsignedp; }
89 | '!' exp %prec UNARY
90 { $$.value = ! $2.value;
91 $$.unsignedp = 0; }
92 | '+' exp %prec UNARY
93 { $$ = $2; }
94 | '~' exp %prec UNARY
95 { $$.value = ~ $2.value;
96 $$.unsignedp = $2.unsignedp; }
97 | '(' exp1 ')'
98 { $$ = $2; }
101 /* Binary operators in order of decreasing precedence. */
102 exp : exp '*' exp
103 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
104 if ($$.unsignedp)
105 $$.value = (unsigned) $1.value * $3.value;
106 else
107 $$.value = $1.value * $3.value; }
108 | exp '/' exp
109 { if ($3.value == 0)
111 error ("division by zero in #if");
112 $3.value = 1;
114 $$.unsignedp = $1.unsignedp || $3.unsignedp;
115 if ($$.unsignedp)
116 $$.value = (unsigned) $1.value / $3.value;
117 else
118 $$.value = $1.value / $3.value; }
119 | exp '%' exp
120 { if ($3.value == 0)
122 error ("division by zero in #if");
123 $3.value = 1;
125 $$.unsignedp = $1.unsignedp || $3.unsignedp;
126 if ($$.unsignedp)
127 $$.value = (unsigned) $1.value % $3.value;
128 else
129 $$.value = $1.value % $3.value; }
130 | exp '+' exp
131 { $$.value = $1.value + $3.value;
132 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
133 | exp '-' exp
134 { $$.value = $1.value - $3.value;
135 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
136 | exp LSH exp
137 { $$.unsignedp = $1.unsignedp;
138 if ($$.unsignedp)
139 $$.value = (unsigned) $1.value << $3.value;
140 else
141 $$.value = $1.value << $3.value; }
142 | exp RSH exp
143 { $$.unsignedp = $1.unsignedp;
144 if ($$.unsignedp)
145 $$.value = (unsigned) $1.value >> $3.value;
146 else
147 $$.value = $1.value >> $3.value; }
148 | exp EQUAL exp
149 { $$.value = ($1.value == $3.value);
150 $$.unsignedp = 0; }
151 | exp NOTEQUAL exp
152 { $$.value = ($1.value != $3.value);
153 $$.unsignedp = 0; }
154 | exp LEQ exp
155 { $$.unsignedp = 0;
156 if ($1.unsignedp || $3.unsignedp)
157 $$.value =
158 (unsigned) $1.value <= (unsigned) $3.value;
159 else
160 $$.value = $1.value <= $3.value; }
161 | exp GEQ exp
162 { $$.unsignedp = 0;
163 if ($1.unsignedp || $3.unsignedp)
164 $$.value =
165 (unsigned) $1.value >= (unsigned) $3.value;
166 else
167 $$.value = $1.value >= $3.value; }
168 | exp '<' exp
169 { $$.unsignedp = 0;
170 if ($1.unsignedp || $3.unsignedp)
171 $$.value =
172 (unsigned) $1.value < (unsigned) $3.value;
173 else
174 $$.value = $1.value < $3.value; }
175 | exp '>' exp
176 { $$.unsignedp = 0;
177 if ($1.unsignedp || $3.unsignedp)
178 $$.value =
179 (unsigned) $1.value > (unsigned) $3.value;
180 else
181 $$.value = $1.value > $3.value; }
182 | exp '&' exp
183 { $$.value = $1.value & $3.value;
184 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
185 | exp '^' exp
186 { $$.value = $1.value ^ $3.value;
187 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
188 | exp '|' exp
189 { $$.value = $1.value | $3.value;
190 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
191 | exp AND exp
192 { $$.value = ($1.value && $3.value);
193 $$.unsignedp = 0; }
194 | exp OR exp
195 { $$.value = ($1.value || $3.value);
196 $$.unsignedp = 0; }
197 | exp '?' exp ':' exp
198 { $$.value = $1.value ? $3.value : $5.value;
199 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
200 | INT
201 { $$ = yylval.integer; }
202 | CHAR
203 { $$ = yylval.integer; }
204 | NAME
205 { $$.value = 0;
206 $$.unsignedp = 0; }
207 | '#' { $$.value =
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 */
218 static int
219 parse_number (olen)
220 int olen;
222 register const char *p = lexptr;
223 register long n = 0;
224 register int c;
225 register int base = 10;
226 register int len = olen;
228 for (c = 0; c < len; c++)
229 if (p[c] == '.') {
230 /* It's a float since it contains a point. */
231 yyerror ("floating point numbers not allowed in #if expressions");
232 return ERROR;
235 yylval.integer.unsignedp = 0;
237 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
238 p += 2;
239 base = 16;
240 len -= 2;
242 else if (*p == '0')
243 base = 8;
245 while (len > 0) {
246 c = *p++;
247 len--;
248 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
250 if (c >= '0' && c <= '9') {
251 n *= base;
252 n += c - '0';
253 } else if (base == 16 && c >= 'a' && c <= 'f') {
254 n *= base;
255 n += c - 'a' + 10;
256 } else {
257 /* `l' means long, and `u' means unsigned. */
258 while (1) {
259 if (c == 'l' || c == 'L')
261 else if (c == 'u' || c == 'U')
262 yylval.integer.unsignedp = 1;
263 else
264 break;
266 if (len == 0)
267 break;
268 c = *p++;
269 len--;
271 /* Don't look for any more digits after the suffixes. */
272 break;
276 if (len != 0) {
277 yyerror ("Invalid number in #if expression");
278 return ERROR;
281 /* If too big to be signed, consider it unsigned. */
282 if (n < 0)
283 yylval.integer.unsignedp = 1;
285 lexptr = p;
286 yylval.integer.value = n;
287 return INT;
290 struct token {
291 const char *operator;
292 int token;
295 #ifndef NULL
296 #define NULL 0
297 #endif
299 static struct token tokentab2[] = {
300 {"&&", AND},
301 {"||", OR},
302 {"<<", LSH},
303 {">>", RSH},
304 {"==", EQUAL},
305 {"!=", NOTEQUAL},
306 {"<=", LEQ},
307 {">=", GEQ},
308 {NULL, ERROR}
311 /* Read one token, getting characters through lexptr. */
313 static int
314 yylex ()
316 register int c;
317 register int namelen;
318 register const char *tokstart;
319 register struct token *toktab;
321 retry:
323 tokstart = lexptr;
324 c = *tokstart;
325 /* See if it is a special token of length 2. */
326 for (toktab = tokentab2; toktab->operator != NULL; toktab++)
327 if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
328 lexptr += 2;
329 return toktab->token;
332 switch (c) {
333 case 0:
334 return 0;
336 case ' ':
337 case '\t':
338 case '\r':
339 case '\n':
340 lexptr++;
341 goto retry;
343 case '\'':
344 lexptr++;
345 c = *lexptr++;
346 if (c == '\\')
347 c = parse_escape (&lexptr);
349 /* Sign-extend the constant if chars are signed on target machine. */
351 if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
352 sizeof ("__CHAR_UNSIGNED__")-1, -1)
353 || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
354 yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
355 else
356 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
359 yylval.integer.unsignedp = 0;
360 c = *lexptr++;
361 if (c != '\'') {
362 yyerror ("Invalid character constant in #if");
363 return ERROR;
366 return CHAR;
368 /* some of these chars are invalid in constant expressions;
369 maybe do something about them later */
370 case '/':
371 case '+':
372 case '-':
373 case '*':
374 case '%':
375 case '|':
376 case '&':
377 case '^':
378 case '~':
379 case '!':
380 case '@':
381 case '<':
382 case '>':
383 case '(':
384 case ')':
385 case '[':
386 case ']':
387 case '.':
388 case '?':
389 case ':':
390 case '=':
391 case '{':
392 case '}':
393 case ',':
394 case '#':
395 lexptr++;
396 return c;
398 case '"':
399 yyerror ("double quoted strings not allowed in #if expressions");
400 return ERROR;
402 if (c >= '0' && c <= '9') {
403 /* It's a number */
404 for (namelen = 0;
405 c = tokstart[namelen], is_idchar (c) || c == '.';
406 namelen++)
408 return parse_number (namelen);
411 if (!is_idstart (c)) {
412 yyerror ("Invalid token in expression");
413 return ERROR;
416 /* It is a name. See how long it is. */
418 for (namelen = 0;
419 is_idchar (tokstart[namelen]);
420 namelen++)
423 lexptr += namelen;
424 return NAME;
428 /* Parse a C escape sequence. STRING_PTR points to a variable
429 containing a pointer to the string to parse. That pointer
430 is updated past the characters we use. The value of the
431 escape sequence is returned.
433 A negative value means the sequence \ newline was seen,
434 which is supposed to be equivalent to nothing at all.
436 If \ is followed by a null character, we return a negative
437 value and leave the string pointer pointing at the null character.
439 If \ is followed by 000, we return 0 and leave the string pointer
440 after the zeros. A value of 0 does not mean end of string. */
442 static int
443 parse_escape (string_ptr)
444 const char **string_ptr;
446 register int c = *(*string_ptr)++;
447 switch (c)
449 case 'a':
450 return TARGET_BELL;
451 case 'b':
452 return TARGET_BS;
453 case 'e':
454 return 033;
455 case 'f':
456 return TARGET_FF;
457 case 'n':
458 return TARGET_NEWLINE;
459 case 'r':
460 return TARGET_CR;
461 case 't':
462 return TARGET_TAB;
463 case 'v':
464 return TARGET_VT;
465 case '\n':
466 return -2;
467 case 0:
468 (*string_ptr)--;
469 return 0;
470 case '^':
471 c = *(*string_ptr)++;
472 if (c == '\\')
473 c = parse_escape (string_ptr);
474 if (c == '?')
475 return 0177;
476 return (c & 0200) | (c & 037);
478 case '0':
479 case '1':
480 case '2':
481 case '3':
482 case '4':
483 case '5':
484 case '6':
485 case '7':
487 register int i = c - '0';
488 register int count = 0;
489 while (++count < 3)
491 c = *(*string_ptr)++;
492 if (c >= '0' && c <= '7')
493 i = (i << 3) + c - '0';
494 else
496 (*string_ptr)--;
497 break;
500 if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
502 i &= (1 << CHAR_TYPE_SIZE) - 1;
503 warning ("octal character constant does not fit in a byte");
505 return i;
507 case 'x':
509 register int i = 0;
510 for (;;)
512 c = *(*string_ptr)++;
513 if (c >= '0' && c <= '9')
514 i = (i << 4) + c - '0';
515 else if (c >= 'a' && c <= 'f')
516 i = (i << 4) + c - 'a' + 10;
517 else if (c >= 'A' && c <= 'F')
518 i = (i << 4) + c - 'A' + 10;
519 else
521 (*string_ptr)--;
522 break;
525 if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
527 i &= (1 << BITS_PER_UNIT) - 1;
528 warning ("hex character constant does not fit in a byte");
530 return i;
532 default:
533 return c;
537 static void
538 yyerror (s)
539 const char *s;
541 error (s);
542 longjmp (parse_return_error, 1);
545 /* This page contains the entry point to this file. */
547 /* Parse STRING as an expression, and complain if this fails
548 to use up all of the contents of STRING. */
549 /* We do not support C comments. They should be removed before
550 this function is called. */
553 parse_c_expression (string)
554 const char *string;
556 lexptr = string;
558 if (lexptr == 0 || *lexptr == 0) {
559 error ("empty #if expression");
560 return 0; /* don't include the #if group */
563 /* if there is some sort of scanning error, just return 0 and assume
564 the parsing routine has printed an error message somewhere.
565 there is surely a better thing to do than this. */
566 if (setjmp (parse_return_error))
567 return 0;
569 if (yyparse ())
570 return 0; /* actually this is never reached
571 the way things stand. */
572 if (*lexptr)
573 error ("Junk after end of expression.");
575 return expression_value; /* set by yyparse () */