Part 1 of Zack's integer parsing overhaul

Neil Booth neil@daikokuya.demon.co.uk
Wed May 29 01:54:00 GMT 2002


Most of this code should be credited to Zack; it's pulled
from a patch of his from last August.  I've made a few tweaks,
and changed some diagnostics (e.g. so that they don't mention
a C89 violation when we're compiling C++, rather it mentions
use of a C99 feature).  -Wtraditional also warns of any
suffix other than L, and the number of diagnostics is reduced
(always a good idea if it can be done without loss of clarity
IMO).  Further, hex and octal numbers with an L or LL suffix
that are forced to being unsigned now warn; previously we
were silent.  I think we can get away without CPP_N_ZERO,
and I've kept the fast paths in number interpretation I
introduced in my previous patch.

I'm breaking it into two stages; with the CPP changes first.
Tests and the front end simplification come next.

Bootstrapped and regtested.

Neil.

2002-05-29  Neil Booth  <neil@daikokuya.demon.co.uk>
	    Zack Weinberg <zack@codesourcery.com>

	* cppexp.c (cpp_num): Move to cpplib.h.
	(CPP_ERROR): Remove.
	(interpret_float_suffix, interpret_int_suffix): New.
	(struct suffix, vsuf_1, vsuf_2, vsuf_3): Remove.
	(cpp_classify_number, cpp_interpret_integer): New.
	(interpret_number): Remove.
	(eval_token): Update to use new routines.
	* cpphash.h (cpp_num_part): Move to cpplib.h.
	* cppinit.c (cpp_post_options): Set warn_long_long.
	* cpplib.h (struct cpp_options): Add warn_long_long.
	(cpp_num, cpp_num_part, CPP_N_CATEGORY, CPP_N_INVALID,
	CPP_N_INTEGER, CPP_N_FLOATING, CPP_N_WIDTH, CPP_N_SMALL,
	CPP_N_MEDIUM, CPP_N_LARGE, CPP_N_RADIX, CPP_N_DEC, CPP_N_HEX,
	CPP_N_OCTAL, CPP_N_UNSIGNED, CPP_N_IMAGINARY, cpp_classify_number,
	cpp_interpret_integer): New.
testsuite:
	* gcc.dg/cpp/c++98-pedantic.c, gcc.dg/cpp/c89-pedantic.c, 
	gcc.dg/cpp/c94-pedantic.c, gcc.dg/cpp/gnuc89-pedantic.c,
	gcc.dg/cpp/if-1.c: Update for modified diagnostics.

============================================================
Index: gcc/cppexp.c
--- gcc/cppexp.c	28 May 2002 05:44:06 -0000	1.119
+++ gcc/cppexp.c	29 May 2002 06:36:51 -0000
@@ -23,23 +23,11 @@ Boston, MA 02111-1307, USA.  */
 #include "cpplib.h"
 #include "cpphash.h"
 
-typedef struct cpp_num cpp_num;
-
 #define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
 #define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
 #define LOW_PART(num_part) (num_part & HALF_MASK)
 #define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
 
