* c-format.c (maybe_read_dollar_number): Use safe-ctype macros
[official-gcc.git] / gcc / tradcif.y
blob167a8db900caffffb0abf7452143bac34007cd30
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
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 "tradcpp.h"
28 #include <setjmp.h>
30 static int yylex PARAMS ((void));
31 static void yyerror PARAMS ((const char *msgid)) ATTRIBUTE_NORETURN;
33 static int parse_number PARAMS ((int));
34 static int parse_escape PARAMS ((const char **));
36 static int expression_value;
37 static jmp_buf parse_return_error;
39 /* During parsing of a C expression, the pointer to the next
40 character is in this variable. */
42 static const char *lexptr;
45 %union {
46 struct constant {long value; int unsignedp;} integer;
47 int voidval;
48 char *sval;
51 %type <integer> exp exp1 start
52 %token <integer> INT CHAR
53 %token <sval> NAME
54 %token <integer> ERROR
56 %right '?' ':'
57 %left ','
58 %left OR
59 %left AND
60 %left '|'
61 %left '^'
62 %left '&'
63 %left EQUAL NOTEQUAL
64 %left '<' '>' LEQ GEQ
65 %left LSH RSH
66 %left '+' '-'
67 %left '*' '/' '%'
68 %right UNARY
70 /* %expect 40 */
74 start : exp1
75 { expression_value = $1.value; }
78 /* Expressions, including the comma operator. */
79 exp1 : exp
80 | exp1 ',' exp
81 { $$ = $3; }
84 /* Expressions, not including the comma operator. */
85 exp : '-' exp %prec UNARY
86 { $$.value = - $2.value;
87 $$.unsignedp = $2.unsignedp; }
88 | '!' exp %prec UNARY
89 { $$.value = ! $2.value;
90 $$.unsignedp = 0; }
91 | '+' exp %prec UNARY
92 { $$ = $2; }
93 | '~' exp %prec UNARY
94 { $$.value = ~ $2.value;
95 $$.unsignedp = $2.unsignedp; }
96 | '(' exp1 ')'
97 { $$ = $2; }
100 /* Binary operators in order of decreasing precedence. */
101 exp : exp '*' exp
102 { $$.unsignedp = $1.unsignedp || $3.unsignedp;
103 if ($$.unsignedp)
104 $$.value = (unsigned) $1.value * $3.value;
105 else
106 $$.value = $1.value * $3.value; }
107 | exp '/' exp
108 { if ($3.value == 0)
110 error ("division by zero in #if");
111 $3.value = 1;
113 $$.unsignedp = $1.unsignedp || $3.unsignedp;
114 if ($$.unsignedp)
115 $$.value = (unsigned) $1.value / $3.value;
116 else
117 $$.value = $1.value / $3.value; }
118 | exp '%' exp
119 { if ($3.value == 0)
121 error ("division by zero in #if");
122 $3.value = 1;
124 $$.unsignedp = $1.unsignedp || $3.unsignedp;
125 if ($$.unsignedp)
126 $$.value = (unsigned) $1.value % $3.value;
127 else
128 $$.value = $1.value % $3.value; }
129 | exp '+' exp
130 { $$.value = $1.value + $3.value;
131 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
132 | exp '-' exp
133 { $$.value = $1.value - $3.value;
134 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
135 | exp LSH exp
136 { $$.unsignedp = $1.unsignedp;
137 if ($$.unsignedp)
138 $$.value = (unsigned) $1.value << $3.value;
139 else
140 $$.value = $1.value << $3.value; }
141 | exp RSH exp
142 { $$.unsignedp = $1.unsignedp;
143 if ($$.unsignedp)
144 $$.value = (unsigned) $1.value >> $3.value;
145 else
146 $$.value = $1.value >> $3.value; }
147 | exp EQUAL exp
148 { $$.value = ($1.value == $3.value);
149 $$.unsignedp = 0; }
150 | exp NOTEQUAL exp
151 { $$.value = ($1.value != $3.value);
152 $$.unsignedp = 0; }
153 | exp LEQ exp
154 { $$.unsignedp = 0;
155 if ($1.unsignedp || $3.unsignedp)
156 $$.value =
157 (unsigned) $1.value <= (unsigned) $3.value;
158 else
159 $$.value = $1.value <= $3.value; }
160 | exp GEQ 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 '<' 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 { $$.value = $1.value & $3.value;
183 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
184 | exp '^' exp
185 { $$.value = $1.value ^ $3.value;
186 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
187 | exp '|' exp
188 { $$.value = $1.value | $3.value;
189 $$.unsignedp = $1.unsignedp || $3.unsignedp; }
190 | exp AND exp
191 { $$.value = ($1.value && $3.value);
192 $$.unsignedp = 0; }
193 | exp OR exp
194 { $$.value = ($1.value || $3.value);
195 $$.unsignedp = 0; }
196 | exp '?' exp ':' exp
197 { $$.value = $1.value ? $3.value : $5.value;
198 $$.unsignedp = $3.unsignedp || $5.unsignedp; }
199 | INT
200 { $$ = yylval.integer; }
201 | CHAR
202 { $$ = yylval.integer; }
203 | NAME
204 { $$.value = 0;
205 $$.unsignedp = 0; }
206 | '#' { $$.value =
207 test_assertion ((unsigned char **) &lexptr); }
211 /* Take care of parsing a number (anything that starts with a digit).
212 Set yylval and return the token type; update lexptr.
213 LEN is the number of characters in it. */
215 /* maybe needs to actually deal with floating point numbers */
217 static int
218 parse_number (olen)
219 int olen;
221 const char *p = lexptr;
222 long n = 0;
223 int c;
224 int base = 10;
225 int len = olen;
227 for (c = 0; c < len; c++)
228 if (p[c] == '.') {
229 /* It's a float since it contains a point. */
230 yyerror ("floating point numbers not allowed in #if expressions");
231 return ERROR;
234 /* Traditionally, all numbers are signed. However, we make it
235 unsigned if requested with a suffix. */
236 yylval.integer.unsignedp = 0;
238 if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
239 p += 2;
240 base = 16;
241 len -= 2;
243 else if (*p == '0')
244 base = 8;
246 while (len > 0) {
247 c = *p++;
248 len--;
249 if (ISUPPER (c))
250 c += 'a' - 'A';
252 if (ISDIGIT (c)) {
253 n *= base;
254 n += c - '0';
255 } else if (base == 16 && c >= 'a' && c <= 'f') {
256 n *= base;
257 n += c - 'a' + 10;
258 } else {
259 /* `l' means long, and `u' means unsigned. */
260 while (1) {
261 if (c == 'l' || c == 'L')
263 else if (c == 'u' || c == 'U')
264 yylval.integer.unsignedp = 1;
265 else
266 break;
268 if (len == 0)
269 break;
270 c = *p++;
271 len--;
273 /* Don't look for any more digits after the suffixes. */
274 break;
278 if (len != 0) {
279 yyerror ("Invalid number in #if expression");
280 return ERROR;
283 lexptr = p;
284 yylval.integer.value = n;
285 return INT;
288 struct token {
289 const char *const operator;
290 const int token;
293 #ifndef NULL
294 #define NULL 0
295 #endif
297 static const struct token tokentab2[] = {
298 {"&&", AND},
299 {"||", OR},
300 {"<<", LSH},
301 {">>", RSH},
302 {"==", EQUAL},
303 {"!=", NOTEQUAL},
304 {"<=", LEQ},
305 {">=", GEQ},
306 {NULL, ERROR}
309 /* Read one token, getting characters through lexptr. */
311 static int
312 yylex ()
314 int c;
315 int namelen;
316 const char *tokstart;
317 const struct token *toktab;
319 retry:
321 tokstart = lexptr;
322 c = *tokstart;
323 /* See if it is a special token of length 2. */
324 for (toktab = tokentab2; toktab->operator != NULL; toktab++)
325 if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
326 lexptr += 2;
327 return toktab->token;
330 switch (c) {
331 case 0:
332 return 0;
334 case ' ':
335 case '\t':
336 case '\r':
337 case '\n':
338 lexptr++;
339 goto retry;
341 case '\'':
342 lexptr++;
343 c = *lexptr++;
344 if (c == '\\')
345 c = parse_escape (&lexptr);
347 /* Sign-extend the constant if chars are signed on target machine. */
349 if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
350 sizeof ("__CHAR_UNSIGNED__")-1, -1)
351 || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
352 yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
353 else
354 yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
357 yylval.integer.unsignedp = 0;
358 c = *lexptr++;
359 if (c != '\'') {
360 yyerror ("Invalid character constant in #if");
361 return ERROR;
364 return CHAR;
366 /* some of these chars are invalid in constant expressions;
367 maybe do something about them later */
368 case '/':
369 case '+':
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 lexptr++;
394 return c;
396 case '"':
397 yyerror ("double quoted strings not allowed in #if expressions");
398 return ERROR;
400 if (ISDIGIT (c)) {
401 /* It's a number */
402 for (namelen = 0;
403 c = tokstart[namelen], is_idchar (c) || c == '.';
404 namelen++)
406 return parse_number (namelen);
409 if (!is_idstart (c)) {
410 yyerror ("Invalid token in expression");
411 return ERROR;
414 /* It is a name. See how long it is. */
416 for (namelen = 0;
417 is_idchar (tokstart[namelen]);
418 namelen++)
421 lexptr += namelen;
422 return NAME;
426 /* Parse a C escape sequence. STRING_PTR points to a variable
427 containing a pointer to the string to parse. That pointer
428 is updated past the characters we use. The value of the
429 escape sequence is returned.
431 A negative value means the sequence \ newline was seen,
432 which is supposed to be equivalent to nothing at all.
434 If \ is followed by a null character, we return a negative
435 value and leave the string pointer pointing at the null character.
437 If \ is followed by 000, we return 0 and leave the string pointer
438 after the zeros. A value of 0 does not mean end of string. */
440 static int
441 parse_escape (string_ptr)
442 const char **string_ptr;
444 int c = *(*string_ptr)++;
445 switch (c)
447 case 'a':
448 return TARGET_BELL;
449 case 'b':
450 return TARGET_BS;
451 case 'e':
452 return 033;
453 case 'f':
454 return TARGET_FF;
455 case 'n':
456 return TARGET_NEWLINE;
457 case 'r':
458 return TARGET_CR;
459 case 't':
460 return TARGET_TAB;
461 case 'v':
462 return TARGET_VT;
463 case '\n':
464 return -2;
465 case 0:
466 (*string_ptr)--;
467 return 0;
468 case '^':
469 c = *(*string_ptr)++;
470 if (c == '\\')
471 c = parse_escape (string_ptr);
472 if (c == '?')
473 return 0177;
474 return (c & 0200) | (c & 037);
476 case '0':
477 case '1':
478 case '2':
479 case '3':
480 case '4':
481 case '5':
482 case '6':
483 case '7':
485 int i = c - '0';
486 int count = 0;
487 while (++count < 3)
489 c = *(*string_ptr)++;
490 if (c >= '0' && c <= '7')
491 i = (i << 3) + c - '0';
492 else
494 (*string_ptr)--;
495 break;
498 if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
500 i &= (1 << CHAR_TYPE_SIZE) - 1;
501 warning ("octal character constant does not fit in a byte");
503 return i;
505 case 'x':
507 int i = 0;
508 for (;;)
510 c = *(*string_ptr)++;
511 if (ISDIGIT (c))
512 i = (i << 4) + c - '0';
513 else if (c >= 'a' && c <= 'f')
514 i = (i << 4) + c - 'a' + 10;
515 else if (c >= 'A' && c <= 'F')
516 i = (i << 4) + c - 'A' + 10;
517 else
519 (*string_ptr)--;
520 break;
523 if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
525 i &= (1 << BITS_PER_UNIT) - 1;
526 warning ("hex character constant does not fit in a byte");
528 return i;
530 default:
531 return c;
535 static void
536 yyerror (s)
537 const char *s;
539 error ("%s", s);
540 longjmp (parse_return_error, 1);
543 /* This page contains the entry point to this file. */
545 /* Parse STRING as an expression, and complain if this fails
546 to use up all of the contents of STRING. */
547 /* We do not support C comments. They should be removed before
548 this function is called. */
551 parse_c_expression (string)
552 const char *string;
554 lexptr = string;
556 if (lexptr == 0 || *lexptr == 0) {
557 error ("empty #if expression");
558 return 0; /* don't include the #if group */
561 /* if there is some sort of scanning error, just return 0 and assume
562 the parsing routine has printed an error message somewhere.
563 there is surely a better thing to do than this. */
564 if (setjmp (parse_return_error))
565 return 0;
567 if (yyparse ())
568 return 0; /* actually this is never reached
569 the way things stand. */
570 if (*lexptr)
571 error ("Junk after end of expression.");
573 return expression_value; /* set by yyparse () */