OSDN Git Service

* gcc.dg/dll-?.c Add thumb to target list.
[pf3gnuchains/gcc-fork.git] / gcc / c-lex.c
index f5d3b40..6e56a3f 100644 (file)
@@ -1,5 +1,5 @@
 /* Lexical analyzer for C and Objective C.
-   Copyright (C) 1987, 88, 89, 92, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 94-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,33 +15,40 @@ 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 <stdio.h>
-#include <errno.h>
+#include "config.h"
+#include "system.h"
 #include <setjmp.h>
 
-#include "config.h"
 #include "rtl.h"
 #include "tree.h"
 #include "input.h"
+#include "output.h"
 #include "c-lex.h"
 #include "c-tree.h"
 #include "flags.h"
 #include "c-parse.h"
-
-#include <ctype.h>
+#include "c-pragma.h"
+#include "toplev.h"
 
 #ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
+#include "mbchar.h"
 #include <locale.h>
-#endif
+#endif /* MULTIBYTE_CHARS */
 
-#ifndef errno
-extern int errno;
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader  parse_in;
+extern cpp_options parse_options;
+#else
+/* Stream for reading from the input file.  */
+FILE *finput;
 #endif
 
+extern void yyprint                    PROTO((FILE *, int, YYSTYPE));
+
 /* The elements of `ridpointers' are identifier nodes
    for the reserved type names and storage classes.
    It is indexed by a RID_... value.  */
@@ -50,6 +57,18 @@ tree ridpointers[(int) RID_MAX];
 /* Cause the `yydebug' variable to be defined.  */
 #define YYDEBUG 1
 
+#if USE_CPPLIB
+extern unsigned char *yy_cur, *yy_lim;
+  
+extern int yy_get_token ();
+  
+#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
@@ -60,8 +79,6 @@ tree lastiddecl;
 
 int doing_objc_thang;
 
-extern tree is_class_name ();
-
 extern int yydebug;
 
 /* File used for outputting assembler code.  */
@@ -83,13 +100,24 @@ 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 ();
+#ifdef HANDLE_GENERIC_PRAGMAS
+static int handle_generic_pragma       PROTO((int));
+#endif /* HANDLE_GENERIC_PRAGMAS */
+static int whitespace_cr               PROTO((int));
+static int skip_white_space            PROTO((int));
+static int skip_white_space_on_line    PROTO((void));
+static char *extend_token_buffer       PROTO((char *));
+static int readescape                  PROTO((int *));
 \f
 /* Do not insert generated code into the source, instead, include it.
    This allows us to build gcc automatically even for targets that
@@ -136,10 +164,57 @@ remember_protocol_qualifiers ()
       wordlist[i].name = "inout";
     else if (wordlist[i].rid == RID_BYCOPY)
       wordlist[i].name = "bycopy";
+    else if (wordlist[i].rid == RID_BYREF)
+      wordlist[i].name = "byref";
     else if (wordlist[i].rid == RID_ONEWAY)
       wordlist[i].name = "oneway";   
 }
 \f
+char *
+init_parse (filename)
+     char *filename;
+{
+#if !USE_CPPLIB
+  /* Open input file.  */
+  if (filename == 0 || !strcmp (filename, "-"))
+    {
+      finput = stdin;
+      filename = "stdin";
+    }
+  else
+    finput = fopen (filename, "r");
+  if (finput == 0)
+    pfatal_with_name (filename);
+
+#ifdef IO_BUFFER_SIZE
+  setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
+#endif
+#endif /* !USE_CPPLIB */
+
+  init_lex ();
+
+#if USE_CPPLIB
+  yy_cur = "\n";
+  yy_lim = yy_cur+1;
+
+  parse_in.show_column = 1;
+  if (! cpp_start_read (&parse_in, filename))
+    abort ();
+#endif
+
+  return filename;
+}
+
+void
+finish_parse ()
+{
+#if USE_CPPLIB
+  cpp_finish (&parse_in);
+#else
+  fclose (finput);
+#endif
+}
+
 void
 init_lex ()
 {
@@ -153,6 +228,7 @@ init_lex ()
 #ifdef MULTIBYTE_CHARS
   /* Change to the native locale for multibyte conversions.  */
   setlocale (LC_CTYPE, "");
+  literal_codeset = getenv ("LANG");
 #endif
 
   maxtoken = 40;
@@ -182,6 +258,7 @@ init_lex ()
   ridpointers[(int) RID_OUT] = get_identifier ("out");
   ridpointers[(int) RID_INOUT] = get_identifier ("inout");
   ridpointers[(int) RID_BYCOPY] = get_identifier ("bycopy");
+  ridpointers[(int) RID_BYREF] = get_identifier ("byref");
   ridpointers[(int) RID_ONEWAY] = get_identifier ("oneway");
   forget_protocol_qualifiers();
 
@@ -243,10 +320,14 @@ yyprint (file, yychar, yylval)
       if (TREE_CODE (t) == INTEGER_CST)
        fprintf (file,
 #if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                " 0x%x%016x",
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
                 " 0x%lx%016lx",
 #else
-                " 0x%x%016x",
+                " 0x%llx%016llx",
+#endif
 #endif
 #else
 #if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
@@ -259,8 +340,30 @@ yyprint (file, yychar, yylval)
       break;
     }
 }
