OSDN Git Service

2004-04-30 Uros Bizjak <uros@kss-loka.si>
[pf3gnuchains/gcc-fork.git] / gcc / cppexp.c
index 3179099..6b47dd7 100644 (file)
@@ -1,5 +1,7 @@
 /* Parse C expressions for cpplib.
-   Copyright (C) 1987, 92, 94, 95, 97, 98, 1999, 2000 Free Software Foundation.
+   Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
+   2002, 2004 Free Software Foundation.
+   Contributed by Per Bothner, 1994.
 
 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
@@ -14,1092 +16,1523 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+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.  */
-
-/* Parse a C expression from text in a string  */
-   
 #include "config.h"
 #include "system.h"
 #include "cpplib.h"
 #include "cpphash.h"
 
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
-#endif
-
-#ifndef MAX_CHAR_TYPE_SIZE
-#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
-#endif
-
-#ifndef MAX_INT_TYPE_SIZE
-#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE
-#endif
-
-#ifndef MAX_LONG_TYPE_SIZE
-#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
-#endif
-
-#ifndef MAX_WCHAR_TYPE_SIZE
-#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
-#endif
-
-#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \
-                   ? (~(~(HOST_WIDEST_INT) 0 << MAX_CHAR_TYPE_SIZE)) \
-                   : ~ (HOST_WIDEST_INT) 0)
-
-#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \
-                            ? ~(~(HOST_WIDEST_INT) 0 << MAX_WCHAR_TYPE_SIZE) \
-                            : ~ (HOST_WIDEST_INT) 0)
-
-/* Yield nonzero if adding two numbers with A's and B's signs can yield a
-   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)
-
-typedef short op_t;
-
-static void integer_overflow PARAMS ((cpp_reader *));
-static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
-                                          unsigned int,
-                                          unsigned HOST_WIDEST_INT));
-static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
-                                           unsigned int,
-                                           unsigned HOST_WIDEST_INT));
-static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *,
-                                             U_CHAR *));
-static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *,
-                                                U_CHAR *));
-static struct operation parse_defined PARAMS ((cpp_reader *));
-static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **,
-                                            HOST_WIDEST_INT));
-static struct operation lex PARAMS ((cpp_reader *, int));
-static const char * op_to_str PARAMS ((op_t, char *));
-
-#define ERROR 299
-#define OROR 300
-#define ANDAND 301
-#define EQUAL 302
-#define NOTEQUAL 303
-#define LEQ 304
-#define GEQ 305
-#define LSH 306
-#define RSH 307
-#define NAME 308
-#define INT 309
-#define CHAR 310
-#define FINISHED 311
-
-struct operation
+#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
+#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
+#define LOW_PART(num_part) (num_part & HALF_MASK)
+#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
+
+struct op
 {
-  op_t op;
-  U_CHAR prio;         /* Priority of op.  */
-  U_CHAR flags;
-  U_CHAR unsignedp;    /* True if value should be treated as unsigned.  */
-  HOST_WIDEST_INT value; /* The value logically "right" of op.  */
+  const cpp_token *token;      /* The token forming op (for diagnostics).  */
+  cpp_num value;               /* The value logically "right" of op.  */
+  enum cpp_ttype op;
 };
 
-/* Parse and convert an integer for #if.  Accepts decimal, hex, or octal
-   with or without size suffixes.  */
+/* Some simple utility routines on double integers.  */
+#define num_zerop(num) ((num.low | num.high) == 0)
+#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
+static bool num_positive (cpp_num, size_t);
+static bool num_greater_eq (cpp_num, cpp_num, size_t);
+static cpp_num num_trim (cpp_num, size_t);
+static cpp_num num_part_mul (cpp_num_part, cpp_num_part);
+
+static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype);
+static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_negate (cpp_num, size_t);
+static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,
+                                 enum cpp_ttype);
+static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
+                               enum cpp_ttype);
+static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);
+static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_lshift (cpp_num, size_t, size_t);
+static cpp_num num_rshift (cpp_num, size_t, size_t);
+
+static cpp_num append_digit (cpp_num, int, int, size_t);
+static cpp_num parse_defined (cpp_reader *);
+static cpp_num eval_token (cpp_reader *, const cpp_token *);
+static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);
+static unsigned int interpret_float_suffix (const uchar *, size_t);
+static unsigned int interpret_int_suffix (const uchar *, size_t);
+static void check_promotion (cpp_reader *, const struct op *);
+
+/* Token type abuse to create unary plus and minus operators.  */
+#define CPP_UPLUS (CPP_LAST_CPP_OP + 1)
+#define CPP_UMINUS (CPP_LAST_CPP_OP + 2)
 
-static struct operation
-parse_number (pfile, start, end)
-     cpp_reader *pfile;
-     U_CHAR *start;
-     U_CHAR *end;
+/* With -O2, gcc appears to produce nice code, moving the error
+   message load and subsequent jump completely out of the main path.  */
+#define SYNTAX_ERROR(msgid) \
+  do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR2(msgid, arg) \
+  do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \
+  while(0)
+
+/* Subroutine of cpp_classify_number.  S points to a float suffix of
+   length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
+   flag vector describing the suffix.  */
+static unsigned int
+interpret_float_suffix (const uchar *s, size_t len)
 {
-  struct operation op;
-  U_CHAR *p = start;
-  int c;
-  unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base;
-  int base = 10;
-  int overflow = 0;
-  int digit, largest_digit = 0;
-  int spec_long = 0;
-
-  op.unsignedp = 0;
-
-  if (p[0] == '0')
+  size_t f = 0, l = 0, i = 0;
+
+  while (len--)
+    switch (s[len])
+      {
+      case 'f': case 'F': f++; break;
+      case 'l': case 'L': l++; break;
+      case 'i': case 'I':
+      case 'j': case 'J': i++; break;
+      default:
+       return 0;
+      }
+
+  if (f + l > 1 || i > 1)
+    return 0;
+
+  return ((i ? CPP_N_IMAGINARY : 0)
+         | (f ? CPP_N_SMALL :
+            l ? CPP_N_LARGE : CPP_N_MEDIUM));
+}
+
+/* Subroutine of cpp_classify_number.  S points to an integer suffix
+   of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
+   flag vector describing the suffix.  */
+static unsigned int
+interpret_int_suffix (const uchar *s, size_t len)
+{
+  size_t u, l, i;
+
+  u = l = i = 0;
+
+  while (len--)
+    switch (s[len])
+      {
+      case 'u': case 'U':      u++; break;
+      case 'i': case 'I':
+      case 'j': case 'J':      i++; break;
+      case 'l': case 'L':      l++;
+       /* If there are two Ls, they must be adjacent and the same case.  */
+       if (l == 2 && s[len] != s[len + 1])
+         return 0;
+       break;
+      default:
+       return 0;
+      }
+
+  if (l > 2 || u > 1 || i > 1)
+    return 0;
+
+  return ((i ? CPP_N_IMAGINARY : 0)
+         | (u ? CPP_N_UNSIGNED : 0)
+         | ((l == 0) ? CPP_N_SMALL
+            : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
+}
+
+/* Categorize numeric constants according to their field (integer,
+   floating point, or invalid), radix (decimal, octal, hexadecimal),
+   and type suffixes.  */
+unsigned int
+cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
+{
+  const uchar *str = token->val.str.text;
+  const uchar *limit;
+  unsigned int max_digit, result, radix;
+  enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
+
+  /* If the lexer has done its job, length one can only be a single
+     digit.  Fast-path this very common case.  */
+  if (token->val.str.len == 1)
+    return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
+
+  limit = str + token->val.str.len;
+  float_flag = NOT_FLOAT;
+  max_digit = 0;
+  radix = 10;
+
+  /* First, interpret the radix.  */
+  if (*str == '0')
     {
-      if (end - start >= 3 && (p[1] == 'x' || p[1] == 'X'))
-       {
-         p += 2;
-         base = 16;
-       }
-      else
+      radix = 8;
+      str++;
+
+      /* Require at least one hex digit to classify it as hex.  */
+      if ((*str == 'x' || *str == 'X')
+         && (str[1] == '.' || ISXDIGIT (str[1])))
        {
-         p += 1;
-         base = 8;
+         radix = 16;
+         str++;
        }
     }
 
-  /* Some buggy compilers (e.g. MPW C) seem to need both casts.  */
-  MAX_over_base = (((unsigned HOST_WIDEST_INT) -1)
-                  / ((unsigned HOST_WIDEST_INT) base));
-
-  while (p < end)
+  /* Now scan for a well-formed integer or float.  */
+  for (;;)
     {
-      c = *p++;
-
-      if (c >= '0' && c <= '9')
-       digit = c - '0';
-      /* FIXME: assumes ASCII */
-      else if (base == 16 && c >= 'a' && c <= 'f')
-       digit = c - 'a' + 10;
-      else if (base == 16 && c >= 'A' && c <= 'F')
-       digit = c - 'A' + 10;
+      unsigned int c = *str++;
+
+      if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
+       {
+         c = hex_value (c);
+         if (c > max_digit)
+           max_digit = c;
+       }
       else if (c == '.')
        {
-         /* It's a float since it contains a point.  */
-         cpp_error (pfile,
-            "floating point numbers are not allowed in #if expressions");
-         goto error;
+         if (float_flag == NOT_FLOAT)
+           float_flag = AFTER_POINT;
+         else
+           SYNTAX_ERROR ("too many decimal points in number");
+       }
+      else if ((radix <= 10 && (c == 'e' || c == 'E'))
+              || (radix == 16 && (c == 'p' || c == 'P')))
+       {
+         float_flag = AFTER_EXPON;
+         break;
        }
       else
        {
-         /* `l' means long, and `u' means unsigned.  */
-         for (;;)
-           {
-             if (c == 'l' || c == 'L')
-                 spec_long++;
-             else if (c == 'u' || c == 'U')
-                 op.unsignedp++;
-             else
-               {
-                 /* Decrement p here so that the error for an invalid
-                    number will be generated below in the case where
-                    this is the last character in the buffer.  */
-                 p--;
-                 break;
-               }
-             if (p == end)
-               break;
-             c = *p++;
-           }
-         /* Don't look for any more digits after the suffixes.  */
+         /* Start of suffix.  */
+         str--;
          break;
        }
-      
-      if (largest_digit < digit)
-       largest_digit = digit;
-      nd = n * base + digit;
-      overflow |= MAX_over_base < n || nd < n;
-      n = nd;
     }
 
-  if (p != end)
-    {
-      cpp_error (pfile, "invalid number in #if expression");
-      goto error;
-    }
-  else if (spec_long > (CPP_OPTION (pfile, c89) ? 1 : 2))
+  if (float_flag != NOT_FLOAT && radix == 8)
+    radix = 10;
+
+  if (max_digit >= radix)
+    SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
+
+  if (float_flag != NOT_FLOAT)
     {
-      cpp_error (pfile, "too many 'l' suffixes in integer constant");
-      goto error;
+      if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "use of C99 hexadecimal floating constant");
+
+      if (float_flag == AFTER_EXPON)
+       {
+         if (*str == '+' || *str == '-')
+           str++;
+
+         /* Exponent is decimal, even if string is a hex float.  */
+         if (!ISDIGIT (*str))
+           SYNTAX_ERROR ("exponent has no digits");
+
+         do
+           str++;
+         while (ISDIGIT (*str));
+       }
+      else if (radix == 16)
+       SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
+
+      result = interpret_float_suffix (str, limit - str);
+      if (result == 0)
+       {
+         cpp_error (pfile, CPP_DL_ERROR,
+                    "invalid suffix \"%.*s\" on floating constant",
+                    (int) (limit - str), str);
+         return CPP_N_INVALID;
+       }
+
+      /* Traditional C didn't accept any floating suffixes.  */
+      if (limit != str
+         && CPP_WTRADITIONAL (pfile)
+         && ! cpp_sys_macro_p (pfile))
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "traditional C rejects the \"%.*s\" suffix",
+                  (int) (limit - str), str);
+
+      result |= CPP_N_FLOATING;
     }
-  else if (op.unsignedp > 1)
+  else
     {
-      cpp_error (pfile, "too many 'u' suffixes in integer constant");
-      goto error;
-    }
-  
-  if (base <= largest_digit)
-    cpp_pedwarn (pfile,
-                "integer constant contains digits beyond the radix");
+      result = interpret_int_suffix (str, limit - str);
+      if (result == 0)
+       {
+         cpp_error (pfile, CPP_DL_ERROR,
+                    "invalid suffix \"%.*s\" on integer constant",
+                    (int) (limit - str), str);
+         return CPP_N_INVALID;
+       }
 
-  if (overflow)
-    cpp_pedwarn (pfile, "integer constant out of range");
+      /* Traditional C only accepted the 'L' suffix.
+         Suppress warning about 'LL' with -Wno-long-long.  */
+      if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
+       {
+         int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
+         int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
 
-  /* If too big to be signed, consider it unsigned.  */
-  else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp)
-    {
-      if (base == 10)
-       cpp_warning (pfile,
-                    "integer constant is so large that it is unsigned");
-      op.unsignedp = 1;
+         if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
+           cpp_error (pfile, CPP_DL_WARNING,
+                      "traditional C rejects the \"%.*s\" suffix",
+                      (int) (limit - str), str);
+       }
+
+      if ((result & CPP_N_WIDTH) == CPP_N_LARGE
+         && ! CPP_OPTION (pfile, c99)
+         && CPP_OPTION (pfile, warn_long_long))
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "use of C99 long long integer constant");
+
+      result |= CPP_N_INTEGER;
     }
 
