OSDN Git Service

(const_binop): Don't pass OVERFLOW to force_fit_type if type is
[pf3gnuchains/gcc-fork.git] / gcc / c-lex.c
index e8759bc..2c10890 100644 (file)
@@ -1,5 +1,5 @@
 /* Lexical analyzer for C and Objective C.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -30,6 +30,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "c-tree.h"
 #include "flags.h"
 #include "c-parse.h"
+#include "c-pragma.h"
+
+#include <ctype.h>
 
 #ifdef MULTIBYTE_CHARS
 #include <stdlib.h>
@@ -58,7 +61,7 @@ tree lastiddecl;
 
 int doing_objc_thang;
 
-extern tree lookup_interface ();
+extern tree is_class_name ();
 
 extern int yydebug;
 
@@ -88,157 +91,11 @@ static int end_of_file;
 static int nextchar = -1;
 
 int check_newline ();
-
-/* Nonzero tells yylex to ignore \ in string constants.  */
-static int ignore_escape_flag = 0;
 \f
-/* C code produced by gperf version 2.5 (GNU C++ version) */
-/* Command-line: gperf -p -j1 -i 1 -g -o -t -N is_reserved_word -k1,3,$ c-parse.gperf  */ 
-struct resword { char *name; short token; enum rid rid; };
-
-#define TOTAL_KEYWORDS 53
-#define MIN_WORD_LENGTH 2
-#define MAX_WORD_LENGTH 13
-#define MIN_HASH_VALUE 7
-#define MAX_HASH_VALUE 102
-/* maximum key range = 96, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#endif
-static unsigned int
-hash (str, len)
-     register char *str;
-     register int unsigned len;
-{
-  static unsigned char asso_values[] =
-    {
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
-     103, 103, 103, 103, 103,   1, 103,   2,   1,  24,
-       1,   5,  19,  39,  16,  13, 103,   1,  25,   1,
-      34,  34,  24, 103,  13,  12,   1,  45,  24,   7,
-     103, 103,   2, 103, 103, 103, 103, 103,
-    };
-  register int hval = len;
-
-  switch (hval)
-    {
-      default:
-      case 3:
-        hval += asso_values[str[2]];
-      case 2:
-      case 1:
-        hval += asso_values[str[0]];
-    }
-  return hval + asso_values[str[len - 1]];
-}
-
-#ifdef __GNUC__
-__inline
-#endif
-struct resword *
-is_reserved_word (str, len)
-     register char *str;
-     register unsigned int len;
-{
-  static struct resword wordlist[] =
-    {
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-      {"asm",  ASM_KEYWORD, NORID},
-      {"",}, 
-      {"__asm",  ASM_KEYWORD, NORID},
-      {"",}, 
-      {"__asm__",  ASM_KEYWORD, NORID},
-      {"break",  BREAK, NORID},
-      {"__typeof__",  TYPEOF, NORID},
-      {"",}, 
-      {"__alignof__",  ALIGNOF, NORID},
-      {"",}, 
-      {"__attribute__",  ATTRIBUTE, NORID},
-      {"int",  TYPESPEC, RID_INT},
-      {"__attribute",  ATTRIBUTE, NORID},
-      {"__extension__",  EXTENSION, NORID},
-      {"",}, 
-      {"__signed",  TYPESPEC, RID_SIGNED},
-      {"",}, 
-      {"__signed__",  TYPESPEC, RID_SIGNED},
-      {"__inline__",  SCSPEC, RID_INLINE},
-      {"else",  ELSE, NORID},
-      {"__inline",  SCSPEC, RID_INLINE},
-      {"default",  DEFAULT, NORID},
-      {"__typeof",  TYPEOF, NORID},
-      {"while",  WHILE, NORID},
-      {"__alignof",  ALIGNOF, NORID},
-      {"struct",  STRUCT, NORID},
-      {"__const",  TYPE_QUAL, RID_CONST},
-      {"if",  IF, NORID},
-      {"__const__",  TYPE_QUAL, RID_CONST},
-      {"__label__",  LABEL, NORID},
-      {"do",  DO, NORID},
-      {"__volatile__",  TYPE_QUAL, RID_VOLATILE},
-      {"sizeof",  SIZEOF, NORID},
-      {"__volatile",  TYPE_QUAL, RID_VOLATILE},
-      {"auto",  SCSPEC, RID_AUTO},
-      {"void",  TYPESPEC, RID_VOID},
-      {"char",  TYPESPEC, RID_CHAR},
-      {"static",  SCSPEC, RID_STATIC},
-      {"case",  CASE, NORID},
-      {"extern",  SCSPEC, RID_EXTERN},
-      {"switch",  SWITCH, NORID},
-      {"for",  FOR, NORID},
-      {"inline",  SCSPEC, RID_INLINE},
-      {"typeof",  TYPEOF, NORID},
-      {"typedef",  SCSPEC, RID_TYPEDEF},
-      {"short",  TYPESPEC, RID_SHORT},
-      {"",}, 
-      {"return",  RETURN, NORID},
-      {"enum",  ENUM, NORID},
-      {"",}, 
-      {"double",  TYPESPEC, RID_DOUBLE},
-      {"signed",  TYPESPEC, RID_SIGNED},
-      {"float",  TYPESPEC, RID_FLOAT},
-      {"",}, {"",}, 
-      {"volatile",  TYPE_QUAL, RID_VOLATILE},
-      {"",}, 
-      {"const",  TYPE_QUAL, RID_CONST},
-      {"",}, 
-      {"unsigned",  TYPESPEC, RID_UNSIGNED},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"continue",  CONTINUE, NORID},
-      {"",}, 
-      {"register",  SCSPEC, RID_REGISTER},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"goto",  GOTO, NORID},
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-      
-      {"union",  UNION, NORID},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"long",  TYPESPEC, RID_LONG},
-    };
-
-  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
-    {
-      register int key = hash (str, len);
-
-      if (key <= MAX_HASH_VALUE && key >= 0)
-        {
-          register char *s = wordlist[key].name;
-
-          if (*s == *str && !strcmp (str + 1, s + 1))
-            return &wordlist[key];
-        }
-    }
-  return 0;
-}
+/* Do not insert generated code into the source, instead, include it.
+   This allows us to build gcc automatically even for targets that
+   need to add or modify the reserved keyword lists.  */
+#include "c-gperf.h"
 \f
 /* Return something to represent absolute declarators containing a *.
    TARGET is the absolute declarator that the * contains.
@@ -256,6 +113,35 @@ make_pointer_declarator (type_quals, target)
 }
 \f
 void
+forget_protocol_qualifiers ()
+{
+  int i, n = sizeof wordlist / sizeof (struct resword);
+
+  for (i = 0; i < n; i++)
+    if ((int) wordlist[i].rid >= (int) RID_IN
+        && (int) wordlist[i].rid <= (int) RID_ONEWAY)
+      wordlist[i].name = "";
+}
+
+void
+remember_protocol_qualifiers ()
+{
+  int i, n = sizeof wordlist / sizeof (struct resword);
+
+  for (i = 0; i < n; i++)
+    if (wordlist[i].rid == RID_IN)
+      wordlist[i].name = "in";
+    else if (wordlist[i].rid == RID_OUT)
+      wordlist[i].name = "out";
+    else if (wordlist[i].rid == RID_INOUT)
+      wordlist[i].name = "inout";
+    else if (wordlist[i].rid == RID_BYCOPY)
+      wordlist[i].name = "bycopy";
+    else if (wordlist[i].rid == RID_ONEWAY)
+      wordlist[i].name = "oneway";   
+}
+\f
+void
 init_lex ()
 {
   /* Make identifier nodes long enough for the language-specific slots.  */
