OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc4/] [libcpp/] [expr.c] - Diff between revs 270 and 519

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 270 Rev 519
/* Parse C expressions for cpplib.
/* Parse C expressions for cpplib.
   Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
   Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
   2002, 2004, 2008, 2009, 2010 Free Software Foundation.
   2002, 2004, 2008, 2009, 2010 Free Software Foundation.
   Contributed by Per Bothner, 1994.
   Contributed by Per Bothner, 1994.
 
 
This program is free software; you can redistribute it and/or modify it
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
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
Free Software Foundation; either version 3, or (at your option) any
later version.
later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING3.  If not see
along with this program; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "cpplib.h"
#include "cpplib.h"
#include "internal.h"
#include "internal.h"
 
 
#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
#define LOW_PART(num_part) (num_part & HALF_MASK)
#define LOW_PART(num_part) (num_part & HALF_MASK)
#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
 
 
struct op
struct op
{
{
  const cpp_token *token;       /* The token forming op (for diagnostics).  */
  const cpp_token *token;       /* The token forming op (for diagnostics).  */
  cpp_num value;                /* The value logically "right" of op.  */
  cpp_num value;                /* The value logically "right" of op.  */
  source_location loc;          /* The location of this value.         */
  source_location loc;          /* The location of this value.         */
  enum cpp_ttype op;
  enum cpp_ttype op;
};
};
 
 
/* Some simple utility routines on double integers.  */
/* Some simple utility routines on double integers.  */
#define num_zerop(num) ((num.low | num.high) == 0)
#define num_zerop(num) ((num.low | num.high) == 0)
#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
static bool num_positive (cpp_num, size_t);
static bool num_positive (cpp_num, size_t);
static bool num_greater_eq (cpp_num, 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_trim (cpp_num, size_t);
static cpp_num num_part_mul (cpp_num_part, cpp_num_part);
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_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_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
static cpp_num num_negate (cpp_num, size_t);
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_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,
static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,
                                  enum cpp_ttype);
                                  enum cpp_ttype);
static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
                                enum cpp_ttype);
                                enum cpp_ttype);
static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);
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_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype,
                           source_location);
                           source_location);
static cpp_num num_lshift (cpp_num, size_t, size_t);
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 num_rshift (cpp_num, size_t, size_t);
 
 
static cpp_num append_digit (cpp_num, int, int, size_t);
static cpp_num append_digit (cpp_num, int, int, size_t);
static cpp_num parse_defined (cpp_reader *);
static cpp_num parse_defined (cpp_reader *);
static cpp_num eval_token (cpp_reader *, const cpp_token *);
static cpp_num eval_token (cpp_reader *, const cpp_token *);
static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);
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_float_suffix (const uchar *, size_t);
static unsigned int interpret_int_suffix (const uchar *, size_t);
static unsigned int interpret_int_suffix (const uchar *, size_t);
static void check_promotion (cpp_reader *, const struct op *);
static void check_promotion (cpp_reader *, const struct op *);
 
 
/* Token type abuse to create unary plus and minus operators.  */
/* Token type abuse to create unary plus and minus operators.  */
#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
 
 
/* With -O2, gcc appears to produce nice code, moving the error
/* With -O2, gcc appears to produce nice code, moving the error
   message load and subsequent jump completely out of the main path.  */
   message load and subsequent jump completely out of the main path.  */
#define SYNTAX_ERROR(msgid) \
#define SYNTAX_ERROR(msgid) \
  do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
  do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
#define SYNTAX_ERROR2(msgid, arg) \
#define SYNTAX_ERROR2(msgid, arg) \
  do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \
  do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \
  while(0)
  while(0)
 
 
/* Subroutine of cpp_classify_number.  S points to a float suffix of
/* Subroutine of cpp_classify_number.  S points to a float suffix of
   length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
   length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
   flag vector describing the suffix.  */
   flag vector describing the suffix.  */
static unsigned int
static unsigned int
interpret_float_suffix (const uchar *s, size_t len)
interpret_float_suffix (const uchar *s, size_t len)
{
{
  size_t flags;
  size_t flags;
  size_t f, d, l, w, q, i;
  size_t f, d, l, w, q, i;
 
 
  flags = 0;
  flags = 0;
  f = d = l = w = q = i = 0;
  f = d = l = w = q = i = 0;
 
 
  /* Process decimal float suffixes, which are two letters starting
  /* Process decimal float suffixes, which are two letters starting
     with d or D.  Order and case are significant.  */
     with d or D.  Order and case are significant.  */
  if (len == 2 && (*s == 'd' || *s == 'D'))
  if (len == 2 && (*s == 'd' || *s == 'D'))
    {
    {
      bool uppercase = (*s == 'D');
      bool uppercase = (*s == 'D');
      switch (s[1])
      switch (s[1])
      {
      {
      case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL): 0); break;
      case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL): 0); break;
      case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break;
      case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break;
      case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM): 0); break;
      case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM): 0); break;
      case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break;
      case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break;
      case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break;
      case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break;
      case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break;
      case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break;
      default:
      default:
        /* Additional two-character suffixes beginning with D are not
        /* Additional two-character suffixes beginning with D are not
           for decimal float constants.  */
           for decimal float constants.  */
        break;
        break;
      }
      }
    }
    }
 
 
  /* Recognize a fixed-point suffix.  */
  /* Recognize a fixed-point suffix.  */
  switch (s[len-1])
  switch (s[len-1])
    {
    {
    case 'k': case 'K': flags = CPP_N_ACCUM; break;
    case 'k': case 'K': flags = CPP_N_ACCUM; break;
    case 'r': case 'R': flags = CPP_N_FRACT; break;
    case 'r': case 'R': flags = CPP_N_FRACT; break;
    default: break;
    default: break;
    }
    }
 
 
  /* Continue processing a fixed-point suffix.  The suffix is case
  /* Continue processing a fixed-point suffix.  The suffix is case
     insensitive except for ll or LL.  Order is significant.  */
     insensitive except for ll or LL.  Order is significant.  */
  if (flags)
  if (flags)
    {
    {
      if (len == 1)
      if (len == 1)
        return flags;
        return flags;
      len--;
      len--;
 
 
      if (*s == 'u' || *s == 'U')
      if (*s == 'u' || *s == 'U')
        {
        {
          flags |= CPP_N_UNSIGNED;
          flags |= CPP_N_UNSIGNED;
          if (len == 1)
          if (len == 1)
            return flags;
            return flags;
          len--;
          len--;
          s++;
          s++;
        }
        }
 
 
      switch (*s)
      switch (*s)
      {
      {
      case 'h': case 'H':
      case 'h': case 'H':
        if (len == 1)
        if (len == 1)
          return flags |= CPP_N_SMALL;
          return flags |= CPP_N_SMALL;
        break;
        break;
      case 'l':
      case 'l':
        if (len == 1)
        if (len == 1)
          return flags |= CPP_N_MEDIUM;
          return flags |= CPP_N_MEDIUM;
        if (len == 2 && s[1] == 'l')
        if (len == 2 && s[1] == 'l')
          return flags |= CPP_N_LARGE;
          return flags |= CPP_N_LARGE;
        break;
        break;
      case 'L':
      case 'L':
        if (len == 1)
        if (len == 1)
          return flags |= CPP_N_MEDIUM;
          return flags |= CPP_N_MEDIUM;
        if (len == 2 && s[1] == 'L')
        if (len == 2 && s[1] == 'L')
          return flags |= CPP_N_LARGE;
          return flags |= CPP_N_LARGE;
        break;
        break;
      default:
      default:
        break;
        break;
      }
      }
      /* Anything left at this point is invalid.  */
      /* Anything left at this point is invalid.  */
      return 0;
      return 0;
    }
    }
 
 
  /* In any remaining valid suffix, the case and order don't matter.  */
  /* In any remaining valid suffix, the case and order don't matter.  */
  while (len--)
  while (len--)
    switch (s[len])
    switch (s[len])
      {
      {
      case 'f': case 'F': f++; break;
      case 'f': case 'F': f++; break;
      case 'd': case 'D': d++; break;
      case 'd': case 'D': d++; break;
      case 'l': case 'L': l++; break;
      case 'l': case 'L': l++; break;
      case 'w': case 'W': w++; break;
      case 'w': case 'W': w++; break;
      case 'q': case 'Q': q++; break;
      case 'q': case 'Q': q++; break;
      case 'i': case 'I':
      case 'i': case 'I':
      case 'j': case 'J': i++; break;
      case 'j': case 'J': i++; break;
      default:
      default:
        return 0;
        return 0;
      }
      }
 
 
  if (f + d + l + w + q > 1 || i > 1)
  if (f + d + l + w + q > 1 || i > 1)
    return 0;
    return 0;
 
 
  return ((i ? CPP_N_IMAGINARY : 0)
  return ((i ? CPP_N_IMAGINARY : 0)
          | (f ? CPP_N_SMALL :
          | (f ? CPP_N_SMALL :
             d ? CPP_N_MEDIUM :
             d ? CPP_N_MEDIUM :
             l ? CPP_N_LARGE :
             l ? CPP_N_LARGE :
             w ? CPP_N_MD_W :
             w ? CPP_N_MD_W :
             q ? CPP_N_MD_Q : CPP_N_DEFAULT));
             q ? CPP_N_MD_Q : CPP_N_DEFAULT));
}
}
 
 
/* Subroutine of cpp_classify_number.  S points to an integer suffix
/* Subroutine of cpp_classify_number.  S points to an integer suffix
   of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
   of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
   flag vector describing the suffix.  */
   flag vector describing the suffix.  */