-  op.value = n;
-  op.op = INT;
-  return op;
+  if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
+    cpp_error (pfile, CPP_DL_PEDWARN,
+              "imaginary constants are a GCC extension");
+
+  if (radix == 10)
+    result |= CPP_N_DECIMAL;
+  else if (radix == 16)
+    result |= CPP_N_HEX;
+  else
+    result |= CPP_N_OCTAL;
 
- error:
-  op.op = ERROR;
-  return op;
+  return result;
+
+ syntax_error:
+  return CPP_N_INVALID;
 }
 
-/* Parse and convert a character constant for #if.  Understands backslash
-   escapes (\n, \031) and multibyte characters (if so configured).  */
-static struct operation
-parse_charconst (pfile, start, end)
-     cpp_reader *pfile;
-     U_CHAR *start;
-     U_CHAR *end;
+/* cpp_interpret_integer converts an integer constant into a cpp_num,
+   of precision options->precision.
+
+   We do not provide any interface for decimal->float conversion,
+   because the preprocessor doesn't need it and we don't want to
+   drag in GCC's floating point emulator.  */
+cpp_num
+cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
+                      unsigned int type)
 {
-  struct operation op;
-  HOST_WIDEST_INT result = 0;
-  int num_chars = 0;
-  int num_bits;
-  unsigned int width = MAX_CHAR_TYPE_SIZE, mask = MAX_CHAR_TYPE_MASK;
-  int max_chars;
-  U_CHAR *ptr = start;
+  const uchar *p, *end;
+  cpp_num result;
 
-  int c = -1;
+  result.low = 0;
+  result.high = 0;
+  result.unsignedp = !!(type & CPP_N_UNSIGNED);
+  result.overflow = false;
 
-  if (*ptr == 'L')
-    {
-      ++ptr;
-      width = MAX_WCHAR_TYPE_SIZE, mask = MAX_WCHAR_TYPE_MASK;
-    }
-  max_chars = MAX_LONG_TYPE_SIZE / width;
-
-  ++ptr;  /* skip initial quote */
+  p = token->val.str.text;
+  end = p + token->val.str.len;
 
-  while (ptr < end)
+  /* Common case of a single digit.  */
+  if (token->val.str.len == 1)
+    result.low = p[0] - '0';
+  else
     {
-      c = *ptr++;
-      if (c == '\'')
-       break;
-      else if (c == '\\')
+      cpp_num_part max;
+      size_t precision = CPP_OPTION (pfile, precision);
+      unsigned int base = 10, c = 0;
+      bool overflow = false;
+
+      if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
        {
-         c = parse_escape (pfile, &ptr, mask);
-         if (width < HOST_BITS_PER_INT
-             && (unsigned int) c >= (unsigned int)(1 << width))
-           cpp_pedwarn (pfile,
-                        "escape sequence out of range for character");
+         base = 8;
+         p++;
        }
-         
-      /* Merge character into result; ignore excess chars.  */
-      if (++num_chars <= max_chars)
+      else if ((type & CPP_N_RADIX) == CPP_N_HEX)
        {
-         if (width < HOST_BITS_PER_INT)
-           result = (result << width) | (c & ((1 << width) - 1));
+         base = 16;
+         p += 2;
+       }
+
+      /* We can add a digit to numbers strictly less than this without
+        needing the precision and slowness of double integers.  */
+      max = ~(cpp_num_part) 0;
+      if (precision < PART_PRECISION)
+       max >>= PART_PRECISION - precision;
+      max = (max - base + 1) / base + 1;
+
+      for (; p < end; p++)
+       {
+         c = *p;
+
+         if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
+           c = hex_value (c);
          else
-           result = c;
+           break;
+
+         /* Strict inequality for when max is set to zero.  */
+         if (result.low < max)
+           result.low = result.low * base + c;
+         else
+           {
+             result = append_digit (result, c, base, precision);
+             overflow |= result.overflow;
+             max = 0;
+           }
+       }
+
+      if (overflow)
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "integer constant is too large for its type");
+      /* If too big to be signed, consider it unsigned.  Only warn for
+        decimal numbers.  Traditional numbers were always signed (but
+        we still honor an explicit U suffix); but we only have
+        traditional semantics in directives.  */
+      else if (!result.unsignedp
+              && !(CPP_OPTION (pfile, traditional)
+                   && pfile->state.in_directive)
+              && !num_positive (result, precision))
+       {
+         if (base == 10)
+           cpp_error (pfile, CPP_DL_WARNING,
+                      "integer constant is so large that it is unsigned");
+         result.unsignedp = true;
        }
     }
 