@@ -290,6 +176,15 @@ init_lex ()
   ridpointers[(int) RID_EXTERN] = get_identifier ("extern");
   ridpointers[(int) RID_TYPEDEF] = get_identifier ("typedef");
   ridpointers[(int) RID_REGISTER] = get_identifier ("register");
+  ridpointers[(int) RID_ITERATOR] = get_identifier ("iterator");
+  ridpointers[(int) RID_COMPLEX] = get_identifier ("complex");
+  ridpointers[(int) RID_ID] = get_identifier ("id");
+  ridpointers[(int) RID_IN] = get_identifier ("in");
+  ridpointers[(int) RID_OUT] = get_identifier ("out");
+  ridpointers[(int) RID_INOUT] = get_identifier ("inout");
+  ridpointers[(int) RID_BYCOPY] = get_identifier ("bycopy");
+  ridpointers[(int) RID_ONEWAY] = get_identifier ("oneway");
+  forget_protocol_qualifiers();
 
   /* Some options inhibit certain reserved words.
      Clear those words out of the hash table so they won't be recognized.  */
@@ -297,6 +192,9 @@ init_lex ()
   do { struct resword *s = is_reserved_word (STRING, sizeof (STRING) - 1); \
        if (s) s->name = ""; } while (0)
 
+  if (! doing_objc_thang)
+    UNSET_RESERVED_WORD ("id");
+
   if (flag_traditional)
     {
       UNSET_RESERVED_WORD ("const");
@@ -304,12 +202,16 @@ init_lex ()
       UNSET_RESERVED_WORD ("typeof");
       UNSET_RESERVED_WORD ("signed");
       UNSET_RESERVED_WORD ("inline");
+      UNSET_RESERVED_WORD ("iterator");
+      UNSET_RESERVED_WORD ("complex");
     }
   if (flag_no_asm)
     {
       UNSET_RESERVED_WORD ("asm");
       UNSET_RESERVED_WORD ("typeof");
       UNSET_RESERVED_WORD ("inline");
+      UNSET_RESERVED_WORD ("iterator");
+      UNSET_RESERVED_WORD ("complex");
     }
 }
 
@@ -331,6 +233,7 @@ yyprint (file, yychar, yylval)
     {
     case IDENTIFIER:
     case TYPENAME:
+    case OBJECTNAME:
       t = yylval.ttype;
       if (IDENTIFIER_POINTER (t))
        fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
@@ -339,8 +242,21 @@ yyprint (file, yychar, yylval)
     case CONSTANT:
       t = yylval.ttype;
       if (TREE_CODE (t) == INTEGER_CST)
-       fprintf (file, " 0x%8x%8x", TREE_INT_CST_HIGH (t),
-                TREE_INT_CST_LOW (t));
+       fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == 64
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+                " 0x%lx%016lx",
+#else
+                " 0x%x%016x",
+#endif
+#else
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+                " 0x%lx%08lx",
+#else
+                " 0x%x%08x",
+#endif
+#endif
+                TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t));
       break;
     }
 }
@@ -481,10 +397,14 @@ check_newline ()
              && getc (finput) == 'a'
              && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
            {
+#ifdef HANDLE_SYSV_PRAGMA
+             return handle_sysv_pragma (finput, c);
+#else /* !HANDLE_SYSV_PRAGMA */
 #ifdef HANDLE_PRAGMA
              HANDLE_PRAGMA (finput);
 #endif /* HANDLE_PRAGMA */
              goto skipline;
+#endif /* !HANDLE_SYSV_PRAGMA */
            }
        }
 
