OSDN Git Service

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