static unsigned int
static unsigned int
interpret_int_suffix (const uchar *s, size_t len)
interpret_int_suffix (const uchar *s, size_t len)
{
{
  size_t u, l, i;
  size_t u, l, i;
 
 
  u = l = i = 0;
  u = l = i = 0;
 
 
  while (len--)
  while (len--)
    switch (s[len])
    switch (s[len])
      {
      {
      case 'u': case 'U':       u++; break;
      case 'u': case 'U':       u++; break;
      case 'i': case 'I':
      case 'i': case 'I':
      case 'j': case 'J':       i++; break;
      case 'j': case 'J':       i++; break;
      case 'l': case 'L':       l++;
      case 'l': case 'L':       l++;
        /* If there are two Ls, they must be adjacent and the same case.  */
        /* If there are two Ls, they must be adjacent and the same case.  */
        if (l == 2 && s[len] != s[len + 1])
        if (l == 2 && s[len] != s[len + 1])
          return 0;
          return 0;
        break;
        break;
      default:
      default:
        return 0;
        return 0;
      }
      }
 
 
  if (l > 2 || u > 1 || i > 1)
  if (l > 2 || u > 1 || i > 1)
    return 0;
    return 0;
 
 
  return ((i ? CPP_N_IMAGINARY : 0)
  return ((i ? CPP_N_IMAGINARY : 0)
          | (u ? CPP_N_UNSIGNED : 0)
          | (u ? CPP_N_UNSIGNED : 0)
          | ((l == 0) ? CPP_N_SMALL
          | ((l == 0) ? CPP_N_SMALL
             : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
             : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
}
}
 
 
/* Categorize numeric constants according to their field (integer,
/* Categorize numeric constants according to their field (integer,
   floating point, or invalid), radix (decimal, octal, hexadecimal),
   floating point, or invalid), radix (decimal, octal, hexadecimal),
   and type suffixes.  */
   and type suffixes.  */
unsigned int
unsigned int
cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
{
{
  const uchar *str = token->val.str.text;
  const uchar *str = token->val.str.text;
  const uchar *limit;
  const uchar *limit;
  unsigned int max_digit, result, radix;
  unsigned int max_digit, result, radix;
  enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
  enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
  bool seen_digit;
  bool seen_digit;
 
 
  /* If the lexer has done its job, length one can only be a single
  /* If the lexer has done its job, length one can only be a single
     digit.  Fast-path this very common case.  */
     digit.  Fast-path this very common case.  */
  if (token->val.str.len == 1)
  if (token->val.str.len == 1)
    return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
    return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
 
 
  limit = str + token->val.str.len;
  limit = str + token->val.str.len;
  float_flag = NOT_FLOAT;
  float_flag = NOT_FLOAT;
  max_digit = 0;
  max_digit = 0;
  radix = 10;
  radix = 10;
  seen_digit = false;
  seen_digit = false;
 
 
  /* First, interpret the radix.  */
  /* First, interpret the radix.  */
  if (*str == '0')
  if (*str == '0')
    {
    {
      radix = 8;
      radix = 8;
      str++;
      str++;
 
 
      /* Require at least one hex digit to classify it as hex.  */
      /* Require at least one hex digit to classify it as hex.  */
      if ((*str == 'x' || *str == 'X')
      if ((*str == 'x' || *str == 'X')
          && (str[1] == '.' || ISXDIGIT (str[1])))
          && (str[1] == '.' || ISXDIGIT (str[1])))
        {
        {
          radix = 16;
          radix = 16;
          str++;
          str++;
        }
        }
      else if ((*str == 'b' || *str == 'B') && (str[1] == '0' || str[1] == '1'))
      else if ((*str == 'b' || *str == 'B') && (str[1] == '0' || str[1] == '1'))
        {
        {
          radix = 2;
          radix = 2;
          str++;
          str++;
        }
        }
    }
    }
 
 
  /* Now scan for a well-formed integer or float.  */
  /* Now scan for a well-formed integer or float.  */
  for (;;)
  for (;;)
    {
    {
      unsigned int c = *str++;
      unsigned int c = *str++;
 
 
      if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
      if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
        {
        {
          seen_digit = true;
          seen_digit = true;
          c = hex_value (c);
          c = hex_value (c);
          if (c > max_digit)
          if (c > max_digit)
            max_digit = c;
            max_digit = c;
        }
        }
      else if (c == '.')
      else if (c == '.')
        {
        {
          if (float_flag == NOT_FLOAT)
          if (float_flag == NOT_FLOAT)
            float_flag = AFTER_POINT;
            float_flag = AFTER_POINT;
          else
          else
            SYNTAX_ERROR ("too many decimal points in number");
            SYNTAX_ERROR ("too many decimal points in number");
        }
        }
      else if ((radix <= 10 && (c == 'e' || c == 'E'))
      else if ((radix <= 10 && (c == 'e' || c == 'E'))
               || (radix == 16 && (c == 'p' || c == 'P')))
               || (radix == 16 && (c == 'p' || c == 'P')))
        {
        {
          float_flag = AFTER_EXPON;
          float_flag = AFTER_EXPON;
          break;
          break;
        }
        }
      else
      else
        {
        {
          /* Start of suffix.  */
          /* Start of suffix.  */
          str--;
          str--;
          break;
          break;
        }
        }
    }
    }
 
 
  /* The suffix may be for decimal fixed-point constants without exponent.  */
  /* The suffix may be for decimal fixed-point constants without exponent.  */
  if (radix != 16 && float_flag == NOT_FLOAT)
  if (radix != 16 && float_flag == NOT_FLOAT)
    {
    {
      result = interpret_float_suffix (str, limit - str);
      result = interpret_float_suffix (str, limit - str);
      if ((result & CPP_N_FRACT) || (result & CPP_N_ACCUM))
      if ((result & CPP_N_FRACT) || (result & CPP_N_ACCUM))
        {
        {
          result |= CPP_N_FLOATING;
          result |= CPP_N_FLOATING;
          /* We need to restore the radix to 10, if the radix is 8.  */
          /* We need to restore the radix to 10, if the radix is 8.  */
          if (radix == 8)
          if (radix == 8)
            radix = 10;
            radix = 10;
 
 
          if (CPP_PEDANTIC (pfile))
          if (CPP_PEDANTIC (pfile))
            cpp_error (pfile, CPP_DL_PEDWARN,
            cpp_error (pfile, CPP_DL_PEDWARN,
                       "fixed-point constants are a GCC extension");
                       "fixed-point constants are a GCC extension");
          goto syntax_ok;
          goto syntax_ok;
        }
        }
      else
      else
        result = 0;
        result = 0;
    }
    }
 
 
  if (float_flag != NOT_FLOAT && radix == 8)
  if (float_flag != NOT_FLOAT && radix == 8)
    radix = 10;
    radix = 10;
 
 
  if (max_digit >= radix)
  if (max_digit >= radix)
    {
    {
      if (radix == 2)
      if (radix == 2)
        SYNTAX_ERROR2 ("invalid digit \"%c\" in binary constant", '0' + max_digit);
        SYNTAX_ERROR2 ("invalid digit \"%c\" in binary constant", '0' + max_digit);
      else
      else
        SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
        SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
    }
    }
 
 
  if (float_flag != NOT_FLOAT)
  if (float_flag != NOT_FLOAT)
    {
    {
      if (radix == 2)
      if (radix == 2)
        {
        {
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "invalid prefix \"0b\" for floating constant");
                     "invalid prefix \"0b\" for floating constant");
          return CPP_N_INVALID;
          return CPP_N_INVALID;
        }
        }
 
 
      if (radix == 16 && !seen_digit)
      if (radix == 16 && !seen_digit)
        SYNTAX_ERROR ("no digits in hexadecimal floating constant");
        SYNTAX_ERROR ("no digits in hexadecimal floating constant");
 
 
      if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
      if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "use of C99 hexadecimal floating constant");
                   "use of C99 hexadecimal floating constant");
 
 
      if (float_flag == AFTER_EXPON)
      if (float_flag == AFTER_EXPON)
        {
        {
          if (*str == '+' || *str == '-')
          if (*str == '+' || *str == '-')
            str++;
            str++;
 
 
          /* Exponent is decimal, even if string is a hex float.  */
          /* Exponent is decimal, even if string is a hex float.  */
          if (!ISDIGIT (*str))
          if (!ISDIGIT (*str))
            SYNTAX_ERROR ("exponent has no digits");
            SYNTAX_ERROR ("exponent has no digits");
 
 
          do
          do
            str++;
            str++;
          while (ISDIGIT (*str));
          while (ISDIGIT (*str));
        }
        }
      else if (radix == 16)
      else if (radix == 16)
        SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
        SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
 
 
      result = interpret_float_suffix (str, limit - str);
      result = interpret_float_suffix (str, limit - str);
      if (result == 0)
      if (result == 0)
        {
        {
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "invalid suffix \"%.*s\" on floating constant",
                     "invalid suffix \"%.*s\" on floating constant",
                     (int) (limit - str), str);
                     (int) (limit - str), str);
          return CPP_N_INVALID;
          return CPP_N_INVALID;
        }
        }
 
 
      /* Traditional C didn't accept any floating suffixes.  */
      /* Traditional C didn't accept any floating suffixes.  */
      if (limit != str
      if (limit != str
          && CPP_WTRADITIONAL (pfile)
          && CPP_WTRADITIONAL (pfile)
          && ! cpp_sys_macro_p (pfile))
          && ! cpp_sys_macro_p (pfile))
        cpp_error (pfile, CPP_DL_WARNING,
        cpp_error (pfile, CPP_DL_WARNING,
                   "traditional C rejects the \"%.*s\" suffix",
                   "traditional C rejects the \"%.*s\" suffix",
                   (int) (limit - str), str);
                   (int) (limit - str), str);
 
 
      /* A suffix for double is a GCC extension via decimal float support.
      /* A suffix for double is a GCC extension via decimal float support.
         If the suffix also specifies an imaginary value we'll catch that
         If the suffix also specifies an imaginary value we'll catch that
         later.  */
         later.  */
      if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile))
      if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile))
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "suffix for double constant is a GCC extension");
                   "suffix for double constant is a GCC extension");
 
 
      /* Radix must be 10 for decimal floats.  */
      /* Radix must be 10 for decimal floats.  */
      if ((result & CPP_N_DFLOAT) && radix != 10)
      if ((result & CPP_N_DFLOAT) && radix != 10)
        {
        {
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "invalid suffix \"%.*s\" with hexadecimal floating constant",
                     "invalid suffix \"%.*s\" with hexadecimal floating constant",
                     (int) (limit - str), str);
                     (int) (limit - str), str);
          return CPP_N_INVALID;
          return CPP_N_INVALID;
        }
        }
 
 
      if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile))
      if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile))
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "fixed-point constants are a GCC extension");
                   "fixed-point constants are a GCC extension");
 
 
      if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile))
      if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile))
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "decimal float constants are a GCC extension");
                   "decimal float constants are a GCC extension");
 
 
      result |= CPP_N_FLOATING;
      result |= CPP_N_FLOATING;
    }
    }
  else
  else
    {
    {
      result = interpret_int_suffix (str, limit - str);
      result = interpret_int_suffix (str, limit - str);
      if (result == 0)
      if (result == 0)
        {
        {
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "invalid suffix \"%.*s\" on integer constant",
                     "invalid suffix \"%.*s\" on integer constant",
                     (int) (limit - str), str);
                     (int) (limit - str), str);
          return CPP_N_INVALID;
          return CPP_N_INVALID;
        }
        }
 
 
      /* Traditional C only accepted the 'L' suffix.
      /* Traditional C only accepted the 'L' suffix.
         Suppress warning about 'LL' with -Wno-long-long.  */
         Suppress warning about 'LL' with -Wno-long-long.  */
      if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
      if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
        {
        {
          int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
          int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
          int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
          int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
 
 
          if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
          if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
            cpp_error (pfile, CPP_DL_WARNING,
            cpp_error (pfile, CPP_DL_WARNING,
                       "traditional C rejects the \"%.*s\" suffix",
                       "traditional C rejects the \"%.*s\" suffix",
                       (int) (limit - str), str);
                       (int) (limit - str), str);
        }
        }
 
 
      if ((result & CPP_N_WIDTH) == CPP_N_LARGE
      if ((result & CPP_N_WIDTH) == CPP_N_LARGE
          && CPP_OPTION (pfile, warn_long_long))
          && CPP_OPTION (pfile, warn_long_long))
        cpp_error (pfile,
        cpp_error (pfile,
                   CPP_OPTION (pfile, c99) ? CPP_DL_WARNING : CPP_DL_PEDWARN,
                   CPP_OPTION (pfile, c99) ? CPP_DL_WARNING : CPP_DL_PEDWARN,
                   CPP_OPTION (pfile, cplusplus)
                   CPP_OPTION (pfile, cplusplus)
                   ? "use of C++0x long long integer constant"
                   ? "use of C++0x long long integer constant"
                   : "use of C99 long long integer constant");
                   : "use of C99 long long integer constant");
 
 
      result |= CPP_N_INTEGER;
      result |= CPP_N_INTEGER;
    }
    }
 
 
 syntax_ok:
 syntax_ok:
  if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
  if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
    cpp_error (pfile, CPP_DL_PEDWARN,
    cpp_error (pfile, CPP_DL_PEDWARN,
               "imaginary constants are a GCC extension");
               "imaginary constants are a GCC extension");
  if (radix == 2 && CPP_PEDANTIC (pfile))
  if (radix == 2 && CPP_PEDANTIC (pfile))
    cpp_error (pfile, CPP_DL_PEDWARN,
    cpp_error (pfile, CPP_DL_PEDWARN,
               "binary constants are a GCC extension");
               "binary constants are a GCC extension");
 
 
  if (radix == 10)
  if (radix == 10)
    result |= CPP_N_DECIMAL;
    result |= CPP_N_DECIMAL;
  else if (radix == 16)
  else if (radix == 16)
    result |= CPP_N_HEX;
    result |= CPP_N_HEX;
  else if (radix == 2)
  else if (radix == 2)
    result |= CPP_N_BINARY;
    result |= CPP_N_BINARY;
  else
  else
    result |= CPP_N_OCTAL;
    result |= CPP_N_OCTAL;
 
 
  return result;
  return result;
 
 
 syntax_error:
 syntax_error:
  return CPP_N_INVALID;
  return CPP_N_INVALID;
}
}
 
 
/* cpp_interpret_integer converts an integer constant into a cpp_num,
/* cpp_interpret_integer converts an integer constant into a cpp_num,
   of precision options->precision.
   of precision options->precision.
 
 
   We do not provide any interface for decimal->float conversion,
   We do not provide any interface for decimal->float conversion,
   because the preprocessor doesn't need it and we don't want to
   because the preprocessor doesn't need it and we don't want to
   drag in GCC's floating point emulator.  */
   drag in GCC's floating point emulator.  */