@@ -615,10 +535,8 @@ linenum:
 
       /* More follows: it must be a string constant (filename).  */
 
-      /* Read the string constant, but don't treat \ as special.  */
-      ignore_escape_flag = 1;
+      /* Read the string constant.  */
       token = yylex ();
-      ignore_escape_flag = 0;
 
       if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
        {
@@ -643,7 +561,13 @@ linenum:
       while (c == ' ' || c == '\t')
        c = getc (finput);
       if (c == '\n')
-       return c;
+       {
+         /* Update the name in the top element of input_file_stack.  */
+         if (input_file_stack)
+           input_file_stack->name = input_filename;
+
+         return c;
+       }
       ungetc (c, finput);
 
       token = yylex ();
@@ -695,6 +619,11 @@ linenum:
            }
        }
 
+      /* Now that we've pushed or popped the input stack,
+        update the name in the top element.  */
+      if (input_file_stack)
+       input_file_stack->name = input_filename;
+
       /* If we have handled a `1' or a `2',
         see if there is another number to read.  */
       if (used_up)
@@ -716,7 +645,20 @@ linenum:
       if (token == CONSTANT
          && TREE_CODE (yylval.ttype) == INTEGER_CST
          && TREE_INT_CST_LOW (yylval.ttype) == 3)
-       in_system_header = 1;
+       in_system_header = 1, used_up = 1;
+
+      if (used_up)
+       {
+         /* Is this the last nonwhite stuff on the line?  */
+         c = getc (finput);
+         while (c == ' ' || c == '\t')
+           c = getc (finput);
+         if (c == '\n')
+           return c;
+         ungetc (c, finput);
+       }
+
+      warning ("unrecognized text at end of #line");
     }
   else
     error ("invalid #-line");
@@ -729,20 +671,64 @@ linenum:
   return c;
 }
 \f
-#define isalnum(char) ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9'))
-#define isdigit(char) (char >= '0' && char <= '9')
+#ifdef HANDLE_SYSV_PRAGMA
+
+/* Handle a #pragma directive.  INPUT is the current input stream,
+   and C is a character to reread.  Processes the entire input line
+   and returns a character for the caller to reread: either \n or EOF.  */
+
+/* This function has to be in this file, in order to get at
+   the token types.  */
+
+int
+handle_sysv_pragma (input, c)
+     FILE *input;
+     int c;
+{
+  for (;;)
+    {
+      while (c == ' ' || c == '\t')
+       c = getc (input);
+      if (c == '\n' || c == EOF)
+       {
+         handle_pragma_token (0, 0);
+         return c;
+       }
+      ungetc (c, input);
+      switch (yylex ())
+       {
+       case IDENTIFIER:
+       case TYPENAME:
+       case STRING:
+       case CONSTANT:
+         handle_pragma_token (token_buffer, yylval.ttype);
+         break;
+       default:
+         handle_pragma_token (token_buffer, 0);
+       }
+      if (nextchar >= 0)
+       c = nextchar, nextchar = -1;
+      else
+       c = getc (input);
+    }
+}
+
+#endif /* HANDLE_SYSV_PRAGMA */
+\f
 #define ENDFILE -1  /* token that represents end-of-file */
 
 /* Read an escape sequence, returning its equivalent as a character,
-   or -1 if it is backslash-newline.  */
+   or store 1 in *ignore_ptr if it is backslash-newline.  */
 
 static int