-
 \f
+/* Iff C is a carriage return, warn about it - if appropriate -
+   and return nonzero.  */
+static int
+whitespace_cr (c)
+     int c;
+{
+  static int newline_warning = 0;
+
+  if (c == '\r')
+    {
+      /* ANSI C says the effects of a carriage return in a source file
+        are undefined.  */
+      if (pedantic && !newline_warning)
+       {
+         warning ("carriage return in source file");
+         warning ("(we only warn about the first carriage return)");
+         newline_warning = 1;
+       }
+      return 1;
+    }
+  return 0;
+}
+
 /* If C is not whitespace, return C.
    Otherwise skip whitespace and return first nonwhite char read.  */
 
@@ -268,8 +371,6 @@ static int
 skip_white_space (c)
      register int c;
 {
-  static int newline_warning = 0;
-
   for (;;)
     {
       switch (c)
@@ -287,28 +388,21 @@ skip_white_space (c)
        case '\f':
        case '\v':
        case '\b':
-         c = getc (finput);
+         c = GETC();
          break;
 
        case '\r':
-         /* ANSI C says the effects of a carriage return in a source file
-            are undefined.  */
-         if (pedantic && !newline_warning)
-           {
-             warning ("carriage return in source file");
-             warning ("(we only warn about the first carriage return)");
-             newline_warning = 1;
-           }
-         c = getc (finput);
+         whitespace_cr (c);
+         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:
@@ -325,12 +419,46 @@ 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));
+}
+
+/* Like skip_white_space, but don't advance beyond the end of line.
+   Moreover, we don't get passed a character to start with.  */
+static int
+skip_white_space_on_line ()
+{
+  register int c;
+
+  while (1)
+    {
+      c = GETC();
+      switch (c)
+       {
+       case '\n':
+       default:
+         break;
+
+       case ' ':
+       case '\t':
+       case '\f':
+       case '\v':
+       case '\b':
+         continue;
+
+       case '\r':
+         whitespace_cr (c);
+         continue;
+       }
+      break;
+    }
+  return c;
 }
 
 /* Make the token buffer longer, preserving the data in it.
@@ -350,6 +478,22 @@ extend_token_buffer (p)
   return token_buffer + offset;
 }
 \f
+#if defined HANDLE_PRAGMA 
+/* Local versions of these macros, that can be passed as function pointers.  */
+static int
+pragma_getc ()
+{
+  return GETC();
+}
+
+static void
+pragma_ungetc (arg)
+     int arg;
+{
+  UNGETC (arg);
+}
+#endif
+
 /* At the beginning of a line, increment the line number
    and process any #-directive on this line.
    If the line is a #-directive, read the entire line and return a newline.
@@ -365,9 +509,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 != '#')
     {
@@ -377,9 +521,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
@@ -389,86 +533,117 @@ 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'
+                  || whitespace_cr (c) ))
            {
-#ifdef HANDLE_SYSV_PRAGMA
-             return handle_sysv_pragma (finput, c);
-#else /* !HANDLE_SYSV_PRAGMA */
+             while (c == ' ' || c == '\t' || whitespace_cr (c))
+               c = GETC ();
+             if (c == '\n')
+               return c;
+
+#if defined HANDLE_PRAGMA || defined HANDLE_GENERIC_PRAGMAS
+             UNGETC (c);
+             token = yylex ();
+             if (token != IDENTIFIER)
+               goto skipline;
+#endif /* HANDLE_PRAGMA || HANDLE_GENERIC_PRAGMAS */
+             
 #ifdef HANDLE_PRAGMA