cpp_num
cpp_num
cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
                       unsigned int type)
                       unsigned int type)
{
{
  const uchar *p, *end;
  const uchar *p, *end;
  cpp_num result;
  cpp_num result;
 
 
  result.low = 0;
  result.low = 0;
  result.high = 0;
  result.high = 0;
  result.unsignedp = !!(type & CPP_N_UNSIGNED);
  result.unsignedp = !!(type & CPP_N_UNSIGNED);
  result.overflow = false;
  result.overflow = false;
 
 
  p = token->val.str.text;
  p = token->val.str.text;
  end = p + token->val.str.len;
  end = p + token->val.str.len;
 
 
  /* Common case of a single digit.  */
  /* Common case of a single digit.  */
  if (token->val.str.len == 1)
  if (token->val.str.len == 1)
    result.low = p[0] - '0';
    result.low = p[0] - '0';
  else
  else
    {
    {
      cpp_num_part max;
      cpp_num_part max;
      size_t precision = CPP_OPTION (pfile, precision);
      size_t precision = CPP_OPTION (pfile, precision);
      unsigned int base = 10, c = 0;
      unsigned int base = 10, c = 0;
      bool overflow = false;
      bool overflow = false;
 
 
      if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
      if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
        {
        {
          base = 8;
          base = 8;
          p++;
          p++;
        }
        }
      else if ((type & CPP_N_RADIX) == CPP_N_HEX)
      else if ((type & CPP_N_RADIX) == CPP_N_HEX)
        {
        {
          base = 16;
          base = 16;
          p += 2;
          p += 2;
        }
        }
      else if ((type & CPP_N_RADIX) == CPP_N_BINARY)
      else if ((type & CPP_N_RADIX) == CPP_N_BINARY)
        {
        {
          base = 2;
          base = 2;
          p += 2;
          p += 2;
        }
        }
 
 
      /* We can add a digit to numbers strictly less than this without
      /* We can add a digit to numbers strictly less than this without
         needing the precision and slowness of double integers.  */
         needing the precision and slowness of double integers.  */
      max = ~(cpp_num_part) 0;
      max = ~(cpp_num_part) 0;
      if (precision < PART_PRECISION)
      if (precision < PART_PRECISION)
        max >>= PART_PRECISION - precision;
        max >>= PART_PRECISION - precision;
      max = (max - base + 1) / base + 1;
      max = (max - base + 1) / base + 1;
 
 
      for (; p < end; p++)
      for (; p < end; p++)
        {
        {
          c = *p;
          c = *p;
 
 
          if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
          if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
            c = hex_value (c);
            c = hex_value (c);
          else
          else
            break;
            break;
 
 
          /* Strict inequality for when max is set to zero.  */
          /* Strict inequality for when max is set to zero.  */
          if (result.low < max)
          if (result.low < max)
            result.low = result.low * base + c;
            result.low = result.low * base + c;
          else
          else
            {
            {
              result = append_digit (result, c, base, precision);
              result = append_digit (result, c, base, precision);
              overflow |= result.overflow;
              overflow |= result.overflow;
              max = 0;
              max = 0;
            }
            }
        }
        }
 
 
      if (overflow)
      if (overflow)
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "integer constant is too large for its type");
                   "integer constant is too large for its type");
      /* If too big to be signed, consider it unsigned.  Only warn for
      /* If too big to be signed, consider it unsigned.  Only warn for
         decimal numbers.  Traditional numbers were always signed (but
         decimal numbers.  Traditional numbers were always signed (but
         we still honor an explicit U suffix); but we only have
         we still honor an explicit U suffix); but we only have
         traditional semantics in directives.  */
         traditional semantics in directives.  */
      else if (!result.unsignedp
      else if (!result.unsignedp
               && !(CPP_OPTION (pfile, traditional)
               && !(CPP_OPTION (pfile, traditional)
                    && pfile->state.in_directive)
                    && pfile->state.in_directive)
               && !num_positive (result, precision))
               && !num_positive (result, precision))
        {
        {
          /* This is for constants within the range of uintmax_t but
          /* This is for constants within the range of uintmax_t but
             not that of intmax_t.  For such decimal constants, a
             not that of intmax_t.  For such decimal constants, a
             diagnostic is required for C99 as the selected type must
             diagnostic is required for C99 as the selected type must
             be signed and not having a type is a constraint violation
             be signed and not having a type is a constraint violation
             (DR#298, TC3), so this must be a pedwarn.  For C90,
             (DR#298, TC3), so this must be a pedwarn.  For C90,
             unsigned long is specified to be used for a constant that
             unsigned long is specified to be used for a constant that
             does not fit in signed long; if uintmax_t has the same
             does not fit in signed long; if uintmax_t has the same
             range as unsigned long this means only a warning is
             range as unsigned long this means only a warning is
             appropriate here.  C90 permits the preprocessor to use a
             appropriate here.  C90 permits the preprocessor to use a
             wider range than unsigned long in the compiler, so if
             wider range than unsigned long in the compiler, so if
             uintmax_t is wider than unsigned long no diagnostic is
             uintmax_t is wider than unsigned long no diagnostic is
             required for such constants in preprocessor #if
             required for such constants in preprocessor #if
             expressions and the compiler will pedwarn for such
             expressions and the compiler will pedwarn for such
             constants outside the range of unsigned long that reach
             constants outside the range of unsigned long that reach
             the compiler so a diagnostic is not required there
             the compiler so a diagnostic is not required there
             either; thus, pedwarn for C99 but use a plain warning for
             either; thus, pedwarn for C99 but use a plain warning for
             C90.  */
             C90.  */
          if (base == 10)
          if (base == 10)
            cpp_error (pfile, (CPP_OPTION (pfile, c99)
            cpp_error (pfile, (CPP_OPTION (pfile, c99)
                               ? CPP_DL_PEDWARN
                               ? CPP_DL_PEDWARN
                               : CPP_DL_WARNING),
                               : CPP_DL_WARNING),
                       "integer constant is so large that it is unsigned");
                       "integer constant is so large that it is unsigned");
          result.unsignedp = true;
          result.unsignedp = true;
        }
        }
    }
    }
 
 
  return result;
  return result;
}
}
 
 
/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE.  */
/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE.  */
static cpp_num
static cpp_num
append_digit (cpp_num num, int digit, int base, size_t precision)
append_digit (cpp_num num, int digit, int base, size_t precision)
{
{
  cpp_num result;
  cpp_num result;
  unsigned int shift;
  unsigned int shift;
  bool overflow;
  bool overflow;
  cpp_num_part add_high, add_low;
  cpp_num_part add_high, add_low;
 
 
  /* Multiply by 2, 8 or 16.  Catching this overflow here means we don't
  /* Multiply by 2, 8 or 16.  Catching this overflow here means we don't
     need to worry about add_high overflowing.  */
     need to worry about add_high overflowing.  */
  switch (base)
  switch (base)
    {
    {
    case 2:
    case 2:
      shift = 1;
      shift = 1;
      break;
      break;
 
 
    case 16:
    case 16:
      shift = 4;
      shift = 4;
      break;
      break;
 
 
    default:
    default:
      shift = 3;
      shift = 3;
    }
    }
  overflow = !!(num.high >> (PART_PRECISION - shift));
  overflow = !!(num.high >> (PART_PRECISION - shift));
  result.high = num.high << shift;
  result.high = num.high << shift;
  result.low = num.low << shift;
  result.low = num.low << shift;
  result.high |= num.low >> (PART_PRECISION - shift);
  result.high |= num.low >> (PART_PRECISION - shift);
  result.unsignedp = num.unsignedp;
  result.unsignedp = num.unsignedp;
 
 
  if (base == 10)
  if (base == 10)
    {
    {
      add_low = num.low << 1;
      add_low = num.low << 1;
      add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
      add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
    }
    }
  else
  else
    add_high = add_low = 0;
    add_high = add_low = 0;
 
 
  if (add_low + digit < add_low)
  if (add_low + digit < add_low)
    add_high++;
    add_high++;
  add_low += digit;
  add_low += digit;
 
 
  if (result.low + add_low < result.low)
  if (result.low + add_low < result.low)
    add_high++;
    add_high++;
  if (result.high + add_high < result.high)
  if (result.high + add_high < result.high)
    overflow = true;
    overflow = true;
 
 
  result.low += add_low;
  result.low += add_low;
  result.high += add_high;
  result.high += add_high;
  result.overflow = overflow;
  result.overflow = overflow;
 
 
  /* The above code catches overflow of a cpp_num type.  This catches
  /* The above code catches overflow of a cpp_num type.  This catches
     overflow of the (possibly shorter) target precision.  */
     overflow of the (possibly shorter) target precision.  */
  num.low = result.low;
  num.low = result.low;
  num.high = result.high;
  num.high = result.high;
  result = num_trim (result, precision);
  result = num_trim (result, precision);
  if (!num_eq (result, num))
  if (!num_eq (result, num))
    result.overflow = true;
    result.overflow = true;
 
 
  return result;
  return result;
}
}
 
 
/* Handle meeting "defined" in a preprocessor expression.  */
/* Handle meeting "defined" in a preprocessor expression.  */
static cpp_num
static cpp_num
parse_defined (cpp_reader *pfile)
parse_defined (cpp_reader *pfile)
{
{
  cpp_num result;
  cpp_num result;
  int paren = 0;
  int paren = 0;
  cpp_hashnode *node = 0;
  cpp_hashnode *node = 0;
  const cpp_token *token;
  const cpp_token *token;
  cpp_context *initial_context = pfile->context;
  cpp_context *initial_context = pfile->context;
 
 
  /* Don't expand macros.  */
  /* Don't expand macros.  */
  pfile->state.prevent_expansion++;
  pfile->state.prevent_expansion++;
 
 
  token = cpp_get_token (pfile);
  token = cpp_get_token (pfile);
  if (token->type == CPP_OPEN_PAREN)
  if (token->type == CPP_OPEN_PAREN)
    {
    {
      paren = 1;
      paren = 1;
      token = cpp_get_token (pfile);
      token = cpp_get_token (pfile);
    }
    }
 
 
  if (token->type == CPP_NAME)
  if (token->type == CPP_NAME)
    {
    {
      node = token->val.node.node;
      node = token->val.node.node;
      if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
      if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
        {
        {
          cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
          cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
          node = 0;
          node = 0;
        }
        }
    }
    }
  else
  else
    {
    {
      cpp_error (pfile, CPP_DL_ERROR,
      cpp_error (pfile, CPP_DL_ERROR,
                 "operator \"defined\" requires an identifier");
                 "operator \"defined\" requires an identifier");
      if (token->flags & NAMED_OP)
      if (token->flags & NAMED_OP)
        {
        {
          cpp_token op;
          cpp_token op;
 
 
          op.flags = 0;
          op.flags = 0;
          op.type = token->type;
          op.type = token->type;
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "(\"%s\" is an alternative token for \"%s\" in C++)",
                     "(\"%s\" is an alternative token for \"%s\" in C++)",
                     cpp_token_as_text (pfile, token),
                     cpp_token_as_text (pfile, token),
                     cpp_token_as_text (pfile, &op));
                     cpp_token_as_text (pfile, &op));
        }
        }
    }
    }
 
 
  if (node)
  if (node)
    {
    {
      if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
      if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
        cpp_error (pfile, CPP_DL_WARNING,
        cpp_error (pfile, CPP_DL_WARNING,
                   "this use of \"defined\" may not be portable");
                   "this use of \"defined\" may not be portable");
 
 
      _cpp_mark_macro_used (node);
      _cpp_mark_macro_used (node);
      if (!(node->flags & NODE_USED))
      if (!(node->flags & NODE_USED))
        {
        {
          node->flags |= NODE_USED;
          node->flags |= NODE_USED;
          if (node->type == NT_MACRO)
          if (node->type == NT_MACRO)
            {
            {
              if (pfile->cb.used_define)
              if (pfile->cb.used_define)
                pfile->cb.used_define (pfile, pfile->directive_line, node);
                pfile->cb.used_define (pfile, pfile->directive_line, node);
            }
            }
          else
          else
            {
            {
              if (pfile->cb.used_undef)
              if (pfile->cb.used_undef)
                pfile->cb.used_undef (pfile, pfile->directive_line, node);
                pfile->cb.used_undef (pfile, pfile->directive_line, node);
            }
            }
        }
        }
 
 
      /* A possible controlling macro of the form #if !defined ().
      /* A possible controlling macro of the form #if !defined ().
         _cpp_parse_expr checks there was no other junk on the line.  */
         _cpp_parse_expr checks there was no other junk on the line.  */
      pfile->mi_ind_cmacro = node;
      pfile->mi_ind_cmacro = node;
    }
    }
 
 
  pfile->state.prevent_expansion--;
  pfile->state.prevent_expansion--;
 
 
  result.unsignedp = false;
  result.unsignedp = false;
  result.high = 0;
  result.high = 0;
  result.overflow = false;
  result.overflow = false;
  result.low = node && node->type == NT_MACRO;
  result.low = node && node->type == NT_MACRO;
  return result;
  return result;
}
}
 
 
/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
   number or character constant, or the result of the "defined" or "#"
   number or character constant, or the result of the "defined" or "#"
   operators).  */
   operators).  */