-/* A preprocessing number.  Code assumes that any unused high bits of
-   the double integer are set to zero.  */
-struct cpp_num
-{
-  cpp_num_part high;
-  cpp_num_part low;
-  bool unsignedp;  /* True if value should be treated as unsigned.  */
-  bool overflow;   /* True if the most recent calculation overflowed.  */
-};
-
 struct op
 {
   cpp_num value;		     /* The value logically "right" of op.  */
@@ -72,15 +60,13 @@ static cpp_num num_lshift PARAMS ((cpp_n
 static cpp_num num_rshift PARAMS ((cpp_num, size_t, size_t));
 
 static cpp_num append_digit PARAMS ((cpp_num, int, int, size_t));
-static cpp_num interpret_number PARAMS ((cpp_reader *, const cpp_token *));
 static cpp_num parse_defined PARAMS ((cpp_reader *));
 static cpp_num eval_token PARAMS ((cpp_reader *, const cpp_token *));
 static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype));
+static unsigned int interpret_float_suffix PARAMS ((const uchar *, size_t));
+static unsigned int interpret_int_suffix PARAMS ((const uchar *, size_t));
 
-/* Token type abuse.  There is no "error" token, but we can't get
-   comments in #if, so we can abuse that token type.  Similarly,
-   create unary plus and minus operators.  */
-#define CPP_ERROR CPP_COMMENT
+/* Token type abuse to create unary plus and minus operators.  */
 #define CPP_UPLUS (CPP_LAST_CPP_OP + 1)
 #define CPP_UMINUS (CPP_LAST_CPP_OP + 2)
 
@@ -91,28 +77,319 @@ static struct op *reduce PARAMS ((cpp_re
 #define SYNTAX_ERROR2(msgid, arg) \
   do { cpp_error (pfile, DL_ERROR, msgid, arg); goto syntax_error; } while(0)
 
-struct suffix
+/* Subroutine of cpp_classify_number.  S points to a float suffix of
+   length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
+   flag vector describing the suffix.  */
+static unsigned int
+interpret_float_suffix (s, len)
+     const uchar *s;
+     size_t len;
 {
-  const unsigned char s[4];
-  const unsigned char u;
-  const unsigned char l;
-};
+  size_t f = 0, l = 0, i = 0;
 
-static const struct suffix vsuf_1[] = {
-  { "u", 1, 0 }, { "U", 1, 0 },
-  { "l", 0, 1 }, { "L", 0, 1 }
-};
+  while (len--)
+    switch (s[len])
+      {
+      case 'f': case 'F': f++; break;
+      case 'l': case 'L': l++; break;
+      case 'i': case 'I':
+      case 'j': case 'J': i++; break;
+      default:
+	return 0;
+      }
 
-static const struct suffix vsuf_2[] = {
-  { "ul", 1, 1 }, { "UL", 1, 1 }, { "uL", 1, 1 }, { "Ul", 1, 1 },
-  { "lu", 1, 1 }, { "LU", 1, 1 }, { "Lu", 1, 1 }, { "lU", 1, 1 },
-  { "ll", 0, 2 }, { "LL", 0, 2 }
-};
+  if (f + l > 1 || i > 1)
+    return 0;
 
-static const struct suffix vsuf_3[] = {
-  { "ull", 1, 2 }, { "ULL", 1, 2 }, { "uLL", 1, 2 }, { "Ull", 1, 2 },
-  { "llu", 1, 2 }, { "LLU", 1, 2 }, { "LLu", 1, 2 }, { "llU", 1, 2 }
-};
+  return ((i ? CPP_N_IMAGINARY : 0)
+	  | (f ? CPP_N_SMALL :
+	     l ? CPP_N_LARGE : CPP_N_MEDIUM));
+}
+
+/* Subroutine of cpp_classify_number.  S points to an integer suffix
+   of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
+   flag vector describing the suffix.  */
+static unsigned int
+interpret_int_suffix (s, len)
+     const uchar *s;
+     size_t len;
+{
+  size_t u, l, i;
+
+  u = l = i = 0;
+
+  while (len--)
+    switch (s[len])
+      {
+      case 'u': case 'U':	u++; break;
+      case 'i': case 'I':
+      case 'j': case 'J':	i++; break;
+      case 'l': case 'L':	l++;
+	/* If there are two Ls, they must be adjacent and the same case.  */
+	if (l == 2 && s[len] != s[len + 1])
+	  return 0;
+	break;
+      default:
+	return 0;
+      }
+
+  if (l > 2 || u > 1 || i > 1)
+    return 0;
+
+  return ((i ? CPP_N_IMAGINARY : 0)
+	  | (u ? CPP_N_UNSIGNED : 0)
+	  | ((l == 0) ? CPP_N_SMALL
+	     : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
+}
+
+/* Categorize numeric constants according to their field (integer,
+   floating point, or invalid), radix (decimal, octal, hexadecimal),
+   and type suffixes.  */
+unsigned int
+cpp_classify_number (pfile, token)
+     cpp_reader *pfile;
+     const cpp_token *token;
+{
+  const uchar *str = token->val.str.text;
+  const uchar *limit;
+  unsigned int max_digit, result, radix;
+  enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
+
+  /* If the lexer has done its job, length one can only be a single
+     digit.  Fast-path this very common case.  */
+  if (token->val.str.len == 1)
+    return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
+
+  limit = str + token->val.str.len;
+  float_flag = NOT_FLOAT;
+  max_digit = 0;
+  radix = 10;
+
+  /* First, interpret the radix.  */
+  if (*str == '0')
+    {
+      radix = 8;
+      str++;
+
+      /* Require at least one hex digit to classify it as hex.  */
+      if ((*str == 'x' || *str == 'X') && ISXDIGIT (str[1]))
+	{
+	  radix = 16;
+	  str++;
+	}
+    }
+
+  /* Now scan for a well-formed integer or float.  */
+  for (;;)
+    {
+      unsigned int c = *str++;
+
+      if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
+	{
+	  c = hex_value (c);
+	  if (c > max_digit)
+	    max_digit = c;
+	}
+      else if (c == '.')
+	{
+	  if (float_flag == NOT_FLOAT)
+	    float_flag = AFTER_POINT;
+	  else
+	    SYNTAX_ERROR ("excess decimal point in number");
+	}
+      else if ((radix <= 10 && (c == 'e' || c == 'E'))
+	       || (radix == 16 && (c == 'p' || c == 'P')))
+	{
+	  float_flag = AFTER_EXPON;
+	  break;
+	}
+      else
+	{
+	  /* Start of suffix.  */
+	  str--;
+	  break;
+	}
+    }
+
+  if (float_flag != NOT_FLOAT && radix == 8)
+    radix = 10;
+
+  if (max_digit >= radix)
+    SYNTAX_ERROR ("invalid digit in octal integer constant");
+
+  if (float_flag != NOT_FLOAT)
+    {
+      if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
+	cpp_error (pfile, DL_PEDWARN,
+		   "use of C99 hexadecimal floating constant");
+
+      if (float_flag == AFTER_EXPON)
+	{
+	  if (*str == '+' || *str == '-')
+	    str++;
+
+	  /* Exponent is decimal, even if string is a hex float.  */
+	  if (!ISDIGIT (*str))
+	    SYNTAX_ERROR ("floating constant exponent has no digits");
+
+	  do
+	    str++;
+	  while (ISDIGIT (*str));
+	}
+      else if (radix == 16)
+	SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
+
+      result = interpret_float_suffix (str, limit - str);
+      if (result == 0)
+	{
+	  cpp_error (pfile, DL_ERROR,
+		     "invalid suffix \"%.*s\" on floating constant",
+		     limit - str, str);
+	  return CPP_N_INVALID;
+	}
+
+      /* Traditional C didn't accept any floating suffixes.  */
+      if (limit != str
+	  && CPP_WTRADITIONAL (pfile)
+	  && ! cpp_sys_macro_p (pfile))
+	cpp_error (pfile, DL_WARNING,
+		   "traditional C rejects the \"%.*s\" suffix",
+		   limit - str, str);
+
+      result |= CPP_N_FLOATING;
+    }
+  else
+    {
+      result = interpret_int_suffix (str, limit - str);
+      if (result == 0)
+	{
+	  cpp_error (pfile, DL_ERROR,
+		     "invalid suffix \"%.*s\" on integer constant",
+		     limit - str, str);
+	  return CPP_N_INVALID;
+	}
+
+      /* Traditional C only accepted the 'L' suffix.  */
+      if (result != CPP_N_SMALL && result != CPP_N_MEDIUM
+	  && CPP_WTRADITIONAL (pfile)
+	  && ! cpp_sys_macro_p (pfile))
+	cpp_error (pfile, DL_WARNING,
+		   "traditional C rejects the \"%.*s\" suffix",
+		   limit - str, str);
+
+      if ((result & CPP_N_WIDTH) == CPP_N_LARGE
+	  && ! CPP_OPTION (pfile, c99)
+	  && CPP_OPTION (pfile, warn_long_long))
+	cpp_error (pfile, DL_PEDWARN, "use of C99 long long integer constant");
+
+      result |= CPP_N_INTEGER;
+    }
+
+  if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
+    cpp_error (pfile, DL_PEDWARN,
+	       "the ISO standard does not include imaginary numeric constants");
+
+  if (radix == 10)
+    result |= CPP_N_DECIMAL;
+  else if (radix == 16)
+    result |= CPP_N_HEX;
+  else
+    result |= CPP_N_OCTAL;
+
+  return result;
+
+ syntax_error:
+  return CPP_N_INVALID;
+}
+
+/* cpp_interpret_integer converts an integer constant into a cpp_num,
+   of precision options->precision.
+
+   We do not provide any interface for decimal->float conversion,
+   because the preprocessor doesn't need it and the floating point
+   handling in GCC proper is too ugly to speak of.  */
+cpp_num
+cpp_interpret_integer (pfile, token, type)
+     cpp_reader *pfile;
+     const cpp_token *token;
+     unsigned int type;
+{
+  const uchar *p, *end;
+  cpp_num result;
+
+  result.low = 0;
+  result.high = 0;
+  result.unsignedp = type & CPP_N_UNSIGNED;
+  result.overflow = 0;
+
+  p = token->val.str.text;
+  end = p + token->val.str.len;
+
+  /* Common case of a single digit.  */
+  if (token->val.str.len == 1)
+    result.low = p[0] - '0';
+  else
+    {
+      cpp_num_part max;
+      size_t precision = CPP_OPTION (pfile, precision);
+      unsigned int base = 10, c = 0;
+      bool overflow = false;
+
+      if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
+	{
+	  base = 8;
+	  p++;
+	}
+      else if ((type & CPP_N_RADIX) == CPP_N_HEX)
+	{
+	  base = 16;
+	  p += 2;
+	}
+
+      /* We can add a digit to numbers strictly less than this without
+	 needing the precision and slowness of double integers.  */
+      max = ~(cpp_num_part) 0;
+      if (precision < PART_PRECISION)
+	max >>= PART_PRECISION - precision;
+      max = (max - base + 1) / base + 1;
+
+      for (; p < end; p++)
+	{
+	  c = *p;
+
+	  if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
+	    c = hex_value (c);
+	  else
+	    break;
+
+	  /* Strict inequality for when max is set to zero.  */
+	  if (result.low < max)
+	    result.low = result.low * base + c;
+	  else
+	    {
+	      result = append_digit (result, c, base, precision);
+	      overflow |= result.overflow;
+	      max = 0;
+	    }
+	}
+
+      if (overflow)
+	cpp_error (pfile, DL_PEDWARN,
+		   "integer constant too large for its type");
+      /* If too big to be signed, consider it unsigned.  Only warn for
+	 decimal numbers, unless the user supplied an L or LL suffix
+	 with no U.  */
+      else if (!result.unsignedp && !num_positive (result, precision))
+	{
+	  if (base == 10 || type & (CPP_N_MEDIUM | CPP_N_LARGE))
+	    cpp_error (pfile, DL_WARNING,
+		       "integer constant is so large that it is unsigned");
+	  result.unsignedp = 1;
+	}
+    }
+
+  return result;
+}
 
 /* Append DIGIT to NUM, a number of PRECISION bits being read in base
    BASE.  */
@@ -167,149 +444,6 @@ append_digit (num, digit, base, precisio
   return result;
 }
 
-/* Parse and convert what is presumably an integer in TOK.  Accepts
-   decimal, hex, or octal with or without size suffixes.  Returned op
-   is CPP_ERROR on error, otherwise it is a CPP_NUMBER.  */
-static cpp_num
-interpret_number (pfile, tok)
-     cpp_reader *pfile;
-     const cpp_token *tok;
-{
-  cpp_num result;
-  cpp_num_part max;
-  const uchar *p = tok->val.str.text;
-  const uchar *end;
-  const struct suffix *sufftab;
-  size_t precision;
-  unsigned int i, nsuff, base, c;
-  bool overflow, big_digit;
-
-  result.low = 0;
-  result.high = 0;
-  result.unsignedp = 0;
-  result.overflow = 0;
-
-  /* Common case of a single digit.  */
-  end = p + tok->val.str.len;
-  if (tok->val.str.len == 1 && (unsigned int) (p[0] - '0') <= 9)
-    {
-      result.low = p[0] - '0';
-      return result;
-    }
-
-  base = 10;
-  if (p[0] == '0')
-    {
-      if (end - p >= 3 && (p[1] == 'x' || p[1] == 'X'))
-	{
-	  p += 2;
-	  base = 16;
-	}
-      else
-	{
-	  p += 1;
-	  base = 8;
-	}
-    }
-
-  c = 0;
-  overflow = big_digit = false;
-  precision = CPP_OPTION (pfile, precision);
-
-  /* We can add a digit to numbers less than this without needing
-     double integers.  9 is the maximum digit for octal and decimal;
-     for hex it is annihilated by the division anyway.  */
-  max = ~(cpp_num_part) 0;
-  if (precision < PART_PRECISION)
-    max >>= PART_PRECISION - precision;
-  max = (max - 9) / base + 1;
-
-  for(; p < end; p++)
-    {
-      c = *p;
-
-      if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
-	c = hex_value (c);
-      else
-	break;
-
-      if (c >= base)
-	big_digit = true;
-
-      /* Strict inequality for when max is set to zero.  */
-      if (result.low < max)
-	result.low = result.low * base + c;
-      else
-	{
-	  result = append_digit (result, c, base, precision);
-	  overflow |= result.overflow;
-	  max = 0;
-	}
-    }
-
-  if (p < end)
-    {
-      /* Check for a floating point constant.  Note that float constants
-	 with an exponent or suffix but no decimal point are technically
-	 invalid (C99 6.4.4.2) but accepted elsewhere.  */
-      if ((c == '.' || c == 'F' || c == 'f')
-	  || (base == 10 && (c == 'E' || c == 'e')
-	      && p+1 < end && (p[1] == '+' || p[1] == '-'))
-	  || (base == 16 && (c == 'P' || c == 'p')
-	      && p+1 < end && (p[1] == '+' || p[1] == '-')))
-	SYNTAX_ERROR ("floating point numbers are not valid in #if");
-
-      /* Determine the suffix. l means long, and u means unsigned.
-	 See the suffix tables, above.  */
-      switch (end - p)
-	{
-	case 1: sufftab = vsuf_1; nsuff = ARRAY_SIZE (vsuf_1); break;
-	case 2: sufftab = vsuf_2; nsuff = ARRAY_SIZE (vsuf_2); break;
-	case 3: sufftab = vsuf_3; nsuff = ARRAY_SIZE (vsuf_3); break;
-	default: goto invalid_suffix;
-	}
-
-      for (i = 0; i < nsuff; i++)
-	if (memcmp (p, sufftab[i].s, end - p) == 0)
-	  break;
-      if (i == nsuff)
-	goto invalid_suffix;
-      result.unsignedp = sufftab[i].u;
-
-      if (CPP_WTRADITIONAL (pfile)
-	  && sufftab[i].u
-	  && ! cpp_sys_macro_p (pfile))
-	cpp_error (pfile, DL_WARNING, "traditional C rejects the `U' suffix");
-      if (sufftab[i].l == 2 && CPP_OPTION (pfile, pedantic)
-	  && ! CPP_OPTION (pfile, c99))
-	cpp_error (pfile, DL_PEDWARN,
-		   "too many 'l' suffixes in integer constant");
-    }
-
-  if (big_digit)
-    cpp_error (pfile, DL_PEDWARN,
-	       "integer constant contains digits beyond the radix");
-
-  if (overflow)
-    cpp_error (pfile, DL_PEDWARN, "integer constant too large for its type");
-  /* If too big to be signed, consider it unsigned.  */
-  else if (!result.unsignedp && !num_positive (result, precision))
-    {
-      if (base == 10)
-	cpp_error (pfile, DL_WARNING,
-		   "integer constant is so large that it is unsigned");
-      result.unsignedp = 1;
-    }
-
-  return result;
-
- invalid_suffix:
-  cpp_error (pfile, DL_ERROR, "invalid suffix '%.*s' on integer constant",
-	     (int) (end - p), p);
- syntax_error:
-  return result;
-}
-
 /* Handle meeting "defined" in a preprocessor expression.  */
 static cpp_num
 parse_defined (pfile)
@@ -379,7 +513,7 @@ parse_defined (pfile)
 
 /* Convert a token into a CPP_NUMBER (an interpreted preprocessing
    number or character constant, or the result of the "defined" or "#"
-   operators), or CPP_ERROR on error.  */
+   operators).  */
 static cpp_num
 eval_token (pfile, token)
      cpp_reader *pfile;
@@ -392,7 +526,26 @@ eval_token (pfile, token)
   switch (token->type)
     {
     case CPP_NUMBER:
-      return interpret_number (pfile, token);
+      temp = cpp_classify_number (pfile, token);
+      switch (temp & CPP_N_CATEGORY)
+	{
+	case CPP_N_FLOATING:
+	  cpp_error (pfile, DL_ERROR,
+		     "floating point constant in preprocessor expression");
+	  break;
+	case CPP_N_INTEGER:
+	  if (!(temp & CPP_N_IMAGINARY))
+	    return cpp_interpret_integer (pfile, token, temp);
+	  cpp_error (pfile, DL_ERROR,
+		     "imaginary number in preprocessor expression");
+	  break;
+
+	case CPP_N_INVALID:
+	  /* Error already issued.  */
+	  break;
+	}
+      result.high = result.low = 0;
+      break;
 
     case CPP_WCHAR:
     case CPP_CHAR:
============================================================
Index: gcc/cpphash.h
--- gcc/cpphash.h	27 May 2002 05:51:01 -0000	1.153
+++ gcc/cpphash.h	29 May 2002 06:36:56 -0000
@@ -29,7 +29,6 @@ struct directive;		/* Deliberately incom
 struct pending_option;
 struct op;
 
-typedef unsigned HOST_WIDE_INT cpp_num_part;
 typedef unsigned char uchar;
 #define U (const uchar *)  /* Intended use: U"string" */
 
============================================================
Index: gcc/cppinit.c
--- gcc/cppinit.c	27 May 2002 05:51:02 -0000	1.234
+++ gcc/cppinit.c	29 May 2002 06:37:05 -0000
@@ -1774,6 +1774,9 @@ cpp_post_options (pfile)
   if (CPP_OPTION (pfile, cplusplus))
     CPP_OPTION (pfile, warn_traditional) = 0;
 
+  CPP_OPTION (pfile, warn_long_long) = (CPP_OPTION (pfile, pedantic)
+					&& !CPP_OPTION (pfile, c99));
+
   /* Permanently disable macro expansion if we are rescanning
      preprocessed text.  Read preprocesed source in ISO mode.  */
   if (CPP_OPTION (pfile, preprocessed))
============================================================
Index: gcc/cpplib.h
--- gcc/cpplib.h	23 May 2002 06:07:45 -0000	1.220
+++ gcc/cpplib.h	29 May 2002 06:37:06 -0000
@@ -327,6 +327,9 @@ struct cpp_options
      traditional C.  */
   unsigned char warn_traditional;
 
+  /* Nonzero means warn about long long numeric constants.  */
+  unsigned char warn_long_long;
+
   /* Nonzero means warn about text after an #endif (or #else).  */
   unsigned char warn_endif_labels;
 
@@ -576,6 +579,51 @@ extern cpp_buffer *cpp_push_buffer PARAM
 					    const unsigned char *, size_t,
 					    int, int));
 extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int));
