OSDN Git Service

* c-lex.c (MULTIBYTE_CHARS): #undef if cross compiling.
[pf3gnuchains/gcc-fork.git] / gcc / c-lex.c
index a561f06..1ec8f23 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-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,14 +15,15 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
+#include "config.h"
 
 #include <stdio.h>
 #include <errno.h>
 #include <setjmp.h>
 
-#include "config.h"
 #include "rtl.h"
 #include "tree.h"
 #include "input.h"
@@ -30,6 +31,16 @@ 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>
+
+/* MULTIBYTE_CHARS support only works for native compilers.
+   ??? Ideally what we want is to model widechar support after
+   the current floating point support.  */
+#ifdef CROSS_COMPILE
+#undef MULTIBYTE_CHARS
+#endif
 
 #ifdef MULTIBYTE_CHARS
 #include <stdlib.h>
@@ -40,6 +51,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int errno;
 #endif
 
+#if USE_CPPLIB
+#include "cpplib.h"
+cpp_reader parse_in;
+cpp_options parse_options;
+static enum cpp_token cpp_token;
+#endif
+
 /* The elements of `ridpointers' are identifier nodes
    for the reserved type names and storage classes.
    It is indexed by a RID_... value.  */
@@ -48,6 +66,32 @@ tree ridpointers[(int) RID_MAX];
 /* Cause the `yydebug' variable to be defined.  */
 #define YYDEBUG 1
 
+#if USE_CPPLIB
+static unsigned char *yy_cur, *yy_lim;
+
+int
+yy_get_token ()
+{
+  for (;;)
+    {
+      parse_in.limit = parse_in.token_buffer;
+      cpp_token = cpp_get_token (&parse_in);
+      if (cpp_token == CPP_EOF)
+       return -1;
+      yy_lim = CPP_PWRITTEN (&parse_in);
+      yy_cur = parse_in.token_buffer;
+      if (yy_cur < yy_lim)
+       return *yy_cur++;
+    }
+}
+
+#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
+#define UNGETC(c) ((c), yy_cur--)
+#else
+#define GETC() getc (finput)
+#define UNGETC(c) ungetc (c, finput)
+#endif
+
 /* the declaration found for the last IDENTIFIER token read in.
    yylex must look this up to detect typedefs, which get token type TYPENAME,
    so it is left around in case the identifier is not a typedef but is
@@ -58,7 +102,7 @@ tree lastiddecl;
 
 int doing_objc_thang;
 
-extern tree lookup_interface ();
+extern tree is_class_name ();
 
 extern int yydebug;
 
@@ -81,164 +125,22 @@ char *token_buffer;       /* Pointer to token buffer.
                           Actual allocated length is maxtoken + 2.
                           This is not static because objc-parse.y uses it.  */
 
+static int indent_level = 0;        /* Number of { minus number of }. */
+
 /* Nonzero if end-of-file has been seen on input.  */
 static int end_of_file;
 
+#if !USE_CPPLIB
 /* Buffered-back input character; faster than using ungetc.  */
 static int nextchar = -1;
+#endif
 
 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 +158,60 @@ 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
+#if USE_CPPLIB
+void
+init_parse (filename)
+     char *filename;
+{
+  init_lex ();
+  yy_cur = "\n";
+  yy_lim = yy_cur+1;
+
+  cpp_reader_init (&parse_in);
+  parse_in.data = &parse_options;
+  cpp_options_init (&parse_options);
+  cpp_handle_options (&parse_in, 0, NULL); /* FIXME */
+  parse_in.show_column = 1;
+  if (! cpp_start_read (&parse_in, filename))
+    abort ();
+}
+
+void
+finish_parse ()
+{
+  cpp_finish (&parse_in);
+}
+#endif
+
+void
 init_lex ()
 {
   /* Make identifier nodes long enough for the language-specific slots.  */
@@ -290,6 +246,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 +262,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 +272,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 +303,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 +312,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;
     }
 }