-readescape ()
+readescape (ignore_ptr)
+     int *ignore_ptr;
 {
   register int c = getc (finput);
   register int code;
   register unsigned count;
-  unsigned firstdig;
+  unsigned firstdig = 0;
+  int nonnull;
 
   switch (c)
     {
@@ -755,6 +741,7 @@ readescape ()
 
       code = 0;
       count = 0;
+      nonnull = 0;
       while (1)
        {
          c = getc (finput);
@@ -772,12 +759,19 @@ readescape ()
            code += c - 'A' + 10;
          if (c >= '0' && c <= '9')
            code += c - '0';
-         if (count == 0)
-           firstdig = code;
-         count++;
+         if (code != 0 || count != 0)
+           {
+             if (count == 0)
+               firstdig = code;
+             count++;
+           }
+         nonnull = 1;
        }
-      if (count == 0)
+      if (! nonnull)
        error ("\\x used with no following hex digits");
+      else if (count == 0)
+       /* Digits are all 0's.  Ok.  */
+       ;
       else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
               || (count > 1
                   && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
@@ -802,7 +796,8 @@ readescape ()
 
     case '\n':
       lineno++;
-      return -1;
+      *ignore_ptr = 1;
+      return 0;
 
     case 'n':
       return TARGET_NEWLINE;
@@ -834,8 +829,10 @@ readescape ()
 #endif
       return TARGET_VT;
 
+    case 'e':
     case 'E':
-      pedwarn ("non-ANSI-standard escape sequence, `\\E'");
+      if (pedantic)
+       pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
       return 033;
 
     case '?':
@@ -845,11 +842,13 @@ readescape ()
     case '(':
     case '{':
     case '[':
+      /* `\%' is used to prevent SCCS from getting confused.  */
+    case '%':
       if (pedantic)
        pedwarn ("non-ANSI escape sequence `\\%c'", c);
       return c;
     }
-  if (c >= 040 && c <= 0177)
+  if (c >= 040 && c < 0177)
     pedwarn ("unknown escape sequence `\\%c'", c);
   else
     pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
@@ -911,6 +910,7 @@ yylex ()
   register char *p;
   register int value;
   int wide_flag = 0;
+  int objc_flag = 0;
 
   if (nextchar >= 0)
     c = nextchar, nextchar = -1;
@@ -922,9 +922,6 @@ yylex ()
   while (1)
     switch (c)
       {
-      case '\r':
-       if (!flag_traditional)  /* ANSI says no */
-         goto found_nonwhite;
       case ' ':
       case '\t':
       case '\f':
@@ -933,6 +930,9 @@ yylex ()
        c = getc (finput);
        break;
 
+      case '\r':
+       /* Call skip_white_space so we can warn if appropriate.  */
+
       case '\n':
       case '/':
       case '\\':
@@ -984,28 +984,19 @@ yylex ()
          value = c;
          break;
        }
-      p = token_buffer;
-      *p++ = '@';
-      c = getc (finput);
-      while (isalnum (c) || c == '_')
+      else
        {
-         if (p >= token_buffer + maxtoken)
-           p = extend_token_buffer (p);
-
-         *p++ = c;
-         c = getc (finput);
+         /* '@' may start a constant string object.  */
+         register int c = getc(finput);
+         if (c == '"')
+           {
+             objc_flag = 1;
+             goto string_constant;
+           }
+         ungetc(c, finput);
+         /* Fall through to treat '@' as the start of an indentifier.  */
        }
 
-      *p = 0;
-      nextchar = c;
-      value = recognize_objc_keyword (token_buffer + 1);
-      if (value != 0)
-       break;
-      error ("invalid Objective C keyword `%s'", token_buffer);
-      /* Cause a syntax error--1 is not a valid token type.  */
-      value = 1;
-      break;
-
     case 'A':  case 'B':  case 'C':  case 'D':  case 'E':
     case 'F':  case 'G':  case 'H':  case 'I':  case 'J':
     case 'K':            case 'M':  case 'N':  case 'O':
@@ -1023,11 +1014,15 @@ yylex ()
       p = token_buffer;
       while (isalnum (c) || c == '_' || c == '$' || c == '@')
        {
-         if (p >= token_buffer + maxtoken)
-           p = extend_token_buffer (p);
+         /* Make sure this char really belongs in an identifier.  */
+         if (c == '@' && ! doing_objc_thang)
+           break;
          if (c == '$' && ! dollars_in_ident)
            break;
 
+         if (p >= token_buffer + maxtoken)
+           p = extend_token_buffer (p);
+
          *p++ = c;
          c = getc (finput);
        }
@@ -1049,6 +1044,16 @@ yylex ()
              yylval.ttype = ridpointers[(int) ptr->rid];
            value = (int) ptr->token;
 
+           /* Only return OBJECTNAME if it is a typedef.  */
+           if (doing_objc_thang && value == OBJECTNAME)
+             {
+               lastiddecl = lookup_name(yylval.ttype);
+
+               if (lastiddecl == NULL_TREE
+                   || TREE_CODE (lastiddecl) != TYPE_DECL)
+                 value = IDENTIFIER;
+             }
+
            /* Even if we decided to recognize asm, still perhaps warn.  */
            if (pedantic
                && (value == ASM_KEYWORD || value == TYPEOF
@@ -1064,14 +1069,34 @@ yylex ()
 
       if (value == IDENTIFIER)
        {
+         if (token_buffer[0] == '@')
+           error("invalid identifier `%s'", token_buffer);
+
           yylval.ttype = get_identifier (token_buffer);
          lastiddecl = lookup_name (yylval.ttype);
 
          if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL)
            value = TYPENAME;
+         /* A user-invisible read-only initialized variable
+            should be replaced by its value.
+            We handle only strings since that's the only case used in C.  */
+         else if (lastiddecl != 0 && TREE_CODE (lastiddecl) == VAR_DECL
+                  && DECL_IGNORED_P (lastiddecl)
+                  && TREE_READONLY (lastiddecl)
+                  && DECL_INITIAL (lastiddecl) != 0
+                  && TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST)
+           {
+             tree stringval = DECL_INITIAL (lastiddecl);
+             
+             /* Copy the string value so that we won't clobber anything
+                if we put something in the TREE_CHAIN of this one.  */
+             yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
+                                          TREE_STRING_POINTER (stringval));
+             value = STRING;
+           }
           else if (doing_objc_thang)
             {
-             tree objc_interface_decl = lookup_interface (yylval.ttype);
+             tree objc_interface_decl = is_class_name (yylval.ttype);
 
              if (objc_interface_decl)
                {
@@ -1092,16 +1117,20 @@ yylex ()
        int largest_digit = 0;
        int numdigits = 0;
        /* for multi-precision arithmetic,
-          we store only 8 live bits in each short,
-          giving us 64 bits of reliable precision */
-       short shorts[8];
+          we actually store only HOST_BITS_PER_CHAR bits in each part.
+          The number of parts is chosen so as to be sufficient to hold
+          the enough bits to fit into the two HOST_WIDE_INTs that contain
+          the integer value (this is always at least as many bits as are
+          in a target `long long' value, but may be wider).  */
+#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2)
+       int parts[TOTAL_PARTS];
        int overflow = 0;
 
        enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag
          = NOT_FLOAT;
 
-       for (count = 0; count < 8; count++)
-         shorts[count] = 0;
+       for (count = 0; count < TOTAL_PARTS; count++)
+         parts[count] = 0;
 
        p = token_buffer;
        *p++ = c;
@@ -1127,18 +1156,25 @@ yylex ()
        /* Read all the digits-and-decimal-points.  */
 
        while (c == '.'
-              || (isalnum (c) && (c != 'l') && (c != 'L')
-                  && (c != 'u') && (c != 'U')
+              || (isalnum (c) && c != 'l' && c != 'L'
+                  && c != 'u' && c != 'U'
+                  && c != 'i' && c != 'I' && c != 'j' && c != 'J'
                   && (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F')))))
          {
            if (c == '.')
              {
                if (base == 16)
                  error ("floating constant may not be in radix 16");
-               if (floatflag == AFTER_POINT)
+               if (floatflag == TOO_MANY_POINTS)
+                 /* We have already emitted an error.  Don't need another.  */
+                 ;
+               else if (floatflag == AFTER_POINT)
                  {
                    error ("malformed floating constant");
                    floatflag = TOO_MANY_POINTS;
+                   /* Avoid another error from atof by forcing all characters
+                      from here on to be ignored.  */
+                   p[-1] = '\0';
                  }
                else
                  floatflag = AFTER_POINT;
@@ -1179,7 +1215,7 @@ yylex ()
                  }
                else if (base <= 10)
                  {
-                   if ((c&~040) == 'E')
+                   if (c == 'e' || c == 'E')
                      {
                        base = 10;
                        floatflag = AFTER_POINT;
@@ -1200,20 +1236,24 @@ yylex ()
                  largest_digit = c;
                numdigits++;
 
-               for (count = 0; count < 8; count++)
+               for (count = 0; count < TOTAL_PARTS; count++)
                  {
-                   shorts[count] *= base;
+                   parts[count] *= base;
                    if (count)
                      {
-                       shorts[count] += (shorts[count-1] >> 8);
-                       shorts[count-1] &= (1<<8)-1;
+                       parts[count]
+                         += (parts[count-1] >> HOST_BITS_PER_CHAR);
+                       parts[count-1]
+                         &= (1 << HOST_BITS_PER_CHAR) - 1;
                      }
-                   else shorts[0] += c;
+                   else
+                     parts[0] += c;
                  }
 
-               if (shorts[7] >= 1<<8
-                   || shorts[7] < - (1 << 8))
-                 overflow = TRUE;
+               /* If the extra highest-order part ever gets anything in it,
+                  the number is certainly too big.  */
+               if (parts[TOTAL_PARTS - 1] != 0)
+                 overflow = 1;
 
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
@@ -1233,8 +1273,8 @@ yylex ()
        if (floatflag != NOT_FLOAT)
          {
            tree type = double_type_node;
-           char f_seen = 0;
-           char l_seen = 0;
+           int garbage_chars = 0, exceeds_double = 0;
+           int imag = 0;
            REAL_VALUE_TYPE value;
            jmp_buf handler;
 
@@ -1273,76 +1313,128 @@ yylex ()
              }
            else
              {
+               int fflag = 0, lflag = 0;
+               /* Copy token_buffer now, while it has just the number
+                  and not the suffixes; once we add `f' or `i',
+                  REAL_VALUE_ATOF may not work any more.  */
+               char *copy = (char *) alloca (p - token_buffer + 1);
+               bcopy (token_buffer, copy, p - token_buffer + 1);
+
                set_float_handler (handler);
-               value = REAL_VALUE_ATOF (token_buffer);
-               set_float_handler (0);
-             }
-#ifdef ERANGE
-           if (errno == ERANGE && !flag_traditional)
-             {
-               char *p1 = token_buffer;
-               /* Check for "0.0" and variants;
-                  Sunos 4 spuriously returns ERANGE for them.  */
-               while (*p1 == '0') p1++;
-               if (*p1 == '.')
-                 {
-                   p1++;
-                   while (*p1 == '0') p1++;
-                 }
-               if (*p1 == 'e' || *p1 == 'E')
+
+               while (1)
                  {
-                   /* with significand==0, ignore the exponent */
-                   p1++;
-                   while (*p1 != 0) p1++;
+                   int lose = 0;
+
+                   /* Read the suffixes to choose a data type.  */
+                   switch (c)
+                     {
+                     case 'f': case 'F':
+                       if (fflag)
+                         error ("more than one `f' in numeric constant");
+                       fflag = 1;
+                       break;
+
+                     case 'l': case 'L':
+                       if (lflag)
+                         error ("more than one `l' in numeric constant");
+                       lflag = 1;
+                       break;
+
+                     case 'i': case 'I':
+                       if (imag)
+                         error ("more than one `i' or `j' in numeric constant");
+                       else if (pedantic)
+                         pedwarn ("ANSI C forbids imaginary numeric constants");
+                       imag = 1;
+                       break;
+
+                     default:
+                       lose = 1;
+                     }
+
+                   if (lose)
+                     break;
+
+                   if (p >= token_buffer + maxtoken - 3)
+                     p = extend_token_buffer (p);
+                   *p++ = c;
+                   *p = 0;
+                   c = getc (finput);
                  }
-               /* ERANGE is also reported for underflow,
-                  so test the value to distinguish overflow from that.  */
-               if (*p1 != 0 && (value > 1.0 || value < -1.0))
-                 warning ("floating point number exceeds range of `double'");
-             }
-#endif
 
-           /* Read the suffixes to choose a data type.  */
-           while (1)
-             {
-               if (c == 'f' || c == 'F')
+               /* The second argument, machine_mode, of REAL_VALUE_ATOF
+                  tells the desired precision of the binary result
+                  of decimal-to-binary conversion.  */
+
+               if (fflag)
                  {
-                   if (f_seen)
-                     error ("two `f's in floating constant");
-                   f_seen = 1;
+                   if (lflag)
+                     error ("both `f' and `l' in floating constant");
+
                    type = float_type_node;
-                   value = REAL_VALUE_TRUNCATE (TYPE_MODE (type), value);
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   /* A diagnostic is required here by some ANSI C testsuites.
+                      This is not pedwarn, become some people don't want
+                      an error for this.  */
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `float'");
                  }
-               else if (c == 'l' || c == 'L')
+               else if (lflag)
                  {
-                   if (l_seen)
-                     error ("two `l's in floating constant");
-                   l_seen = 1;
                    type = long_double_type_node;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `long double'");
                  }
                else
                  {
-                   if (isalnum (c))
-                     {
-                       error ("garbage at end of number");
-                       while (isalnum (c))
-                         {
-                           if (p >= token_buffer + maxtoken - 3)
-                             p = extend_token_buffer (p);
-                           *p++ = c;
-                           c = getc (finput);
-                         }
-                     }
-                   break;
+                   value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   if (REAL_VALUE_ISINF (value) && pedantic)
+                     warning ("floating point number exceeds range of `double'");
                  }
+
+               set_float_handler (NULL_PTR);
+           }
+#ifdef ERANGE
+           if (errno == ERANGE && !flag_traditional && pedantic)
+             {
+               /* ERANGE is also reported for underflow,
+                  so test the value to distinguish overflow from that.  */
+               if (REAL_VALUES_LESS (dconst1, value)
+                   || REAL_VALUES_LESS (value, dconstm1))
+                 {
+                   warning ("floating point number exceeds range of `double'");
+                   exceeds_double = 1;
+                 }
+             }
+#endif
+           garbage_chars = 0;
+           while (isalnum (c) || c == '.' || c == '_'
+                  || (!flag_traditional && (c == '+' || c == '-')
+                      && (p[-1] == 'e' || p[-1] == 'E')))
+             {
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
                *p++ = c;
                c = getc (finput);
+               garbage_chars++;
              }
+           if (garbage_chars > 0)
+             error ("garbage at end of number");
+
+           /* If the result is not a number, assume it must have been
+              due to some error message above, so silently convert
+              it to a zero.  */
+           if (REAL_VALUE_ISNAN (value))
+             value = dconst0;
 
            /* Create a node with determined type and value.  */
-           yylval.ttype = build_real (type, value);
+           if (imag)
+             yylval.ttype = build_complex (convert (type, integer_zero_node),
+                                           build_real (type, value));
+           else
+             yylval.ttype = build_real (type, value);
 
            ungetc (c, finput);
            *p = 0;
@@ -1350,9 +1442,11 @@ yylex ()
        else
          {
            tree traditional_type, ansi_type, type;
+           HOST_WIDE_INT high, low;
            int spec_unsigned = 0;
            int spec_long = 0;
            int spec_long_long = 0;
+           int spec_imag = 0;
            int bytes, warn, i;
 
            while (1)
@@ -1375,12 +1469,24 @@ yylex ()
                      }
                    spec_long = 1;
                  }
+               else if (c == 'i' || c == 'j' || c == 'I' || c == 'J')
+                 {
+                   if (spec_imag)
+                     error ("more than one `i' or `j' in numeric constant");
+                   else if (pedantic)
+                     pedwarn ("ANSI C forbids imaginary numeric constants");
+                   spec_imag = 1;
+                 }
                else
                  {
-                   if (isalnum (c))
+                   if (isalnum (c) || c == '.' || c == '_'
+                       || (!flag_traditional && (c == '+' || c == '-')
+                           && (p[-1] == 'e' || p[-1] == 'E')))
                      {
                        error ("garbage at end of number");
-                       while (isalnum (c))
+                       while (isalnum (c) || c == '.' || c == '_'
+                              || (!flag_traditional && (c == '+' || c == '-')
+                                  && (p[-1] == 'e' || p[-1] == 'E')))
                          {
                            if (p >= token_buffer + maxtoken - 3)
                              p = extend_token_buffer (p);
@@ -1413,107 +1519,29 @@ yylex ()
            else
              bytes = TYPE_PRECISION (long_integer_type_node) / 8;
 
-           if (bytes <= 8)
-             {
-               warn = overflow;
-               for (i = bytes; i < 8; i++)
-                 if (shorts[i])
-                   {
-                     /* If LL was not used, then clear any excess precision.
-                        This is equivalent to the original code, but it is
-                        not clear why this is being done.  Perhaps to prevent
-                        ANSI programs from creating long long constants
-                        by accident?  */
-                     if (! spec_long_long)
-                       shorts[i] = 0;
-                     warn = 1;
-                   }
-               if (warn)
-                 warning ("integer constant out of range");
-             }
-           else if (overflow)
-             warning ("integer constant larger than compiler can handle");
-
-           /* If it overflowed our internal buffer, then make it unsigned.
-              We can't distinguish based on the tree node because
-              any integer constant fits any long long type.  */
-           if (overflow)
-             spec_unsigned = 1;
+           warn = overflow;
+           for (i = bytes; i < TOTAL_PARTS; i++)
+             if (parts[i])
+               warn = 1;
+           if (warn)
+             pedwarn ("integer constant out of range");
 
            /* This is simplified by the fact that our constant
               is always positive.  */
-           /* The casts in the following statement should not be
-              needed, but they get around bugs in some C compilers.  */
-           yylval.ttype
-             = (build_int_2
-                ((((long)shorts[3]<<24) + ((long)shorts[2]<<16)
-                  + ((long)shorts[1]<<8) + (long)shorts[0]),
-                 (((long)shorts[7]<<24) + ((long)shorts[6]<<16)
-                  + ((long)shorts[5]<<8) + (long)shorts[4])));
 
-#if 0
-           /* Find the first allowable type that the value fits in.  */
-           type = 0;
-           for (i = 0; i < sizeof (type_sequence) / sizeof (type_sequence[0]);
-                i++)
-             if (!(spec_long && !type_sequence[i].long_flag)
-                 && !(spec_long_long && !type_sequence[i].long_long_flag)
-                 && !(spec_unsigned && !type_sequence[i].unsigned_flag)
-                 /* A decimal constant can't be unsigned int
-                    unless explicitly specified.  */
-                 && !(base == 10 && !spec_unsigned
-                      && *type_sequence[i].node_var == unsigned_type_node))
-               if (int_fits_type_p (yylval.ttype, *type_sequence[i].node_var))
-                 {
-                   type = *type_sequence[i].node_var;
-                   break;
-                 }
-           if (flag_traditional && type == long_unsigned_type_node
-               && !spec_unsigned)
-             type = long_integer_type_node;
-             
-           if (type == 0)
-             {
-               type = long_long_integer_type_node;
-               warning ("integer constant out of range");
-             }
+           high = low = 0;
 
-           /* Warn about some cases where the type of a given constant
-              changes from traditional C to ANSI C.  */
-           if (warn_traditional)
+           for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++)
              {
-               tree other_type = 0;
-
-               /* This computation is the same as the previous one
-                  except that flag_traditional is used backwards.  */
-               for (i = 0; i < sizeof (type_sequence) / sizeof (type_sequence[0]);
-                    i++)
-                 if (!(spec_long && !type_sequence[i].long_flag)
-                     && !(spec_long_long && !type_sequence[i].long_long_flag)
-                     && !(spec_unsigned && !type_sequence[i].unsigned_flag)
-                     /* A decimal constant can't be unsigned int
-                        unless explicitly specified.  */
-                     && !(base == 10 && !spec_unsigned
-                          && *type_sequence[i].node_var == unsigned_type_node))
-                   if (int_fits_type_p (yylval.ttype, *type_sequence[i].node_var))
-                     {
-                       other_type = *type_sequence[i].node_var;
-                       break;
-                     }
-               if (!flag_traditional && type == long_unsigned_type_node
-                   && !spec_unsigned)
-                 type = long_integer_type_node;
-             
-               if (other_type != 0 && other_type != type)
-                 {
-                   if (flag_traditional)
-                     warning ("type of integer constant would be different without -traditional");
-                   else
-                     warning ("type of integer constant would be different with -traditional");
-                 }
+               high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT
+                                                   / HOST_BITS_PER_CHAR)]
+                        << (i * HOST_BITS_PER_CHAR));
+               low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR);
              }
+           
+           yylval.ttype = build_int_2 (low, high);
+           TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
 
-#else /* 1 */
            /* If warn_traditional, calculate both the ANSI type and the
               traditional type, then see if they disagree.
               Otherwise, calculate only the type for the dialect in use.  */
@@ -1536,9 +1564,7 @@ yylex ()
                         && int_fits_type_p (yylval.ttype, integer_type_node))
                  traditional_type = (spec_unsigned ? unsigned_type_node
                                      : integer_type_node);
-               else if (! spec_long_long
-                        && int_fits_type_p (yylval.ttype,
-                                            long_unsigned_type_node))
+               else if (! spec_long_long)
                  traditional_type = (spec_unsigned ? long_unsigned_type_node
                                      : long_integer_type_node);
                else
@@ -1558,11 +1584,11 @@ yylex ()
                else if (! spec_unsigned && !spec_long_long
                         && int_fits_type_p (yylval.ttype, long_integer_type_node))
                  ansi_type = long_integer_type_node;
-               else if (! spec_long_long
-                        && int_fits_type_p (yylval.ttype,
-                                            long_unsigned_type_node))
+               else if (! spec_long_long)
                  ansi_type = long_unsigned_type_node;
                else if (! spec_unsigned
+                        /* Verify value does not overflow into sign bit.  */
+                        && TREE_INT_CST_HIGH (yylval.ttype) >= 0
                         && int_fits_type_p (yylval.ttype,
                                             long_long_integer_type_node))
                  ansi_type = long_long_integer_type_node;
@@ -1583,9 +1609,37 @@ yylex ()
                else
                  warning ("width of integer constant may change on other systems with -traditional");
              }