+
+/* A preprocessing number.  Code assumes that any unused high bits of
+   the double integer are set to zero.  */
+typedef unsigned HOST_WIDE_INT cpp_num_part;
+typedef struct cpp_num cpp_num;
+struct cpp_num
+{
+  cpp_num_part high;
+  cpp_num_part low;
+  bool unsignedp;  /* True if value should be treated as unsigned.  */
+  bool overflow;   /* True if the most recent calculation overflowed.  */
+};
+
+/* cpplib provides two interfaces for interpretation of preprocessing
+   numbers.
+
+   cpp_classify_number categorizes numeric constants according to
+   their field (integer, floating point, or invalid), radix (decimal,
+   octal, hexadecimal), and type suffixes.  */
+
+#define CPP_N_CATEGORY  0x000F
+#define CPP_N_INVALID	0x0000
+#define CPP_N_INTEGER	0x0001
+#define CPP_N_FLOATING	0x0002
+
+#define CPP_N_WIDTH	0x00F0
+#define CPP_N_SMALL	0x0010	/* int, float.  */
+#define CPP_N_MEDIUM	0x0020	/* long, double.  */
+#define CPP_N_LARGE	0x0040	/* long long, long double.  */
+
+#define CPP_N_RADIX	0x0F00
+#define CPP_N_DECIMAL	0x0100
+#define CPP_N_HEX	0x0200
+#define CPP_N_OCTAL	0x0400
+
+#define CPP_N_UNSIGNED	0x1000	/* Properties.  */
+#define CPP_N_IMAGINARY	0x2000
+
+/* Classify a CPP_NUMBER token.  The return value is a combination of
+   the flags from the above sets.  */
+extern unsigned cpp_classify_number PARAMS ((cpp_reader *, const cpp_token *));
+
+/* Evaluate a token classified as category CPP_N_INTEGER.  */
+extern cpp_num cpp_interpret_integer PARAMS ((cpp_reader *, const cpp_token *,
+					      unsigned int type));
 
 /* Diagnostic levels.  To get a dianostic without associating a
    position in the translation unit with it, use cpp_error_with_line
============================================================
Index: gcc/testsuite/gcc.dg/cpp/c++98-pedantic.c
--- gcc/testsuite/gcc.dg/cpp/c++98-pedantic.c	2 Dec 2000 10:16:01 -0000	1.1
+++ gcc/testsuite/gcc.dg/cpp/c++98-pedantic.c	29 May 2002 06:37:06 -0000
@@ -6,5 +6,5 @@
 /* This file is for testing the preprocessor in -std=c++98 -pedantic mode.
    Neil Booth, 2 Dec 2000.  */
 