static cpp_num
static cpp_num
eval_token (cpp_reader *pfile, const cpp_token *token)
eval_token (cpp_reader *pfile, const cpp_token *token)
{
{
  cpp_num result;
  cpp_num result;
  unsigned int temp;
  unsigned int temp;
  int unsignedp = 0;
  int unsignedp = 0;
 
 
  result.unsignedp = false;
  result.unsignedp = false;
  result.overflow = false;
  result.overflow = false;
 
 
  switch (token->type)
  switch (token->type)
    {
    {
    case CPP_NUMBER:
    case CPP_NUMBER:
      temp = cpp_classify_number (pfile, token);
      temp = cpp_classify_number (pfile, token);
      switch (temp & CPP_N_CATEGORY)
      switch (temp & CPP_N_CATEGORY)
        {
        {
        case CPP_N_FLOATING:
        case CPP_N_FLOATING:
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "floating constant in preprocessor expression");
                     "floating constant in preprocessor expression");
          break;
          break;
        case CPP_N_INTEGER:
        case CPP_N_INTEGER:
          if (!(temp & CPP_N_IMAGINARY))
          if (!(temp & CPP_N_IMAGINARY))
            return cpp_interpret_integer (pfile, token, temp);
            return cpp_interpret_integer (pfile, token, temp);
          cpp_error (pfile, CPP_DL_ERROR,
          cpp_error (pfile, CPP_DL_ERROR,
                     "imaginary number in preprocessor expression");
                     "imaginary number in preprocessor expression");
          break;
          break;
 
 
        case CPP_N_INVALID:
        case CPP_N_INVALID:
          /* Error already issued.  */
          /* Error already issued.  */
          break;
          break;
        }
        }
      result.high = result.low = 0;
      result.high = result.low = 0;
      break;
      break;
 
 
    case CPP_WCHAR:
    case CPP_WCHAR:
    case CPP_CHAR:
    case CPP_CHAR:
    case CPP_CHAR16:
    case CPP_CHAR16:
    case CPP_CHAR32:
    case CPP_CHAR32:
      {
      {
        cppchar_t cc = cpp_interpret_charconst (pfile, token,
        cppchar_t cc = cpp_interpret_charconst (pfile, token,
                                                &temp, &unsignedp);
                                                &temp, &unsignedp);
 
 
        result.high = 0;
        result.high = 0;
        result.low = cc;
        result.low = cc;
        /* Sign-extend the result if necessary.  */
        /* Sign-extend the result if necessary.  */
        if (!unsignedp && (cppchar_signed_t) cc < 0)
        if (!unsignedp && (cppchar_signed_t) cc < 0)
          {
          {
            if (PART_PRECISION > BITS_PER_CPPCHAR_T)
            if (PART_PRECISION > BITS_PER_CPPCHAR_T)
              result.low |= ~(~(cpp_num_part) 0
              result.low |= ~(~(cpp_num_part) 0
                              >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
                              >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
            result.high = ~(cpp_num_part) 0;
            result.high = ~(cpp_num_part) 0;
            result = num_trim (result, CPP_OPTION (pfile, precision));
            result = num_trim (result, CPP_OPTION (pfile, precision));
          }
          }
      }
      }
      break;
      break;
 
 
    case CPP_NAME:
    case CPP_NAME:
      if (token->val.node.node == pfile->spec_nodes.n_defined)
      if (token->val.node.node == pfile->spec_nodes.n_defined)
        return parse_defined (pfile);
        return parse_defined (pfile);
      else if (CPP_OPTION (pfile, cplusplus)
      else if (CPP_OPTION (pfile, cplusplus)
               && (token->val.node.node == pfile->spec_nodes.n_true
               && (token->val.node.node == pfile->spec_nodes.n_true
                   || token->val.node.node == pfile->spec_nodes.n_false))
                   || token->val.node.node == pfile->spec_nodes.n_false))
        {
        {
          result.high = 0;
          result.high = 0;
          result.low = (token->val.node.node == pfile->spec_nodes.n_true);
          result.low = (token->val.node.node == pfile->spec_nodes.n_true);
        }
        }
      else
      else
        {
        {
          result.high = 0;
          result.high = 0;
          result.low = 0;
          result.low = 0;
          if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
          if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
            cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
            cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
                       NODE_NAME (token->val.node.node));
                       NODE_NAME (token->val.node.node));
        }
        }
      break;
      break;
 
 
    case CPP_HASH:
    case CPP_HASH:
      if (!pfile->state.skipping)
      if (!pfile->state.skipping)
        {
        {
          /* A pedantic warning takes precedence over a deprecated
          /* A pedantic warning takes precedence over a deprecated
             warning here.  */
             warning here.  */
          if (CPP_PEDANTIC (pfile))
          if (CPP_PEDANTIC (pfile))
            cpp_error (pfile, CPP_DL_PEDWARN,
            cpp_error (pfile, CPP_DL_PEDWARN,
                       "assertions are a GCC extension");
                       "assertions are a GCC extension");
          else if (CPP_OPTION (pfile, warn_deprecated))
          else if (CPP_OPTION (pfile, warn_deprecated))
            cpp_error (pfile, CPP_DL_WARNING,
            cpp_error (pfile, CPP_DL_WARNING,
                       "assertions are a deprecated extension");
                       "assertions are a deprecated extension");
        }
        }
      _cpp_test_assertion (pfile, &temp);
      _cpp_test_assertion (pfile, &temp);
      result.high = 0;
      result.high = 0;
      result.low = temp;
      result.low = temp;
      break;
      break;
 
 
    default:
    default:
      abort ();
      abort ();
    }
    }
 
 
  result.unsignedp = !!unsignedp;
  result.unsignedp = !!unsignedp;
  return result;
  return result;
}
}


/* Operator precedence and flags table.
/* Operator precedence and flags table.
 
 
After an operator is returned from the lexer, if it has priority less
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
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,
operator and repeat the test.  Since equal priorities do not reduce,
this is naturally right-associative.
this is naturally right-associative.
 
 
We handle left-associative operators by decrementing the priority of
We handle left-associative operators by decrementing the priority of
just-lexed operators by one, but retaining the priority of operators
just-lexed operators by one, but retaining the priority of operators
already on the stack.
already on the stack.
 
 
The remaining cases are '(' and ')'.  We handle '(' by skipping the
The remaining cases are '(' and ')'.  We handle '(' by skipping the
reduction phase completely.  ')' is given lower priority than
reduction phase completely.  ')' is given lower priority than
everything else, including '(', effectively forcing a reduction of the
everything else, including '(', effectively forcing a reduction of the
parenthesized expression.  If there is a matching '(', the routine
parenthesized expression.  If there is a matching '(', the routine
reduce() exits immediately.  If the normal exit route sees a ')', then
reduce() exits immediately.  If the normal exit route sees a ')', then
there cannot have been a matching '(' and an error message is output.
there cannot have been a matching '(' and an error message is output.
 
 
The parser assumes all shifted operators require a left operand unless
The parser assumes all shifted operators require a left operand unless
the flag NO_L_OPERAND is set.  These semantics are automatic; any
the flag NO_L_OPERAND is set.  These semantics are automatic; any
extra semantics need to be handled with operator-specific code.  */
extra semantics need to be handled with operator-specific code.  */
 
 
/* Flags.  If CHECK_PROMOTION, we warn if the effective sign of an
/* Flags.  If CHECK_PROMOTION, we warn if the effective sign of an
   operand changes because of integer promotions.  */
   operand changes because of integer promotions.  */
#define NO_L_OPERAND    (1 << 0)
#define NO_L_OPERAND    (1 << 0)
#define LEFT_ASSOC      (1 << 1)
#define LEFT_ASSOC      (1 << 1)
#define CHECK_PROMOTION (1 << 2)
#define CHECK_PROMOTION (1 << 2)
 
 
/* Operator to priority map.  Must be in the same order as the first
/* Operator to priority map.  Must be in the same order as the first
   N entries of enum cpp_ttype.  */
   N entries of enum cpp_ttype.  */