-#endif
 
-           TREE_TYPE (yylval.ttype) = type;
+           if (!flag_traditional && !int_fits_type_p (yylval.ttype, type)
+               && !warn)
+             pedwarn ("integer constant out of range");
+
+           if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
+             warning ("decimal constant is so large that it is unsigned");
+
+           if (spec_imag)
+             {
+               if (TYPE_PRECISION (type)
+                   <= TYPE_PRECISION (integer_type_node))
+                 yylval.ttype
+                   = build_complex (integer_zero_node,
+                                    convert (integer_type_node, yylval.ttype));
+               else
+                 error ("complex integer constant is too wide for `complex int'");
+             }
+           else if (flag_traditional && !int_fits_type_p (yylval.ttype, type))
+             /* The traditional constant 0x80000000 is signed
+                but doesn't fit in the range of int.
+                This will change it to -0x80000000, which does fit.  */
+             {
+               TREE_TYPE (yylval.ttype) = unsigned_type (type);
+               yylval.ttype = convert (type, yylval.ttype);
+               TREE_OVERFLOW (yylval.ttype)
+                 = TREE_CONSTANT_OVERFLOW (yylval.ttype) = 0;
+             }
+           else
+             TREE_TYPE (yylval.ttype) = type;
+
            *p = 0;
          }
 