-#if 1LL				/* { dg-warning "too many" } */
+#if 1LL				/* { dg-warning "long long" } */
 #endif
============================================================
Index: gcc/testsuite/gcc.dg/cpp/c89-pedantic.c
--- gcc/testsuite/gcc.dg/cpp/c89-pedantic.c	2 Dec 2000 10:16:01 -0000	1.1
+++ gcc/testsuite/gcc.dg/cpp/c89-pedantic.c	29 May 2002 06:37:06 -0000
@@ -6,5 +6,5 @@
 /* This file is for testing the preprocessor in -std=c89 -pedantic mode.
    Neil Booth, 2 Dec 2000.  */
 
-#if 1LL				/* { dg-warning "too many" } */
+#if 1LL				/* { dg-warning "long long" } */
 #endif
============================================================
Index: gcc/testsuite/gcc.dg/cpp/c94-pedantic.c
--- gcc/testsuite/gcc.dg/cpp/c94-pedantic.c	2 Dec 2000 10:16:01 -0000	1.1
+++ gcc/testsuite/gcc.dg/cpp/c94-pedantic.c	29 May 2002 06:37:06 -0000
@@ -6,5 +6,5 @@
 /* This file is for testing the preprocessor in -std=iso9899:199409
    -pedantic mode.  Neil Booth, 2 Dec 2000.  */
 
