OSDN Git Service

* fixinc/fixtests.c(stdc_0_in_system_headers_test): Must return "FIX"
[pf3gnuchains/gcc-fork.git] / gcc / tradcif.y
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
7
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.
12
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.
17
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.  */
21
22 /* Parse a C expression from text in a string  */
23    
24 %{
25 #include "config.h"
26 #include "system.h"
27 #include "tradcpp.h"
28 #include <setjmp.h>
29
30   static int yylex PARAMS ((void));
31   static void yyerror PARAMS ((const char *msgid)) ATTRIBUTE_NORETURN;
32
33   static int parse_number PARAMS ((int));
34   static int parse_escape PARAMS ((const char **));
35
36   static int expression_value;
37   static jmp_buf parse_return_error;
38
39   /* During parsing of a C expression, the pointer to the next
40      character is in this variable.  */
41
42   static const char *lexptr;
43 %}
44
45 %union {
46   struct constant {long value; int unsignedp;} integer;
47   int voidval;
48   char *sval;
49 }
50
51 %type <integer> exp exp1 start
52 %token <integer> INT CHAR
53 %token <sval> NAME
54 %token <integer> ERROR
55
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
69
70 /* %expect 40 */
71 \f
72 %%
73
74 start   :       exp1
75                 { expression_value = $1.value; }
76         ;
77
78 /* Expressions, including the comma operator.  */
79 exp1    :       exp
80         |       exp1 ',' exp
81                         { $$ = $3; }
82         ;
83
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; }
98         ;
99
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)
109                             {
110                               error ("division by zero in #if");
111                               $3.value = 1;
112                             }
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)
120                             {
121                               error ("division by zero in #if");
122                               $3.value = 1;
123                             }
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); }
208         ;
209 %%
210 \f
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.  */
214
215 /* maybe needs to actually deal with floating point numbers */
216
217 static int
218 parse_number (olen)
219      int olen;
220 {
221   register const char *p = lexptr;
222   register long n = 0;
223   register int c;
224   register int base = 10;
225   register int len = olen;
226
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;
232     }
233
234   yylval.integer.unsignedp = 0;
235
236   if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
237     p += 2;
238     base = 16;
239     len -= 2;
240   }
241   else if (*p == '0')
242     base = 8;
243
244   while (len > 0) {
245     c = *p++;
246     len--;
247     if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
248
249     if (c >= '0' && c <= '9') {
250       n *= base;
251       n += c - '0';
252     } else if (base == 16 && c >= 'a' && c <= 'f') {
253       n *= base;
254       n += c - 'a' + 10;
255     } else {
256       /* `l' means long, and `u' means unsigned.  */
257       while (1) {
258         if (c == 'l' || c == 'L')
259           ;
260         else if (c == 'u' || c == 'U')
261           yylval.integer.unsignedp = 1;
262         else
263           break;
264
265         if (len == 0)
266           break;
267         c = *p++;
268         len--;
269       }
270       /* Don't look for any more digits after the suffixes.  */
271       break;
272     }
273   }
274
275   if (len != 0) {
276     yyerror ("Invalid number in #if expression");
277     return ERROR;
278   }
279
280   /* If too big to be signed, consider it unsigned.  */
281   if (n < 0)
282     yylval.integer.unsignedp = 1;
283
284   lexptr = p;
285   yylval.integer.value = n;
286   return INT;
287 }
288
289 struct token {
290   const char *operator;
291   int token;
292 };
293
294 #ifndef NULL
295 #define NULL 0
296 #endif
297
298 static struct token tokentab2[] = {
299   {"&&", AND},
300   {"||", OR},
301   {"<<", LSH},
302   {">>", RSH},
303   {"==", EQUAL},
304   {"!=", NOTEQUAL},
305   {"<=", LEQ},
306   {">=", GEQ},
307   {NULL, ERROR}
308 };
309
310 /* Read one token, getting characters through lexptr.  */
311
312 static int
313 yylex ()
314 {
315   register int c;
316   register int namelen;
317   register const char *tokstart;
318   register struct token *toktab;
319
320  retry:
321
322   tokstart = lexptr;
323   c = *tokstart;
324   /* See if it is a special token of length 2.  */
325   for (toktab = tokentab2; toktab->operator != NULL; toktab++)
326     if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
327       lexptr += 2;
328       return toktab->token;
329     }
330
331   switch (c) {
332   case 0:
333     return 0;
334     
335   case ' ':
336   case '\t':
337   case '\r':
338   case '\n':
339     lexptr++;
340     goto retry;
341     
342   case '\'':
343     lexptr++;
344     c = *lexptr++;
345     if (c == '\\')
346       c = parse_escape (&lexptr);
347
348     /* Sign-extend the constant if chars are signed on target machine.  */
349     {
350       if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
351                    sizeof ("__CHAR_UNSIGNED__")-1, -1)
352           || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
353         yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
354       else
355         yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
356     }
357
358     yylval.integer.unsignedp = 0;
359     c = *lexptr++;
360     if (c != '\'') {
361       yyerror ("Invalid character constant in #if");
362       return ERROR;
363     }
364     
365     return CHAR;
366
367     /* some of these chars are invalid in constant expressions;
368        maybe do something about them later */
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   case '#':
394     lexptr++;
395     return c;
396     
397   case '"':
398     yyerror ("double quoted strings not allowed in #if expressions");
399     return ERROR;
400   }
401   if (c >= '0' && c <= '9') {
402     /* It's a number */
403     for (namelen = 0;
404          c = tokstart[namelen], is_idchar (c) || c == '.'; 
405          namelen++)
406       ;
407     return parse_number (namelen);
408   }
409   
410   if (!is_idstart (c)) {
411     yyerror ("Invalid token in expression");
412     return ERROR;
413   }
414   
415   /* It is a name.  See how long it is.  */
416   
417   for (namelen = 0;
418        is_idchar (tokstart[namelen]);
419        namelen++)
420     ;
421   
422   lexptr += namelen;
423   return NAME;
424 }
425
426
427 /* Parse a C escape sequence.  STRING_PTR points to a variable
428    containing a pointer to the string to parse.  That pointer
429    is updated past the characters we use.  The value of the
430    escape sequence is returned.
431
432    A negative value means the sequence \ newline was seen,
433    which is supposed to be equivalent to nothing at all.
434
435    If \ is followed by a null character, we return a negative
436    value and leave the string pointer pointing at the null character.
437
438    If \ is followed by 000, we return 0 and leave the string pointer
439    after the zeros.  A value of 0 does not mean end of string.  */
440
441 static int
442 parse_escape (string_ptr)
443      const char **string_ptr;
444 {
445   register int c = *(*string_ptr)++;
446   switch (c)
447     {
448     case 'a':
449       return TARGET_BELL;
450     case 'b':
451       return TARGET_BS;
452     case 'e':
453       return 033;
454     case 'f':
455       return TARGET_FF;
456     case 'n':
457       return TARGET_NEWLINE;
458     case 'r':
459       return TARGET_CR;
460     case 't':
461       return TARGET_TAB;
462     case 'v':
463       return TARGET_VT;
464     case '\n':
465       return -2;
466     case 0:
467       (*string_ptr)--;
468       return 0;
469     case '^':
470       c = *(*string_ptr)++;
471       if (c == '\\')
472         c = parse_escape (string_ptr);
473       if (c == '?')
474         return 0177;
475       return (c & 0200) | (c & 037);
476       
477     case '0':
478     case '1':
479     case '2':
480     case '3':
481     case '4':
482     case '5':
483     case '6':
484     case '7':
485       {
486         register int i = c - '0';
487         register int count = 0;
488         while (++count < 3)
489           {
490             c = *(*string_ptr)++;
491             if (c >= '0' && c <= '7')
492               i = (i << 3) + c - '0';
493             else
494               {
495                 (*string_ptr)--;
496                 break;
497               }
498           }
499         if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
500           {
501             i &= (1 << CHAR_TYPE_SIZE) - 1;
502             warning ("octal character constant does not fit in a byte");
503           }
504         return i;
505       }
506     case 'x':
507       {
508         register int i = 0;
509         for (;;)
510           {
511             c = *(*string_ptr)++;
512             if (c >= '0' && c <= '9')
513               i = (i << 4) + c - '0';
514             else if (c >= 'a' && c <= 'f')
515               i = (i << 4) + c - 'a' + 10;
516             else if (c >= 'A' && c <= 'F')
517               i = (i << 4) + c - 'A' + 10;
518             else
519               {
520                 (*string_ptr)--;
521                 break;
522               }
523           }
524         if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
525           {
526             i &= (1 << BITS_PER_UNIT) - 1;
527             warning ("hex character constant does not fit in a byte");
528           }
529         return i;
530       }
531     default:
532       return c;
533     }
534 }
535
536 static void
537 yyerror (s)
538      const char *s;
539 {
540   error ("%s", s);
541   longjmp (parse_return_error, 1);
542 }
543 \f
544 /* This page contains the entry point to this file.  */
545
546 /* Parse STRING as an expression, and complain if this fails
547    to use up all of the contents of STRING.  */
548 /* We do not support C comments.  They should be removed before
549    this function is called.  */
550
551 int
552 parse_c_expression (string)
553      const char *string;
554 {
555   lexptr = string;
556   
557   if (lexptr == 0 || *lexptr == 0) {
558     error ("empty #if expression");
559     return 0;                   /* don't include the #if group */
560   }
561
562   /* if there is some sort of scanning error, just return 0 and assume
563      the parsing routine has printed an error message somewhere.
564      there is surely a better thing to do than this.     */
565   if (setjmp (parse_return_error))
566     return 0;
567
568   if (yyparse ())
569     return 0;                   /* actually this is never reached
570                                    the way things stand. */
571   if (*lexptr)
572     error ("Junk after end of expression.");
573
574   return expression_value;      /* set by yyparse () */
575 }