@@ -1596,7 +1650,7 @@ yylex ()
     char_constant:
       {
        register int result = 0;
-       register num_chars = 0;
+       register int num_chars = 0;
        unsigned width = TYPE_PRECISION (char_type_node);
        int max_chars;
 
@@ -1623,12 +1677,17 @@ yylex ()
 
            if (c == '\\')
              {
-               c = readescape ();
-               if (c < 0)
+               int ignore = 0;
+               c = readescape (&ignore);
+               if (ignore)
                  goto tryagain;
                if (width < HOST_BITS_PER_INT
                    && (unsigned) c >= (1 << width))
                  pedwarn ("escape sequence out of range for character");
+#ifdef MAP_CHARACTER
+               if (isprint (c))
+                 c = MAP_CHARACTER (c);
+#endif
              }
            else if (c == '\n')
              {
@@ -1636,6 +1695,10 @@ yylex ()
                  pedwarn ("ANSI C forbids newline in character constant");
                lineno++;
              }
+#ifdef MAP_CHARACTER
+           else
+             c = MAP_CHARACTER (c);
+#endif
 
            num_chars++;
            if (num_chars > maxtoken - 4)
@@ -1672,17 +1735,21 @@ yylex ()
        if (! wide_flag)
          {
            int num_bits = num_chars * width;
-           if (TREE_UNSIGNED (char_type_node)
-               || ((result >> (num_bits - 1)) & 1) == 0)
+           if (num_bits == 0)
+             /* We already got an error; avoid invalid shift.  */
+             yylval.ttype = build_int_2 (0, 0);
+           else if (TREE_UNSIGNED (char_type_node)
+                    || ((result >> (num_bits - 1)) & 1) == 0)
              yylval.ttype
-               = build_int_2 (result & ((unsigned) ~0
-                                        >> (HOST_BITS_PER_INT - num_bits)),
+               = build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
+                                        >> (HOST_BITS_PER_WIDE_INT - num_bits)),
                               0);
            else
              yylval.ttype
-               = build_int_2 (result | ~((unsigned) ~0
-                                         >> (HOST_BITS_PER_INT - num_bits)),
+               = build_int_2 (result | ~((unsigned HOST_WIDE_INT) ~0
+                                         >> (HOST_BITS_PER_WIDE_INT - num_bits)),
                               -1);
+           TREE_TYPE (yylval.ttype) = integer_type_node;
          }
        else
          {
@@ -1695,7 +1762,7 @@ yylex ()
                || (num_chars == 1 && token_buffer[1] != '\0'))
              {
                wchar_t wc;
-               (void) mbtowc (NULL, NULL, 0);
+               (void) mbtowc (NULL_PTR, NULL_PTR, 0);
                if (mbtowc (& wc, token_buffer + 1, num_chars) == num_chars)
                  result = wc;
                else
@@ -1703,9 +1770,9 @@ yylex ()
              }
 #endif
            yylval.ttype = build_int_2 (result, 0);
+           TREE_TYPE (yylval.ttype) = wchar_type_node;
          }
 