-  if (num_chars == 0)
+  return result;
+}
+
+/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE.  */
+static cpp_num
+append_digit (cpp_num num, int digit, int base, size_t precision)
+{
+  cpp_num result;
+  unsigned int shift = 3 + (base == 16);
+  bool overflow;
+  cpp_num_part add_high, add_low;
+
+  /* Multiply by 8 or 16.  Catching this overflow here means we don't
+     need to worry about add_high overflowing.  */
+  overflow = !!(num.high >> (PART_PRECISION - shift));
+  result.high = num.high << shift;
+  result.low = num.low << shift;
+  result.high |= num.low >> (PART_PRECISION - shift);
+
+  if (base == 10)
     {
-      cpp_error (pfile, "empty character constant");
-      goto error;
+      add_low = num.low << 1;
+      add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
     }
-  else if (c != '\'')
+  else
+    add_high = add_low = 0;
+
+  if (add_low + digit < add_low)
+    add_high++;
+  add_low += digit;
+    
+  if (result.low + add_low < result.low)
+    add_high++;
+  if (result.high + add_high < result.high)
+    overflow = true;
+
+  result.low += add_low;
+  result.high += add_high;
+
+  /* The above code catches overflow of a cpp_num type.  This catches
+     overflow of the (possibly shorter) target precision.  */
+  num.low = result.low;
+  num.high = result.high;
+  result = num_trim (result, precision);
+  if (!num_eq (result, num))
+    overflow = true;
+
+  result.unsignedp = num.unsignedp;
+  result.overflow = overflow;
+  return result;
+}
+
+/* Handle meeting "defined" in a preprocessor expression.  */
+static cpp_num
+parse_defined (cpp_reader *pfile)
+{
+  cpp_num result;
+  int paren = 0;
+  cpp_hashnode *node = 0;
+  const cpp_token *token;
+  cpp_context *initial_context = pfile->context;
+
+  /* Don't expand macros.  */
+  pfile->state.prevent_expansion++;
+
+  token = cpp_get_token (pfile);
+  if (token->type == CPP_OPEN_PAREN)
     {
-      /* cpp_get_token has already emitted an error if !traditional. */
-      if (! CPP_TRADITIONAL (pfile))
-       cpp_error (pfile, "malformatted character constant");
-      goto error;
+      paren = 1;
+      token = cpp_get_token (pfile);
     }
-  else if (num_chars > max_chars)
+
+  if (token->type == CPP_NAME)
     {
-      cpp_error (pfile, "character constant too long");
-      goto error;
+      node = token->val.node;
+      if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
+       {
+         cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
+         node = 0;
+       }
     }
-  else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile))
-    cpp_warning (pfile, "multi-character character constant");
-
-  /* If char type is signed, sign-extend the constant.  */
-  num_bits = num_chars * width;
-      
-  if (cpp_defined (pfile, (const U_CHAR *)"__CHAR_UNSIGNED__",
-                  sizeof ("__CHAR_UNSIGNED__")-1)
-      || ((result >> (num_bits - 1)) & 1) == 0)
-    op.value = result & ((unsigned HOST_WIDEST_INT) ~0
-                        >> (HOST_BITS_PER_WIDEST_INT - num_bits));
   else
-    op.value = result | ~((unsigned HOST_WIDEST_INT) ~0
-                         >> (HOST_BITS_PER_WIDEST_INT - num_bits));
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+                "operator \"defined\" requires an identifier");
+      if (token->flags & NAMED_OP)
+       {
+         cpp_token op;
+
+         op.flags = 0;
+         op.type = token->type;
+         cpp_error (pfile, CPP_DL_ERROR,
+                    "(\"%s\" is an alternative token for \"%s\" in C++)",
+                    cpp_token_as_text (pfile, token),
+                    cpp_token_as_text (pfile, &op));
+       }
+    }
+
+  if (node)
+    {
+      if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "this use of \"defined\" may not be portable");
+
+      _cpp_mark_macro_used (node);
+
+      /* A possible controlling macro of the form #if !defined ().
+        _cpp_parse_expr checks there was no other junk on the line.  */
+      pfile->mi_ind_cmacro = node;
+    }
 
-  /* This is always a signed type.  */
-  op.unsignedp = 0;
-  op.op = CHAR;
-  return op;
+  pfile->state.prevent_expansion--;
 
- error:
-  op.op = ERROR;
-  return op;
+  result.unsignedp = false;
+  result.high = 0;
+  result.overflow = false;
+  result.low = node && node->type == NT_MACRO;
+  return result;
 }
 
-static struct operation
-parse_defined (pfile)
-     cpp_reader *pfile;
+/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
+   number or character constant, or the result of the "defined" or "#"
+   operators).  */
+static cpp_num
+eval_token (cpp_reader *pfile, const cpp_token *token)
 {
-  int paren = 0, len;
-  U_CHAR *tok;
-  enum cpp_token token;
-  struct operation op;
-  long old_written = CPP_WRITTEN (pfile);
-
-  op.unsignedp = 0;
-  op.op = INT;
-
-  pfile->no_macro_expand++;
-  token = _cpp_get_directive_token (pfile);
-  if (token == CPP_LPAREN)
+  cpp_num result;
+  unsigned int temp;
+  int unsignedp = 0;
+
+  switch (token->type)
     {
-      paren++;
-      CPP_SET_WRITTEN (pfile, old_written);
-      token = _cpp_get_directive_token (pfile);
-    }
+    case CPP_NUMBER:
+      temp = cpp_classify_number (pfile, token);
+      switch (temp & CPP_N_CATEGORY)
+       {
+       case CPP_N_FLOATING:
+         cpp_error (pfile, CPP_DL_ERROR,
+                    "floating constant in preprocessor expression");
+         break;
+       case CPP_N_INTEGER:
+         if (!(temp & CPP_N_IMAGINARY))
+           return cpp_interpret_integer (pfile, token, temp);
+         cpp_error (pfile, CPP_DL_ERROR,
+                    "imaginary number in preprocessor expression");
+         break;
 
-  if (token != CPP_NAME)
-    goto oops;
+       case CPP_N_INVALID:
+         /* Error already issued.  */
+         break;
+       }
+      result.high = result.low = 0;
+      break;
 
-  tok = pfile->token_buffer + old_written;
-  len = CPP_PWRITTEN (pfile) - tok;
-  op.value = cpp_defined (pfile, tok, len);
+    case CPP_WCHAR:
+    case CPP_CHAR:
+      {
+       cppchar_t cc = cpp_interpret_charconst (pfile, token,
+                                               &temp, &unsignedp);
 
-  if (paren)
-    {
-      if (_cpp_get_directive_token (pfile) != CPP_RPAREN)
-       goto oops;
-    }
-  CPP_SET_WRITTEN (pfile, old_written);
-  pfile->no_macro_expand--;
-  return op;
+       result.high = 0;
+       result.low = cc;
+       /* Sign-extend the result if necessary.  */
+       if (!unsignedp && (cppchar_signed_t) cc < 0)
+         {
+           if (PART_PRECISION > BITS_PER_CPPCHAR_T)
+             result.low |= ~(~(cpp_num_part) 0
+                             >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
+           result.high = ~(cpp_num_part) 0;
+           result = num_trim (result, CPP_OPTION (pfile, precision));
+         }
+      }
+      break;
+
+    case CPP_NAME:
+      if (token->val.node == pfile->spec_nodes.n_defined)
+       return parse_defined (pfile);
+      else if (CPP_OPTION (pfile, cplusplus)
+              && (token->val.node == pfile->spec_nodes.n_true
+                  || token->val.node == pfile->spec_nodes.n_false))
+       {
+         result.high = 0;
+         result.low = (token->val.node == pfile->spec_nodes.n_true);
+       }
+      else
+       {
+         result.high = 0;
+         result.low = 0;
+         if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
+           cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
+                      NODE_NAME (token->val.node));
+       }
+      break;
 
- oops:
-  CPP_SET_WRITTEN (pfile, old_written);
-  pfile->no_macro_expand--;
-  cpp_error (pfile, "'defined' without an identifier");
+    default: /* CPP_HASH */
+      _cpp_test_assertion (pfile, &temp);
+      result.high = 0;
+      result.low = temp;
+    }
 
-  op.op = ERROR;
-  return op;
+  result.unsignedp = !!unsignedp;
+  result.overflow = false;
+  return result;
 }