-             HANDLE_PRAGMA (finput);
+             /* We invoke HANDLE_PRAGMA before HANDLE_GENERIC_PRAGMAS (if
+                both are defined), in order to give the back end a chance to
+                override the interpretation of generic style pragmas.  */
+#if !USE_CPPLIB
+             if (nextchar >= 0)
+               {
+                 c = nextchar, nextchar = -1;
+                 UNGETC (c);
+               }
+#endif /* !USE_CPPLIB */
+             
+             if (TREE_CODE (yylval.ttype) != IDENTIFIER_NODE)
+               goto skipline;
+
+             if (HANDLE_PRAGMA (pragma_getc, pragma_ungetc,
+                                IDENTIFIER_POINTER (yylval.ttype)))
+               return GETC ();
 #endif /* HANDLE_PRAGMA */
+             
+#ifdef HANDLE_GENERIC_PRAGMAS
+             if (handle_generic_pragma (token))
+               return GETC ();
+#endif /* HANDLE_GENERIC_PRAGMAS */
+             
+             /* Issue a warning message if we have been asked to do so.
+                Ignoring unknown pragmas in system header file unless
+                an explcit -Wunknown-pragmas has been given. */
+             if (warn_unknown_pragmas > 1
+                 || (warn_unknown_pragmas && ! in_system_header))
+               warning ("ignoring pragma: %s", token_buffer);
+             
              goto skipline;
-#endif /* !HANDLE_SYSV_PRAGMA */
            }
        }
 
       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.  */
 
              /* Here we have just seen `#ident '.
                 A string constant should follow.  */
 
-             while (c == ' ' || c == '\t')
-               c = getc (finput);
+             c = skip_white_space_on_line ();
 
              /* 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)
@@ -497,8 +672,11 @@ linenum:
   /* Here we have either `#line' or `# <nonletter>'.
      In either case, it should be a line number; a digit should follow.  */
 
-  while (c == ' ' || c == '\t')
-    c = getc (finput);
+  /* Can't use skip_white_space here, but must handle all whitespace
+     that is not '\n', lest we get a recursion for '\r' '\n' when
+     calling yylex.  */
+  UNGETC (c);
+  c = skip_white_space_on_line ();
 
   /* If the # is the only nonwhite char on the line,
      just ignore it.  Check the new newline.  */
@@ -507,7 +685,7 @@ linenum:
 
   /* Something follows the #; read a token.  */
 
-  ungetc (c, finput);
+  UNGETC (c);
   token = yylex ();
 
   if (token == CONSTANT
@@ -521,16 +699,14 @@ linenum:
       int l = TREE_INT_CST_LOW (yylval.ttype) - 1;
 
       /* Is this the last nonwhite stuff on the line?  */
-      c = getc (finput);
-      while (c == ' ' || c == '\t')
-       c = getc (finput);
+      c = skip_white_space_on_line ();
       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).  */
 
@@ -556,9 +732,7 @@ linenum:
        main_input_filename = input_filename;
 
       /* Is this the last nonwhite stuff on the line?  */
-      c = getc (finput);
-      while (c == ' ' || c == '\t')
-       c = getc (finput);
+      c = skip_white_space_on_line ();
       if (c == '\n')
        {
          /* Update the name in the top element of input_file_stack.  */
@@ -567,7 +741,7 @@ linenum:
 
          return c;
        }
-      ungetc (c, finput);
+      UNGETC (c);
 
       token = yylex ();
       used_up = 0;
