OSDN Git Service

* toplev.c (flag_new_exceptions): Remove extraneous `extern'.
[pf3gnuchains/gcc-fork.git] / gcc / cppexp.c
index 70da378..44f8a66 100644 (file)
@@ -1,5 +1,5 @@
 /* Parse C expressions for CCCP.
-   Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
+   Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998 Free Software Foundation.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -13,29 +13,29 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
 
  In other words, you are welcome to use, share and improve this program.
  You are forbidden to forbid anyone else to use, share and improve
  what you give them.   Help stamp out software-hoarding!
 
-Written by Per Bothner 1994. */
+Written by Per Bothner 1994.  */
 
 /* Parse a C expression from text in a string  */
    
 #include "config.h"
+#include "system.h"
+#include "gansidecl.h"
 #include "cpplib.h"
 
 extern char *xmalloc PARAMS ((unsigned));
-extern char *xrealloc PARAMS ((char *, unsigned));
+extern char *xrealloc PARAMS ((void *, unsigned));
 
 #ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
 #include <locale.h>
 #endif
 
-#include <stdio.h>
-
 /* This is used for communicating lists of keywords with cccp.c.  */
 struct arglist {
   struct arglist *next;
@@ -44,26 +44,6 @@ struct arglist {
   int argno;
 };
 
-/* Define a generic NULL if one hasn't already been defined.  */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
-#endif
-
-extern char *xmalloc ();
-
 #ifndef CHAR_TYPE_SIZE
 #define CHAR_TYPE_SIZE BITS_PER_UNIT
 #endif
@@ -100,9 +80,9 @@ extern char *xmalloc ();
    number with SUM's sign, where A, B, and SUM are all C integers.  */
 #define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
 
-static void integer_overflow ();
-static long left_shift ();
-static long right_shift ();
+static void integer_overflow PARAMS ((cpp_reader *));
+static long left_shift PARAMS ((cpp_reader *, long, int, unsigned long));
+static long right_shift PARAMS ((cpp_reader *, long, int, unsigned long));
 
 #define ERROR 299
 #define OROR 300
@@ -120,26 +100,47 @@ static long right_shift ();
 #define LEFT_OPERAND_REQUIRED 1
 #define RIGHT_OPERAND_REQUIRED 2
 #define HAVE_VALUE 4
-/*#define UNSIGNEDP 8*/
-
-#ifndef HOST_BITS_PER_WIDE_INT
+/* SKIP_OPERAND is set for '&&' '||' '?' and ':' when the
+   following operand should be short-circuited instead of evaluated.  */
+#define SKIP_OPERAND 8
+/*#define UNSIGNEDP 16*/
+
+/* Find the largest host integer type and set its size and type.
+   Watch out: on some crazy hosts `long' is shorter than `int'.  */
+
+#ifndef HOST_WIDE_INT
+# if HAVE_INTTYPES_H
+#  include <inttypes.h>
+#  define HOST_WIDE_INT intmax_t
+# else
+#  if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT \
+       && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
+#   define HOST_WIDE_INT int
+#  else
+#  if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG \
+       || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
+#   define HOST_WIDE_INT long
+#  else
+#   define HOST_WIDE_INT long long
+#  endif
+#  endif
+# endif
+#endif
 
-#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
-#define HOST_WIDE_INT long
-#else
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
-#define HOST_WIDE_INT int
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
 #endif
 
+#ifndef HOST_BITS_PER_WIDE_INT
+#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT))
 #endif
 
 struct operation {
     short op;
-    char rprio; /* Priority of op (relative to it right operand). */
+    char rprio; /* Priority of op (relative to it right operand).  */
     char flags;
     char unsignedp;    /* true if value should be treated as unsigned */
-    HOST_WIDE_INT value;        /* The value logically "right" of op. */
+    HOST_WIDE_INT value;        /* The value logically "right" of op.  */
 };
 \f
 /* Take care of parsing a number (anything that starts with a digit).
@@ -182,7 +183,7 @@ parse_number (pfile, start, olen)
   else if (*p == '0')
     base = 8;
 
-  /* Some buggy compilers (e.g. MPW C) seem to need both casts. */
+  /* Some buggy compilers (e.g. MPW C) seem to need both casts.  */
   ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base);
 
   for (; len > 0; len--) {
@@ -222,7 +223,7 @@ parse_number (pfile, start, olen)
     if (largest_digit < digit)
       largest_digit = digit;
     nd = n * base + digit;
-    overflow |= ULONG_MAX_over_base < n | nd < n;
+    overflow |= ULONG_MAX_over_base < n || nd < n;
     n = nd;
   }
 