-       TREE_TYPE (yylval.ttype) = integer_type_node;
        value = CONSTANT;
        break;
       }
@@ -1718,11 +1785,11 @@ yylex ()
 
        while (c != '"' && c >= 0)
          {
-           /* ignore_escape_flag is set for reading the filename in #line.  */
-           if (!ignore_escape_flag && c == '\\')
+           if (c == '\\')
              {
-               c = readescape ();
-               if (c < 0)
+               int ignore = 0;
+               c = readescape (&ignore);
+               if (ignore)
                  goto skipnewline;
                if (!wide_flag
                    && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
@@ -1745,6 +1812,9 @@ yylex ()
          }
        *p = 0;
 
+       if (c < 0)
+         error ("Unterminated string constant");
+
        /* We have read the entire constant.
           Construct a STRING_CST for the result.  */
 
@@ -1757,7 +1827,7 @@ yylex ()
 
 #ifdef MULTIBYTE_CHARS
            len = mbstowcs ((wchar_t *) widep, token_buffer + 1, p - token_buffer);
-           if ((unsigned) len >= (p - token_buffer))
+           if (len < 0 || len >= (p - token_buffer))
              {
                warning ("Ignoring invalid multibyte string");
                len = 0;
@@ -1782,23 +1852,35 @@ yylex ()
 #endif
            yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
            TREE_TYPE (yylval.ttype) = wchar_array_type_node;
+           value = STRING;
+         }
+       else if (objc_flag)
+         {
+           extern tree build_objc_string();
+           /* Return an Objective-C @"..." constant string object.  */
+           yylval.ttype = build_objc_string (p - token_buffer,
+                                             token_buffer + 1);
+           TREE_TYPE (yylval.ttype) = char_array_type_node;
+           value = OBJC_STRING;
          }
        else
          {
            yylval.ttype = build_string (p - token_buffer, token_buffer + 1);
            TREE_TYPE (yylval.ttype) = char_array_type_node;
+           value = STRING;
          }
 
        *p++ = '"';
        *p = 0;
 
-       value = STRING; break;
+       break;
       }
 
     case '+':
     case '-':
     case '&':
     case '|':
+    case ':':
     case '<':
     case '>':
     case '*':
@@ -1876,8 +1958,28 @@ yylex ()
              c = RSHIFT;
              goto combine;
            }
-       else if ((c == '-') && (c1 == '>'))
-         { value = POINTSAT; goto done; }
+       else
+         switch (c)
+           {
+           case '-':
+             if (c1 == '>')
+               { value = POINTSAT; goto done; }
+             break;
+           case ':':
+             if (c1 == '>')
+               { value = ']'; goto done; }
+             break;
+           case '<':
+             if (c1 == '%')
+               { value = '{'; goto done; }
+             if (c1 == ':')
+               { value = '['; goto done; }
+             break;
+           case '%':
+             if (c1 == '>')
+               { value = '}'; goto done; }
+             break;
+           }
        ungetc (c1, finput);
        token_buffer[1] = 0;