@@ -586,14 +760,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)
@@ -602,14 +772,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");
@@ -628,12 +802,10 @@ linenum:
       if (used_up)
        {
          /* Is this the last nonwhite stuff on the line?  */
-         c = getc (finput);
-         while (c == ' ' || c == '\t')
-           c = getc (finput);
+         c = skip_white_space_on_line ();
          if (c == '\n')
            return c;
-         ungetc (c, finput);
+         UNGETC (c);
 
          token = yylex ();
          used_up = 0;
@@ -649,12 +821,10 @@ linenum:
       if (used_up)
        {
          /* Is this the last nonwhite stuff on the line?  */
-         c = getc (finput);
-         while (c == ' ' || c == '\t')
-           c = getc (finput);
+         c = skip_white_space_on_line ();
          if (c == '\n')
            return c;
-         ungetc (c, finput);
+         UNGETC (c);
        }
 
       warning ("unrecognized text at end of #line");
@@ -664,37 +834,33 @@ linenum:
 
   /* 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
-#ifdef HANDLE_SYSV_PRAGMA
+#ifdef HANDLE_GENERIC_PRAGMAS
 
-/* 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.  */
+/* Handle a #pragma directive.
+   TOKEN is the token we read after `#pragma'.  Processes the entire input
+   line and return non-zero iff the pragma has been successfully parsed.  */
 
 /* 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;
+static int
+handle_generic_pragma (token)
+     register int token;
 {
+  register 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 ())
+      switch (token)
        {
        case IDENTIFIER:
        case TYPENAME:
@@ -703,16 +869,27 @@ handle_sysv_pragma (input, c)
          handle_pragma_token (token_buffer, yylval.ttype);
          break;
        default:
-         handle_pragma_token (token_buffer, 0);
+         handle_pragma_token (token_buffer, NULL);
        }
+#if !USE_CPPLIB
       if (nextchar >= 0)
        c = nextchar, nextchar = -1;
       else
-       c = getc (input);
+#endif
+       c = GETC ();
+
+      while (c == ' ' || c == '\t')
+       c = GETC ();
+      UNGETC (c);
+      
+      if (c == '\n' || c == EOF)
+       return handle_pragma_token (NULL, NULL);
+
+      token = yylex ();
     }
 }
 
-#endif /* HANDLE_SYSV_PRAGMA */
+#endif /* HANDLE_GENERIC_PRAGMAS */
 \f
 #define ENDFILE -1  /* token that represents end-of-file */
 
@@ -723,7 +900,7 @@ static int
 readescape (ignore_ptr)
      int *ignore_ptr;
 {
-  register int c = getc (finput);
+  register int c = GETC();
   register int code;
   register unsigned count;
   unsigned firstdig = 0;
@@ -743,12 +920,12 @@ readescape (ignore_ptr)
       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;
@@ -785,9 +962,9 @@ readescape (ignore_ptr)
       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 '"':
@@ -911,10 +1088,12 @@ yylex ()
   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.  */
@@ -926,7 +1105,7 @@ yylex ()
       case '\f':
       case '\v':
       case '\b':
-       c = getc (finput);
+       c = GETC();
        break;
 
       case '\r':
@@ -954,15 +1133,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;
@@ -973,7 +1147,7 @@ yylex ()
            wide_flag = 1;
            goto string_constant;
          }
-       ungetc (c, finput);
+       UNGETC (c);
       }
       goto letter;
 
@@ -986,14 +1160,14 @@ yylex ()
       else
        {
          /* '@' may start a constant string object.  */
-         register int c = getc(finput);
+         register int c = GETC ();
          if (c == '"')
            {
              objc_flag = 1;
              goto string_constant;
            }
-         ungetc(c, finput);
-         /* Fall through to treat '@' as the start of an indentifier.  */
+         UNGETC (c);
+         /* Fall through to treat '@' as the start of an identifier.  */
        }
 
     case 'A':  case 'B':  case 'C':  case 'D':  case 'E':
@@ -1009,25 +1183,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 == '@')
+      while (ISALNUM (c) || c == '_' || c == '$' || c == '@')
        {
          /* Make sure this char really belongs in an identifier.  */
          if (c == '@' && ! doing_objc_thang)
            break;
-         if (c == '$' && ! dollars_in_ident)
-           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);
 
          *p++ = c;
-         c = getc (finput);
+         c = GETC();
        }
 
       *p = 0;
+#if USE_CPPLIB
+      UNGETC (c);
+#else
       nextchar = c;
+#endif
 
       value = IDENTIFIER;
       yylval.itype = 0;