@@ -372,7 +358,7 @@ skip_white_space (c)
        case '\f':
        case '\v':
        case '\b':
-         c = getc (finput);
+         c = GETC();
          break;
 
        case '\r':
@@ -384,16 +370,16 @@ skip_white_space (c)
              warning ("(we only warn about the first carriage return)");
              newline_warning = 1;
            }
-         c = getc (finput);
+         c = GETC();
          break;
 
        case '\\':
-         c = getc (finput);
+         c = GETC();
          if (c == '\n')
            lineno++;
          else
            error ("stray '\\' in program");
-         c = getc (finput);
+         c = GETC();
          break;
 
        default:
@@ -410,12 +396,14 @@ position_after_white_space ()
 {
   register int c;
 
+#if !USE_CPPLIB
   if (nextchar != -1)
     c = nextchar, nextchar = -1;
   else
-    c = getc (finput);
+#endif
+    c = GETC();
 
-  ungetc (skip_white_space (c), finput);
+  UNGETC (skip_white_space (c));
 }
 
 /* Make the token buffer longer, preserving the data in it.
@@ -434,6 +422,89 @@ extend_token_buffer (p)
 
   return token_buffer + offset;
 }
+
+\f
+#if !USE_CPPLIB
+#define GET_DIRECTIVE_LINE() get_directive_line (finput)
+#else /* USE_CPPLIB */
+/* Read the rest of a #-directive from input stream FINPUT.
+   In normal use, the directive name and the white space after it
+   have already been read, so they won't be included in the result.
+   We allow for the fact that the directive line may contain
+   a newline embedded within a character or string literal which forms
+   a part of the directive.
+
+   The value is a string in a reusable buffer.  It remains valid
+   only until the next time this function is called.  */
+
+static char *
+GET_DIRECTIVE_LINE ()
+{
+  static char *directive_buffer = NULL;
+  static unsigned buffer_length = 0;
+  register char *p;
+  register char *buffer_limit;
+  register int looking_for = 0;
+  register int char_escaped = 0;
+
+  if (buffer_length == 0)
+    {
+      directive_buffer = (char *)xmalloc (128);
+      buffer_length = 128;
+    }
+
+  buffer_limit = &directive_buffer[buffer_length];
+
+  for (p = directive_buffer; ; )
+    {
+      int c;
+
+      /* Make buffer bigger if it is full.  */
+      if (p >= buffer_limit)
+        {
+         register unsigned bytes_used = (p - directive_buffer);
+
+         buffer_length *= 2;
+         directive_buffer
+           = (char *)xrealloc (directive_buffer, buffer_length);
+         p = &directive_buffer[bytes_used];
+         buffer_limit = &directive_buffer[buffer_length];
+        }
+
+      c = GETC ();
+
+      /* Discard initial whitespace.  */
+      if ((c == ' ' || c == '\t') && p == directive_buffer)
+       continue;
+
+      /* Detect the end of the directive.  */
+      if (c == '\n' && looking_for == 0)
+       {
+          UNGETC (c);
+         c = '\0';
+       }
+
+      *p++ = c;
+
+      if (c == 0)
+       return directive_buffer;
+
+      /* Handle string and character constant syntax.  */
+      if (looking_for)
+       {
+         if (looking_for == c && !char_escaped)
+           looking_for = 0;    /* Found terminator... stop looking.  */
+       }
+      else
+        if (c == '\'' || c == '"')
+         looking_for = c;      /* Don't stop buffering until we see another
+                                  another one of these (or an EOF).  */
+
+      /* Handle backslash.  */
+      char_escaped = (c == '\\' && ! char_escaped);
+    }
+}
+#endif /* USE_CPPLIB */
 \f
 /* At the beginning of a line, increment the line number
    and process any #-directive on this line.
@@ -450,9 +521,9 @@ check_newline ()
 
   /* Read first nonwhite char on the line.  */
 
-  c = getc (finput);
+  c = GETC();
   while (c == ' ' || c == '\t')
