* cpplib.c (_cpp_check_directive): Issue -Wtraditional
[official-gcc.git] / gcc / tradcif.y
blob4a70bed89a3642ddf5626a7abb652a9faff95263
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
7 later version.
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 */
27 #include "config.h"
28 #include "system.h"
29 #include <setjmp.h>
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 *));
41 int expression_value;
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
49 #endif
52 %union {
53 struct constant {long value; int unsignedp;} integer;
54 int voidval;
55 char *sval;
58 %type <integer> exp exp1 start
59 %token <integer> INT CHAR
60 %token <sval> NAME
61 %token <integer> ERROR
63 %right '?' ':'
64 %left ','
65 %left OR
66 %left AND
67 %left '|'
68 %left '^'
69 %left '&'
70 %left EQUAL NOTEQUAL
71 %left '<' '>' LEQ GEQ
72 %left LSH RSH
73 %left '+' '-'
74 %left '*' '/' '%'
75 %right UNARY
77 /* %expect 40 */
81 start : exp1
82 { expression_value = $1.value; }
85 /* Expressions, including the comma operator. */
86 exp1 : exp
87 | exp1 ',' exp
88 { $$ = $3; }
91 /* Expressions, not including the comma operator. */
92 exp : '-' exp %prec UNARY
93 { $$.value = - $2.value;
94 $$.unsignedp = $2.unsignedp; }
95 | '!' exp %prec UNARY
96 { $$.value = ! $2.value;
97 $$.unsignedp = 0; }
98 | '+' exp %prec UNARY
99 { $$ = $2; }
100 | '~' exp %prec UNARY
101 { $$.value = ~ $2.value;
102 $$.unsignedp = $2.unsignedp; }
103 | '(' exp1 ')'
104 { $$ = $2; }
107 /* Binary operators in order of decreasing precedence. */
108 exp : exp '*' exp
109 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
110 if ($$.unsignedp)
111 $$.value = (unsigned) $1.value * $3.value;
112 else
113 $$.value = $1.value * $3.value; }
114 | exp '/' exp
115 { if ($3.value == 0)
117 error ("division by zero in #if");
118 $3.value = 1;
120 $$.unsignedp = $1.unsignedp || $3.unsignedp;
121 if ($$.unsignedp)
122 $$.value = (unsigned) $1.value / $3.value;
123 else
124 $$.value = $1.value / $3.value; }
125 | exp '%' exp
126 { if ($3.value == 0)
128 error ("division by zero in #if");
129 $3.value = 1;
131 $$.unsignedp = $1.unsignedp || $3.unsignedp;
132 if ($$.unsignedp)
133 $$.value = (unsigned) $1.value % $3.value;
134 else
135 $$.value = $1.value % $3.value; }
136 | exp '+' exp
137 { $$.value = $1.value + $3.value;
138 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
139 | exp '-' exp
140 { $$.value = $1.value - $3.value;
141 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
142 | exp LSH 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 RSH exp
149 { $$.unsignedp = $1.unsignedp;
150 if ($$.unsignedp)
151 $$.value = (unsigned) $1.value >> $3.value;
152 else
153 $$.value = $1.value >> $3.value; }
154 | exp EQUAL exp
155 { $$.value = ($1.value == $3.value);
156 $$.unsignedp = 0; }
157 | exp NOTEQUAL exp
158 { $$.value = ($1.value != $3.value);
159 $$.unsignedp = 0; }
160 | exp LEQ exp
161 { $$.unsignedp = 0;
162 if ($1.unsignedp || $3.unsignedp)
163 $$.value =
164 (unsigned) $1.value <= (unsigned) $3.value;
165 else
166 $$.value = $1.value <= $3.value; }
167 | exp GEQ exp
168 { $$.unsignedp = 0;
169 if ($1.unsignedp || $3.unsignedp)
170 $$.value =
171 (unsigned) $1.value >= (unsigned) $3.value;
172 else
173 $$.value = $1.value >= $3.value; }
174 | exp '<' exp
175 { $$.unsignedp = 0;
176 if ($1.unsignedp || $3.unsignedp)
177 $$.value =
178 (unsigned) $1.value < (unsigned) $3.value;
179 else
180 $$.value = $1.value < $3.value; }
181 | exp '>' exp
182 { $$.unsignedp = 0;
183 if ($1.unsignedp || $3.unsignedp)
184 $$.value =
185 (unsigned) $1.value > (unsigned) $3.value;
186 else
187 $$.value = $1.value > $3.value; }
188 | exp '&' exp
189 { $$.value = $1.value & $3.value;
190 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
191 | exp '^' exp
192 { $$.value = $1.value ^ $3.value;
193 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
194 | exp '|' exp
195 { $$.value = $1.value | $3.value;
196 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
197 | exp AND exp
198 { $$.value = ($1.value && $3.value);
199 $$.unsignedp = 0; }
200 | exp OR exp
201 { $$.value = ($1.value || $3.value);
202 $$.unsignedp = 0; }
203 | exp '?' exp ':' exp
204 { $$.value = $1.value ? $3.value : $5.value;
205 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
206 | INT
207 { $$ = yylval.integer; }
208 | CHAR
209 { $$ = yylval.integer; }
210 | NAME
211 { $$.value = 0;
212 $$.unsignedp = 0; }
216 /* During parsing of a C expression, the pointer to the next character
217 is in this variable. */
219 static char *lexptr;
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 */
228 parse_number (olen)
229 int olen;
231 register char *p = lexptr;
232 register long n = 0;
233 register int c;
234 register int base = 10;
235 register int len = olen;
237 for (c = 0; c < len; c++)
238 if (p[c] == '.') {
239 /* It's a float since it contains a point. */
240 yyerror ("floating point numbers not allowed in #if expressions");
241 return ERROR;
244 yylval.integer.unsignedp = 0;
246 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
247 p += 2;
248 base = 16;
249 len -= 2;
251 else if (*p == '0')
252 base = 8;
254 while (len > 0) {
255 c = *p++;
256 len--;
257 if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
259 if (c >= '0' && c <= '9') {
260 n *= base;
261 n += c - '0';
262 } else if (base == 16 && c >= 'a' && c <= 'f') {
263 n *= base;
264 n += c - 'a' + 10;
265 } else {
266 /* `l' means long, and `u' means unsigned. */
267 while (1) {
268 if (c == 'l' || c == 'L')
270 else if (c == 'u' || c == 'U')
271 yylval.integer.unsignedp = 1;
272 else
273 break;
275 if (len == 0)
276 break;
277 c = *p++;
278 len--;
280 /* Don't look for any more digits after the suffixes. */
281 break;
285 if (len != 0) {
286 yyerror ("Invalid number in #if expression");
287 return ERROR;
290 /* If too big to be signed, consider it unsigned. */
291 if (n < 0)
292 yylval.integer.unsignedp = 1;
294 lexptr = p;
295 yylval.integer.value = n;
296 return INT;
299 struct token {
300 const char *operator;
301 int token;
304 #ifndef NULL
305 #define NULL 0
306 #endif
308 static struct token tokentab2[] = {
309 {"&&", AND},
310 {"||", OR},
311 {"<<", LSH},
312 {">>", RSH},
313 {"==", EQUAL},
314 {"!=", NOTEQUAL},
315 {"<=", LEQ},
316 {">=", GEQ},
317 {NULL, ERROR}
320 /* Read one token, getting characters through lexptr. */
323 yylex ()
325 register int c;
326 register int namelen;
327 register char *tokstart;
328 register struct token *toktab;
330 retry:
332 tokstart = lexptr;
333 c = *tokstart;
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]) {
337 lexptr += 2;
338 return toktab->token;
341 switch (c) {
342 case 0:
343 return 0;
345 case ' ':
346 case '\t':
347 case '\r':
348 case '\n':
349 lexptr++;
350 goto retry;
352 case '\'':
353 lexptr++;
354 c = *lexptr++;
355 if (c == '\\')
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);
364 else
365 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
368 yylval.integer.unsignedp = 0;
369 c = *lexptr++;
370 if (c != '\'') {
371 yyerror ("Invalid character constant in #if");
372 return ERROR;
375 return CHAR;
377 /* some of these chars are invalid in constant expressions;
378 maybe do something about them later */
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 case ']':
396 case '.':
397 case '?':
398 case ':':
399 case '=':
400 case '{':
401 case '}':
402 case ',':
403 lexptr++;
404 return c;
406 case '"':
407 yyerror ("double quoted strings not allowed in #if expressions");
408 return ERROR;
410 if (c >= '0' && c <= '9') {
411 /* It's a number */
412 for (namelen = 0;
413 c = tokstart[namelen], is_idchar[c] || c == '.';
414 namelen++)
416 return parse_number (namelen);
419 if (!is_idstart[c]) {
420 yyerror ("Invalid token in expression");
421 return ERROR;
424 /* It is a name. See how long it is. */
426 for (namelen = 0;
427 is_idchar[(int)(unsigned char)tokstart[namelen]];
428 namelen++)
431 lexptr += namelen;
432 return NAME;
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)
452 char **string_ptr;
454 register int c = *(*string_ptr)++;
455 switch (c)
457 case 'a':
458 return TARGET_BELL;
459 case 'b':
460 return TARGET_BS;
461 case 'e':
462 return 033;
463 case 'f':
464 return TARGET_FF;
465 case 'n':
466 return TARGET_NEWLINE;
467 case 'r':
468 return TARGET_CR;
469 case 't':
470 return TARGET_TAB;
471 case 'v':
472 return TARGET_VT;
473 case '\n':
474 return -2;
475 case 0:
476 (*string_ptr)--;
477 return 0;
478 case '^':
479 c = *(*string_ptr)++;
480 if (c == '\\')
481 c = parse_escape (string_ptr);
482 if (c == '?')
483 return 0177;
484 return (c & 0200) | (c & 037);
486 case '0':
487 case '1':
488 case '2':
489 case '3':
490 case '4':
491 case '5':
492 case '6':
493 case '7':
495 register int i = c - '0';
496 register int count = 0;
497 while (++count < 3)
499 c = *(*string_ptr)++;
500 if (c >= '0' && c <= '7')
501 i = (i << 3) + c - '0';
502 else
504 (*string_ptr)--;
505 break;
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");
513 return i;
515 case 'x':
517 register int i = 0;
518 for (;;)
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;
527 else
529 (*string_ptr)--;
530 break;
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");
538 return i;
540 default:
541 return c;
545 void
546 yyerror (s)
547 const char *s;
549 error (s);
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)
562 char *string;
564 lexptr = 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))
575 return 0;
577 if (yyparse ())
578 return 0; /* actually this is never reached
579 the way things stand. */
580 if (*lexptr)
581 error ("Junk after end of expression.");
583 return expression_value; /* set by yyparse () */