@@ -1037,7 +1221,7 @@ yylex ()
       {
        register struct resword *ptr;
 
-       if (ptr = is_reserved_word (token_buffer, p - token_buffer))
+       if ((ptr = is_reserved_word (token_buffer, p - token_buffer)))
          {
            if (ptr->rid)
              yylval.ttype = ridpointers[(int) ptr->rid];
@@ -1107,7 +1291,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 '.':
       {
@@ -1136,11 +1336,11 @@ yylex ()
 
        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')
@@ -1155,7 +1355,7 @@ yylex ()
        /* Read all the digits-and-decimal-points.  */
 
        while (c == '.'
-              || (isalnum (c) && c != 'l' && c != 'L'
+              || (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')))))
@@ -1179,16 +1379,16 @@ yylex ()
                  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
                   and use the '.' as a structural token.  */
-               if (p == token_buffer + 2 && !isdigit (c))
+               if (p == token_buffer + 2 && !ISDIGIT (c))
                  {
                    if (c == '.')
                      {
-                       c = getc (finput);
+                       c = GETC();
                        if (c == '.')
                          {
                            *p++ = c;
@@ -1197,7 +1397,7 @@ yylex ()
                          }
                        error ("parse error at `..'");
                      }
-                   ungetc (c, finput);
+                   UNGETC (c);
                    token_buffer[1] = 0;
                    value = '.';
                    goto done;
@@ -1208,7 +1408,7 @@ yylex ()
                /* It is not a decimal point.
                   It should be a digit (perhaps a hex digit).  */
 
-               if (isdigit (c))
+               if (ISDIGIT (c))
                  {
                    c = c - '0';
                  }
@@ -1256,7 +1456,7 @@ yylex ()
 
                if (p >= token_buffer + maxtoken - 3)
                  p = extend_token_buffer (p);
-               *p++ = (c = getc (finput));
+               *p++ = (c = GETC());
              }
          }
 
@@ -1271,9 +1471,9 @@ yylex ()
 
        if (floatflag != NOT_FLOAT)
          {
-           tree type = long_double_type_node;
-           int garbage_chars = 0, exceeds_double = 0;
+           tree type = double_type_node;
            int imag = 0;
+           int conversion_errno = 0;
            REAL_VALUE_TYPE value;
            jmp_buf handler;
 
@@ -1284,25 +1484,24 @@ 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))
+               if (! ISDIGIT (c))
                  error ("floating constant exponent has no digits");
-               while (isdigit (c))
+               while (ISDIGIT (c))
                  {
                    if (p >= token_buffer + maxtoken - 3)
                      p = extend_token_buffer (p);
                    *p++ = c;
-                   c = getc (finput);
+                   c = GETC();
                  }
              }
 
            *p = 0;
-           errno = 0;
 
            /* Convert string to a double, checking for overflow.  */
            if (setjmp (handler))
@@ -1359,7 +1558,7 @@ yylex ()
                      p = extend_token_buffer (p);
                    *p++ = c;
                    *p = 0;
-                   c = getc (finput);
+                   c = GETC();
                  }
 
                /* The second argument, machine_mode, of REAL_VALUE_ATOF
@@ -1372,7 +1571,9 @@ yylex ()
                      error ("both `f' and `l' in floating constant");
 
                    type = float_type_node;
+                   errno = 0;
                    value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   conversion_errno = errno;
                    /* A diagnostic is required here by some ANSI C testsuites.
                       This is not pedwarn, become some people don't want
                       an error for this.  */
@@ -1382,13 +1583,17 @@ yylex ()
                else if (lflag)
                  {
                    type = long_double_type_node;
+                   errno = 0;
                    value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   conversion_errno = errno;
                    if (REAL_VALUE_ISINF (value) && pedantic)
                      warning ("floating point number exceeds range of `long double'");
                  }
                else
                  {
+                   errno = 0;
                    value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+                   conversion_errno = errno;
                    if (REAL_VALUE_ISINF (value) && pedantic)
                      warning ("floating point number exceeds range of `double'");
                  }
@@ -1396,31 +1601,13 @@ yylex ()
                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;
-                 }
-             }
+           /* ERANGE is also reported for underflow,
+              so test the value to distinguish overflow from that.  */
+           if (conversion_errno == ERANGE && !flag_traditional && pedantic
+               && (REAL_VALUES_LESS (dconst1, value)
+                   || REAL_VALUES_LESS (value, dconstm1)))
+             warning ("floating point number exceeds range of `double'");
 #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
@@ -1430,13 +1617,11 @@ yylex ()
 
            /* Create a node with determined type and value.  */
            if (imag)
-             yylval.ttype = build_complex (convert (type, integer_zero_node),
+             yylval.ttype = build_complex (NULL_TREE,
+                                           convert (type, integer_zero_node),
                                            build_real (type, value));
            else
              yylval.ttype = build_real (type, value);
-
-           ungetc (c, finput);
-           *p = 0;
          }
        else
          {
@@ -1448,6 +1633,7 @@ yylex ()
            int spec_imag = 0;
            int bytes, warn, i;
 
+           traditional_type = ansi_type = type = NULL_TREE;
            while (1)
              {
                if (c == 'u' || c == 'U')
@@ -1462,7 +1648,7 @@ yylex ()
                      {
                        if (spec_long_long)
                          error ("three `l's in integer constant");
-                       else if (pedantic)
+                       else if (pedantic && ! in_system_header && warn_long_long)
                          pedwarn ("ANSI C forbids long long integer constants");
                        spec_long_long = 1;
                      }
@@ -1477,46 +1663,22 @@ yylex ()
                    spec_imag = 1;
                  }
                else
-                 {
-                   if (isalnum (c) || c == '.' || c == '_'
-                       || (!flag_traditional && (c == '+' || c == '-')
-                           && (p[-1] == 'e' || p[-1] == 'E')))
-                     {
-                       error ("garbage at end of number");
-                       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);
-                         }
-                     }
-                   break;
-                 }
+                 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
-              of range.  */
+           /* If the constant won't fit in an unsigned long long,
+              then warn that the constant is out of range.  */
 
            /* ??? This assumes that long long and long integer types are
               a multiple of 8 bits.  This better than the original code
               though which assumed that long was exactly 32 bits and long
               long was exactly 64 bits.  */
 