-    c = getc (finput);
+    c = GETC();
 
   if (c != '#')
     {
@@ -462,9 +533,9 @@ check_newline ()
 
   /* Read first nonwhite char after the `#'.  */
 
-  c = getc (finput);
+  c = GETC();
   while (c == ' ' || c == '\t')
-    c = getc (finput);
+    c = GETC();
 
   /* If a letter follows, then if the word here is `line', skip
      it and ignore it; otherwise, ignore the line, with an error
@@ -474,68 +545,86 @@ check_newline ()
     {
       if (c == 'p')
        {
-         if (getc (finput) == 'r'
-             && getc (finput) == 'a'
-             && getc (finput) == 'g'
-             && getc (finput) == 'm'
-             && getc (finput) == 'a'
-             && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+         if (GETC() == 'r'
+             && GETC() == 'a'
+             && GETC() == 'g'
+             && GETC() == 'm'
+             && GETC() == 'a'
+             && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
            {
+             while (c == ' ' || c == '\t')
+               c = GETC ();
+             if (c == '\n')
+               return c;
+#ifdef HANDLE_SYSV_PRAGMA
+             UNGETC (c);
+             token = yylex ();
+             if (token != IDENTIFIER)
+               goto skipline;
+             return handle_sysv_pragma (token);
+#else /* !HANDLE_SYSV_PRAGMA */
 #ifdef HANDLE_PRAGMA
-             HANDLE_PRAGMA (finput);
+#if !USE_CPPLIB
+             UNGETC (c);
+             token = yylex ();
+             if (token != IDENTIFIER)
+               goto skipline;
+             if (HANDLE_PRAGMA (finput, yylval.ttype))
+               {
+                 c = GETC ();
+                 return c;
+               }
+#else
+             ??? do not know what to do ???;
+#endif /* !USE_CPPLIB */
 #endif /* HANDLE_PRAGMA */
+#endif /* !HANDLE_SYSV_PRAGMA */
              goto skipline;
            }
        }
 
       else if (c == 'd')
        {
-         if (getc (finput) == 'e'
-             && getc (finput) == 'f'
-             && getc (finput) == 'i'
-             && getc (finput) == 'n'
-             && getc (finput) == 'e'
-             && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+         if (GETC() == 'e'
+             && GETC() == 'f'
+             && GETC() == 'i'
+             && GETC() == 'n'
+             && GETC() == 'e'
+             && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
            {
-#ifdef DWARF_DEBUGGING_INFO
-             if ((debug_info_level == DINFO_LEVEL_VERBOSE)
-                 && (write_symbols == DWARF_DEBUG))
-               dwarfout_define (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+             if (c != '\n')
+               debug_define (lineno, GET_DIRECTIVE_LINE ());
              goto skipline;
            }
        }
       else if (c == 'u')
        {
-         if (getc (finput) == 'n'
-             && getc (finput) == 'd'
-             && getc (finput) == 'e'
-             && getc (finput) == 'f'
-             && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+         if (GETC() == 'n'
+             && GETC() == 'd'
+             && GETC() == 'e'
+             && GETC() == 'f'
+             && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
            {
-#ifdef DWARF_DEBUGGING_INFO
-             if ((debug_info_level == DINFO_LEVEL_VERBOSE)
-                 && (write_symbols == DWARF_DEBUG))
-               dwarfout_undef (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+             if (c != '\n')
+               debug_undef (lineno, GET_DIRECTIVE_LINE ());
              goto skipline;
            }
        }
       else if (c == 'l')
        {
-         if (getc (finput) == 'i'
-             && getc (finput) == 'n'
-             && getc (finput) == 'e'
-             && ((c = getc (finput)) == ' ' || c == '\t'))
+         if (GETC() == 'i'
+             && GETC() == 'n'
+             && GETC() == 'e'
+             && ((c = GETC()) == ' ' || c == '\t'))
            goto linenum;
        }
       else if (c == 'i')
        {
-         if (getc (finput) == 'd'
-             && getc (finput) == 'e'
-             && getc (finput) == 'n'
-             && getc (finput) == 't'
-             && ((c = getc (finput)) == ' ' || c == '\t'))
+         if (GETC() == 'd'
+             && GETC() == 'e'
+             && GETC() == 'n'
+             && GETC() == 't'
+             && ((c = GETC()) == ' ' || c == '\t'))
            {
              /* #ident.  The pedantic warning is now in cccp.c.  */
 
@@ -543,13 +632,13 @@ check_newline ()
                 A string constant should follow.  */
 
              while (c == ' ' || c == '\t')
-               c = getc (finput);
+               c = GETC();
 
              /* If no argument, ignore the line.  */
              if (c == '\n')
                return c;
 
-             ungetc (c, finput);
+             UNGETC (c);
              token = yylex ();
              if (token != STRING
                  || TREE_CODE (yylval.ttype) != STRING_CST)
@@ -579,7 +668,7 @@ linenum:
      In either case, it should be a line number; a digit should follow.  */
 
   while (c == ' ' || c == '\t')
-    c = getc (finput);
+    c = GETC();
 
   /* If the # is the only nonwhite char on the line,
      just ignore it.  Check the new newline.  */
@@ -588,7 +677,7 @@ linenum:
 
   /* Something follows the #; read a token.  */
 
-  ungetc (c, finput);
+  UNGETC (c);
   token = yylex ();
 
   if (token == CONSTANT
@@ -602,23 +691,21 @@ linenum:
       int l = TREE_INT_CST_LOW (yylval.ttype) - 1;
 
       /* Is this the last nonwhite stuff on the line?  */
-      c = getc (finput);
+      c = GETC();
       while (c == ' ' || c == '\t')
-       c = getc (finput);
+       c = GETC();
       if (c == '\n')
        {
          /* No more: store the line number and check following line.  */
          lineno = l;
          return c;
        }
-      ungetc (c, finput);
+      UNGETC (c);
 
       /* 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)
        {
@@ -639,12 +726,18 @@ linenum:
        main_input_filename = input_filename;
 
       /* Is this the last nonwhite stuff on the line?  */
-      c = getc (finput);
+      c = GETC();
       while (c == ' ' || c == '\t')
-       c = getc (finput);
+       c = GETC();
       if (c == '\n')
-       return c;
-      ungetc (c, finput);
+       {
+         /* 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);
 
       token = yylex ();
       used_up = 0;
@@ -663,14 +756,10 @@ linenum:
              input_file_stack->line = old_lineno;
              p->next = input_file_stack;
              p->name = input_filename;
+             p->indent_level = indent_level;
              input_file_stack = p;
              input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
-             if (debug_info_level == DINFO_LEVEL_VERBOSE
-                 && write_symbols == DWARF_DEBUG)
-               dwarfout_start_new_source_file (input_filename);
-#endif /* DWARF_DEBUGGING_INFO */
-
+             debug_start_source_file (input_filename);
              used_up = 1;
            }
          else if (TREE_INT_CST_LOW (yylval.ttype) == 2)
@@ -679,14 +768,18 @@ linenum:
              if (input_file_stack->next)
                {
                  struct file_stack *p = input_file_stack;
+                 if (indent_level != p->indent_level)
+                   {
+                     warning_with_file_and_line 
+                       (p->name, old_lineno,
+                        "This file contains more `%c's than `%c's.",
+                        indent_level > p->indent_level ? '{' : '}',
+                        indent_level > p->indent_level ? '}' : '{');
+                   }
                  input_file_stack = p->next;
                  free (p);
                  input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
-                 if (debug_info_level == DINFO_LEVEL_VERBOSE
-                     && write_symbols == DWARF_DEBUG)
-                   dwarfout_resume_previous_source_file (input_file_stack->line);
-#endif /* DWARF_DEBUGGING_INFO */
+                 debug_end_source_file (input_file_stack->line);
                }
              else
                error ("#-lines for entering and leaving files don't match");
@@ -695,17 +788,22 @@ 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)
        {
          /* Is this the last nonwhite stuff on the line?  */
-         c = getc (finput);
+         c = GETC();
          while (c == ' ' || c == '\t')
-           c = getc (finput);
+           c = GETC();
          if (c == '\n')
            return c;
-         ungetc (c, finput);
+         UNGETC (c);
 
          token = yylex ();
          used_up = 0;
@@ -716,33 +814,98 @@ 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();
+         while (c == ' ' || c == '\t')
+           c = GETC();
+         if (c == '\n')
+           return c;
+         UNGETC (c);
+       }
+
+      warning ("unrecognized text at end of #line");
     }
   else
     error ("invalid #-line");
 
   /* skip the rest of this line.  */
  skipline:
-  if (c == '\n')
-    return c;
-  while ((c = getc (finput)) != EOF && c != '\n');
+#if !USE_CPPLIB
+  if (c != '\n' && c != EOF && nextchar >= 0)
+    c = nextchar, nextchar = -1;
+#endif
+  while (c != '\n' && c != EOF)
+    c = GETC();
   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.
+   TOKEN is the token we read after `#pragma'.  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 (token)
+     register int token;
+{
+  register int c;
+
+  for (;;)
+    {
+      switch (token)
+       {
+       case IDENTIFIER:
+       case TYPENAME:
+       case STRING:
+       case CONSTANT:
+         handle_pragma_token (token_buffer, yylval.ttype);
+         break;
+       default:
+         handle_pragma_token (token_buffer, 0);
+       }
+#if !USE_CPPLIB
+      if (nextchar >= 0)
+       c = nextchar, nextchar = -1;
+      else
+#endif
+       c = GETC ();
+
+      while (c == ' ' || c == '\t')
+       c = GETC ();
+      if (c == '\n' || c == EOF)
+       {
+         handle_pragma_token (0, 0);
+         return c;
+       }
+      UNGETC (c);
+      token = yylex ();
+    }
+}
+
+#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 c = GETC();
   register int code;
   register unsigned count;
-  unsigned firstdig;
+  unsigned firstdig = 0;
+  int nonnull;
 
   switch (c)
     {
@@ -755,14 +918,15 @@ readescape ()
 
       code = 0;
       count = 0;
+      nonnull = 0;
       while (1)
        {
-         c = getc (finput);
+         c = GETC();
          if (!(c >= 'a' && c <= 'f')
              && !(c >= 'A' && c <= 'F')
              && !(c >= '0' && c <= '9'))
            {
-             ungetc (c, finput);
+             UNGETC (c);
              break;
            }
          code *= 16;
@@ -772,12 +936,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))
@@ -792,9 +963,9 @@ readescape ()
       while ((c <= '7') && (c >= '0') && (count++ < 3))
        {
          code = (code * 8) + (c - '0');
-         c = getc (finput);
+         c = GETC();
        }
-      ungetc (c, finput);
+      UNGETC (c);
       return code;
 
     case '\\': case '\'': case '"':
@@ -802,7 +973,8 @@ readescape ()
 
     case '\n':
       lineno++;
-      return -1;
+      *ignore_ptr = 1;
+      return 0;
 
     case 'n':
       return TARGET_NEWLINE;
@@ -834,8 +1006,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 +1019,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,28 +1087,31 @@ yylex ()
   register char *p;
   register int value;
   int wide_flag = 0;
+  int objc_flag = 0;
 
+#if !USE_CPPLIB
   if (nextchar >= 0)
     c = nextchar, nextchar = -1;
   else
-    c = getc (finput);
+#endif
+    c = GETC();
 
   /* Effectively do c = skip_white_space (c)
      but do it faster in the usual cases.  */
   while (1)
     switch (c)
       {
-      case '\r':
-       if (!flag_traditional)  /* ANSI says no */
-         goto found_nonwhite;
       case ' ':
       case '\t':
       case '\f':
       case '\v':
       case '\b':
-       c = getc (finput);
+       c = GETC();
        break;
 
+      case '\r':
+       /* Call skip_white_space so we can warn if appropriate.  */
+
       case '\n':
       case '/':
       case '\\':
@@ -955,15 +1134,10 @@ yylex ()
       value = ENDFILE;
       break;
 
-    case '$':
-      if (dollars_in_ident)
-       goto letter;
-      return '$';
-
     case 'L':
       /* Capital L may start a wide-string or wide-character constant.  */
       {
-       register int c = getc (finput);
+       register int c = GETC();
        if (c == '\'')
          {
            wide_flag = 1;
@@ -974,7 +1148,7 @@ yylex ()
            wide_flag = 1;
            goto string_constant;
          }
-       ungetc (c, finput);
+       UNGETC (c);
       }
       goto letter;
 
@@ -984,28 +1158,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 ();
+         if (c == '"')
+           {
+             objc_flag = 1;
+             goto string_constant;
+           }
+         UNGETC (c);
+         /* Fall through to treat '@' as the start of an identifier.  */
        }
 
-      *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':
@@ -1019,21 +1184,35 @@ yylex ()
     case 'u':  case 'v':  case 'w':  case 'x':  case 'y':
     case 'z':
     case '_':
+    case '$':
     letter:
       p = token_buffer;
       while (isalnum (c) || c == '_' || c == '$' || c == '@')
        {
+         /* Make sure this char really belongs in an identifier.  */
+         if (c == '@' && ! doing_objc_thang)
+           break;
+         if (c == '$')
+           {
+             if (! dollars_in_ident)
+               error ("`$' in identifier");
+             else if (pedantic)
+               pedwarn ("`$' in identifier");
+           }
+
          if (p >= token_buffer + maxtoken)
            p = extend_token_buffer (p);
-         if (c == '$' && ! dollars_in_ident)
-           break;
 
          *p++ = c;
-         c = getc (finput);
+         c = GETC();
        }
 
       *p = 0;
+#if USE_CPPLIB
+      UNGETC (c);
+#else
       nextchar = c;
+#endif
 
       value = IDENTIFIER;
       yylval.itype = 0;
@@ -1049,6 +1228,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,6 +1253,9 @@ 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);
 
@@ -1078,12 +1270,17 @@ yylex ()
                   && DECL_INITIAL (lastiddecl) != 0
                   && TREE_CODE (DECL_INITIAL (lastiddecl)) == STRING_CST)
            {
-             yylval.ttype = DECL_INITIAL (lastiddecl);
+             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)
                {
@@ -1095,7 +1292,23 @@ yylex ()
 
       break;
 
-    case '0':  case '1':  case '2':  case '3':  case '4':
+    case '0':  case '1':
+      {
+       int next_c;
+       /* Check first for common special case:  single-digit 0 or 1.  */
+
+       next_c = GETC ();
+       UNGETC (next_c);        /* Always undo this lookahead.  */
+       if (!isalnum (next_c) && next_c != '.')
+         {
+           token_buffer[0] = (char)c,  token_buffer[1] = '\0';
+           yylval.ttype = (c == '0') ? integer_zero_node : integer_one_node;
+           value = CONSTANT;
+           break;
+         }
+       /*FALLTHRU*/
+      }
+    case '2':  case '3':  case '4':
     case '5':  case '6':  case '7':  case '8':  case '9':
     case '.':
       {
@@ -1104,27 +1317,31 @@ 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;
 
        if (c == '0')
          {
-           *p++ = (c = getc (finput));
+           *p++ = (c = GETC());
            if ((c == 'x') || (c == 'X'))
              {
                base = 16;
-               *p++ = (c = getc (finput));
+               *p++ = (c = GETC());
              }
            /* Leading 0 forces octal unless the 0 is the only digit.  */
            else if (c >= '0' && c <= '9')
@@ -1139,24 +1356,31 @@ 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;
 
                base = 10;
-               *p++ = c = getc (finput);
+               *p++ = c = GETC();
                /* Accept '.' as the start of a floating-point number
                   only when it is followed by a digit.
                   Otherwise, unread the following non-digit
@@ -1165,7 +1389,7 @@ yylex ()
                  {
                    if (c == '.')
                      {
-                       c = getc (finput);
+                       c = GETC();
                        if (c == '.')
                          {
                            *p++ = c;
@@ -1174,7 +1398,7 @@ yylex ()
                          }
                        error ("parse error at `..'");
                      }
-                   ungetc (c, finput);
+                   UNGETC (c);
                    token_buffer[1] = 0;
                    value = '.';
                    goto done;
@@ -1191,7 +1415,7 @@ yylex ()
                  }
                else if (base <= 10)
                  {
-                   if ((c&~040) == 'E')
+                   if (c == 'e' || c == 'E')
                      {
                        base = 10;
                        floatflag = AFTER_POINT;
@@ -1212,24 +1436,28 @@ 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);
-               *p++ = (c = getc (finput));
+               *p++ = (c = GETC());
              }
          }
 
@@ -1245,8 +1473,8 @@ yylex ()
        if (floatflag != NOT_FLOAT)
          {
            tree type = double_type_node;
-           char f_seen = 0;
-           char l_seen = 0;
+           int exceeds_double = 0;
+           int imag = 0;
            REAL_VALUE_TYPE value;
            jmp_buf handler;
 
@@ -1257,11 +1485,11 @@ yylex ()
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
                *p++ = c;
-               c = getc (finput);
+               c = GETC();
                if ((c == '+') || (c == '-'))
                  {
                    *p++ = c;
-                   c = getc (finput);
+                   c = GETC();
                  }
                if (! isdigit (c))
                  error ("floating constant exponent has no digits");
@@ -1270,7 +1498,7 @@ yylex ()
                    if (p >= token_buffer + maxtoken - 3)
                      p = extend_token_buffer (p);
                    *p++ = c;
-                   c = getc (finput);
+                   c = GETC();
                  }
              }
 
@@ -1285,86 +1513,125 @@ 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();
                  }
-               /* ERANGE is also reported for underflow,
-                  so test the value to distinguish overflow from that.  */
-               if (*p1 != 0 && (value > 1.0 || value < -1.0))
-                 pedwarn ("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;
                  }
-               if (p >= token_buffer + maxtoken - 3)
-                 p = extend_token_buffer (p);
-               *p++ = c;
-               c = getc (finput);
              }
+#endif
 
-           /* Create a node with determined type and value.  */
-           yylval.ttype = build_real (type, value);
+           /* 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;
 
-           ungetc (c, finput);
-           *p = 0;
+           /* Create a node with determined type and value.  */
+           if (imag)
+             yylval.ttype = build_complex (NULL_TREE,
+                                           convert (type, integer_zero_node),
+                                           build_real (type, value));
+           else
+             yylval.ttype = build_real (type, value);
          }
        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)
@@ -1387,29 +1654,22 @@ yylex ()
                      }
                    spec_long = 1;
                  }
-               else
+               else if (c == 'i' || c == 'j' || c == 'I' || c == 'J')
                  {
-                   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;
+                   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
+                 break;
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
                *p++ = c;
-               c = getc (finput);
+               c = GETC();
              }
 
-           ungetc (c, finput);
-
            /* If the constant is not long long and it won't fit in an
               unsigned long, or if the constant is long long and won't fit
               in an unsigned long long, then warn that the constant is out
@@ -1425,107 +1685,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.  */
@@ -1548,9 +1730,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
@@ -1570,9 +1750,7 @@ 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
                         && int_fits_type_p (yylval.ttype,
@@ -1595,12 +1773,47 @@ yylex ()
                else
                  warning ("width of integer constant may change on other systems with -traditional");
              }
-#endif
 
-           TREE_TYPE (yylval.ttype) = type;
-           *p = 0;
+           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 (NULL_TREE, 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;
          }
 
+       UNGETC (c);
+       *p = 0;
+
+       if (isalnum (c) || c == '.' || c == '_' || c == '$'
+           || (!flag_traditional && (c == '-' || c == '+')
+               && (p[-1] == 'e' || p[-1] == 'E')))
+         error ("missing white space after number `%s'", token_buffer);
+
        value = CONSTANT; break;
       }
 
