OSDN Git Service

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