-           if (spec_long_long)
-             bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
-           else
-             bytes = TYPE_PRECISION (long_integer_type_node) / 8;
+           bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
 
            warn = overflow;
            for (i = bytes; i < TOTAL_PARTS; i++)
@@ -1583,11 +1745,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)
+               else if (! spec_long_long
+                        && int_fits_type_p (yylval.ttype,
+                                            long_unsigned_type_node))
                  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;
@@ -1609,8 +1771,9 @@ yylex ()
                  warning ("width of integer constant may change on other systems with -traditional");
              }
 
-           if (!flag_traditional && !int_fits_type_p (yylval.ttype, type)
-               && !warn)
+           if (pedantic && !flag_traditional && !spec_long_long && !warn
+               && (TYPE_PRECISION (long_integer_type_node)
+                   < TYPE_PRECISION (type)))
              pedwarn ("integer constant out of range");
 
            if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
@@ -1621,8 +1784,9 @@ yylex ()
                if (TYPE_PRECISION (type)
                    <= TYPE_PRECISION (integer_type_node))
                  yylval.ttype
-                   = build_complex (integer_zero_node,
-                                    convert (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'");
              }
@@ -1638,10 +1802,16 @@ yylex ()
              }
            else
              TREE_TYPE (yylval.ttype) = type;
-
-           *p = 0;
          }
 
+       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;
       }
 
@@ -1650,30 +1820,27 @@ yylex ()
       {
        register int result = 0;
        register int num_chars = 0;
+       int chars_seen = 0;
        unsigned width = TYPE_PRECISION (char_type_node);
        int max_chars;
-
-       if (wide_flag)
-         {
-           width = WCHAR_TYPE_SIZE;
 #ifdef MULTIBYTE_CHARS
-           max_chars = MB_CUR_MAX;
-#else
-           max_chars = 1;
+       int longest_char = local_mb_cur_max ();
+       (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
 #endif
-         }
-       else
-         max_chars = TYPE_PRECISION (integer_type_node) / width;
+
+       max_chars = TYPE_PRECISION (integer_type_node) / width;
+       if (wide_flag)
+         width = WCHAR_TYPE_SIZE;
 
        while (1)
          {
          tryagain:
-
-           c = getc (finput);
+           c = GETC();
 
            if (c == '\'' || c == EOF)
              break;
 
+           ++chars_seen;
            if (c == '\\')
              {
                int ignore = 0;
@@ -1684,7 +1851,7 @@ yylex ()
                    && (unsigned) c >= (1 << width))
                  pedwarn ("escape sequence out of range for character");
 #ifdef MAP_CHARACTER
-               if (isprint (c))
+               if (ISPRINT (c))
                  c = MAP_CHARACTER (c);
 #endif
              }
@@ -1694,18 +1861,76 @@ yylex ()
                  pedwarn ("ANSI C forbids newline in character constant");
                lineno++;
              }
-#ifdef MAP_CHARACTER
            else
-             c = MAP_CHARACTER (c);
+             {
+#ifdef MULTIBYTE_CHARS
+               wchar_t wc;
+               int i;
+               int char_len = -1;
+               for (i = 1; i <= longest_char; ++i)
+                 {
+                   if (i > maxtoken - 4)
+                     extend_token_buffer (token_buffer);
+
+                   token_buffer[i] = c;
+                   char_len = local_mbtowc (& wc,
+                                            token_buffer + 1,
+                                            i);
+                   if (char_len != -1)
+                     break;
+                   c = GETC ();
+                 }
+               if (char_len > 1)
+                 {
+                   /* mbtowc sometimes needs an extra char before accepting */
+                   if (char_len < i)
+                     UNGETC (c);
+                   if (! wide_flag)
+                     {
+                       /* Merge character into result; ignore excess chars.  */
+                       for (i = 1; i <= char_len; ++i)
+                         {
+                           if (i > max_chars)
+                             break;
+                           if (width < HOST_BITS_PER_INT)
+                             result = (result << width)
+                               | (token_buffer[i]
+                                  & ((1 << width) - 1));
+                           else
+                             result = token_buffer[i];
+                         }
+                       num_chars += char_len;
+                       goto tryagain;
+                     }
+                   c = wc;
+                 }
+               else
+                 {
+                   if (char_len == -1)
+                     warning ("Ignoring invalid multibyte character");
+                   if (wide_flag)
+                     c = wc;
+#ifdef MAP_CHARACTER
+                   else
+                     c = MAP_CHARACTER (c);
 #endif
+                 }
+#else /* ! MULTIBYTE_CHARS */
+#ifdef MAP_CHARACTER
+               c = MAP_CHARACTER (c);
+#endif
+#endif /* ! MULTIBYTE_CHARS */
+             }
 
-           num_chars++;
-           if (num_chars > maxtoken - 4)
-             extend_token_buffer (token_buffer);
-
-           token_buffer[num_chars] = c;
+           if (wide_flag)
+             {
+               if (chars_seen == 1) /* only keep the first one */
+                 result = c;
+               goto tryagain;
+             }
 
            /* Merge character into result; ignore excess chars.  */
+           num_chars += (width / TYPE_PRECISION (char_type_node));
            if (num_chars < max_chars + 1)
              {
                if (width < HOST_BITS_PER_INT)
@@ -1715,19 +1940,16 @@ yylex ()
              }
          }
 