+\f
+/* Operator precedence and flags table.
 
-struct token
+After an operator is returned from the lexer, if it has priority less
+than the operator on the top of the stack, we reduce the stack by one
+operator and repeat the test.  Since equal priorities do not reduce,
+this is naturally right-associative.
+
+We handle left-associative operators by decrementing the priority of
+just-lexed operators by one, but retaining the priority of operators
+already on the stack.
+
+The remaining cases are '(' and ')'.  We handle '(' by skipping the
+reduction phase completely.  ')' is given lower priority than
+everything else, including '(', effectively forcing a reduction of the
+parenthesized expression.  If there is a matching '(', the routine
+reduce() exits immediately.  If the normal exit route sees a ')', then
+there cannot have been a matching '(' and an error message is output.
+
+The parser assumes all shifted operators require a left operand unless
+the flag NO_L_OPERAND is set.  These semantics are automatic; any
+extra semantics need to be handled with operator-specific code.  */
+
+/* Flags.  If CHECK_PROMOTION, we warn if the effective sign of an
+   operand changes because of integer promotions.  */
+#define NO_L_OPERAND   (1 << 0)
+#define LEFT_ASSOC     (1 << 1)
+#define CHECK_PROMOTION        (1 << 2)
+
+/* Operator to priority map.  Must be in the same order as the first
+   N entries of enum cpp_ttype.  */
+static const struct operator
 {
-  const char *operator;
-  op_t token;
+  uchar prio;
+  uchar flags;
+} optab[] =
+{
+  /* EQ */             {0, 0}, /* Shouldn't happen.  */
+  /* NOT */            {16, NO_L_OPERAND},
+  /* GREATER */                {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* LESS */           {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* PLUS */           {14, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MINUS */          {14, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MULT */           {15, LEFT_ASSOC | CHECK_PROMOTION},
+  /* DIV */            {15, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MOD */            {15, LEFT_ASSOC | CHECK_PROMOTION},
+  /* AND */            {9, LEFT_ASSOC | CHECK_PROMOTION},
+  /* OR */             {7, LEFT_ASSOC | CHECK_PROMOTION},
+  /* XOR */            {8, LEFT_ASSOC | CHECK_PROMOTION},
+  /* RSHIFT */         {13, LEFT_ASSOC},
+  /* LSHIFT */         {13, LEFT_ASSOC},
+
+  /* MIN */            {10, LEFT_ASSOC | CHECK_PROMOTION},
+  /* MAX */            {10, LEFT_ASSOC | CHECK_PROMOTION},
+
+  /* COMPL */          {16, NO_L_OPERAND},
+  /* AND_AND */                {6, LEFT_ASSOC},
+  /* OR_OR */          {5, LEFT_ASSOC},
+  /* QUERY */          {3, 0},
+  /* COLON */          {4, LEFT_ASSOC | CHECK_PROMOTION},
+  /* COMMA */          {2, LEFT_ASSOC},
+  /* OPEN_PAREN */     {1, NO_L_OPERAND},
+  /* CLOSE_PAREN */    {0, 0},
+  /* EOF */            {0, 0},
+  /* EQ_EQ */          {11, LEFT_ASSOC},
+  /* NOT_EQ */         {11, LEFT_ASSOC},
+  /* GREATER_EQ */     {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* LESS_EQ */                {12, LEFT_ASSOC | CHECK_PROMOTION},
+  /* UPLUS */          {16, NO_L_OPERAND},
+  /* UMINUS */         {16, NO_L_OPERAND}
 };
 
-static const struct token tokentab2[] =
+/* Parse and evaluate a C expression, reading from PFILE.
+   Returns the truth value of the expression.
+
+   The implementation is an operator precedence parser, i.e. a
+   bottom-up parser, using a stack for not-yet-reduced tokens.
+
+   The stack base is op_stack, and the current stack pointer is 'top'.
+   There is a stack element for each operator (only), and the most
+   recently pushed operator is 'top->op'.  An operand (value) is
+   stored in the 'value' field of the stack element of the operator
+   that precedes it.  */
+bool
+_cpp_parse_expr (cpp_reader *pfile)
 {
-  {"&&", ANDAND},
-  {"||", OROR},
-  {"<<", LSH},
-  {">>", RSH},
-  {"==", EQUAL},
-  {"!=", NOTEQUAL},
-  {"<=", LEQ},
-  {">=", GEQ},
-  {"++", ERROR},
-  {"--", ERROR},
-  {NULL, ERROR}
-};
+  struct op *top = pfile->op_stack;
+  unsigned int lex_count;
+  bool saw_leading_not, want_value = true;
 
-/* Read one token.  */
+  pfile->state.skip_eval = 0;
 
-static struct operation
-lex (pfile, skip_evaluation)
-     cpp_reader *pfile;
-     int skip_evaluation;
-{
-  const struct token *toktab;
-  enum cpp_token token;
-  struct operation op;
-  U_CHAR *tok_start, *tok_end;
-  long old_written;
-
-  old_written = CPP_WRITTEN (pfile);
-  token = _cpp_get_directive_token (pfile);
-
-  tok_start = pfile->token_buffer + old_written;
-  tok_end = CPP_PWRITTEN (pfile);
-  CPP_SET_WRITTEN (pfile, old_written);
-  switch (token)
+  /* Set up detection of #if ! defined().  */
+  pfile->mi_ind_cmacro = 0;
+  saw_leading_not = false;
+  lex_count = 0;
+
+  /* Lowest priority operator prevents further reductions.  */
+  top->op = CPP_EOF;
+
+  for (;;)
     {
-    case CPP_EOF: /* Should not happen ...  */
-    case CPP_VSPACE:
-      op.op = 0;
-      return op;
-    case CPP_NUMBER:
-      return parse_number (pfile, tok_start, tok_end);
-    case CPP_STRING:
-    case CPP_WSTRING:
-      cpp_error (pfile,
-                "string constants are not allowed in #if expressions");
-      op.op = ERROR;
-      return op;
+      struct op op;
 
-    case CPP_CHAR:
-    case CPP_WCHAR:
-      return parse_charconst (pfile, tok_start, tok_end);
+      lex_count++;
+      op.token = cpp_get_token (pfile);
+      op.op = op.token->type;
 
-    case CPP_NAME:
-      if (!strcmp (tok_start, "defined"))
-       return parse_defined (pfile);
+      switch (op.op)
+       {
+         /* These tokens convert into values.  */
+       case CPP_NUMBER:
+       case CPP_CHAR:
+       case CPP_WCHAR:
+       case CPP_NAME:
+       case CPP_HASH:
+         if (!want_value)
+           SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
+                          cpp_token_as_text (pfile, op.token));
+         want_value = false;
+         top->value = eval_token (pfile, op.token);
+         continue;
+
+       case CPP_NOT:
+         saw_leading_not = lex_count == 1;
+         break;
+       case CPP_PLUS:
+         if (want_value)
+           op.op = CPP_UPLUS;
+         break;
+       case CPP_MINUS:
+         if (want_value)
+           op.op = CPP_UMINUS;
+         break;
 
-      op.op = INT;
-      op.unsignedp = 0;
-      op.value = 0;
-
-      if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
-       cpp_warning (pfile, "'%.*s' is not defined",
-                    (int) (tok_end - tok_start), tok_start);
-      return op;
-
-    case CPP_ASSERTION:
-      op.op = INT;
-      op.unsignedp = 0;
-      op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
-      return op;
-
-    case CPP_OTHER:
-      /* See if it is a special token of length 2.  */
-      if (tok_start + 2 == tok_end)
-        {
-         for (toktab = tokentab2; toktab->operator != NULL; toktab++)
-           if (tok_start[0] == toktab->operator[0]
-               && tok_start[1] == toktab->operator[1])
-               break;
-         if (toktab->token == ERROR)
-           cpp_error (pfile, "'%s' not allowed in operand of #if",
-                      tok_start);
-         op.op = toktab->token; 
-         return op;
+       default:
+         if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
+           SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
+                          cpp_token_as_text (pfile, op.token));
+         break;
        }
-      /* fall through */
-    default:
-      op.op = *tok_start;
-      return op;
-  }
+
+      /* Check we have a value or operator as appropriate.  */
+      if (optab[op.op].flags & NO_L_OPERAND)
+       {
+         if (!want_value)
+           SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
+                          cpp_token_as_text (pfile, op.token));
+       }
+      else if (want_value)
+       {
+         /* Ordering here is subtle and intended to favor the
+            missing parenthesis diagnostics over alternatives.  */
+         if (op.op == CPP_CLOSE_PAREN)
+           {
+             if (top->op == CPP_OPEN_PAREN)
+               SYNTAX_ERROR ("void expression between '(' and ')'");
+           }
+         else if (top->op == CPP_EOF)
+           SYNTAX_ERROR ("#if with no expression");
+         if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
+           SYNTAX_ERROR2 ("operator '%s' has no right operand",
+                          cpp_token_as_text (pfile, top->token));
+       }
+
+      top = reduce (pfile, top, op.op);
+      if (!top)
+       goto syntax_error;
+
+      if (op.op == CPP_EOF)
+       break;
+
+      switch (op.op)
+       {
+       case CPP_CLOSE_PAREN:
+         continue;
+       case CPP_OR_OR:
+         if (!num_zerop (top->value))
+           pfile->state.skip_eval++;
+         break;
+       case CPP_AND_AND:
+       case CPP_QUERY:
+         if (num_zerop (top->value))
+           pfile->state.skip_eval++;
+         break;
+       case CPP_COLON:
+         if (top->op != CPP_QUERY)
+           SYNTAX_ERROR (" ':' without preceding '?'");
+         if (!num_zerop (top[-1].value)) /* Was '?' condition true?  */
+           pfile->state.skip_eval++;
+         else
+           pfile->state.skip_eval--;
+       default:
+         break;
+       }
+
+      want_value = true;
+
+      /* Check for and handle stack overflow.  */
+      if (++top == pfile->op_limit)
+       top = _cpp_expand_op_stack (pfile);
+
+      top->op = op.op;
+      top->token = op.token;
+    }
+
+  /* The controlling macro expression is only valid if we called lex 3
+     times: <!> <defined expression> and <EOF>.  push_conditional ()
+     checks that we are at top-of-file.  */
+  if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
+    pfile->mi_ind_cmacro = 0;
+
+  if (top != pfile->op_stack)
+    {
+      cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in #if");
+    syntax_error:
+      return false;  /* Return false on syntax error.  */
+    }
+
+  return !num_zerop (top->value);
 }
 
-/* Convert an operator ID to a string.  BUFF is a buffer at least 5
-   characters long which might be used to store the string.  */
-/* XXX FIXME: Remove BUFF when new lexer is implemented.  */
-static const char *
-op_to_str (op, buff)
-     op_t op;
-     char *buff;
+/* Reduce the operator / value stack if possible, in preparation for
+   pushing operator OP.  Returns NULL on error, otherwise the top of
+   the stack.  */
+static struct op *
+reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op)
 {
-  const struct token *toktab;
+  unsigned int prio;
 
-  /* See if it is a special token of length 2.  */
-  for (toktab = tokentab2; toktab->operator != NULL; toktab++)
-    if (op == toktab->token)
-      return toktab->operator;
+  if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
+    {
+    bad_op:
+      cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op);
+      return 0;
+    }
 
-  if (ISGRAPH (op))
-    sprintf (buff, "%c", (int) op);
-  else
-    sprintf (buff, "\\%03o", (int) op);
-  return buff;
-}
+  if (op == CPP_OPEN_PAREN)
+    return top;
 
-/* Parse a C escape sequence.  STRING_PTR points to a variable
-   containing a pointer to the string to parse.  That pointer
-   is updated past the characters we use.  The value of the
-   escape sequence is returned.
+  /* Decrement the priority of left-associative operators to force a
+     reduction with operators of otherwise equal priority.  */
+  prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
+  while (prio < optab[top->op].prio)
+    {
+      if (CPP_OPTION (pfile, warn_num_sign_change)
+         && optab[top->op].flags & CHECK_PROMOTION)
+       check_promotion (pfile, top);
 
-   A negative value means the sequence \ newline was seen,
-   which is supposed to be equivalent to nothing at all.
+      switch (top->op)
+       {
+       case CPP_UPLUS:
+       case CPP_UMINUS:
+       case CPP_NOT:
+       case CPP_COMPL:
+         top[-1].value = num_unary_op (pfile, top->value, top->op);
+         break;
 
-   If \ is followed by a null character, we return a negative
-   value and leave the string pointer pointing at the null character.
+       case CPP_PLUS:
+       case CPP_MINUS:
+       case CPP_RSHIFT:
+       case CPP_LSHIFT:
+       case CPP_MIN:
+       case CPP_MAX:
+       case CPP_COMMA:
+         top[-1].value = num_binary_op (pfile, top[-1].value,
+                                        top->value, top->op);
+         break;
 
-   If \ is followed by 000, we return 0 and leave the string pointer
-   after the zeros.  A value of 0 does not mean end of string.  */
+       case CPP_GREATER:
+       case CPP_LESS:
+       case CPP_GREATER_EQ:
+       case CPP_LESS_EQ:
+         top[-1].value
+           = num_inequality_op (pfile, top[-1].value, top->value, top->op);
+         break;
 
-static HOST_WIDEST_INT
-parse_escape (pfile, string_ptr, result_mask)
-     cpp_reader *pfile;
-     U_CHAR **string_ptr;
-     HOST_WIDEST_INT result_mask;
-{
-  register int c = *(*string_ptr)++;
-  switch (c)
+       case CPP_EQ_EQ:
+       case CPP_NOT_EQ:
+         top[-1].value
+           = num_equality_op (pfile, top[-1].value, top->value, top->op);
+         break;
+
+       case CPP_AND:
+       case CPP_OR:
+       case CPP_XOR:
+         top[-1].value
+           = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
+         break;
+
+       case CPP_MULT:
+         top[-1].value = num_mul (pfile, top[-1].value, top->value);
+         break;
+
+       case CPP_DIV:
+       case CPP_MOD:
+         top[-1].value = num_div_op (pfile, top[-1].value,
+                                     top->value, top->op);
+         break;
+
+       case CPP_OR_OR:
+         top--;
+         if (!num_zerop (top->value))
+           pfile->state.skip_eval--;
+         top->value.low = (!num_zerop (top->value)
+                           || !num_zerop (top[1].value));
+         top->value.high = 0;
+         top->value.unsignedp = false;
+         top->value.overflow = false;
+         continue;
+
+       case CPP_AND_AND:
+         top--;
+         if (num_zerop (top->value))
+           pfile->state.skip_eval--;
+         top->value.low = (!num_zerop (top->value)
+                           && !num_zerop (top[1].value));
+         top->value.high = 0;
+         top->value.unsignedp = false;
+         top->value.overflow = false;
+         continue;
+
+       case CPP_OPEN_PAREN:
+         if (op != CPP_CLOSE_PAREN)
+           {
+             cpp_error (pfile, CPP_DL_ERROR, "missing ')' in expression");
+             return 0;
+           }
+         top--;
+         top->value = top[1].value;
+         return top;
+
+       case CPP_COLON:
+         top -= 2;
+         if (!num_zerop (top->value))
+           {
+             pfile->state.skip_eval--;
+             top->value = top[1].value;
+           }
+         else
+           top->value = top[2].value;
+         top->value.unsignedp = (top[1].value.unsignedp
+                                 || top[2].value.unsignedp);
+         continue;
+
+       case CPP_QUERY:
+         cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
+         return 0;
+
+       default:
+         goto bad_op;
+       }
+
+      top--;
+      if (top->value.overflow && !pfile->state.skip_eval)
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "integer overflow in preprocessor expression");
+    }
+
+  if (op == CPP_CLOSE_PAREN)
     {
-    case 'a':
-      return TARGET_BELL;
-    case 'b':
-      return TARGET_BS;
-    case 'e':
-    case 'E':
-      if (CPP_PEDANTIC (pfile))
-       cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, '\\%c'", c);
-      return TARGET_ESC;
-    case 'f':
-      return TARGET_FF;
-    case 'n':
-      return TARGET_NEWLINE;
-    case 'r':
-      return TARGET_CR;
-    case 't':
-      return TARGET_TAB;
-    case 'v':
-      return TARGET_VT;
-    case '\n':
-      return -2;
-    case 0:
-      (*string_ptr)--;
+      cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
       return 0;
-      
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-      {
-       register HOST_WIDEST_INT i = c - '0';
-       register int count = 0;
-       while (++count < 3)
-         {
-           c = *(*string_ptr)++;
-           if (c >= '0' && c <= '7')
-             i = (i << 3) + c - '0';
-           else
-             {
-               (*string_ptr)--;
-               break;
-             }
-         }
-       if (i != (i & result_mask))
-         {
-           i &= result_mask;
-           cpp_pedwarn (pfile, "octal escape sequence out of range");
-         }
-       return i;
-      }
-    case 'x':
-      {
-       register unsigned HOST_WIDEST_INT i = 0, overflow = 0;
-       register int digits_found = 0, digit;
-       for (;;)
-         {
-           c = *(*string_ptr)++;
-           if (c >= '0' && c <= '9')
-             digit = c - '0';
-           else if (c >= 'a' && c <= 'f')
-             digit = c - 'a' + 10;
-           else if (c >= 'A' && c <= 'F')
-             digit = c - 'A' + 10;
-           else
-             {
-               (*string_ptr)--;
-               break;
-             }
-           overflow |= i ^ (i << 4 >> 4);
-           i = (i << 4) + digit;
-           digits_found = 1;
-         }
-       if (!digits_found)
-         cpp_error (pfile, "\\x used with no following hex digits");
-       if (overflow | (i != (i & result_mask)))
-         {
-           i &= result_mask;
-           cpp_pedwarn (pfile, "hex escape sequence out of range");
-         }
-       return i;
-      }
-    default:
-      return c;
     }
+
+  return top;
+}
+
+/* Returns the position of the old top of stack after expansion.  */
+struct op *
+_cpp_expand_op_stack (cpp_reader *pfile)
+{
+  size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
+  size_t new_size = old_size * 2 + 20;
+
+  pfile->op_stack = xrealloc (pfile->op_stack, new_size * sizeof (struct op));
+  pfile->op_limit = pfile->op_stack + new_size;
+
+  return pfile->op_stack + old_size;
 }
 
