OSDN Git Service

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