@@ -234,10 +235,10 @@ parse_number (pfile, start, olen)
     }
 
   if (base <= largest_digit)
-    cpp_warning (pfile, "integer constant contains digits beyond the radix");
+    cpp_pedwarn (pfile, "integer constant contains digits beyond the radix");
 
   if (overflow)
-    cpp_warning (pfile, "integer constant out of range");
+    cpp_pedwarn (pfile, "integer constant out of range");
 
   /* If too big to be signed, consider it unsigned.  */
   if ((long) n < 0 && ! op.unsignedp)
@@ -271,14 +272,14 @@ static struct token tokentab2[] = {
   {NULL, ERROR}
 };
 
-/* Read one token. */
+/* Read one token.  */
 
 struct operation
-cpp_lex (pfile)
-cpp_reader *pfile;
+cpp_lex (pfile, skip_evaluation)
+     cpp_reader *pfile;
+     int skip_evaluation;
 {
   register int c;
-  register int namelen;
   register struct token *toktab;
   enum cpp_token token;
   struct operation op;
@@ -306,16 +307,17 @@ cpp_reader *pfile;
   pfile->limit = tok_start;
   switch (token)
   {
-    case CPP_EOF: /* Should not happen ... */
+    case CPP_EOF: /* Should not happen ...  */
+    case CPP_VSPACE:
       op.op = 0;
       return op;
-    case CPP_VSPACE:
     case CPP_POP:
       if (CPP_BUFFER (pfile)->fname != NULL)
        {
          op.op = 0;
          return op;
        }
+      cpp_pop_buffer (pfile);
       goto retry;
     case CPP_HSPACE:   case CPP_COMMENT: 
       goto retry;
@@ -331,7 +333,7 @@ cpp_reader *pfile;
         It is mostly copied from c-lex.c.  */
       {
         register int result = 0;
-       register num_chars = 0;
+       register int num_chars = 0;
        unsigned width = MAX_CHAR_TYPE_SIZE;
        int wide_flag = 0;
        int max_chars;
@@ -356,14 +358,12 @@ cpp_reader *pfile;
        else
            max_chars = MAX_LONG_TYPE_SIZE / width;
 
-       while (1)
+       ++ptr;
+       while (ptr < tok_end && ((c = *ptr++) != '\''))
          {
-           if (ptr >= CPP_PWRITTEN (pfile) || (c = *ptr++) == '\'')
-             break;
-
            if (c == '\\')
              {
-               c = cpp_parse_escape (pfile, &ptr);
+               c = cpp_parse_escape (pfile, (char **) &ptr);
                if (width < HOST_BITS_PER_INT
                  && (unsigned) c >= (1 << width))
                    cpp_pedwarn (pfile,
@@ -402,7 +402,7 @@ cpp_reader *pfile;
          {
            int num_bits = num_chars * width;
 
-           if (cpp_lookup (pfile, "__CHAR_UNSIGNED__",
+           if (cpp_lookup (pfile, (U_CHAR *)"__CHAR_UNSIGNED__",
                            sizeof ("__CHAR_UNSIGNED__")-1, -1)
                || ((result >> (num_bits - 1)) & 1) == 0)
                op.value
@@ -426,7 +426,7 @@ cpp_reader *pfile;
                  if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
                    result = wc;
                  else
-                   cpp_warning (pfile,"Ignoring invalid multibyte character");
+                   cpp_pedwarn (pfile,"Ignoring invalid multibyte character");
                }
 #endif
              op.value = result;
@@ -440,6 +440,9 @@ cpp_reader *pfile;
       return op;
 
     case CPP_NAME:
+      if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
+       cpp_warning (pfile, "`%.*s' is not defined",
+                    (int) (tok_end - tok_start), tok_start);
       return parse_number (pfile, "0", 0);
 
     case CPP_OTHER:
@@ -539,7 +542,7 @@ cpp_parse_escape (pfile, string_ptr)
        if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
          {
            i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
-           cpp_warning (pfile,
+           cpp_pedwarn (pfile,
                          "octal character constant does not fit in a byte");
          }
        return i;
@@ -570,7 +573,7 @@ cpp_parse_escape (pfile, string_ptr)
        if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1)))
          {
            i &= (1 << BITS_PER_UNIT) - 1;
-           cpp_warning (pfile,
+           cpp_pedwarn (pfile,
                         "hex character constant does not fit in a byte");
          }
        return i;
@@ -614,7 +617,7 @@ left_shift (pfile, a, unsignedp, b)
 
 static long
 right_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile;
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
      long a;
      int unsignedp;
      unsigned long b;
@@ -627,7 +630,7 @@ right_shift (pfile, a, unsignedp, b)
     return a >> b;
 }
 \f
-/* These priorities are all even, so we can handle associatively. */
+/* These priorities are all even, so we can handle associatively.  */
 #define PAREN_INNER_PRIO 0
 #define COMMA_PRIO 4
 #define COND_PRIO (COMMA_PRIO+2)
@@ -671,6 +674,7 @@ cpp_parse_expr (pfile)
   struct operation *limit = stack + INIT_STACK_SIZE;
   register struct operation *top = stack;
   int lprio, rprio;
+  int skip_evaluation = 0;
 
   top->rprio = 0;
   top->flags = 0;
@@ -680,17 +684,16 @@ cpp_parse_expr (pfile)
       char flags = 0;
 
       /* Read a token */
-      op =  cpp_lex (pfile);
+      op =  cpp_lex (pfile, skip_evaluation);
 
       /* See if the token is an operand, in which case go to set_value.
         If the token is an operator, figure out its left and right
-        priorities, and then goto maybe_reduce. */
+        priorities, and then goto maybe_reduce.  */
 
       switch (op.op)
        {
        case NAME:
-         top->value = 0, top->unsignedp = 0;
-         goto set_value;
+         abort ();
        case INT:  case CHAR:
          top->value = op.value;
          top->unsignedp = op.unsignedp;
@@ -741,7 +744,7 @@ cpp_parse_expr (pfile)
        }
 
     set_value:
-      /* Push a value onto the stack. */
+      /* Push a value onto the stack.  */
       if (top->flags & HAVE_VALUE)
        {
          cpp_error (pfile, "syntax error in #if");
@@ -751,7 +754,7 @@ cpp_parse_expr (pfile)
       continue;
 
     maybe_reduce:
-      /* Push an operator, and check if we can reduce now. */
+      /* Push an operator, and check if we can reduce now.  */
       while (top->rprio > lprio)
        {
          long v1 = top[-1].value, v2 = top[0].value;
@@ -783,7 +786,7 @@ cpp_parse_expr (pfile)
                {
                  top->value = v1 + v2;
                  top->unsignedp = unsigned1 || unsigned2;
-                 if (! top->unsignedp
+                 if (! top->unsignedp && ! skip_evaluation
                      && ! possible_sum_sign (v1, v2, top->value))
                    integer_overflow (pfile);
                }
@@ -792,7 +795,7 @@ cpp_parse_expr (pfile)
              if (!(top->flags & HAVE_VALUE))
                { /* Unary '-' */
                  top->value = - v2;
-                 if ((top->value & v2) < 0 && ! unsigned2)
+                 if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2)
                    integer_overflow (pfile);
                  top->unsignedp = unsigned2;
                  top->flags |= HAVE_VALUE;
@@ -801,7 +804,7 @@ cpp_parse_expr (pfile)
                { /* Binary '-' */
                  top->value = v1 - v2;
                  top->unsignedp = unsigned1 || unsigned2;
-                 if (! top->unsignedp
+                 if (! top->unsignedp && ! skip_evaluation
                      && ! possible_sum_sign (top->value, v2, v1))
                    integer_overflow (pfile);
                }
@@ -810,7 +813,7 @@ cpp_parse_expr (pfile)
              top->unsignedp = unsigned1 || unsigned2;
              if (top->unsignedp)
                top->value = (unsigned long) v1 * v2;
-             else
+             else if (!skip_evaluation)
                {
                  top->value = v1 * v2;
                  if (v1
@@ -820,6 +823,8 @@ cpp_parse_expr (pfile)
                }
              break;
            case '/':
+             if (skip_evaluation)
+               break;
              if (v2 == 0)
                {
                  cpp_error (pfile, "division by zero in #if");
@@ -836,6 +841,8 @@ cpp_parse_expr (pfile)
                }
              break;
            case '%':
+             if (skip_evaluation)
+               break;
              if (v2 == 0)
                {
                  cpp_error (pfile, "division by zero in #if");
@@ -880,6 +887,8 @@ cpp_parse_expr (pfile)
              top->unsignedp = 0;
              break;
            case LSH:
+             if (skip_evaluation)
+               break;
              top->unsignedp = unsigned1;
              if (v2 < 0 && ! unsigned2)
                top->value = right_shift (pfile, v1, unsigned1, -v2);
@@ -887,6 +896,8 @@ cpp_parse_expr (pfile)
                top->value = left_shift (pfile, v1, unsigned1, v2);
              break;
            case RSH:
+             if (skip_evaluation)
+               break;
              top->unsignedp = unsigned1;
              if (v2 < 0 && ! unsigned2)
                top->value = left_shift (pfile, v1, unsigned1, -v2);
@@ -900,9 +911,13 @@ cpp_parse_expr (pfile)
            case '^':  LOGICAL(^);  break;
            case '|':  LOGICAL(|);  break;
            case ANDAND:
-             top->value = v1 && v2;  top->unsignedp = 0;  break;
+             top->value = v1 && v2;  top->unsignedp = 0;
+             if (!v1) skip_evaluation--;
+             break;
            case OROR:
-             top->value = v1 || v2;  top->unsignedp = 0;  break;
+             top->value = v1 || v2;  top->unsignedp = 0;
+             if (v1) skip_evaluation--;
+             break;
            case ',':
              if (CPP_PEDANTIC (pfile))
                cpp_pedwarn (pfile, "comma operator in operand of `#if'");
@@ -929,6 +944,7 @@ cpp_parse_expr (pfile)
              else
                {
                  top--;
+                 if (top->value) skip_evaluation--;
                  top->value = top->value ? v1 : v2;
                  top->unsignedp = unsigned1 || unsigned2;
                }
@@ -968,27 +984,40 @@ cpp_parse_expr (pfile)
        }
       top++;
       
-      /* Check for and handle stack overflow. */
+      /* Check for and handle stack overflow.  */
       if (top == limit)
        {
          struct operation *new_stack;
-         int old_size = (char*)limit - (char*)stack;
+         int old_size = (char *) limit - (char *) stack;
          int new_size = 2 * old_size;
          if (stack != init_stack)
-           new_stack = (struct operation*) xrealloc (stack, new_size);
+           new_stack = (struct operation *) xrealloc (stack, new_size);
          else
            {
-             new_stack = (struct operation*) xmalloc (new_size);
+             new_stack = (struct operation *) xmalloc (new_size);
              bcopy ((char *) stack, (char *) new_stack, old_size);
            }
          stack = new_stack;
-         top = (struct operation*)((char*) new_stack + old_size);
-         limit = (struct operation*)((char*) new_stack + new_size);
+         top = (struct operation *) ((char *) new_stack + old_size);
+         limit = (struct operation *) ((char *) new_stack + new_size);
        }
       
       top->flags = flags;
       top->rprio = rprio;
       top->op = op.op;
+      if ((op.op == OROR && top[-1].value)
+         || (op.op == ANDAND && !top[-1].value)
+         || (op.op == '?' && !top[-1].value))
+       {
+         skip_evaluation++;
+       }
+      else if (op.op == ':')
+       {
+         if (top[-2].value) /* Was condition true? */
+           skip_evaluation++;
+         else
+           skip_evaluation--;
+       }
     }
  syntax_error:
   if (stack != init_stack)