+/* Emits a warning if the effective sign of either operand of OP
+   changes because of integer promotions.  */
 static void
-integer_overflow (pfile)
-     cpp_reader *pfile;
+check_promotion (cpp_reader *pfile, const struct op *op)
 {
-  if (CPP_PEDANTIC (pfile))
-    cpp_pedwarn (pfile, "integer overflow in preprocessor expression");
+  if (op->value.unsignedp == op[-1].value.unsignedp)
+    return;
+
+  if (op->value.unsignedp)
+    {
+      if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "the left operand of \"%s\" changes sign when promoted",
+                  cpp_token_as_text (pfile, op->token));
+    }
+  else if (!num_positive (op->value, CPP_OPTION (pfile, precision)))
+    cpp_error (pfile, CPP_DL_WARNING,
+              "the right operand of \"%s\" changes sign when promoted",
+              cpp_token_as_text (pfile, op->token));
 }
 
-static HOST_WIDEST_INT
-left_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile;
-     HOST_WIDEST_INT a;
-     unsigned int unsignedp;
-     unsigned HOST_WIDEST_INT b;
+/* Clears the unused high order bits of the number pointed to by PNUM.  */
+static cpp_num
+num_trim (cpp_num num, size_t precision)
 {
-  if (b >= HOST_BITS_PER_WIDEST_INT)
+  if (precision > PART_PRECISION)
     {
-      if (! unsignedp && a != 0)
-       integer_overflow (pfile);
-      return 0;
+      precision -= PART_PRECISION;
+      if (precision < PART_PRECISION)
+       num.high &= ((cpp_num_part) 1 << precision) - 1;
     }
-  else if (unsignedp)
-    return (unsigned HOST_WIDEST_INT) a << b;
   else
     {
-      HOST_WIDEST_INT l = a << b;
-      if (l >> b != a)
-       integer_overflow (pfile);
-      return l;
+      if (precision < PART_PRECISION)
+       num.low &= ((cpp_num_part) 1 << precision) - 1;
+      num.high = 0;
     }
+
+  return num;
 }
 
-static HOST_WIDEST_INT
-right_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     HOST_WIDEST_INT a;
-     unsigned int unsignedp;
-     unsigned HOST_WIDEST_INT b;
+/* True iff A (presumed signed) >= 0.  */
+static bool
+num_positive (cpp_num num, size_t precision)
 {
-  if (b >= HOST_BITS_PER_WIDEST_INT)
-    return unsignedp ? 0 : a >> (HOST_BITS_PER_WIDEST_INT - 1);
-  else if (unsignedp)
-    return (unsigned HOST_WIDEST_INT) a >> b;
-  else
-    return a >> b;
+  if (precision > PART_PRECISION)
+    {
+      precision -= PART_PRECISION;
+      return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
+    }
+
+  return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
 }