static const struct cpp_operator
static const struct cpp_operator
{
{
  uchar prio;
  uchar prio;
  uchar flags;
  uchar flags;
} optab[] =
} optab[] =
{
{
  /* EQ */              {0, 0},   /* Shouldn't happen.  */
  /* EQ */              {0, 0},   /* Shouldn't happen.  */
  /* NOT */             {16, NO_L_OPERAND},
  /* NOT */             {16, NO_L_OPERAND},
  /* GREATER */         {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* GREATER */         {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* LESS */            {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* LESS */            {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* PLUS */            {14, LEFT_ASSOC | CHECK_PROMOTION},
  /* PLUS */            {14, LEFT_ASSOC | CHECK_PROMOTION},
  /* MINUS */           {14, LEFT_ASSOC | CHECK_PROMOTION},
  /* MINUS */           {14, LEFT_ASSOC | CHECK_PROMOTION},
  /* MULT */            {15, LEFT_ASSOC | CHECK_PROMOTION},
  /* MULT */            {15, LEFT_ASSOC | CHECK_PROMOTION},
  /* DIV */             {15, LEFT_ASSOC | CHECK_PROMOTION},
  /* DIV */             {15, LEFT_ASSOC | CHECK_PROMOTION},
  /* MOD */             {15, LEFT_ASSOC | CHECK_PROMOTION},
  /* MOD */             {15, LEFT_ASSOC | CHECK_PROMOTION},
  /* AND */             {9, LEFT_ASSOC | CHECK_PROMOTION},
  /* AND */             {9, LEFT_ASSOC | CHECK_PROMOTION},
  /* OR */              {7, LEFT_ASSOC | CHECK_PROMOTION},
  /* OR */              {7, LEFT_ASSOC | CHECK_PROMOTION},
  /* XOR */             {8, LEFT_ASSOC | CHECK_PROMOTION},
  /* XOR */             {8, LEFT_ASSOC | CHECK_PROMOTION},
  /* RSHIFT */          {13, LEFT_ASSOC},
  /* RSHIFT */          {13, LEFT_ASSOC},
  /* LSHIFT */          {13, LEFT_ASSOC},
  /* LSHIFT */          {13, LEFT_ASSOC},
 
 
  /* COMPL */           {16, NO_L_OPERAND},
  /* COMPL */           {16, NO_L_OPERAND},
  /* AND_AND */         {6, LEFT_ASSOC},
  /* AND_AND */         {6, LEFT_ASSOC},
  /* OR_OR */           {5, LEFT_ASSOC},
  /* OR_OR */           {5, LEFT_ASSOC},
  /* Note that QUERY, COLON, and COMMA must have the same precedence.
  /* Note that QUERY, COLON, and COMMA must have the same precedence.
     However, there are some special cases for these in reduce().  */
     However, there are some special cases for these in reduce().  */
  /* QUERY */           {4, 0},
  /* QUERY */           {4, 0},
  /* COLON */           {4, LEFT_ASSOC | CHECK_PROMOTION},
  /* COLON */           {4, LEFT_ASSOC | CHECK_PROMOTION},
  /* COMMA */           {4, LEFT_ASSOC},
  /* COMMA */           {4, LEFT_ASSOC},
  /* OPEN_PAREN */      {1, NO_L_OPERAND},
  /* OPEN_PAREN */      {1, NO_L_OPERAND},
  /* CLOSE_PAREN */     {0, 0},
  /* CLOSE_PAREN */     {0, 0},
  /* EOF */             {0, 0},
  /* EOF */             {0, 0},
  /* EQ_EQ */           {11, LEFT_ASSOC},
  /* EQ_EQ */           {11, LEFT_ASSOC},
  /* NOT_EQ */          {11, LEFT_ASSOC},
  /* NOT_EQ */          {11, LEFT_ASSOC},
  /* GREATER_EQ */      {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* GREATER_EQ */      {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* LESS_EQ */         {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* LESS_EQ */         {12, LEFT_ASSOC | CHECK_PROMOTION},
  /* UPLUS */           {16, NO_L_OPERAND},
  /* UPLUS */           {16, NO_L_OPERAND},
  /* UMINUS */          {16, NO_L_OPERAND}
  /* UMINUS */          {16, NO_L_OPERAND}
};
};
 
 
/* Parse and evaluate a C expression, reading from PFILE.
/* Parse and evaluate a C expression, reading from PFILE.
   Returns the truth value of the expression.
   Returns the truth value of the expression.
 
 
   The implementation is an operator precedence parser, i.e. a
   The implementation is an operator precedence parser, i.e. a
   bottom-up parser, using a stack for not-yet-reduced tokens.
   bottom-up parser, using a stack for not-yet-reduced tokens.
 
 
   The stack base is op_stack, and the current stack pointer is 'top'.
   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
   There is a stack element for each operator (only), and the most
   recently pushed operator is 'top->op'.  An operand (value) is
   recently pushed operator is 'top->op'.  An operand (value) is
   stored in the 'value' field of the stack element of the operator
   stored in the 'value' field of the stack element of the operator
   that precedes it.  */
   that precedes it.  */
bool
bool
_cpp_parse_expr (cpp_reader *pfile, bool is_if)
_cpp_parse_expr (cpp_reader *pfile, bool is_if)
{
{
  struct op *top = pfile->op_stack;
  struct op *top = pfile->op_stack;
  unsigned int lex_count;
  unsigned int lex_count;
  bool saw_leading_not, want_value = true;
  bool saw_leading_not, want_value = true;
 
 
  pfile->state.skip_eval = 0;
  pfile->state.skip_eval = 0;
 
 
  /* Set up detection of #if ! defined().  */
  /* Set up detection of #if ! defined().  */
  pfile->mi_ind_cmacro = 0;
  pfile->mi_ind_cmacro = 0;
  saw_leading_not = false;
  saw_leading_not = false;
  lex_count = 0;
  lex_count = 0;
 
 
  /* Lowest priority operator prevents further reductions.  */
  /* Lowest priority operator prevents further reductions.  */
  top->op = CPP_EOF;
  top->op = CPP_EOF;
 
 
  for (;;)
  for (;;)
    {
    {
      struct op op;
      struct op op;
 
 
      lex_count++;
      lex_count++;
      op.token = cpp_get_token (pfile);
      op.token = cpp_get_token (pfile);
      op.op = op.token->type;
      op.op = op.token->type;
      op.loc = op.token->src_loc;
      op.loc = op.token->src_loc;
 
 
      switch (op.op)
      switch (op.op)
        {
        {
          /* These tokens convert into values.  */
          /* These tokens convert into values.  */
        case CPP_NUMBER:
        case CPP_NUMBER:
        case CPP_CHAR:
        case CPP_CHAR:
        case CPP_WCHAR:
        case CPP_WCHAR:
        case CPP_CHAR16:
        case CPP_CHAR16:
        case CPP_CHAR32:
        case CPP_CHAR32:
        case CPP_NAME:
        case CPP_NAME:
        case CPP_HASH:
        case CPP_HASH:
          if (!want_value)
          if (!want_value)
            SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
            SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
                           cpp_token_as_text (pfile, op.token));
                           cpp_token_as_text (pfile, op.token));
          want_value = false;
          want_value = false;
          top->value = eval_token (pfile, op.token);
          top->value = eval_token (pfile, op.token);
          continue;
          continue;
 
 
        case CPP_NOT:
        case CPP_NOT:
          saw_leading_not = lex_count == 1;
          saw_leading_not = lex_count == 1;
          break;
          break;
        case CPP_PLUS:
        case CPP_PLUS:
          if (want_value)
          if (want_value)
            op.op = CPP_UPLUS;
            op.op = CPP_UPLUS;
          break;
          break;
        case CPP_MINUS:
        case CPP_MINUS:
          if (want_value)
          if (want_value)
            op.op = CPP_UMINUS;
            op.op = CPP_UMINUS;
          break;
          break;
 
 
        default:
        default:
          if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
          if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
            SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
            SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
                           cpp_token_as_text (pfile, op.token));
                           cpp_token_as_text (pfile, op.token));
          break;
          break;
        }
        }
 
 
      /* Check we have a value or operator as appropriate.  */
      /* Check we have a value or operator as appropriate.  */
      if (optab[op.op].flags & NO_L_OPERAND)
      if (optab[op.op].flags & NO_L_OPERAND)
        {
        {
          if (!want_value)
          if (!want_value)
            SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
            SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
                           cpp_token_as_text (pfile, op.token));
                           cpp_token_as_text (pfile, op.token));
        }
        }
      else if (want_value)
      else if (want_value)
        {
        {
          /* We want a number (or expression) and haven't got one.
          /* We want a number (or expression) and haven't got one.
             Try to emit a specific diagnostic.  */
             Try to emit a specific diagnostic.  */
          if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN)
          if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN)
            SYNTAX_ERROR ("missing expression between '(' and ')'");
            SYNTAX_ERROR ("missing expression between '(' and ')'");
 
 
          if (op.op == CPP_EOF && top->op == CPP_EOF)
          if (op.op == CPP_EOF && top->op == CPP_EOF)
            SYNTAX_ERROR2 ("%s with no expression", is_if ? "#if" : "#elif");
            SYNTAX_ERROR2 ("%s with no expression", is_if ? "#if" : "#elif");
 
 
          if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
          if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
            SYNTAX_ERROR2 ("operator '%s' has no right operand",
            SYNTAX_ERROR2 ("operator '%s' has no right operand",
                           cpp_token_as_text (pfile, top->token));
                           cpp_token_as_text (pfile, top->token));
          else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF)
          else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF)
            /* Complain about missing paren during reduction.  */;
            /* Complain about missing paren during reduction.  */;
          else
          else
            SYNTAX_ERROR2 ("operator '%s' has no left operand",
            SYNTAX_ERROR2 ("operator '%s' has no left operand",
                           cpp_token_as_text (pfile, op.token));
                           cpp_token_as_text (pfile, op.token));
        }
        }
 
 
      top = reduce (pfile, top, op.op);
      top = reduce (pfile, top, op.op);
      if (!top)
      if (!top)
        goto syntax_error;
        goto syntax_error;
 
 
      if (op.op == CPP_EOF)
      if (op.op == CPP_EOF)
        break;
        break;
 
 
      switch (op.op)
      switch (op.op)
        {
        {
        case CPP_CLOSE_PAREN:
        case CPP_CLOSE_PAREN:
          continue;
          continue;
        case CPP_OR_OR:
        case CPP_OR_OR:
          if (!num_zerop (top->value))
          if (!num_zerop (top->value))
            pfile->state.skip_eval++;
            pfile->state.skip_eval++;
          break;
          break;
        case CPP_AND_AND:
        case CPP_AND_AND:
        case CPP_QUERY:
        case CPP_QUERY:
          if (num_zerop (top->value))
          if (num_zerop (top->value))
            pfile->state.skip_eval++;
            pfile->state.skip_eval++;
          break;
          break;
        case CPP_COLON:
        case CPP_COLON:
          if (top->op != CPP_QUERY)
          if (top->op != CPP_QUERY)
            SYNTAX_ERROR (" ':' without preceding '?'");
            SYNTAX_ERROR (" ':' without preceding '?'");
          if (!num_zerop (top[-1].value)) /* Was '?' condition true?  */
          if (!num_zerop (top[-1].value)) /* Was '?' condition true?  */
            pfile->state.skip_eval++;
            pfile->state.skip_eval++;
          else
          else
            pfile->state.skip_eval--;
            pfile->state.skip_eval--;
        default:
        default:
          break;
          break;
        }
        }
 
 
      want_value = true;
      want_value = true;
 
 
      /* Check for and handle stack overflow.  */
      /* Check for and handle stack overflow.  */
      if (++top == pfile->op_limit)
      if (++top == pfile->op_limit)
        top = _cpp_expand_op_stack (pfile);
        top = _cpp_expand_op_stack (pfile);
 
 
      top->op = op.op;
      top->op = op.op;
      top->token = op.token;
      top->token = op.token;
      top->loc = op.token->src_loc;
      top->loc = op.token->src_loc;
    }
    }
 
 
  /* The controlling macro expression is only valid if we called lex 3
  /* The controlling macro expression is only valid if we called lex 3
     times: <!> <defined expression> and <EOF>.  push_conditional ()
     times: <!> <defined expression> and <EOF>.  push_conditional ()
     checks that we are at top-of-file.  */
     checks that we are at top-of-file.  */
  if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
  if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
    pfile->mi_ind_cmacro = 0;
    pfile->mi_ind_cmacro = 0;
 
 
  if (top != pfile->op_stack)
  if (top != pfile->op_stack)
    {
    {
      cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in %s",
      cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in %s",
                 is_if ? "#if" : "#elif");
                 is_if ? "#if" : "#elif");
    syntax_error:
    syntax_error:
      return false;  /* Return false on syntax error.  */
      return false;  /* Return false on syntax error.  */
    }
    }
 
 
  return !num_zerop (top->value);
  return !num_zerop (top->value);
}
}
 
 
/* Reduce the operator / value stack if possible, in preparation for
/* Reduce the operator / value stack if possible, in preparation for
   pushing operator OP.  Returns NULL on error, otherwise the top of
   pushing operator OP.  Returns NULL on error, otherwise the top of
   the stack.  */
   the stack.  */
