OSDN Git Service

* tradcpp.c, tradcif.y: Update FSF mailing address, delete
[pf3gnuchains/gcc-fork.git] / gcc / tradcif.y
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
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 "defaults.h"
28 #include <setjmp.h>
29
30   int yylex PARAMS ((void));
31   void yyerror PARAMS ((const char *msgid));
32   extern void error   PARAMS ((const char *msgid, ...));
33   extern void warning PARAMS ((const char *msgid, ...));
34   extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
35
36   int parse_number PARAMS ((int));
37   int parse_escape PARAMS ((char **));
38   int parse_c_expression PARAMS ((char *));
39
40   int expression_value;
41   static jmp_buf parse_return_error;
42
43   /* some external tables of character types */
44   extern unsigned char is_idstart[], is_idchar[];
45
46 %}
47
48 %union {
49   struct constant {long value; int unsignedp;} integer;
50   int voidval;
51   char *sval;
52 }
53
54 %type <integer> exp exp1 start
55 %token <integer> INT CHAR
56 %token <sval> NAME
57 %token <integer> ERROR
58
59 %right '?' ':'
60 %left ','
61 %left OR
62 %left AND
63 %left '|'
64 %left '^'
65 %left '&'
66 %left EQUAL NOTEQUAL
67 %left '<' '>' LEQ GEQ
68 %left LSH RSH
69 %left '+' '-'
70 %left '*' '/' '%'
71 %right UNARY
72
73 /* %expect 40 */
74 \f
75 %%
76
77 start   :       exp1
78                 { expression_value = $1.value; }
79         ;
80
81 /* Expressions, including the comma operator.  */
82 exp1    :       exp
83         |       exp1 ',' exp
84                         { $$ = $3; }
85         ;
86
87 /* Expressions, not including the comma operator.  */
88 exp     :       '-' exp    %prec UNARY
89                         { $$.value = - $2.value;
90                           $$.unsignedp = $2.unsignedp; }
91         |       '!' exp    %prec UNARY
92                         { $$.value = ! $2.value;
93                           $$.unsignedp = 0; }
94         |       '+' exp    %prec UNARY
95                         { $$ = $2; }
96         |       '~' exp    %prec UNARY
97                         { $$.value = ~ $2.value;
98                           $$.unsignedp = $2.unsignedp; }
99         |       '(' exp1 ')'
100                         { $$ = $2; }
101         ;
102
103 /* Binary operators in order of decreasing precedence.  */
104 exp     :       exp '*' exp
105                         { $$.unsignedp = $1.unsignedp || $3.unsignedp;
106                           if ($$.unsignedp)
107                             $$.value = (unsigned) $1.value * $3.value;
108                           else
109                             $$.value = $1.value * $3.value; }
110         |       exp '/' exp
111                         { if ($3.value == 0)
112                             {
113                               error ("division by zero in #if");
114                               $3.value = 1;
115                             }
116                           $$.unsignedp = $1.unsignedp || $3.unsignedp;
117                           if ($$.unsignedp)
118                             $$.value = (unsigned) $1.value / $3.value;
119                           else
120                             $$.value = $1.value / $3.value; }
121         |       exp '%' exp
122                         { if ($3.value == 0)
123                             {
124                               error ("division by zero in #if");
125                               $3.value = 1;
126                             }
127                           $$.unsignedp = $1.unsignedp || $3.unsignedp;
128                           if ($$.unsignedp)
129                             $$.value = (unsigned) $1.value % $3.value;
130                           else
131                             $$.value = $1.value % $3.value; }
132         |       exp '+' exp
133                         { $$.value = $1.value + $3.value;
134                           $$.unsignedp = $1.unsignedp || $3.unsignedp; }
135         |       exp '-' exp
136                         { $$.value = $1.value - $3.value;
137                           $$.unsignedp = $1.unsignedp || $3.unsignedp; }
138         |       exp LSH exp
139                         { $$.unsignedp = $1.unsignedp;
140                           if ($$.unsignedp)
141                             $$.value = (unsigned) $1.value << $3.value;
142                           else
143                             $$.value = $1.value << $3.value; }
144         |       exp RSH exp
145                         { $$.unsignedp = $1.unsignedp;
146                           if ($$.unsignedp)
147                             $$.value = (unsigned) $1.value >> $3.value;
148                           else
149                             $$.value = $1.value >> $3.value; }
150         |       exp EQUAL exp
151                         { $$.value = ($1.value == $3.value);
152                           $$.unsignedp = 0; }
153         |       exp NOTEQUAL exp
154                         { $$.value = ($1.value != $3.value);
155                           $$.unsignedp = 0; }
156         |       exp LEQ exp
157                         { $$.unsignedp = 0;
158                           if ($1.unsignedp || $3.unsignedp)
159                             $$.value =
160                               (unsigned) $1.value <= (unsigned) $3.value;
161                           else
162                             $$.value = $1.value <= $3.value; }
163         |       exp GEQ exp
164                         { $$.unsignedp = 0;
165                           if ($1.unsignedp || $3.unsignedp)
166                             $$.value =
167                               (unsigned) $1.value >= (unsigned) $3.value;
168                           else
169                             $$.value = $1.value >= $3.value; }
170         |       exp '<' exp
171                         { $$.unsignedp = 0;
172                           if ($1.unsignedp || $3.unsignedp)
173                             $$.value =
174                               (unsigned) $1.value < (unsigned) $3.value;
175                           else
176                             $$.value = $1.value < $3.value; }
177         |       exp '>' exp
178                         { $$.unsignedp = 0;
179                           if ($1.unsignedp || $3.unsignedp)
180                             $$.value =
181                               (unsigned) $1.value > (unsigned) $3.value;
182                           else
183                             $$.value = $1.value > $3.value; }
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 '|' exp
191                         { $$.value = $1.value | $3.value;
192                           $$.unsignedp = $1.unsignedp || $3.unsignedp; }
193         |       exp AND exp
194                         { $$.value = ($1.value && $3.value);
195                           $$.unsignedp = 0; }
196         |       exp OR exp
197                         { $$.value = ($1.value || $3.value);
198                           $$.unsignedp = 0; }
199         |       exp '?' exp ':' exp
200                         { $$.value = $1.value ? $3.value : $5.value;
201                           $$.unsignedp = $3.unsignedp || $5.unsignedp; }
202         |       INT
203                         { $$ = yylval.integer; }
204         |       CHAR
205                         { $$ = yylval.integer; }
206         |       NAME
207                         { $$.value = 0;
208                           $$.unsignedp = 0; }
209         ;
210 %%
211 \f
212 /* During parsing of a C expression, the pointer to the next character
213    is in this variable.  */
214
215 static char *lexptr;
216
217 /* Take care of parsing a number (anything that starts with a digit).
218    Set yylval and return the token type; update lexptr.
219    LEN is the number of characters in it.  */
220
221 /* maybe needs to actually deal with floating point numbers */
222
223 int
224 parse_number (olen)
225      int olen;
226 {
227   register char *p = lexptr;
228   register long n = 0;
229   register int c;
230   register int base = 10;
231   register int len = olen;
232
233   for (c = 0; c < len; c++)
234     if (p[c] == '.') {
235       /* It's a float since it contains a point.  */
236       yyerror ("floating point numbers not allowed in #if expressions");
237       return ERROR;
238     }
239
240   yylval.integer.unsignedp = 0;
241
242   if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
243     p += 2;
244     base = 16;
245     len -= 2;
246   }
247   else if (*p == '0')
248     base = 8;
249
250   while (len > 0) {
251     c = *p++;
252     len--;
253     if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
254
255     if (c >= '0' && c <= '9') {
256       n *= base;
257       n += c - '0';
258     } else if (base == 16 && c >= 'a' && c <= 'f') {
259       n *= base;
260       n += c - 'a' + 10;
261     } else {
262       /* `l' means long, and `u' means unsigned.  */
263       while (1) {
264         if (c == 'l' || c == 'L')
265           ;
266         else if (c == 'u' || c == 'U')
267           yylval.integer.unsignedp = 1;
268         else
269           break;
270
271         if (len == 0)
272           break;
273         c = *p++;
274         len--;
275       }
276       /* Don't look for any more digits after the suffixes.  */
277       break;
278     }
279   }
280
281   if (len != 0) {
282     yyerror ("Invalid number in #if expression");
283     return ERROR;
284   }
285
286   /* If too big to be signed, consider it unsigned.  */
287   if (n < 0)
288     yylval.integer.unsignedp = 1;
289
290   lexptr = p;
291   yylval.integer.value = n;
292   return INT;
293 }
294
295 struct token {
296   const char *operator;
297   int token;
298 };
299
300 #ifndef NULL
301 #define NULL 0
302 #endif
303
304 static struct token tokentab2[] = {
305   {"&&", AND},
306   {"||", OR},
307   {"<<", LSH},
308   {">>", RSH},
309   {"==", EQUAL},
310   {"!=", NOTEQUAL},
311   {"<=", LEQ},
312   {">=", GEQ},
313   {NULL, ERROR}
314 };
315
316 /* Read one token, getting characters through lexptr.  */
317
318 int
319 yylex ()
320 {
321   register int c;
322   register int namelen;
323   register char *tokstart;
324   register struct token *toktab;
325
326  retry:
327
328   tokstart = lexptr;
329   c = *tokstart;
330   /* See if it is a special token of length 2.  */
331   for (toktab = tokentab2; toktab->operator != NULL; toktab++)
332     if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
333       lexptr += 2;
334       return toktab->token;
335     }
336
337   switch (c) {
338   case 0:
339     return 0;
340     
341   case ' ':
342   case '\t':
343   case '\r':
344   case '\n':
345     lexptr++;
346     goto retry;
347     
348   case '\'':
349     lexptr++;
350     c = *lexptr++;
351     if (c == '\\')
352       c = parse_escape (&lexptr);
353
354     /* Sign-extend the constant if chars are signed on target machine.  */
355     {
356       if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
357                    sizeof ("__CHAR_UNSIGNED__")-1, -1)
358           || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
359         yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
360       else
361         yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
362     }
363
364     yylval.integer.unsignedp = 0;
365     c = *lexptr++;
366     if (c != '\'') {
367       yyerror ("Invalid character constant in #if");
368       return ERROR;
369     }
370     
371     return CHAR;
372
373     /* some of these chars are invalid in constant expressions;
374        maybe do something about them later */
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   case '=':
396   case '{':
397   case '}':
398   case ',':
399     lexptr++;
400     return c;
401     
402   case '"':
403     yyerror ("double quoted strings not allowed in #if expressions");
404     return ERROR;
405   }
406   if (c >= '0' && c <= '9') {
407     /* It's a number */
408     for (namelen = 0;
409          c = tokstart[namelen], is_idchar[c] || c == '.'; 
410          namelen++)
411       ;
412     return parse_number (namelen);
413   }
414   
415   if (!is_idstart[c]) {
416     yyerror ("Invalid token in expression");
417     return ERROR;
418   }
419   
420   /* It is a name.  See how long it is.  */
421   
422   for (namelen = 0;
423        is_idchar[(int)(unsigned char)tokstart[namelen]];
424        namelen++)
425     ;
426   
427   lexptr += namelen;
428   return NAME;
429 }
430
431
432 /* Parse a C escape sequence.  STRING_PTR points to a variable
433    containing a pointer to the string to parse.  That pointer
434    is updated past the characters we use.  The value of the
435    escape sequence is returned.
436
437    A negative value means the sequence \ newline was seen,
438    which is supposed to be equivalent to nothing at all.
439
440    If \ is followed by a null character, we return a negative
441    value and leave the string pointer pointing at the null character.
442
443    If \ is followed by 000, we return 0 and leave the string pointer
444    after the zeros.  A value of 0 does not mean end of string.  */
445
446 int
447 parse_escape (string_ptr)
448      char **string_ptr;
449 {
450   register int c = *(*string_ptr)++;
451   switch (c)
452     {
453     case 'a':
454       return TARGET_BELL;
455     case 'b':
456       return TARGET_BS;
457     case 'e':
458       return 033;
459     case 'f':
460       return TARGET_FF;
461     case 'n':
462       return TARGET_NEWLINE;
463     case 'r':
464       return TARGET_CR;
465     case 't':
466       return TARGET_TAB;
467     case 'v':
468       return TARGET_VT;
469     case '\n':
470       return -2;
471     case 0:
472       (*string_ptr)--;
473       return 0;
474     case '^':
475       c = *(*string_ptr)++;
476       if (c == '\\')
477         c = parse_escape (string_ptr);
478       if (c == '?')
479         return 0177;
480       return (c & 0200) | (c & 037);
481       
482     case '0':
483     case '1':
484     case '2':
485     case '3':
486     case '4':
487     case '5':
488     case '6':
489     case '7':
490       {
491         register int i = c - '0';
492         register int count = 0;
493         while (++count < 3)
494           {
495             c = *(*string_ptr)++;
496             if (c >= '0' && c <= '7')
497               i = (i << 3) + c - '0';
498             else
499               {
500                 (*string_ptr)--;
501                 break;
502               }
503           }
504         if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
505           {
506             i &= (1 << CHAR_TYPE_SIZE) - 1;
507             warning ("octal character constant does not fit in a byte");
508           }
509         return i;
510       }
511     case 'x':
512       {
513         register int i = 0;
514         for (;;)
515           {
516             c = *(*string_ptr)++;
517             if (c >= '0' && c <= '9')
518               i = (i << 4) + c - '0';
519             else if (c >= 'a' && c <= 'f')
520               i = (i << 4) + c - 'a' + 10;
521             else if (c >= 'A' && c <= 'F')
522               i = (i << 4) + c - 'A' + 10;
523             else
524               {
525                 (*string_ptr)--;
526                 break;
527               }
528           }
529         if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
530           {
531             i &= (1 << BITS_PER_UNIT) - 1;
532             warning ("hex character constant does not fit in a byte");
533           }
534         return i;
535       }
536     default:
537       return c;
538     }
539 }
540
541 void
542 yyerror (s)
543      const char *s;
544 {
545   error (s);
546   longjmp (parse_return_error, 1);
547 }
548 \f
549 /* This page contains the entry point to this file.  */
550
551 /* Parse STRING as an expression, and complain if this fails
552    to use up all of the contents of STRING.  */
553 /* We do not support C comments.  They should be removed before
554    this function is called.  */
555
556 int
557 parse_c_expression (string)
558      char *string;
559 {
560   lexptr = string;
561   
562   if (lexptr == 0 || *lexptr == 0) {
563     error ("empty #if expression");
564     return 0;                   /* don't include the #if group */
565   }
566
567   /* if there is some sort of scanning error, just return 0 and assume
568      the parsing routine has printed an error message somewhere.
569      there is surely a better thing to do than this.     */
570   if (setjmp (parse_return_error))
571     return 0;
572
573   if (yyparse ())
574     return 0;                   /* actually this is never reached
575                                    the way things stand. */
576   if (*lexptr)
577     error ("Junk after end of expression.");
578
579   return expression_value;      /* set by yyparse () */
580 }