@@ -1608,7 +1821,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;
 
@@ -1628,19 +1841,24 @@ yylex ()
          {
          tryagain:
 
-           c = getc (finput);
+           c = GETC();
 
            if (c == '\'' || c == EOF)
              break;
 
            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')
              {
@@ -1648,6 +1866,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)
@@ -1684,17 +1906,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
          {
@@ -1707,7 +1933,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
@@ -1715,9 +1941,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;
       }
@@ -1725,16 +1951,16 @@ yylex ()
     case '"':
     string_constant:
       {
-       c = getc (finput);
+       c = GETC();
        p = token_buffer + 1;
 
        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
@@ -1753,10 +1979,13 @@ yylex ()
            *p++ = c;
 
          skipnewline:
-           c = getc (finput);
+           c = GETC();
          }
        *p = 0;
 
+       if (c < 0)
+         error ("Unterminated string constant");
+
        /* We have read the entire constant.
           Construct a STRING_CST for the result.  */
 
@@ -1769,7 +1998,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;
@@ -1777,15 +2006,9 @@ yylex ()
            bzero (widep + (len * WCHAR_BYTES), WCHAR_BYTES);
 #else
            {
-             union { long l; char c[sizeof (long)]; } u;
-             int big_endian;
              char *wp, *cp;
 
-             /* Determine whether host is little or big endian.  */
-             u.l = 1;
-             big_endian = u.c[sizeof (long) - 1];
-             wp = widep + (big_endian ? WCHAR_BYTES - 1 : 0);
-
+             wp = widep + (BYTES_BIG_ENDIAN ? WCHAR_BYTES - 1 : 0);
              bzero (widep, (p - token_buffer) * WCHAR_BYTES);
              for (cp = token_buffer + 1; cp < p; cp++)
                *wp = *cp, wp += WCHAR_BYTES;
@@ -1794,23 +2017,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 '*':
@@ -1852,7 +2087,7 @@ yylex ()
            yylval.code = GT_EXPR; break;
          }
 
-       token_buffer[1] = c1 = getc (finput);
+       token_buffer[1] = c1 = GETC();
        token_buffer[2] = 0;
 
        if (c1 == '=')
@@ -1888,9 +2123,29 @@ yylex ()
              c = RSHIFT;
              goto combine;
            }
-       else if ((c == '-') && (c1 == '>'))
-         { value = POINTSAT; goto done; }
-       ungetc (c1, finput);
+       else
+         switch (c)
+           {
+           case '-':
+             if (c1 == '>')
+               { value = POINTSAT; goto done; }
+             break;
+           case ':':
+             if (c1 == '>')
+               { value = ']'; goto done; }
+             break;
+           case '<':
+             if (c1 == '%')
+               { value = '{'; indent_level++; goto done; }
+             if (c1 == ':')
+               { value = '['; goto done; }
+             break;
+           case '%':
+             if (c1 == '>')
+               { value = '}'; indent_level--; goto done; }
+             break;
+           }
+       UNGETC (c1);
        token_buffer[1] = 0;
 
        if ((c == '<') || (c == '>'))
@@ -1904,6 +2159,16 @@ yylex ()
       value = 1;
       break;
 
+    case '{':
+      indent_level++;
+      value = c;
+      break;
+
+    case '}':
+      indent_level--;
+      value = c;
+      break;
+
     default:
       value = c;
     }