static struct op *
static struct op *
reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op)
reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op)
{
{
  unsigned int prio;
  unsigned int prio;
 
 
  if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
  if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
    {
    {
    bad_op:
    bad_op:
      cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op);
      cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op);
      return 0;
      return 0;
    }
    }
 
 
  if (op == CPP_OPEN_PAREN)
  if (op == CPP_OPEN_PAREN)
    return top;
    return top;
 
 
  /* Decrement the priority of left-associative operators to force a
  /* Decrement the priority of left-associative operators to force a
     reduction with operators of otherwise equal priority.  */
     reduction with operators of otherwise equal priority.  */
  prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
  prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
  while (prio < optab[top->op].prio)
  while (prio < optab[top->op].prio)
    {
    {
      if (CPP_OPTION (pfile, warn_num_sign_change)
      if (CPP_OPTION (pfile, warn_num_sign_change)
          && optab[top->op].flags & CHECK_PROMOTION)
          && optab[top->op].flags & CHECK_PROMOTION)
        check_promotion (pfile, top);
        check_promotion (pfile, top);
 
 
      switch (top->op)
      switch (top->op)
        {
        {
        case CPP_UPLUS:
        case CPP_UPLUS:
        case CPP_UMINUS:
        case CPP_UMINUS:
        case CPP_NOT:
        case CPP_NOT:
        case CPP_COMPL:
        case CPP_COMPL:
          top[-1].value = num_unary_op (pfile, top->value, top->op);
          top[-1].value = num_unary_op (pfile, top->value, top->op);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_PLUS:
        case CPP_PLUS:
        case CPP_MINUS:
        case CPP_MINUS:
        case CPP_RSHIFT:
        case CPP_RSHIFT:
        case CPP_LSHIFT:
        case CPP_LSHIFT:
        case CPP_COMMA:
        case CPP_COMMA:
          top[-1].value = num_binary_op (pfile, top[-1].value,
          top[-1].value = num_binary_op (pfile, top[-1].value,
                                         top->value, top->op);
                                         top->value, top->op);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_GREATER:
        case CPP_GREATER:
        case CPP_LESS:
        case CPP_LESS:
        case CPP_GREATER_EQ:
        case CPP_GREATER_EQ:
        case CPP_LESS_EQ:
        case CPP_LESS_EQ:
          top[-1].value
          top[-1].value
            = num_inequality_op (pfile, top[-1].value, top->value, top->op);
            = num_inequality_op (pfile, top[-1].value, top->value, top->op);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_EQ_EQ:
        case CPP_EQ_EQ:
        case CPP_NOT_EQ:
        case CPP_NOT_EQ:
          top[-1].value
          top[-1].value
            = num_equality_op (pfile, top[-1].value, top->value, top->op);
            = num_equality_op (pfile, top[-1].value, top->value, top->op);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_AND:
        case CPP_AND:
        case CPP_OR:
        case CPP_OR:
        case CPP_XOR:
        case CPP_XOR:
          top[-1].value
          top[-1].value
            = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
            = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_MULT:
        case CPP_MULT:
          top[-1].value = num_mul (pfile, top[-1].value, top->value);
          top[-1].value = num_mul (pfile, top[-1].value, top->value);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_DIV:
        case CPP_DIV:
        case CPP_MOD:
        case CPP_MOD:
          top[-1].value = num_div_op (pfile, top[-1].value,
          top[-1].value = num_div_op (pfile, top[-1].value,
                                      top->value, top->op, top->loc);
                                      top->value, top->op, top->loc);
          top[-1].loc = top->loc;
          top[-1].loc = top->loc;
          break;
          break;
 
 
        case CPP_OR_OR:
        case CPP_OR_OR:
          top--;
          top--;
          if (!num_zerop (top->value))
          if (!num_zerop (top->value))
            pfile->state.skip_eval--;
            pfile->state.skip_eval--;
          top->value.low = (!num_zerop (top->value)
          top->value.low = (!num_zerop (top->value)
                            || !num_zerop (top[1].value));
                            || !num_zerop (top[1].value));
          top->value.high = 0;
          top->value.high = 0;
          top->value.unsignedp = false;
          top->value.unsignedp = false;
          top->value.overflow = false;
          top->value.overflow = false;
          top->loc = top[1].loc;
          top->loc = top[1].loc;
          continue;
          continue;
 
 
        case CPP_AND_AND:
        case CPP_AND_AND:
          top--;
          top--;
          if (num_zerop (top->value))
          if (num_zerop (top->value))
            pfile->state.skip_eval--;
            pfile->state.skip_eval--;
          top->value.low = (!num_zerop (top->value)
          top->value.low = (!num_zerop (top->value)
                            && !num_zerop (top[1].value));
                            && !num_zerop (top[1].value));
          top->value.high = 0;
          top->value.high = 0;
          top->value.unsignedp = false;
          top->value.unsignedp = false;
          top->value.overflow = false;
          top->value.overflow = false;
          top->loc = top[1].loc;
          top->loc = top[1].loc;
          continue;
          continue;
 
 
        case CPP_OPEN_PAREN:
        case CPP_OPEN_PAREN:
          if (op != CPP_CLOSE_PAREN)
          if (op != CPP_CLOSE_PAREN)
            {
            {
              cpp_error_with_line (pfile, CPP_DL_ERROR,
              cpp_error_with_line (pfile, CPP_DL_ERROR,
                                   top->token->src_loc,
                                   top->token->src_loc,
                                   0, "missing ')' in expression");
                                   0, "missing ')' in expression");
              return 0;
              return 0;
            }
            }
          top--;
          top--;
          top->value = top[1].value;
          top->value = top[1].value;
          top->loc = top[1].loc;
          top->loc = top[1].loc;
          return top;
          return top;
 
 
        case CPP_COLON:
        case CPP_COLON:
          top -= 2;
          top -= 2;
          if (!num_zerop (top->value))
          if (!num_zerop (top->value))
            {
            {
              pfile->state.skip_eval--;
              pfile->state.skip_eval--;
              top->value = top[1].value;
              top->value = top[1].value;
              top->loc = top[1].loc;
              top->loc = top[1].loc;
            }
            }
          else
          else
            {
            {
              top->value = top[2].value;
              top->value = top[2].value;
              top->loc = top[2].loc;
              top->loc = top[2].loc;
            }
            }
          top->value.unsignedp = (top[1].value.unsignedp
          top->value.unsignedp = (top[1].value.unsignedp
                                  || top[2].value.unsignedp);
                                  || top[2].value.unsignedp);
          continue;
          continue;
 
 
        case CPP_QUERY:
        case CPP_QUERY:
          /* COMMA and COLON should not reduce a QUERY operator.  */
          /* COMMA and COLON should not reduce a QUERY operator.  */
          if (op == CPP_COMMA || op == CPP_COLON)
          if (op == CPP_COMMA || op == CPP_COLON)
            return top;
            return top;
          cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
          cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
          return 0;
          return 0;
 
 
        default:
        default:
          goto bad_op;
          goto bad_op;
        }
        }
 
 
      top--;
      top--;
      if (top->value.overflow && !pfile->state.skip_eval)
      if (top->value.overflow && !pfile->state.skip_eval)
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "integer overflow in preprocessor expression");
                   "integer overflow in preprocessor expression");
    }
    }
 
 
  if (op == CPP_CLOSE_PAREN)
  if (op == CPP_CLOSE_PAREN)
    {
    {
      cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
      cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
      return 0;
      return 0;
    }
    }
 
 
  return top;
  return top;
}
}
 
 
/* Returns the position of the old top of stack after expansion.  */
/* Returns the position of the old top of stack after expansion.  */
struct op *
struct op *
_cpp_expand_op_stack (cpp_reader *pfile)
_cpp_expand_op_stack (cpp_reader *pfile)
{
{
  size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
  size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
  size_t new_size = old_size * 2 + 20;
  size_t new_size = old_size * 2 + 20;
 
 
  pfile->op_stack = XRESIZEVEC (struct op, pfile->op_stack, new_size);
  pfile->op_stack = XRESIZEVEC (struct op, pfile->op_stack, new_size);
  pfile->op_limit = pfile->op_stack + new_size;
  pfile->op_limit = pfile->op_stack + new_size;
 
 
  return pfile->op_stack + old_size;
  return pfile->op_stack + old_size;
}
}
 
 
/* Emits a warning if the effective sign of either operand of OP
/* Emits a warning if the effective sign of either operand of OP
   changes because of integer promotions.  */
   changes because of integer promotions.  */
static void
static void
check_promotion (cpp_reader *pfile, const struct op *op)
check_promotion (cpp_reader *pfile, const struct op *op)
{
{
  if (op->value.unsignedp == op[-1].value.unsignedp)
  if (op->value.unsignedp == op[-1].value.unsignedp)
    return;
    return;
 
 
  if (op->value.unsignedp)
  if (op->value.unsignedp)
    {
    {
      if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
      if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
        cpp_error_with_line (pfile, CPP_DL_WARNING, op[-1].loc, 0,
        cpp_error_with_line (pfile, CPP_DL_WARNING, op[-1].loc, 0,
                             "the left operand of \"%s\" changes sign when promoted",
                             "the left operand of \"%s\" changes sign when promoted",
                             cpp_token_as_text (pfile, op->token));
                             cpp_token_as_text (pfile, op->token));
    }
    }
  else if (!num_positive (op->value, CPP_OPTION (pfile, precision)))
  else if (!num_positive (op->value, CPP_OPTION (pfile, precision)))
    cpp_error_with_line (pfile, CPP_DL_WARNING, op->loc, 0,
    cpp_error_with_line (pfile, CPP_DL_WARNING, op->loc, 0,
               "the right operand of \"%s\" changes sign when promoted",
               "the right operand of \"%s\" changes sign when promoted",
               cpp_token_as_text (pfile, op->token));
               cpp_token_as_text (pfile, op->token));
}
}
 
 
/* Clears the unused high order bits of the number pointed to by PNUM.  */
/* Clears the unused high order bits of the number pointed to by PNUM.  */
static cpp_num
static cpp_num
num_trim (cpp_num num, size_t precision)
num_trim (cpp_num num, size_t precision)
{
{
  if (precision > PART_PRECISION)
  if (precision > PART_PRECISION)
    {
    {
      precision -= PART_PRECISION;
      precision -= PART_PRECISION;
      if (precision < PART_PRECISION)
      if (precision < PART_PRECISION)
        num.high &= ((cpp_num_part) 1 << precision) - 1;
        num.high &= ((cpp_num_part) 1 << precision) - 1;
    }
    }
  else
  else
    {
    {
      if (precision < PART_PRECISION)
      if (precision < PART_PRECISION)
        num.low &= ((cpp_num_part) 1 << precision) - 1;
        num.low &= ((cpp_num_part) 1 << precision) - 1;
      num.high = 0;
      num.high = 0;
    }
    }
 
 
  return num;
  return num;
}
}
 
 
/* True iff A (presumed signed) >= 0.  */
/* True iff A (presumed signed) >= 0.  */
static bool
static bool
num_positive (cpp_num num, size_t precision)
num_positive (cpp_num num, size_t precision)
{
{
  if (precision > PART_PRECISION)
  if (precision > PART_PRECISION)
    {
    {
      precision -= PART_PRECISION;
      precision -= PART_PRECISION;
      return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
      return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
    }
    }
 
 
  return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
  return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
}
}
 
 
/* Sign extend a number, with PRECISION significant bits and all
/* Sign extend a number, with PRECISION significant bits and all
   others assumed clear, to fill out a cpp_num structure.  */
   others assumed clear, to fill out a cpp_num structure.  */