-\f
-/* Operator precedence and flags table.
 
-After an operator is returned from the lexer, if it has priority less
-than or equal to the operator on the top of the stack, we reduce the
-stack by one operator and repeat the test.  Since equal priorities
-reduce, this is naturally left-associative.
-
-We handle right-associative operators by clearing the lower bit of all
-left-associative operators, and setting it for right-associative ones.
-After the reduction phase of a new operator, just before it is pushed
-onto the stack, its RIGHT_ASSOC bit is cleared.  The effect is that
-during the reduction phase, the current right-associative operator has
-a priority one greater than any other operator of otherwise equal
-precedence that has been pushed on the top of the stack.  This avoids
-a reduction pass, and effectively makes the logic right-associative.
+/* Sign extend a number, with PRECISION significant bits and all
+   others assumed clear, to fill out a cpp_num structure.  */
+cpp_num
+cpp_num_sign_extend (cpp_num num, size_t precision)
+{
+  if (!num.unsignedp)
+    {
+      if (precision > PART_PRECISION)
+       {
+         precision -= PART_PRECISION;
+         if (precision < PART_PRECISION
+             && (num.high & (cpp_num_part) 1 << (precision - 1)))
+           num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
+       }
+      else if (num.low & (cpp_num_part) 1 << (precision - 1))
+       {
+         if (precision < PART_PRECISION)
+           num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
+         num.high = ~(cpp_num_part) 0;
+       }
+    }
 
-The remaining cases are '(' and ')'.  We handle '(' by skipping the
-reduction phase completely.  ')' is given lower priority than
-everything else, including '(', effectively forcing a reduction of the
-parenthesised expression.  If there is no matching '(', the stack will
-be reduced all the way to the beginning, exiting the parser in the
-same way as the ultra-low priority end-of-expression dummy operator.
-The exit code checks to see if the operator that caused it is ')', and
-if so outputs an appropriate error message.
-
-The parser assumes all shifted operators require a right operand
-unless the flag NO_R_OPERAND is set, and similarly for NO_L_OPERAND.
-These semantics are automatically checked, any extra semantics need to
-be handled with operator-specific code.  */
-
-#define FLAG_BITS  8
-#define FLAG_MASK ((1 << FLAG_BITS) - 1)
-#define PRIO_SHIFT (FLAG_BITS + 1)
-#define EXTRACT_PRIO(cnst) (cnst >> FLAG_BITS)
-#define EXTRACT_FLAGS(cnst) (cnst & FLAG_MASK)
-
-/* Flags.  */
-#define HAVE_VALUE     (1 << 0)
-#define NO_L_OPERAND   (1 << 1)
-#define NO_R_OPERAND   (1 << 2)
-#define SHORT_CIRCUIT  (1 << 3)
-
-/* Priority and flag combinations.  */
-#define RIGHT_ASSOC         (1 << FLAG_BITS)
-#define FORCE_REDUCE_PRIO   (0 << PRIO_SHIFT)
-#define CLOSE_PAREN_PRIO    (1 << PRIO_SHIFT)
-#define OPEN_PAREN_PRIO    ((2 << PRIO_SHIFT) | NO_L_OPERAND)
-#define COMMA_PRIO          (3 << PRIO_SHIFT)
-#define COND_PRIO          ((4 << PRIO_SHIFT) | RIGHT_ASSOC | SHORT_CIRCUIT)
-#define COLON_PRIO         ((5 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define OROR_PRIO          ((6 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define ANDAND_PRIO        ((7 << PRIO_SHIFT) | SHORT_CIRCUIT)
-#define OR_PRIO             (8 << PRIO_SHIFT)
-#define XOR_PRIO            (9 << PRIO_SHIFT)
-#define AND_PRIO           (10 << PRIO_SHIFT)
-#define EQUAL_PRIO         (11 << PRIO_SHIFT)
-#define LESS_PRIO          (12 << PRIO_SHIFT)
-#define SHIFT_PRIO         (13 << PRIO_SHIFT)
-#define PLUS_PRIO          (14 << PRIO_SHIFT)
-#define MUL_PRIO           (15 << PRIO_SHIFT)
-#define UNARY_PRIO        ((16 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND)
-
-#define COMPARE(OP) \
-  top->unsignedp = 0; \
-  top->value = (unsigned1 | unsigned2) \
-  ? (unsigned HOST_WIDEST_INT) v1 OP (unsigned HOST_WIDEST_INT) v2 \
-  : (v1 OP v2)
-#define EQUALITY(OP) \
-  top->value = v1 OP v2; \
-  top->unsignedp = 0;
-#define LOGICAL(OP) \
-  top->value = v1 OP v2; \
-  top->unsignedp = unsigned1 | unsigned2;
+  return num;
+}
 
-/* With -O2, gcc appears to produce nice code, moving the error
-   message load and subsequent jump completely out of the main path.  */
-#define CPP_ICE(msgid) \
-  do { cpp_ice (pfile, msgid); goto syntax_error; } while(0)
-#define SYNTAX_ERROR(msgid) \
-  do { cpp_error (pfile, msgid); goto syntax_error; } while(0)
-#define SYNTAX_ERROR2(msgid, arg) \
-  do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0)
+/* Returns the negative of NUM.  */
+static cpp_num
+num_negate (cpp_num num, size_t precision)
+{
+  cpp_num copy;
 
-/* Parse and evaluate a C expression, reading from PFILE.
-   Returns the truth value of the expression.  */
+  copy = num;
+  num.high = ~num.high;
+  num.low = ~num.low;
+  if (++num.low == 0)
+    num.high++;
+  num = num_trim (num, precision);
+  num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
+
+  return num;
+}
 
-int
-_cpp_parse_expr (pfile)
-     cpp_reader *pfile;
+/* Returns true if A >= B.  */
+static bool
+num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
 {
-  /* The implementation is an operator precedence parser, i.e. a
-     bottom-up parser, using a stack for not-yet-reduced tokens.
-
-     The stack base is 'stack', and the current stack pointer is 'top'.
-     There is a stack element for each operator (only),
-     and the most recently pushed operator is 'top->op'.
-     An operand (value) is stored in the 'value' field of the stack
-     element of the operator that precedes it.
-     In that case the 'flags' field has the HAVE_VALUE flag set.  */
-
-#define INIT_STACK_SIZE 20
-  struct operation init_stack[INIT_STACK_SIZE];
-  struct operation *stack = init_stack;
-  struct operation *limit = stack + INIT_STACK_SIZE;
-  register struct operation *top = stack + 1;
-  long old_written = CPP_WRITTEN (pfile);
-  int skip_evaluation = 0;
-  int result;
-  char buff[5];
-
-  pfile->parsing_if_directive++;
-  /* We've finished when we try to reduce this.  */
-  top->op = FINISHED;
-  /* Nifty way to catch missing '('.  */
-  top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO);
-  /* Avoid missing right operand checks.  */
-  top->flags = NO_R_OPERAND;
+  bool unsignedp;
 