-#if 1LL				/* { dg-warning "too many" } */
+#if 1LL				/* { dg-warning "long long" } */
 #endif
============================================================
Index: gcc/testsuite/gcc.dg/cpp/gnuc89-pedantic.c
--- gcc/testsuite/gcc.dg/cpp/gnuc89-pedantic.c	2 Dec 2000 10:16:01 -0000	1.1
+++ gcc/testsuite/gcc.dg/cpp/gnuc89-pedantic.c	29 May 2002 06:37:06 -0000
@@ -6,5 +6,5 @@
 /* This file is for testing the preprocessor in -std=gnu89 -pedantic mode.
    Neil Booth, 2 Dec 2000.  */
 
-#if 1LL				/* { dg-warning "too many" } */
+#if 1LL				/* { dg-warning "long long" } */
 #endif
============================================================
Index: gcc/testsuite/gcc.dg/cpp/if-1.c
--- gcc/testsuite/gcc.dg/cpp/if-1.c	26 May 2002 18:42:20 -0000	1.3
+++ gcc/testsuite/gcc.dg/cpp/if-1.c	29 May 2002 06:37:06 -0000
@@ -22,7 +22,7 @@
 #error 0xabc	/* { dg-bogus "#error" "normal conversion" } */
 #endif
 
-#if 1.2 /* { dg-error "loating point numbers" "floating point in #if" } */
+#if 1.2 /* { dg-error "loating point" "floating point in #if" } */
 #endif
 
 #if 4uu /* { dg-error "invalid suffix" "too many suffixes" } */
@@ -34,7 +34,7 @@
 #if 1234lul	/* { dg-error "invalid suffix" "u between ls" } */
 #endif
 
-#if 099 /* { dg-error "digits beyond the radix" "decimal in octal constant" } */
+#if 099 /* { dg-error "invalid digit" "decimal in octal constant" } */
 #endif
 
 #if 0xfffffffffffffffff /* { dg-error "integer constant" "range error" } */



More information about the Gcc-patches mailing list