cpp_num
cpp_num
cpp_num_sign_extend (cpp_num num, size_t precision)
cpp_num_sign_extend (cpp_num num, size_t precision)
{
{
  if (!num.unsignedp)
  if (!num.unsignedp)
    {
    {
      if (precision > PART_PRECISION)
      if (precision > PART_PRECISION)
        {
        {
          precision -= PART_PRECISION;
          precision -= PART_PRECISION;
          if (precision < PART_PRECISION
          if (precision < PART_PRECISION
              && (num.high & (cpp_num_part) 1 << (precision - 1)))
              && (num.high & (cpp_num_part) 1 << (precision - 1)))
            num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
            num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
        }
        }
      else if (num.low & (cpp_num_part) 1 << (precision - 1))
      else if (num.low & (cpp_num_part) 1 << (precision - 1))
        {
        {
          if (precision < PART_PRECISION)
          if (precision < PART_PRECISION)
            num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
            num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
          num.high = ~(cpp_num_part) 0;
          num.high = ~(cpp_num_part) 0;
        }
        }
    }
    }
 
 
  return num;
  return num;
}
}
 
 
/* Returns the negative of NUM.  */
/* Returns the negative of NUM.  */
static cpp_num
static cpp_num
num_negate (cpp_num num, size_t precision)
num_negate (cpp_num num, size_t precision)
{
{
  cpp_num copy;
  cpp_num copy;
 
 
  copy = num;
  copy = num;
  num.high = ~num.high;
  num.high = ~num.high;
  num.low = ~num.low;
  num.low = ~num.low;
  if (++num.low == 0)
  if (++num.low == 0)
    num.high++;
    num.high++;
  num = num_trim (num, precision);
  num = num_trim (num, precision);
  num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
  num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
 
 
  return num;
  return num;
}
}
 
 
/* Returns true if A >= B.  */
/* Returns true if A >= B.  */
static bool
static bool
num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
{
{
  bool unsignedp;
  bool unsignedp;
 
 
  unsignedp = pa.unsignedp || pb.unsignedp;
  unsignedp = pa.unsignedp || pb.unsignedp;
 
 
  if (!unsignedp)
  if (!unsignedp)
    {
    {
      /* Both numbers have signed type.  If they are of different
      /* Both numbers have signed type.  If they are of different
       sign, the answer is the sign of A.  */
       sign, the answer is the sign of A.  */
      unsignedp = num_positive (pa, precision);
      unsignedp = num_positive (pa, precision);
 
 
      if (unsignedp != num_positive (pb, precision))
      if (unsignedp != num_positive (pb, precision))
        return unsignedp;
        return unsignedp;
 
 
      /* Otherwise we can do an unsigned comparison.  */
      /* Otherwise we can do an unsigned comparison.  */
    }
    }
 
 
  return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
  return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
}
}
 
 
/* Returns LHS OP RHS, where OP is a bit-wise operation.  */
/* Returns LHS OP RHS, where OP is a bit-wise operation.  */
static cpp_num
static cpp_num
num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
                cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
                cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
{
{
  lhs.overflow = false;
  lhs.overflow = false;
  lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
  lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
 
 
  /* As excess precision is zeroed, there is no need to num_trim () as
  /* As excess precision is zeroed, there is no need to num_trim () as
     these operations cannot introduce a set bit there.  */
     these operations cannot introduce a set bit there.  */
  if (op == CPP_AND)
  if (op == CPP_AND)
    {
    {
      lhs.low &= rhs.low;
      lhs.low &= rhs.low;
      lhs.high &= rhs.high;
      lhs.high &= rhs.high;
    }
    }
  else if (op == CPP_OR)
  else if (op == CPP_OR)
    {
    {
      lhs.low |= rhs.low;
      lhs.low |= rhs.low;
      lhs.high |= rhs.high;
      lhs.high |= rhs.high;
    }
    }
  else
  else
    {
    {
      lhs.low ^= rhs.low;
      lhs.low ^= rhs.low;
      lhs.high ^= rhs.high;
      lhs.high ^= rhs.high;
    }
    }
 
 
  return lhs;
  return lhs;
}
}
 
 
/* Returns LHS OP RHS, where OP is an inequality.  */
/* Returns LHS OP RHS, where OP is an inequality.  */
static cpp_num
static cpp_num
num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs,
num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs,
                   enum cpp_ttype op)
                   enum cpp_ttype op)
{
{
  bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
  bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
 
 
  if (op == CPP_GREATER_EQ)
  if (op == CPP_GREATER_EQ)
    lhs.low = gte;
    lhs.low = gte;
  else if (op == CPP_LESS)
  else if (op == CPP_LESS)
    lhs.low = !gte;
    lhs.low = !gte;
  else if (op == CPP_GREATER)
  else if (op == CPP_GREATER)
    lhs.low = gte && !num_eq (lhs, rhs);
    lhs.low = gte && !num_eq (lhs, rhs);
  else /* CPP_LESS_EQ.  */
  else /* CPP_LESS_EQ.  */
    lhs.low = !gte || num_eq (lhs, rhs);
    lhs.low = !gte || num_eq (lhs, rhs);
 
 
  lhs.high = 0;
  lhs.high = 0;
  lhs.overflow = false;
  lhs.overflow = false;
  lhs.unsignedp = false;
  lhs.unsignedp = false;
  return lhs;
  return lhs;
}
}
 
 
/* Returns LHS OP RHS, where OP is == or !=.  */
/* Returns LHS OP RHS, where OP is == or !=.  */
static cpp_num
static cpp_num
num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
                 cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
                 cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
{
{
  /* Work around a 3.0.4 bug; see PR 6950.  */
  /* Work around a 3.0.4 bug; see PR 6950.  */
  bool eq = num_eq (lhs, rhs);
  bool eq = num_eq (lhs, rhs);
  if (op == CPP_NOT_EQ)
  if (op == CPP_NOT_EQ)
    eq = !eq;
    eq = !eq;
  lhs.low = eq;
  lhs.low = eq;
  lhs.high = 0;
  lhs.high = 0;
  lhs.overflow = false;
  lhs.overflow = false;
  lhs.unsignedp = false;
  lhs.unsignedp = false;
  return lhs;
  return lhs;
}
}
 
 
/* Shift NUM, of width PRECISION, right by N bits.  */
/* Shift NUM, of width PRECISION, right by N bits.  */
static cpp_num
static cpp_num
num_rshift (cpp_num num, size_t precision, size_t n)
num_rshift (cpp_num num, size_t precision, size_t n)
{
{
  cpp_num_part sign_mask;
  cpp_num_part sign_mask;
  bool x = num_positive (num, precision);
  bool x = num_positive (num, precision);
 
 
  if (num.unsignedp || x)
  if (num.unsignedp || x)
    sign_mask = 0;
    sign_mask = 0;
  else
  else
    sign_mask = ~(cpp_num_part) 0;
    sign_mask = ~(cpp_num_part) 0;
 
 
  if (n >= precision)
  if (n >= precision)
    num.high = num.low = sign_mask;
    num.high = num.low = sign_mask;
  else
  else
    {
    {
      /* Sign-extend.  */
      /* Sign-extend.  */
      if (precision < PART_PRECISION)
      if (precision < PART_PRECISION)
        num.high = sign_mask, num.low |= sign_mask << precision;
        num.high = sign_mask, num.low |= sign_mask << precision;
      else if (precision < 2 * PART_PRECISION)
      else if (precision < 2 * PART_PRECISION)
        num.high |= sign_mask << (precision - PART_PRECISION);
        num.high |= sign_mask << (precision - PART_PRECISION);
 
 
      if (n >= PART_PRECISION)
      if (n >= PART_PRECISION)
        {
        {
          n -= PART_PRECISION;
          n -= PART_PRECISION;
          num.low = num.high;
          num.low = num.high;
          num.high = sign_mask;
          num.high = sign_mask;
        }
        }
 
 
      if (n)
      if (n)
        {
        {
          num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
          num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
          num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
          num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
        }
        }
    }
    }
 
 
  num = num_trim (num, precision);
  num = num_trim (num, precision);
  num.overflow = false;
  num.overflow = false;
  return num;
  return num;
}
}
 
 
/* Shift NUM, of width PRECISION, left by N bits.  */
/* Shift NUM, of width PRECISION, left by N bits.  */
static cpp_num
static cpp_num
num_lshift (cpp_num num, size_t precision, size_t n)
num_lshift (cpp_num num, size_t precision, size_t n)
{
{
  if (n >= precision)
  if (n >= precision)
    {
    {
      num.overflow = !num.unsignedp && !num_zerop (num);
      num.overflow = !num.unsignedp && !num_zerop (num);
      num.high = num.low = 0;
      num.high = num.low = 0;
    }
    }
  else
  else
    {
    {
      cpp_num orig, maybe_orig;
      cpp_num orig, maybe_orig;
      size_t m = n;
      size_t m = n;
 
 
      orig = num;
      orig = num;
      if (m >= PART_PRECISION)
      if (m >= PART_PRECISION)
        {
        {
          m -= PART_PRECISION;
          m -= PART_PRECISION;
          num.high = num.low;
          num.high = num.low;
          num.low = 0;
          num.low = 0;
        }
        }
      if (m)
      if (m)
        {
        {
          num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
          num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
          num.low <<= m;
          num.low <<= m;
        }
        }
      num = num_trim (num, precision);
      num = num_trim (num, precision);
 
 
      if (num.unsignedp)
      if (num.unsignedp)
        num.overflow = false;
        num.overflow = false;
      else
      else
        {
        {
          maybe_orig = num_rshift (num, precision, n);
          maybe_orig = num_rshift (num, precision, n);
          num.overflow = !num_eq (orig, maybe_orig);
          num.overflow = !num_eq (orig, maybe_orig);
        }
        }
    }
    }
 
 
  return num;
  return num;
}
}
 
 
/* The four unary operators: +, -, ! and ~.  */
/* The four unary operators: +, -, ! and ~.  */
static cpp_num
static cpp_num
num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op)
num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op)
{
{
  switch (op)
  switch (op)
    {
    {
    case CPP_UPLUS:
    case CPP_UPLUS:
      if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
      if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
        cpp_error (pfile, CPP_DL_WARNING,
        cpp_error (pfile, CPP_DL_WARNING,
                   "traditional C rejects the unary plus operator");
                   "traditional C rejects the unary plus operator");
      num.overflow = false;
      num.overflow = false;
      break;
      break;
 
 
    case CPP_UMINUS:
    case CPP_UMINUS:
      num = num_negate (num, CPP_OPTION (pfile, precision));
      num = num_negate (num, CPP_OPTION (pfile, precision));
      break;
      break;
 
 
    case CPP_COMPL:
    case CPP_COMPL:
      num.high = ~num.high;
      num.high = ~num.high;
      num.low = ~num.low;
      num.low = ~num.low;
      num = num_trim (num, CPP_OPTION (pfile, precision));
      num = num_trim (num, CPP_OPTION (pfile, precision));
      num.overflow = false;
      num.overflow = false;
      break;
      break;
 
 
    default: /* case CPP_NOT: */
    default: /* case CPP_NOT: */
      num.low = num_zerop (num);
      num.low = num_zerop (num);
      num.high = 0;
      num.high = 0;
      num.overflow = false;
      num.overflow = false;
      num.unsignedp = false;
      num.unsignedp = false;
      break;
      break;
    }
    }
 
 
  return num;
  return num;
}
}
 
 
/* The various binary operators.  */
/* The various binary operators.  */
static cpp_num
static cpp_num
num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
{
{
  cpp_num result;
  cpp_num result;
  size_t precision = CPP_OPTION (pfile, precision);
  size_t precision = CPP_OPTION (pfile, precision);
  size_t n;
  size_t n;
 
 
  switch (op)
  switch (op)
    {
    {
      /* Shifts.  */
      /* Shifts.  */
    case CPP_LSHIFT:
    case CPP_LSHIFT:
    case CPP_RSHIFT:
    case CPP_RSHIFT:
      if (!rhs.unsignedp && !num_positive (rhs, precision))
      if (!rhs.unsignedp && !num_positive (rhs, precision))
        {
        {
          /* A negative shift is a positive shift the other way.  */
          /* A negative shift is a positive shift the other way.  */
          if (op == CPP_LSHIFT)
          if (op == CPP_LSHIFT)
            op = CPP_RSHIFT;
            op = CPP_RSHIFT;
          else
          else
            op = CPP_LSHIFT;
            op = CPP_LSHIFT;
          rhs = num_negate (rhs, precision);
          rhs = num_negate (rhs, precision);
        }
        }
      if (rhs.high)
      if (rhs.high)
        n = ~0;                  /* Maximal.  */
        n = ~0;                  /* Maximal.  */
      else
      else
        n = rhs.low;
        n = rhs.low;
      if (op == CPP_LSHIFT)
      if (op == CPP_LSHIFT)
        lhs = num_lshift (lhs, precision, n);
        lhs = num_lshift (lhs, precision, n);
      else
      else
        lhs = num_rshift (lhs, precision, n);
        lhs = num_rshift (lhs, precision, n);
      break;
      break;
 
 
      /* Arithmetic.  */
      /* Arithmetic.  */
    case CPP_MINUS:
    case CPP_MINUS:
      rhs = num_negate (rhs, precision);
      rhs = num_negate (rhs, precision);
    case CPP_PLUS:
    case CPP_PLUS:
      result.low = lhs.low + rhs.low;
      result.low = lhs.low + rhs.low;
      result.high = lhs.high + rhs.high;
      result.high = lhs.high + rhs.high;
      if (result.low < lhs.low)
      if (result.low < lhs.low)
        result.high++;
        result.high++;
      result.unsignedp = lhs.unsignedp || rhs.unsignedp;
      result.unsignedp = lhs.unsignedp || rhs.unsignedp;
      result.overflow = false;
      result.overflow = false;
 
 
      result = num_trim (result, precision);
      result = num_trim (result, precision);
      if (!result.unsignedp)
      if (!result.unsignedp)
        {
        {
          bool lhsp = num_positive (lhs, precision);
          bool lhsp = num_positive (lhs, precision);
          result.overflow = (lhsp == num_positive (rhs, precision)
          result.overflow = (lhsp == num_positive (rhs, precision)
                             && lhsp != num_positive (result, precision));
                             && lhsp != num_positive (result, precision));
        }
        }
      return result;
      return result;
 
 
      /* Comma.  */
      /* Comma.  */
    default: /* case CPP_COMMA: */
    default: /* case CPP_COMMA: */
      if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99)
      if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99)
                                   || !pfile->state.skip_eval))
                                   || !pfile->state.skip_eval))
        cpp_error (pfile, CPP_DL_PEDWARN,
        cpp_error (pfile, CPP_DL_PEDWARN,
                   "comma operator in operand of #if");
                   "comma operator in operand of #if");
      lhs = rhs;
      lhs = rhs;
      break;
      break;
    }
    }
 
 
  return lhs;
  return lhs;
}
}
 
 
/* Multiplies two unsigned cpp_num_parts to give a cpp_num.  This
/* Multiplies two unsigned cpp_num_parts to give a cpp_num.  This
   cannot overflow.  */
   cannot overflow.  */