-  for (;;)
+  unsignedp = pa.unsignedp || pb.unsignedp;
+
+  if (!unsignedp)
     {
-      unsigned int prio;
-      unsigned int flags;
-      struct operation op;
+      /* Both numbers have signed type.  If they are of different
+       sign, the answer is the sign of A.  */
+      unsignedp = num_positive (pa, precision);
 
-      /* Read a token */
-      op = lex (pfile, skip_evaluation);
+      if (unsignedp != num_positive (pb, precision))
+       return unsignedp;
 
-      /* If the token is an operand, push its value and get next
-        token.  If it is an operator, get its priority and flags, and
-        try to reduce the expression on the stack.  */
-      switch (op.op)
+      /* Otherwise we can do an unsigned comparison.  */
+    }
+
+  return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
+}
+
+/* Returns LHS OP RHS, where OP is a bit-wise operation.  */
+static cpp_num
+num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
+               cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
+{
+  lhs.overflow = false;
+  lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+  /* As excess precision is zeroed, there is no need to num_trim () as
+     these operations cannot introduce a set bit there.  */
+  if (op == CPP_AND)
+    {
+      lhs.low &= rhs.low;
+      lhs.high &= rhs.high;
+    }
+  else if (op == CPP_OR)
+    {
+      lhs.low |= rhs.low;
+      lhs.high |= rhs.high;
+    }
+  else
+    {
+      lhs.low ^= rhs.low;
+      lhs.high ^= rhs.high;
+    }
+
+  return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is an inequality.  */
+static cpp_num
+num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs,
+                  enum cpp_ttype op)
+{
+  bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
+
+  if (op == CPP_GREATER_EQ)
+    lhs.low = gte;
+  else if (op == CPP_LESS)
+    lhs.low = !gte;
+  else if (op == CPP_GREATER)
+    lhs.low = gte && !num_eq (lhs, rhs);
+  else /* CPP_LESS_EQ.  */
+    lhs.low = !gte || num_eq (lhs, rhs);
+
+  lhs.high = 0;
+  lhs.overflow = false;
+  lhs.unsignedp = false;
+  return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is == or !=.  */
+static cpp_num
+num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
+                cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
+{
+  /* Work around a 3.0.4 bug; see PR 6950.  */
+  bool eq = num_eq (lhs, rhs);
+  if (op == CPP_NOT_EQ)
+    eq = !eq;
+  lhs.low = eq;
+  lhs.high = 0;
+  lhs.overflow = false;
+  lhs.unsignedp = false;
+  return lhs;
+}
+
+/* Shift NUM, of width PRECISION, right by N bits.  */
+static cpp_num
+num_rshift (cpp_num num, size_t precision, size_t n)
+{
+  cpp_num_part sign_mask;
+
+  if (num.unsignedp || num_positive (num, precision))
+    sign_mask = 0;
+  else
+    sign_mask = ~(cpp_num_part) 0;
+
+  if (n >= precision)
+    num.high = num.low = sign_mask;
+  else
+    {
+      /* Sign-extend.  */
+      if (precision < PART_PRECISION)
+       num.high = sign_mask, num.low |= sign_mask << precision;
+      else if (precision < 2 * PART_PRECISION)
+       num.high |= sign_mask << (precision - PART_PRECISION);
+
+      if (n >= PART_PRECISION)
        {
-       case NAME:
-         CPP_ICE ("lex returns a NAME");
-       case ERROR:
-         goto syntax_error;
-       case '#':
-         /* We get '#' when get_directive_token hits a syntactically
-            invalid assertion predicate.  _cpp_parse_assertion has
-            already issued an error.  */
-         goto syntax_error;
-       default:
-         SYNTAX_ERROR ("invalid character in #if");
-
-       push_immediate:
-       case INT:
-       case CHAR:
-         /* Push a value onto the stack.  */
-         if (top->flags & HAVE_VALUE)
-           SYNTAX_ERROR ("missing binary operator");
-         top->value = op.value;
-         top->unsignedp = op.unsignedp;
-         top->flags |= HAVE_VALUE;
-         continue;
+         n -= PART_PRECISION;
+         num.low = num.high;
+         num.high = sign_mask;
+       }
 
-       case '+':
-       case '-':    prio = PLUS_PRIO;  if (top->flags & HAVE_VALUE) break;
-          /* else unary; fall through */
-       case '!':
-       case '~':    prio = UNARY_PRIO;  break;
-
-       case '*':
-       case '/':
-       case '%':    prio = MUL_PRIO;  break;
-       case '<':
-       case '>':
-       case LEQ:
-       case GEQ:    prio = LESS_PRIO;  break;
-       case NOTEQUAL:
-       case EQUAL:  prio = EQUAL_PRIO;  break;
-       case LSH:
-       case RSH:    prio = SHIFT_PRIO;  break;
-       case '&':    prio = AND_PRIO;  break;
-       case '^':    prio = XOR_PRIO;  break;
-       case '|':    prio = OR_PRIO;  break;
-       case ANDAND: prio = ANDAND_PRIO;  break;
-       case OROR:   prio = OROR_PRIO;  break;
-       case ',':    prio = COMMA_PRIO;  break;
-       case '(':    prio = OPEN_PAREN_PRIO; break;
-       case ')':    prio = CLOSE_PAREN_PRIO;  break;
-        case ':':    prio = COLON_PRIO;  break;
-        case '?':    prio = COND_PRIO;  break;
-       case 0:      prio = FORCE_REDUCE_PRIO;  break;
+      if (n)
+       {
+         num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
+         num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
        }
+    }
 
-      /* Separate the operator's code into priority and flags.  */
-      flags = EXTRACT_FLAGS(prio);
-      prio = EXTRACT_PRIO(prio);
-      if (op.op == '(')
-       goto skip_reduction;
+  num = num_trim (num, precision);
+  num.overflow = false;
+  return num;
+}
 
-      /* Check for reductions.  Then push the operator.  */
-      while (prio <= top->prio)
-       {
-         HOST_WIDEST_INT v1, v2;
-         unsigned int unsigned1, unsigned2;
-         
-         /* Most operators that can appear on the stack require a
-            right operand.  Check this before trying to reduce.  */
-         if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0)
-           {
-             if (top->op == '(')
-               SYNTAX_ERROR ("void expression between '(' and ')'");
-             else
-               SYNTAX_ERROR2 ("operator '%s' has no right operand",
-                              op_to_str (top->op, buff));
-           }
+/* Shift NUM, of width PRECISION, left by N bits.  */
+static cpp_num
+num_lshift (cpp_num num, size_t precision, size_t n)
+{
+  if (n >= precision)
+    {
+      num.overflow = !num.unsignedp && !num_zerop (num);
+      num.high = num.low = 0;
+    }
+  else
+    {
+      cpp_num orig, maybe_orig;
+      size_t m = n;
 
-         unsigned2 = top->unsignedp, v2 = top->value;
-         top--;
-         unsigned1 = top->unsignedp, v1 = top->value;
+      orig = num;
+      if (m >= PART_PRECISION)
+       {
+         m -= PART_PRECISION;
+         num.high = num.low;
+         num.low = 0;
+       }
+      if (m)
+       {
+         num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
+         num.low <<= m;
+       }
+      num = num_trim (num, precision);
 
-         /* Now set top->value = (top[1].op)(v1, v2); */
-         switch (top[1].op)
-           {
-           case '+':
-             if (!(top->flags & HAVE_VALUE))
-               { /* Unary '+' */
-                 top->value = v2;
-                 top->unsignedp = unsigned2;
-                 top->flags |= HAVE_VALUE;
-               }
-             else
-               {
-                 top->value = v1 + v2;
-                 top->unsignedp = unsigned1 | unsigned2;
-                 if (! top->unsignedp && ! skip_evaluation
-                     && ! possible_sum_sign (v1, v2, top->value))
-                   integer_overflow (pfile);
-               }
-             break;
-           case '-':
-             if (!(top->flags & HAVE_VALUE))
-               { /* Unary '-' */
-                 top->value = - v2;
-                 if (!skip_evaluation && (top->value & v2) < 0
-                     && !unsigned2)
-                   integer_overflow (pfile);
-                 top->unsignedp = unsigned2;
-                 top->flags |= HAVE_VALUE;
-               }
-             else
-               { /* Binary '-' */
-                 top->value = v1 - v2;
-                 top->unsignedp = unsigned1 | unsigned2;
-                 if (! top->unsignedp && ! skip_evaluation
-                     && ! possible_sum_sign (top->value, v2, v1))
-                   integer_overflow (pfile);
-               }
-             break;
-           case '*':
-             top->unsignedp = unsigned1 | unsigned2;
-             if (top->unsignedp)
-               top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
-             else if (!skip_evaluation)
-               {
-                 top->value = v1 * v2;
-                 if (v1 && (top->value / v1 != v2
-                            || (top->value & v1 & v2) < 0))
-                   integer_overflow (pfile);
-               }
-             break;
-           case '/':
-           case '%':
-             if (skip_evaluation)
-               break;
-             if (v2 == 0)
-               SYNTAX_ERROR ("division by zero in #if");
-             top->unsignedp = unsigned1 | unsigned2;
-             if (top[1].op == '/')
-               {
-                 if (top->unsignedp)
-                   top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
-                 else
-                   {
-                     top->value = v1 / v2;
-                     if ((top->value & v1 & v2) < 0)
-                       integer_overflow (pfile);
-                   }
-               }
-             else
-               {
-                 if (top->unsignedp)
-                   top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
-                 else
-                   top->value = v1 % v2;
-               }
-             break;
-           case '!':
-             top->value = ! v2;
-             top->unsignedp = 0;
-             top->flags |= HAVE_VALUE;
-             break;
-           case '~':
-             top->value = ~ v2;
-             top->unsignedp = unsigned2;
-             top->flags |= HAVE_VALUE;
-             break;
-           case '<':  COMPARE(<);  break;
-           case '>':  COMPARE(>);  break;
-           case LEQ:  COMPARE(<=);  break;
-           case GEQ:  COMPARE(>=);  break;
-           case EQUAL:    EQUALITY(==);  break;
-           case NOTEQUAL: EQUALITY(!=);  break;
-           case LSH:
-             if (skip_evaluation)
-               break;
-             top->unsignedp = unsigned1;
-             if (v2 < 0 && ! unsigned2)
-               top->value = right_shift (pfile, v1, unsigned1, -v2);
-             else
-               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);
-             else
-               top->value = right_shift (pfile, v1, unsigned1, v2);
-             break;
-           case '&':  LOGICAL(&); break;
-           case '^':  LOGICAL(^);  break;
-           case '|':  LOGICAL(|);  break;
-           case ANDAND:
-             top->value = v1 && v2;  top->unsignedp = 0;
-             if (!v1) skip_evaluation--;
-             break;
-           case OROR:
-             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");
-             top->value = v2;
-             top->unsignedp = unsigned2;
-             break;
-           case '?':
-             SYNTAX_ERROR ("syntax error '?' without following ':'");
-           case ':':
-             if (top[0].op != '?')
-               SYNTAX_ERROR ("syntax error ':' without preceding '?'");
-             top--;
-             if (top->value) skip_evaluation--;
-             top->value = top->value ? v1 : v2;
-             top->unsignedp = unsigned1 | unsigned2;
-             break;
-           case '(':
-             if (op.op != ')')
-               SYNTAX_ERROR ("missing ')' in expression");
-             op.value = v2;
-             op.unsignedp = unsigned2;
-             goto push_immediate;
-           default:
-             SYNTAX_ERROR2 ("unimplemented operator '%s'",
-                            op_to_str (top[1].op, buff));
-           case FINISHED:
-             /* Reducing this dummy operator indicates we've finished.  */
-             if (op.op == ')')
-               SYNTAX_ERROR ("missing '(' in expression");
-             goto done;
-           }
+      if (num.unsignedp)
+       num.overflow = false;
+      else
+       {
+         maybe_orig = num_rshift (num, precision, n);
+         num.overflow = !num_eq (orig, maybe_orig);
        }
+    }
 
-      /* Handle short-circuit evaluations.  */
-      if (flags & SHORT_CIRCUIT)
-       switch (op.op)
-         {
-         case OROR:    if (top->value) skip_evaluation++; break;
-         case ANDAND:
-         case '?':     if (!top->value) skip_evaluation++; break;
-         case ':':
-           if (top[-1].value) /* Was '?' condition true?  */
-             skip_evaluation++;
-           else
-             skip_evaluation--;
-         }
+  return num;
+}
+
+/* The four unary operators: +, -, ! and ~.  */
+static cpp_num
+num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op)
+{
+  switch (op)
+    {
+    case CPP_UPLUS:
+      if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "traditional C rejects the unary plus operator");
+      num.overflow = false;
+      break;
+
+    case CPP_UMINUS:
+      num = num_negate (num, CPP_OPTION (pfile, precision));
+      break;
+
+    case CPP_COMPL:
+      num.high = ~num.high;
+      num.low = ~num.low;
+      num = num_trim (num, CPP_OPTION (pfile, precision));
+      num.overflow = false;
+      break;
+
+    default: /* case CPP_NOT: */
+      num.low = num_zerop (num);
+      num.high = 0;
+      num.overflow = false;
+      num.unsignedp = false;
+      break;
+    }
+
+  return num;
+}
+
+/* The various binary operators.  */
+static cpp_num
+num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
+{
+  cpp_num result;
+  size_t precision = CPP_OPTION (pfile, precision);
+  bool gte;
+  size_t n;
 
-    skip_reduction:
-      /* Check we have a left operand iff we need one.  */
-      if (flags & NO_L_OPERAND)
+  switch (op)
+    {
+      /* Shifts.  */
+    case CPP_LSHIFT:
+    case CPP_RSHIFT:
+      if (!rhs.unsignedp && !num_positive (rhs, precision))
        {
-         if (top->flags & HAVE_VALUE)
-           SYNTAX_ERROR2 ("missing binary operator before '%s'",
-                          op_to_str (op.op, buff));
+         /* A negative shift is a positive shift the other way.  */
+         if (op == CPP_LSHIFT)
+           op = CPP_RSHIFT;
+         else
+           op = CPP_LSHIFT;
+         rhs = num_negate (rhs, precision);
        }
+      if (rhs.high)
+       n = ~0;                 /* Maximal.  */
+      else
+       n = rhs.low;
+      if (op == CPP_LSHIFT)
+       lhs = num_lshift (lhs, precision, n);
+      else
+       lhs = num_rshift (lhs, precision, n);
+      break;
+
+      /* Min / Max.  */
+    case CPP_MIN:
+    case CPP_MAX:
+      {
+       bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+       gte = num_greater_eq (lhs, rhs, precision);
+       if (op == CPP_MIN)
+         gte = !gte;
+       if (!gte)
+         lhs = rhs;
+       lhs.unsignedp = unsignedp;
+      }
+      break;
+
+      /* Arithmetic.  */
+    case CPP_MINUS:
+      rhs = num_negate (rhs, precision);
+    case CPP_PLUS:
+      result.low = lhs.low + rhs.low;
+      result.high = lhs.high + rhs.high;
+      if (result.low < lhs.low)
+       result.high++;
+
+      result = num_trim (result, precision);
+      result.unsignedp = lhs.unsignedp || rhs.unsignedp;
+      if (result.unsignedp)
+       result.overflow = false;
       else
        {
-         if (!(top->flags & HAVE_VALUE))
-           SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          op_to_str (op.op, buff));
+         bool lhsp = num_positive (lhs, precision);
+         result.overflow = (lhsp == num_positive (rhs, precision)
+                            && lhsp != num_positive (result, precision));
        }
+      return result;
+
+      /* Comma.  */
+    default: /* case CPP_COMMA: */
+      if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99)
+                                  || !pfile->state.skip_eval))
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "comma operator in operand of #if");
+      lhs = rhs;
+      break;
+    }
 