-       token_buffer[num_chars + 1] = '\'';
-       token_buffer[num_chars + 2] = 0;
-
        if (c != '\'')
          error ("malformatted character constant");
-       else if (num_chars == 0)
+       else if (chars_seen == 0)
          error ("empty character constant");
        else if (num_chars > max_chars)
          {
            num_chars = max_chars;
            error ("character constant too long");
          }
-       else if (num_chars != 1 && ! flag_traditional)
+       else if (chars_seen != 1 && ! flag_traditional && warn_multichar)
          warning ("multi-character character constant");
 
        /* If char type is signed, sign-extend the constant.  */
@@ -1740,34 +1962,18 @@ yylex ()
            else if (TREE_UNSIGNED (char_type_node)
                     || ((result >> (num_bits - 1)) & 1) == 0)
              yylval.ttype
-               = build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
+               = 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 HOST_WIDE_INT) ~0
+               = 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
          {
-#ifdef MULTIBYTE_CHARS
-           /* Set the initial shift state and convert the next sequence.  */
-           result = 0;
-           /* In all locales L'\0' is zero and mbtowc will return zero,
-              so don't use it.  */
-           if (num_chars > 1
-               || (num_chars == 1 && token_buffer[1] != '\0'))
-             {
-               wchar_t wc;
-               (void) mbtowc (NULL_PTR, NULL_PTR, 0);
-               if (mbtowc (& wc, token_buffer + 1, num_chars) == num_chars)
-                 result = wc;
-               else
-                 warning ("Ignoring invalid multibyte character");
-             }
-#endif
            yylval.ttype = build_int_2 (result, 0);
            TREE_TYPE (yylval.ttype) = wchar_type_node;
          }
@@ -1779,7 +1985,13 @@ yylex ()
     case '"':
     string_constant:
       {
-       c = getc (finput);
+       unsigned width = wide_flag ? WCHAR_TYPE_SIZE
+                                  : TYPE_PRECISION (char_type_node);
+#ifdef MULTIBYTE_CHARS
+       int longest_char = local_mb_cur_max ();
+       (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
+#endif
+       c = GETC ();
        p = token_buffer + 1;
 
        while (c != '"' && c >= 0)
@@ -1790,9 +2002,8 @@ yylex ()
                c = readescape (&ignore);
                if (ignore)
                  goto skipnewline;
-               if (!wide_flag
-                   && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
-                   && c >= (1 << TYPE_PRECISION (char_type_node)))
+               if (width < HOST_BITS_PER_INT
+                   && (unsigned) c >= (1 << width))
                  pedwarn ("escape sequence out of range for character");
              }
            else if (c == '\n')
@@ -1801,15 +2012,94 @@ yylex ()
                  pedwarn ("ANSI C forbids newline in string constant");
                lineno++;
              }