static cpp_num
static cpp_num
num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
{
{
  cpp_num result;
  cpp_num result;
  cpp_num_part middle[2], temp;
  cpp_num_part middle[2], temp;
 
 
  result.low = LOW_PART (lhs) * LOW_PART (rhs);
  result.low = LOW_PART (lhs) * LOW_PART (rhs);
  result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
  result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
 
 
  middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
  middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
  middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
  middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
 
 
  temp = result.low;
  temp = result.low;
  result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
  result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
  if (result.low < temp)
  if (result.low < temp)
    result.high++;
    result.high++;
 
 
  temp = result.low;
  temp = result.low;
  result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
  result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
  if (result.low < temp)
  if (result.low < temp)
    result.high++;
    result.high++;
 
 
  result.high += HIGH_PART (middle[0]);
  result.high += HIGH_PART (middle[0]);
  result.high += HIGH_PART (middle[1]);
  result.high += HIGH_PART (middle[1]);
  result.unsignedp = true;
  result.unsignedp = true;
  result.overflow = false;
  result.overflow = false;
 
 
  return result;
  return result;
}
}
 
 
/* Multiply two preprocessing numbers.  */
/* Multiply two preprocessing numbers.  */
static cpp_num
static cpp_num
num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
{
{
  cpp_num result, temp;
  cpp_num result, temp;
  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
  bool overflow, negate = false;
  bool overflow, negate = false;
  size_t precision = CPP_OPTION (pfile, precision);
  size_t precision = CPP_OPTION (pfile, precision);
 
 
  /* Prepare for unsigned multiplication.  */
  /* Prepare for unsigned multiplication.  */
  if (!unsignedp)
  if (!unsignedp)
    {
    {
      if (!num_positive (lhs, precision))
      if (!num_positive (lhs, precision))
        negate = !negate, lhs = num_negate (lhs, precision);
        negate = !negate, lhs = num_negate (lhs, precision);
      if (!num_positive (rhs, precision))
      if (!num_positive (rhs, precision))
        negate = !negate, rhs = num_negate (rhs, precision);
        negate = !negate, rhs = num_negate (rhs, precision);
    }
    }
 
 
  overflow = lhs.high && rhs.high;
  overflow = lhs.high && rhs.high;
  result = num_part_mul (lhs.low, rhs.low);
  result = num_part_mul (lhs.low, rhs.low);
 
 
  temp = num_part_mul (lhs.high, rhs.low);
  temp = num_part_mul (lhs.high, rhs.low);
  result.high += temp.low;
  result.high += temp.low;
  if (temp.high)
  if (temp.high)
    overflow = true;
    overflow = true;
 
 
  temp = num_part_mul (lhs.low, rhs.high);
  temp = num_part_mul (lhs.low, rhs.high);
  result.high += temp.low;
  result.high += temp.low;
  if (temp.high)
  if (temp.high)
    overflow = true;
    overflow = true;
 
 
  temp.low = result.low, temp.high = result.high;
  temp.low = result.low, temp.high = result.high;
  result = num_trim (result, precision);
  result = num_trim (result, precision);
  if (!num_eq (result, temp))
  if (!num_eq (result, temp))
    overflow = true;
    overflow = true;
 
 
  if (negate)
  if (negate)
    result = num_negate (result, precision);
    result = num_negate (result, precision);
 
 
  if (unsignedp)
  if (unsignedp)
    result.overflow = false;
    result.overflow = false;
  else
  else
    result.overflow = overflow || (num_positive (result, precision) ^ !negate
    result.overflow = overflow || (num_positive (result, precision) ^ !negate
                                   && !num_zerop (result));
                                   && !num_zerop (result));
  result.unsignedp = unsignedp;
  result.unsignedp = unsignedp;
 
 
  return result;
  return result;
}
}
 
 
/* Divide two preprocessing numbers, LHS and RHS, returning the answer
/* Divide two preprocessing numbers, LHS and RHS, returning the answer
   or the remainder depending upon OP. LOCATION is the source location
   or the remainder depending upon OP. LOCATION is the source location
   of this operator (for diagnostics).  */
   of this operator (for diagnostics).  */
 
 
static cpp_num
static cpp_num
num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op,
num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op,
            source_location location)
            source_location location)
{
{
  cpp_num result, sub;
  cpp_num result, sub;
  cpp_num_part mask;
  cpp_num_part mask;
  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
  bool negate = false, lhs_neg = false;
  bool negate = false, lhs_neg = false;
  size_t i, precision = CPP_OPTION (pfile, precision);
  size_t i, precision = CPP_OPTION (pfile, precision);
 
 
  /* Prepare for unsigned division.  */
  /* Prepare for unsigned division.  */
  if (!unsignedp)
  if (!unsignedp)
    {
    {
      if (!num_positive (lhs, precision))
      if (!num_positive (lhs, precision))
        negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
        negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
      if (!num_positive (rhs, precision))
      if (!num_positive (rhs, precision))
        negate = !negate, rhs = num_negate (rhs, precision);
        negate = !negate, rhs = num_negate (rhs, precision);
    }
    }
 
 
  /* Find the high bit.  */
  /* Find the high bit.  */
  if (rhs.high)
  if (rhs.high)
    {
    {
      i = precision - 1;
      i = precision - 1;
      mask = (cpp_num_part) 1 << (i - PART_PRECISION);
      mask = (cpp_num_part) 1 << (i - PART_PRECISION);
      for (; ; i--, mask >>= 1)
      for (; ; i--, mask >>= 1)
        if (rhs.high & mask)
        if (rhs.high & mask)
          break;
          break;
    }
    }
  else if (rhs.low)
  else if (rhs.low)
    {
    {
      if (precision > PART_PRECISION)
      if (precision > PART_PRECISION)
        i = precision - PART_PRECISION - 1;
        i = precision - PART_PRECISION - 1;
      else
      else
        i = precision - 1;
        i = precision - 1;
      mask = (cpp_num_part) 1 << i;
      mask = (cpp_num_part) 1 << i;
      for (; ; i--, mask >>= 1)
      for (; ; i--, mask >>= 1)
        if (rhs.low & mask)
        if (rhs.low & mask)
          break;
          break;
    }
    }
  else
  else
    {
    {
      if (!pfile->state.skip_eval)
      if (!pfile->state.skip_eval)
        cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0,
        cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0,
                             "division by zero in #if");
                             "division by zero in #if");
      return lhs;
      return lhs;
    }
    }
 
 
  /* First nonzero bit of RHS is bit I.  Do naive division by
  /* First nonzero bit of RHS is bit I.  Do naive division by
     shifting the RHS fully left, and subtracting from LHS if LHS is
     shifting the RHS fully left, and subtracting from LHS if LHS is
     at least as big, and then repeating but with one less shift.
     at least as big, and then repeating but with one less shift.
     This is not very efficient, but is easy to understand.  */
     This is not very efficient, but is easy to understand.  */
 
 
  rhs.unsignedp = true;
  rhs.unsignedp = true;
  lhs.unsignedp = true;
  lhs.unsignedp = true;
  i = precision - i - 1;
  i = precision - i - 1;
  sub = num_lshift (rhs, precision, i);
  sub = num_lshift (rhs, precision, i);
 
 
  result.high = result.low = 0;
  result.high = result.low = 0;
  for (;;)
  for (;;)
    {
    {
      if (num_greater_eq (lhs, sub, precision))
      if (num_greater_eq (lhs, sub, precision))
        {
        {
          lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
          lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
          if (i >= PART_PRECISION)
          if (i >= PART_PRECISION)
            result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
            result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
          else
          else
            result.low |= (cpp_num_part) 1 << i;
            result.low |= (cpp_num_part) 1 << i;
        }
        }
      if (i-- == 0)
      if (i-- == 0)
        break;
        break;
      sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
      sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
      sub.high >>= 1;
      sub.high >>= 1;
    }
    }
 
 
  /* We divide so that the remainder has the sign of the LHS.  */
  /* We divide so that the remainder has the sign of the LHS.  */
  if (op == CPP_DIV)
  if (op == CPP_DIV)
    {
    {
      result.unsignedp = unsignedp;
      result.unsignedp = unsignedp;
      result.overflow = false;
      result.overflow = false;
      if (!unsignedp)
      if (!unsignedp)
        {
        {
          if (negate)
          if (negate)
            result = num_negate (result, precision);
            result = num_negate (result, precision);
          result.overflow = (num_positive (result, precision) ^ !negate
          result.overflow = (num_positive (result, precision) ^ !negate
                             && !num_zerop (result));
                             && !num_zerop (result));
        }
        }
 
 
      return result;
      return result;
    }
    }
 
 
  /* CPP_MOD.  */
  /* CPP_MOD.  */
  lhs.unsignedp = unsignedp;
  lhs.unsignedp = unsignedp;
  lhs.overflow = false;
  lhs.overflow = false;
  if (lhs_neg)
  if (lhs_neg)
    lhs = num_negate (lhs, precision);
    lhs = num_negate (lhs, precision);
 
 
  return lhs;
  return lhs;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.