-      /* Check for and handle stack overflow.  */
-      top++;
-      if (top == limit)
+  return lhs;
+}
+
+/* Multiplies two unsigned cpp_num_parts to give a cpp_num.  This
+   cannot overflow.  */
+static cpp_num
+num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
+{
+  cpp_num result;
+  cpp_num_part middle[2], temp;
+
+  result.low = LOW_PART (lhs) * LOW_PART (rhs);
+  result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
+
+  middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
+  middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
+
+  temp = result.low;
+  result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
+  if (result.low < temp)
+    result.high++;
+
+  temp = result.low;
+  result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
+  if (result.low < temp)
+    result.high++;
+
+  result.high += HIGH_PART (middle[0]);
+  result.high += HIGH_PART (middle[1]);
+  result.unsignedp = 1;
+
+  return result;
+}
+
+/* Multiply two preprocessing numbers.  */
+static cpp_num
+num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
+{
+  cpp_num result, temp;
+  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+  bool overflow, negate = false;
+  size_t precision = CPP_OPTION (pfile, precision);
+
+  /* Prepare for unsigned multiplication.  */
+  if (!unsignedp)
+    {
+      if (!num_positive (lhs, precision))
+       negate = !negate, lhs = num_negate (lhs, precision);
+      if (!num_positive (rhs, precision))
+       negate = !negate, rhs = num_negate (rhs, precision);
+    }
+
+  overflow = lhs.high && rhs.high;
+  result = num_part_mul (lhs.low, rhs.low);
+
+  temp = num_part_mul (lhs.high, rhs.low);
+  result.high += temp.low;
+  if (temp.high)
+    overflow = true;
+
+  temp = num_part_mul (lhs.low, rhs.high);
+  result.high += temp.low;
+  if (temp.high)
+    overflow = true;
+
+  temp.low = result.low, temp.high = result.high;
+  result = num_trim (result, precision);
+  if (!num_eq (result, temp))
+    overflow = true;
+
+  if (negate)
+    result = num_negate (result, precision);
+
+  if (unsignedp)
+    result.overflow = false;
+  else
+    result.overflow = overflow || (num_positive (result, precision) ^ !negate
+                                  && !num_zerop (result));
+  result.unsignedp = unsignedp;
+
+  return result;
+}
+
+/* Divide two preprocessing numbers, returning the answer or the
+   remainder depending upon OP.  */
+static cpp_num
+num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
+{
+  cpp_num result, sub;
+  cpp_num_part mask;
+  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+  bool negate = false, lhs_neg = false;
+  size_t i, precision = CPP_OPTION (pfile, precision);
+
+  /* Prepare for unsigned division.  */
+  if (!unsignedp)
+    {
+      if (!num_positive (lhs, precision))
+       negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
+      if (!num_positive (rhs, precision))
+       negate = !negate, rhs = num_negate (rhs, precision);
+    }
+
+  /* Find the high bit.  */
+  if (rhs.high)
+    {
+      i = precision - 1;
+      mask = (cpp_num_part) 1 << (i - PART_PRECISION);
+      for (; ; i--, mask >>= 1)
+       if (rhs.high & mask)
+         break;
+    }
+  else if (rhs.low)
+    {
+      if (precision > PART_PRECISION)
+       i = precision - PART_PRECISION - 1;
+      else
+       i = precision - 1;
+      mask = (cpp_num_part) 1 << i;
+      for (; ; i--, mask >>= 1)
+       if (rhs.low & mask)
+         break;
+    }
+  else
+    {
+      if (!pfile->state.skip_eval)
+       cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if");
+      return lhs;
+    }
+
+  /* First nonzero bit of RHS is bit I.  Do naive division by
+     shifting the RHS fully left, and subtracting from LHS if LHS is
+     at least as big, and then repeating but with one less shift.
+     This is not very efficient, but is easy to understand.  */
+
+  rhs.unsignedp = true;
+  lhs.unsignedp = true;
+  i = precision - i - 1;
+  sub = num_lshift (rhs, precision, i);
+
+  result.high = result.low = 0;
+  for (;;)
+    {
+      if (num_greater_eq (lhs, sub, precision))
        {
-         struct operation *new_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);
+         lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
+         if (i >= PART_PRECISION)
+           result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
          else
-           {
-             new_stack = (struct operation *) xmalloc (new_size);
-             memcpy (new_stack, stack, old_size);
-           }
-         stack = new_stack;
-         top = (struct operation *) ((char *) new_stack + old_size);
-         limit = (struct operation *) ((char *) new_stack + new_size);
+           result.low |= (cpp_num_part) 1 << i;
        }
-      
-      top->flags = flags;
-      top->prio = prio & ~EXTRACT_PRIO(RIGHT_ASSOC);
-      top->op = op.op;
+      if (i-- == 0)
+       break;
+      sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
+      sub.high >>= 1;
     }
 
- done:
-  result = (top[1].value != 0);
-  if (top != stack)
-    CPP_ICE ("unbalanced stack in #if expression");
-  else if (!(top[1].flags & HAVE_VALUE))
+  /* We divide so that the remainder has the sign of the LHS.  */
+  if (op == CPP_DIV)
     {
-      SYNTAX_ERROR ("#if with no expression");
-    syntax_error:
-      _cpp_skip_rest_of_line (pfile);
-      result = 0;  /* Return 0 on syntax error.  */
+      result.unsignedp = unsignedp;
+      if (unsignedp)
+       result.overflow = false;
+      else
+       {
+         if (negate)
+           result = num_negate (result, precision);
+         result.overflow = num_positive (result, precision) ^ !negate;
+       }
+
+      return result;
     }
 
-  /* Free dynamic stack if we allocated one.  */
-  if (stack != init_stack)
-    free (stack);
-  pfile->parsing_if_directive--;
-  CPP_SET_WRITTEN (pfile, old_written);
-  return result;
+  /* CPP_MOD.  */
+  lhs.unsignedp = unsignedp;
+  lhs.overflow = false;
+  if (lhs_neg)
+    lhs = num_negate (lhs, precision);
+
+  return lhs;
 }