+           else
+             {
+#ifdef MULTIBYTE_CHARS
+               wchar_t wc;
+               int i;
+               int char_len = -1;
+               for (i = 0; i < longest_char; ++i)
+                 {
+                   if (p + i >= token_buffer + maxtoken)
+                     p = extend_token_buffer (p);
+                   p[i] = c;
 
-           if (p == token_buffer + maxtoken)
-             p = extend_token_buffer (p);
-           *p++ = c;
+                   char_len = local_mbtowc (& wc, p, i + 1);
+                   if (char_len != -1)
+                     break;
+                   c = GETC ();
+                 }
+               if (char_len == -1)
+                 warning ("Ignoring invalid multibyte character");
+               else
+                 {
+                   /* mbtowc sometimes needs an extra char before accepting */
+                   if (char_len <= i)
+                     UNGETC (c);
+                   if (wide_flag)
+                     {
+                       *(wchar_t *)p = wc;
+                       p += sizeof (wc);
+                     }
+                   else
+                     p += (i + 1);
+                   c = GETC ();
+                   continue;
+                 }
+#endif /* MULTIBYTE_CHARS */
+             }
+
+           /* Add this single character into the buffer either as a wchar_t
+              or as a single byte.  */
+           if (wide_flag)
+             {
+               unsigned width = TYPE_PRECISION (char_type_node);
+               unsigned bytemask = (1 << width) - 1;
+               int byte;
+
+               if (p + WCHAR_BYTES > token_buffer + maxtoken)
+                 p = extend_token_buffer (p);
+
+               for (byte = 0; byte < WCHAR_BYTES; ++byte)
+                 {
+                   int value;
+                   if (byte >= sizeof (c))
+                     value = 0;
+                   else
+                     value = (c >> (byte * width)) & bytemask;
+                   if (BYTES_BIG_ENDIAN)
+                     p[WCHAR_BYTES - byte - 1] = value;
+                   else
+                     p[byte] = value;
+                 }
+               p += WCHAR_BYTES;
+             }
+           else
+             {
+               if (p >= token_buffer + maxtoken)
+                 p = extend_token_buffer (p);
+               *p++ = c;
+             }
 
          skipnewline:
-           c = getc (finput);
+           c = GETC ();
+         }
+
+       /* Terminate the string value, either with a single byte zero
+          or with a wide zero.  */
+       if (wide_flag)
+         {
+           if (p + WCHAR_BYTES > token_buffer + maxtoken)
+             p = extend_token_buffer (p);
+           bzero (p, WCHAR_BYTES);
+           p += WCHAR_BYTES;
+         }
+       else
+         {
+           if (p >= token_buffer + maxtoken)
+             p = extend_token_buffer (p);
+           *p++ = 0;
          }
-       *p = 0;
 
        if (c < 0)
          error ("Unterminated string constant");
@@ -1819,59 +2109,27 @@ yylex ()
 
        if (wide_flag)
          {
-           /* If this is a L"..." wide-string, convert the multibyte string
-              to a wide character string.  */
-           char *widep = (char *) alloca ((p - token_buffer) * WCHAR_BYTES);
-           int len;
-
-#ifdef MULTIBYTE_CHARS
-           len = mbstowcs ((wchar_t *) widep, token_buffer + 1, p - token_buffer);
-           if (len < 0 || len >= (p - token_buffer))
-             {
-               warning ("Ignoring invalid multibyte string");
-               len = 0;
-             }
-           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);
-
-             bzero (widep, (p - token_buffer) * WCHAR_BYTES);
-             for (cp = token_buffer + 1; cp < p; cp++)
-               *wp = *cp, wp += WCHAR_BYTES;
-             len = p - token_buffer - 1;
-           }
-#endif
-           yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
+           yylval.ttype = build_string (p - (token_buffer + 1),
+                                        token_buffer + 1);
            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,
+           yylval.ttype = build_objc_string (p - (token_buffer + 1),
                                              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);
+           yylval.ttype = build_string (p - (token_buffer + 1),
+                                        token_buffer + 1);
            TREE_TYPE (yylval.ttype) = char_array_type_node;
            value = STRING;
          }
 
-       *p++ = '"';
-       *p = 0;
-
        break;
       }
 
@@ -1879,6 +2137,7 @@ yylex ()
     case '-':
     case '&':
     case '|':
+    case ':':
     case '<':
     case '>':
     case '*':
@@ -1920,7 +2179,7 @@ yylex ()
            yylval.code = GT_EXPR; break;
          }
 
-       token_buffer[1] = c1 = getc (finput);
+       token_buffer[1] = c1 = GETC();
        token_buffer[2] = 0;
 
        if (c1 == '=')
@@ -1956,9 +2215,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 == '>'))
@@ -1972,6 +2251,16 @@ yylex ()
       value = 1;
       break;
 
+    case '{':
+      indent_level++;
+      value = c;
+      break;
+
+    case '}':
+      indent_level--;
+      value = c;
+      break;
+
     default:
       value = c;
     }