OSDN Git Service

* c-opts.c (set_std_cxx98, set_std_c89): New.
[pf3gnuchains/gcc-fork.git] / gcc / cp / spew.c
index 296c8f6..efeae64 100644 (file)
@@ -1,5 +1,6 @@
 /* Type Analyzer for GNU C++.
-   Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    Hacked... nay, bludgeoned... by Mark Eichin (eichin@cygnus.com)
 
 This file is part of GNU CC.
@@ -16,427 +17,1489 @@ 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.  */
 
 /* This file is the type analyzer for GNU C++.  To debug it, define SPEW_DEBUG
    when compiling parse.c and spew.c.  */
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include "input.h"
 #include "tree.h"
+#include "cp-tree.h"
+#include "cpplib.h"
+#include "c-pragma.h"
 #include "lex.h"
 #include "parse.h"
-#include "cp-tree.h"
 #include "flags.h"
 #include "obstack.h"
+#include "toplev.h"
+#include "ggc.h"
+#include "intl.h"
+#include "timevar.h"
+
+#ifdef SPEW_DEBUG
+#define SPEW_INLINE
+#else
+#define SPEW_INLINE inline
+#endif
 
 /* This takes a token stream that hasn't decided much about types and
    tries to figure out as much as it can, with excessive lookahead and
-   backtracking. */
+   backtracking.  */
 
-/* fifo of tokens recognized and available to parser. */
-struct token  {
+/* fifo of tokens recognized and available to parser.  */
+struct token GTY(())
+{
   /* The values for YYCHAR will fit in a short.  */
   short                yychar;
-  short                end_of_file;
-  YYSTYPE      yylval;
+  unsigned int lineno;
+  YYSTYPE GTY ((desc ("%1.yychar"))) yylval;
+};
+
+/* Since inline methods can refer to text which has not yet been seen,
+   we store the text of the method in a structure which is placed in the
+   DECL_PENDING_INLINE_INFO field of the FUNCTION_DECL.
+   After parsing the body of the class definition, the FUNCTION_DECL's are
+   scanned to see which ones have this field set.  Those are then digested
+   one at a time.
+
+   This function's FUNCTION_DECL will have a bit set in its common so
+   that we know to watch out for it.  */
+
+#define TOKEN_CHUNK_SIZE 20
+struct token_chunk GTY(())
+{
+  struct token_chunk *next;
+  struct token toks[TOKEN_CHUNK_SIZE];
+};
+
+struct unparsed_text GTY(())
+{
+  struct unparsed_text *next;  /* process this one next */
+  tree decl;           /* associated declaration */
+  location_t locus;     /* location we got the text from */
+  int interface;       /* remembering interface_unknown and interface_only */
+
+  struct token_chunk * tokens; /* Start of the token list.  */
+
+  struct token_chunk *last_chunk; /* End of the token list.  */
+  short last_pos;      /* Number of tokens used in the last chunk of
+                          TOKENS. */
+
+  short cur_pos;       /* Current token in 'cur_chunk', when rescanning.  */
+  struct token_chunk *cur_chunk;  /* Current chunk, when rescanning.  */
+};
+
+/* Stack of state saved off when we return to an inline method or
+   default argument that has been stored for later parsing.  */
+struct feed GTY(())
+{
+  struct unparsed_text *input;
+  location_t locus;
+  int yychar;
+  YYSTYPE GTY ((desc ("%1.yychar"))) yylval;
+  int first_token;
+  struct obstack GTY ((skip (""))) token_obstack;
+  struct feed *next;
 };
 
-static int do_aggr ();
+static GTY(()) struct feed *feed;
+
+static SPEW_INLINE void do_aggr PARAMS ((void));
+static SPEW_INLINE int identifier_type PARAMS ((tree));
+static void scan_tokens PARAMS ((int));
+static void feed_defarg PARAMS ((tree));
+static void finish_defarg PARAMS ((void));
+static void yylexstring PARAMS ((struct token *));
+static int read_token PARAMS ((struct token *));
+
+static SPEW_INLINE int num_tokens PARAMS ((void));
+static SPEW_INLINE struct token *nth_token PARAMS ((int));
+static SPEW_INLINE int next_token PARAMS ((struct token *));
+static SPEW_INLINE int shift_token PARAMS ((void));
+static SPEW_INLINE void push_token PARAMS ((struct token *));
+static SPEW_INLINE void consume_token PARAMS ((void));
+static SPEW_INLINE int read_process_identifier PARAMS ((YYSTYPE *));
+
+static SPEW_INLINE void feed_input PARAMS ((struct unparsed_text *));
+static SPEW_INLINE struct token * space_for_token
+  PARAMS ((struct unparsed_text *t));
+static SPEW_INLINE struct token * remove_last_token
+  PARAMS ((struct unparsed_text *t));
+static struct unparsed_text * alloc_unparsed_text
+  PARAMS ((const location_t *, tree decl, int interface));
+
+static void snarf_block PARAMS ((struct unparsed_text *t));
+static tree snarf_defarg PARAMS ((void));
+static int frob_id PARAMS ((int, int, tree *));
+
+/* The list of inline functions being held off until we reach the end of
+   the current class declaration.  */
+static GTY(()) struct unparsed_text *pending_inlines;
+static GTY(()) struct unparsed_text *pending_inlines_tail;
+
+/* The list of previously-deferred inline functions currently being parsed.
+   This exists solely to be a GC root.  */
+static GTY(()) struct unparsed_text *processing_these_inlines;
+
+static void begin_parsing_inclass_inline PARAMS ((struct unparsed_text *));
+
+#ifdef SPEW_DEBUG
+int spew_debug = 0;
+static unsigned int yylex_ctr = 0;
+
+static void debug_yychar PARAMS ((int));
+
+/* In parse.y: */
+extern char *debug_yytranslate PARAMS ((int));
+#endif
+static enum cpp_ttype last_token;
+static tree last_token_id;
 
 /* From lex.c: */
-/* 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
-   used in a context which makes it a reference to a variable.  */
+/* the declaration found for the last IDENTIFIER token read in.  yylex
+   must look this up to detect typedefs, which get token type
+   tTYPENAME, so it is left around in case the identifier is not a
+   typedef but is used in a context which makes it a reference to a
+   variable.  */
 extern tree lastiddecl;                /* let our brains leak out here too */
 extern int     yychar;         /*  the lookahead symbol                */
 extern YYSTYPE yylval;         /*  the semantic value of the           */
                                /*  lookahead symbol                    */
-extern int end_of_file;
+/* The token fifo lives in this obstack.  */
+static struct obstack token_obstack;
+static int first_token;
 
-struct obstack token_obstack;
-int first_token;
-  
-#ifdef SPEW_DEBUG
-int spew_debug = 0;
-static unsigned int yylex_ctr = 0;
-static int debug_yychar ();
-#endif
+/* When we see a default argument in a method declaration, we snarf it as
+   text using snarf_defarg.  When we get up to namespace scope, we then go
+   through and parse all of them using do_pending_defargs.  Since yacc
+   parsers are not reentrant, we retain defargs state in these two
+   variables so that subsequent calls to do_pending_defargs can resume
+   where the previous call left off. DEFARG_FNS is a tree_list where
+   the TREE_TYPE is the current_class_type, TREE_VALUE is the FUNCTION_DECL,
+   and TREE_PURPOSE is the list unprocessed dependent functions.  */
+
+/* list of functions with unprocessed defargs */
+static GTY(()) tree defarg_fns;
+/* current default parameter */
+static GTY(()) tree defarg_parm;
+/* list of unprocessed fns met during current fn. */
+static GTY(()) tree defarg_depfns;
+/* list of fns with circular defargs */
+static GTY(()) tree defarg_fnsdone;
+
+/* Initialize obstacks. Called once, from cxx_init.  */
 
-/* Initialize token_obstack. Called once, from init_lex.  */
 void
 init_spew ()
 {
-  gcc_obstack_init(&token_obstack);
+  gcc_obstack_init (&token_obstack);
 }
 
-#ifdef SPEW_DEBUG
-/* Use functions for debugging...  */
+/* Subroutine of read_token.  */
+static SPEW_INLINE int
+read_process_identifier (pyylval)
+     YYSTYPE *pyylval;
+{
+  tree id = pyylval->ttype;
+
+  if (C_IS_RESERVED_WORD (id))
+    {
+      pyylval->ttype = ridpointers[C_RID_CODE (id)];
+      return C_RID_YYCODE (id);
+    }
+
+  /* Make sure that user does not collide with our internal naming
+     scheme.  This is not necessary if '.' is used to remove them from
+     the user's namespace, but is if '$' or double underscores are.  */
+
+#if !defined(JOINER) || JOINER == '$'
+  if (VPTR_NAME_P (id)
+      || VTABLE_NAME_P (id)
+      || TEMP_NAME_P (id)
+      || ANON_AGGRNAME_P (id))
+     warning (
+"identifier name `%s' conflicts with GNU C++ internal naming strategy",
+             IDENTIFIER_POINTER (id));
+#endif
+  return IDENTIFIER;
+}
+
+/* Concatenate strings before returning them to the parser.  This isn't quite
+   as good as having it done in the lexer, but it's better than nothing.  */
+
+static void
+yylexstring (t)
+     struct token *t;
+{
+  enum cpp_ttype next_type;
+  tree next;
+
+  next_type = c_lex (&next);
+  if (next_type == CPP_STRING || next_type == CPP_WSTRING)
+    {
+      varray_type strings;
+
+      VARRAY_TREE_INIT (strings, 32, "strings");
+      VARRAY_PUSH_TREE (strings, t->yylval.ttype);
+
+      do
+       {
+         VARRAY_PUSH_TREE (strings, next);
+         next_type = c_lex (&next);
+       }
+      while (next_type == CPP_STRING || next_type == CPP_WSTRING);
+
+      t->yylval.ttype = combine_strings (strings);
+      last_token_id = t->yylval.ttype;
+    }
 
-/* Return the number of tokens available on the fifo. */
+  /* We will have always read one token too many.  */
+  _cpp_backup_tokens (parse_in, 1);
+
+  t->yychar = STRING;
+}
+
+/* Read the next token from the input file.  The token is written into
+   T, and its type number is returned.  */
 static int
+read_token (t)
+     struct token *t;
+{
+ retry:
+
+  last_token = c_lex (&last_token_id);
+  t->yylval.ttype = last_token_id;
+
+  switch (last_token)
+    {
+#define YYCHAR(YY)     t->yychar = (YY); break;
+#define YYCODE(C)      t->yylval.code = (C);
+
+    case CPP_EQ:                               YYCHAR('=');
+    case CPP_NOT:                              YYCHAR('!');
+    case CPP_GREATER:  YYCODE(GT_EXPR);        YYCHAR('>');
+    case CPP_LESS:     YYCODE(LT_EXPR);        YYCHAR('<');
+    case CPP_PLUS:     YYCODE(PLUS_EXPR);      YYCHAR('+');
+    case CPP_MINUS:    YYCODE(MINUS_EXPR);     YYCHAR('-');
+    case CPP_MULT:     YYCODE(MULT_EXPR);      YYCHAR('*');
+    case CPP_DIV:      YYCODE(TRUNC_DIV_EXPR); YYCHAR('/');
+    case CPP_MOD:      YYCODE(TRUNC_MOD_EXPR); YYCHAR('%');
+    case CPP_AND:      YYCODE(BIT_AND_EXPR);   YYCHAR('&');
+    case CPP_OR:       YYCODE(BIT_IOR_EXPR);   YYCHAR('|');
+    case CPP_XOR:      YYCODE(BIT_XOR_EXPR);   YYCHAR('^');
+    case CPP_RSHIFT:   YYCODE(RSHIFT_EXPR);    YYCHAR(RSHIFT);
+    case CPP_LSHIFT:   YYCODE(LSHIFT_EXPR);    YYCHAR(LSHIFT);
+
+    case CPP_COMPL:                            YYCHAR('~');
+    case CPP_AND_AND:                          YYCHAR(ANDAND);
+    case CPP_OR_OR:                            YYCHAR(OROR);
+    case CPP_QUERY:                            YYCHAR('?');
+    case CPP_COLON:                            YYCHAR(':');
+    case CPP_COMMA:                            YYCHAR(',');
+    case CPP_OPEN_PAREN:                       YYCHAR('(');
+    case CPP_CLOSE_PAREN:                      YYCHAR(')');
+    case CPP_EQ_EQ:    YYCODE(EQ_EXPR);        YYCHAR(EQCOMPARE);
+    case CPP_NOT_EQ:   YYCODE(NE_EXPR);        YYCHAR(EQCOMPARE);
+    case CPP_GREATER_EQ:YYCODE(GE_EXPR);       YYCHAR(ARITHCOMPARE);
+    case CPP_LESS_EQ:  YYCODE(LE_EXPR);        YYCHAR(ARITHCOMPARE);
+
+    case CPP_PLUS_EQ:  YYCODE(PLUS_EXPR);      YYCHAR(ASSIGN);
+    case CPP_MINUS_EQ: YYCODE(MINUS_EXPR);     YYCHAR(ASSIGN);
+    case CPP_MULT_EQ:  YYCODE(MULT_EXPR);      YYCHAR(ASSIGN);
+    case CPP_DIV_EQ:   YYCODE(TRUNC_DIV_EXPR); YYCHAR(ASSIGN);
+    case CPP_MOD_EQ:   YYCODE(TRUNC_MOD_EXPR); YYCHAR(ASSIGN);
+    case CPP_AND_EQ:   YYCODE(BIT_AND_EXPR);   YYCHAR(ASSIGN);
+    case CPP_OR_EQ:    YYCODE(BIT_IOR_EXPR);   YYCHAR(ASSIGN);
+    case CPP_XOR_EQ:   YYCODE(BIT_XOR_EXPR);   YYCHAR(ASSIGN);
+    case CPP_RSHIFT_EQ:        YYCODE(RSHIFT_EXPR);    YYCHAR(ASSIGN);
+    case CPP_LSHIFT_EQ:        YYCODE(LSHIFT_EXPR);    YYCHAR(ASSIGN);
+
+    case CPP_OPEN_SQUARE:                      YYCHAR('[');
+    case CPP_CLOSE_SQUARE:                     YYCHAR(']');
+    case CPP_OPEN_BRACE:                       YYCHAR('{');
+    case CPP_CLOSE_BRACE:                      YYCHAR('}');
+    case CPP_SEMICOLON:                                YYCHAR(';');
+    case CPP_ELLIPSIS:                         YYCHAR(ELLIPSIS);
+
+    case CPP_PLUS_PLUS:                                YYCHAR(PLUSPLUS);
+    case CPP_MINUS_MINUS:                      YYCHAR(MINUSMINUS);
+    case CPP_DEREF:                            YYCHAR(POINTSAT);
+    case CPP_DOT:                              YYCHAR('.');
+
+    /* These tokens are C++ specific.  */
+    case CPP_SCOPE:                            YYCHAR(SCOPE);
+    case CPP_DEREF_STAR:                       YYCHAR(POINTSAT_STAR);
+    case CPP_DOT_STAR:                         YYCHAR(DOT_STAR);
+    case CPP_MIN_EQ:   YYCODE(MIN_EXPR);       YYCHAR(ASSIGN);
+    case CPP_MAX_EQ:   YYCODE(MAX_EXPR);       YYCHAR(ASSIGN);
+    case CPP_MIN:      YYCODE(MIN_EXPR);       YYCHAR(MIN_MAX);
+    case CPP_MAX:      YYCODE(MAX_EXPR);       YYCHAR(MIN_MAX);
+#undef YYCHAR
+#undef YYCODE
+
+    case CPP_EOF:
+      t->yychar = 0;
+      break;
+
+    case CPP_NAME:
+      t->yychar = read_process_identifier (&t->yylval);
+      break;
+
+    case CPP_NUMBER:
+    case CPP_CHAR:
+    case CPP_WCHAR:
+      t->yychar = CONSTANT;
+      break;
+
+    case CPP_STRING:
+    case CPP_WSTRING:
+      yylexstring (t);
+      break;
+
+    default:
+      yyerror ("parse error");
+      goto retry;
+    }
+
+  t->lineno = lineno;
+  return t->yychar;
+}
+
+static void
+feed_input (input)
+     struct unparsed_text *input;
+{
+  struct feed *f;
+#if 0
+  if (feed)
+    abort ();
+#endif
+
+  f = ggc_alloc (sizeof (struct feed));
+
+  input->cur_chunk = input->tokens;
+  input->cur_pos = 0;
+
+#ifdef SPEW_DEBUG
+  if (spew_debug)
+    fprintf (stderr, "\tfeeding %s:%d [%d tokens]\n",
+            input->locus.file, input->locus.line, input->limit - input->pos);
+#endif
+
+  f->input = input;
+  f->locus.file = input_filename;
+  f->locus.line = lineno;
+  f->yychar = yychar;
+  f->yylval = yylval;
+  f->first_token = first_token;
+  f->token_obstack = token_obstack;
+  f->next = feed;
+
+  input_filename = input->locus.file;
+  lineno = input->locus.line;
+  yychar = YYEMPTY;
+  yylval.ttype = NULL_TREE;
+  first_token = 0;
+  gcc_obstack_init (&token_obstack);
+  feed = f;
+}
+
+void
+end_input ()
+{
+  struct feed *f = feed;
+
+  input_filename = f->locus.file;
+  lineno = f->locus.line;
+  yychar = f->yychar;
+  yylval = f->yylval;
+  first_token = f->first_token;
+  obstack_free (&token_obstack, 0);
+  token_obstack = f->token_obstack;
+  feed = f->next;
+
+#ifdef SPEW_DEBUG
+  if (spew_debug)
+    fprintf (stderr, "\treturning to %s:%d\n", input_filename, lineno);
+#endif
+}
+
+/* Token queue management.  */
+
+/* Return the number of tokens available on the fifo.  */
+static SPEW_INLINE int
 num_tokens ()
 {
-  return (obstack_object_size(&token_obstack)/sizeof(struct token))
+  return (obstack_object_size (&token_obstack) / sizeof (struct token))
     - first_token;
 }
 
-/* Fetch the token N down the line from the head of the fifo. */
-static struct token*
+/* Fetch the token N down the line from the head of the fifo.  */
+
+static SPEW_INLINE struct token*
 nth_token (n)
      int n;
 {
+#ifdef ENABLE_CHECKING
   /* could just have this do slurp_ implicitly, but this way is easier
-   * to debug... */
-  my_friendly_assert (n < num_tokens(), 298);
-  return ((struct token*)obstack_base(&token_obstack))+n+first_token;
+     to debug...  */
+  my_friendly_assert (n >= 0 && n < num_tokens (), 298);
+#endif
+  return ((struct token*)obstack_base (&token_obstack)) + n + first_token;
 }
 
-/* Add a token to the token fifo. */
-static void
-add_token (t)
-     struct token* t;
+static const struct token Teosi = { END_OF_SAVED_INPUT, 0 UNION_INIT_ZERO };
+static const struct token Tpad = { EMPTY, 0 UNION_INIT_ZERO };
+
+/* Copy the next token into T and return its value.  */
+static SPEW_INLINE int
+next_token (t)
+     struct token *t;
 {
-  obstack_grow(&token_obstack,t,sizeof (struct token));
+  if (!feed)
+    return read_token (t);
+
+  if (feed->input->cur_chunk != feed->input->last_chunk
+      || feed->input->cur_pos != feed->input->last_pos)
+    {
+      if (feed->input->cur_pos == TOKEN_CHUNK_SIZE)
+       {
+         feed->input->cur_chunk = feed->input->cur_chunk->next;
+         feed->input->cur_pos = 0;
+       }
+      memcpy (t, feed->input->cur_chunk->toks + feed->input->cur_pos,
+             sizeof (struct token));
+      feed->input->cur_pos++;
+      return t->yychar;
+    }
+
+  memcpy (t, &Teosi, sizeof (struct token));
+  return END_OF_SAVED_INPUT;
+}
+
+/* Shift the next token onto the fifo.  */
+static SPEW_INLINE int
+shift_token ()
+{
+  size_t point = obstack_object_size (&token_obstack);
+  obstack_blank (&token_obstack, sizeof (struct token));
+  return next_token ((struct token *) (obstack_base (&token_obstack) + point));
 }
 
 /* Consume the next token out of the fifo.  */
-static void
-consume_token()
+
+static SPEW_INLINE void
+consume_token ()
 {
-  if (num_tokens() == 1)
+  if (num_tokens () == 1)
     {
-      obstack_free(&token_obstack, obstack_base (&token_obstack));
+      obstack_free (&token_obstack, obstack_base (&token_obstack));
       first_token = 0;
     }
   else
     first_token++;
 }
 
-#else
-/* ...otherwise use macros.  */
-
-#define num_tokens() \
-  ((obstack_object_size(&token_obstack)/sizeof(struct token)) - first_token)
-
-#define nth_token(N) \
-  (((struct token*)obstack_base(&token_obstack))+(N)+first_token)
-
-#define add_token(T) obstack_grow(&token_obstack, (T), sizeof (struct token))
+/* Push a token at the head of the queue; it will be the next token read.  */
+static SPEW_INLINE void
+push_token (t)
+     struct token *t;
+{
+  if (first_token == 0)  /* We hope this doesn't happen often.  */
+    {
+      size_t active = obstack_object_size (&token_obstack);
+      obstack_blank (&token_obstack, sizeof (struct token));
+      if (active)
+       memmove (obstack_base (&token_obstack) + sizeof (struct token),
+                obstack_base (&token_obstack), active);
+      first_token++;
+    }
+  first_token--;
+  memcpy (nth_token (0), t, sizeof (struct token));
+}
 
-#define consume_token() \
-  (num_tokens() == 1                                                   \
-   ? (obstack_free (&token_obstack, obstack_base (&token_obstack)),    \
-      (first_token = 0))                                               \
-   : first_token++)
-#endif
 
-/* Pull in enough tokens from real_yylex that the queue is N long beyond
-   the current token.  */
+/* Pull in enough tokens that the queue is N long beyond the current
+   token.  */
 
 static void
 scan_tokens (n)
      int n;
 {
   int i;
-  struct token *tmp;
+  int num = num_tokens ();
+  int yychar;
 
-  /* We cannot read past certain tokens, so make sure we don't.  */
-  i = num_tokens ();
-  if (i > n)
+  /* First, prune any empty tokens at the end.  */
+  i = num;
+  while (i > 0 && nth_token (i - 1)->yychar == EMPTY)
+    i--;
+  if (i < num)
+    {
+      obstack_blank (&token_obstack, -((num - i) * sizeof (struct token)));
+      num = i;
+    }
+
+  /* Now, if we already have enough tokens, return.  */
+  if (num > n)
     return;
-  while (i-- > 0)
+
+  /* Never read past these characters: they might separate
+     the current input stream from one we save away later.  */
+  for (i = 0; i < num; i++)
     {
-      tmp = nth_token (i);
-      /* Never read past these characters: they might separate
-        the current input stream from one we save away later.  */
-      if (tmp->yychar == '{' || tmp->yychar == ':' || tmp->yychar == ';')
+      yychar = nth_token (i)->yychar;
+      if (yychar == '{' || yychar == ':' || yychar == ';')
        goto pad_tokens;
     }
 
-  while (num_tokens() <= n)
+  while (num_tokens () <= n)
     {
-      obstack_blank(&token_obstack,sizeof (struct token));
-      tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
-      tmp->yychar = real_yylex();
-      tmp->end_of_file = end_of_file;
-      tmp->yylval = yylval;
-      end_of_file = 0;
-      if (tmp->yychar == '{'
-         || tmp->yychar == ':'
-         || tmp->yychar == ';')
-       {
-       pad_tokens:
-         while (num_tokens () <= n)
-           {
-             obstack_blank(&token_obstack,sizeof (struct token));
-             tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
-             tmp->yychar = EMPTY;
-             tmp->end_of_file = 0;
-           }
-       }
+      yychar = shift_token ();
+      if (yychar == '{' || yychar == ':' || yychar == ';')
+       goto pad_tokens;
     }
+  return;
+
+ pad_tokens:
+  while (num_tokens () <= n)
+    obstack_grow (&token_obstack, &Tpad, sizeof (struct token));
 }
 
-/* Create room for N tokens at the front of the fifo.  This is used
-   to insert new tokens into the stream ahead of the current token.  */
+int looking_for_typename;
+int looking_for_template;
 
-static void
-shift_tokens (n)
-     int n;
+static int after_friend;
+static int after_new;
+static int do_snarf_defarg;
+
+tree got_scope;
+tree got_object;
+
+static SPEW_INLINE int
+identifier_type (decl)
+     tree decl;
 {
-  if (first_token >= n)
-    first_token -= n;
-  else
+  tree t;
+
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    {
+      if (TREE_CODE (DECL_TEMPLATE_RESULT (decl)) == TYPE_DECL)
+       return PTYPENAME;
+      else if (looking_for_template)
+       return PFUNCNAME;
+    }
+  if (looking_for_template && really_overloaded_fn (decl))
     {
-      int old_token_count = num_tokens ();
-      char *tmp;
+      /* See through a baselink.  */
+      if (TREE_CODE (decl) == BASELINK)
+       decl = BASELINK_FUNCTIONS (decl);
 
-      obstack_blank (&token_obstack, (n-first_token) * sizeof (struct token));
-      if (old_token_count)
-       {
-         tmp = (char *)alloca ((num_tokens () + (n-first_token))
-                               * sizeof (struct token));
-         /* This move does not rely on the system being able to handle
-            overlapping moves.  */
-         bcopy ((char *) nth_token (0), tmp,
-                old_token_count * sizeof (struct token));
-         bcopy (tmp, (char *) nth_token (n),
-                old_token_count * sizeof (struct token));
-       }
-      first_token = 0;
+      for (t = decl; t != NULL_TREE; t = OVL_CHAIN (t))
+       if (DECL_FUNCTION_TEMPLATE_P (OVL_FUNCTION (t)))
+         return PFUNCNAME;
     }
+  if (TREE_CODE (decl) == NAMESPACE_DECL)
+    return NSNAME;
+  if (TREE_CODE (decl) != TYPE_DECL)
+    return IDENTIFIER;
+  if (DECL_ARTIFICIAL (decl) && TREE_TYPE (decl) == current_class_type)
+    return SELFNAME;
+
+  /* A constructor declarator for a template type will get here as an
+     implicit typename, a TYPENAME_TYPE with a type.  */
+  t = got_scope;
+  if (t && TREE_CODE (t) == TYPENAME_TYPE)
+    t = TREE_TYPE (t);
+  decl = TREE_TYPE (decl);
+  if (TREE_CODE (decl) == TYPENAME_TYPE)
+    decl = TREE_TYPE (decl);
+  if (t && t == decl)
+    return SELFNAME;
+
+  return tTYPENAME;
 }
 
-static int
-probe_obstack (h, obj, nlevels)
-     struct obstack *h;
-     tree obj;
-     unsigned int nlevels;
+/* token[0] == AGGR (struct/union/enum)
+   Thus, token[1] is either a tTYPENAME or a TYPENAME_DEFN.
+   If token[2] == '{' or ':' then it's TYPENAME_DEFN.
+   It's also a definition if it's a forward declaration (as in 'struct Foo;')
+   which we can tell if token[2] == ';' *and* token[-1] != FRIEND or NEW.  */
+
+static SPEW_INLINE void
+do_aggr ()
 {
-  register struct _obstack_chunk*  lp; /* below addr of any objects in this chunk */
-  register struct _obstack_chunk*  plp;        /* point to previous chunk if any */
+  int yc1, yc2;
 
-  lp = (h)->chunk;
-  /* We use >= rather than > since the object cannot be exactly at
-     the beginning of the chunk but might be an empty object exactly
-     at the end of an adjacent chunk. */
-  for (; nlevels != 0 && lp != 0 && ((tree)lp >= obj || (tree)lp->limit < obj);
-       nlevels -= 1)
+  scan_tokens (2);
+  yc1 = nth_token (1)->yychar;
+  if (yc1 != tTYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
+    return;
+  yc2 = nth_token (2)->yychar;
+  if (yc2 == ';')
     {
-      plp = lp->prev;
-      lp = plp;      
+      /* It's a forward declaration iff we were not preceded by
+         'friend' or `new'.  */
+      if (after_friend || after_new)
+       return;
     }
-  return nlevels != 0 && lp != 0;
-}
+  else if (yc2 != '{' && yc2 != ':')
+    return;
 
-/* from lex.c: */
-/* Value is 1 (or 2) if we should try to make the next identifier look like
-   a typename (when it may be a local variable or a class variable).
-   Value is 0 if we treat this name in a default fashion. */
-extern int looking_for_typename;
-int looking_for_template;
+  switch (yc1)
+    {
+    case tTYPENAME:
+      nth_token (1)->yychar = TYPENAME_DEFN;
+      break;
+    case PTYPENAME:
+      nth_token (1)->yychar = PTYPENAME_DEFN;
+      break;
+    case IDENTIFIER:
+      nth_token (1)->yychar = IDENTIFIER_DEFN;
+      break;
+    default:
+      abort ();
+    }
+}
 
-extern struct obstack *current_obstack, *saveable_obstack;
-tree got_scope;
-tree got_object;
+void
+see_typename ()
+{
+  /* Only types expected, not even namespaces. */
+  looking_for_typename = 2;
+  if (yychar < 0)
+    if ((yychar = yylex ()) < 0) yychar = 0;
+  looking_for_typename = 0;
+  if (yychar == IDENTIFIER)
+    {
+      lastiddecl = lookup_name (yylval.ttype, -2);
+      if (lastiddecl)
+       yychar = identifier_type (lastiddecl);
+    }
+}
 
 int
-yylex()
+yylex ()
 {
-  struct token tmp_token;
-  tree trrr;
+  int yychr;
+  int old_looking_for_typename = 0;
+  int just_saw_new = 0;
+  int just_saw_friend = 0;
+
+  timevar_push (TV_LEX);
 
  retry:
 #ifdef SPEW_DEBUG
   if (spew_debug)
   {
     yylex_ctr ++;
-    fprintf(stderr, "\t\t## %d ##",yylex_ctr);
+    fprintf (stderr, "\t\t## %d @%d ", yylex_ctr, lineno);
   }
 #endif
 
-  /* if we've got tokens, send them */
-  if (num_tokens())
+  if (do_snarf_defarg)
     {
-      tmp_token= *nth_token(0);
-
-      /* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack.
-        If we don't find it in CURRENT_OBSTACK's current or immediately
-        previous chunk, assume it was and copy it to the current obstack.  */
-      if ((tmp_token.yychar == CONSTANT
-          || tmp_token.yychar == STRING)
-         && ! TREE_PERMANENT (tmp_token.yylval.ttype)
-         && ! probe_obstack (current_obstack, tmp_token.yylval.ttype, 2)
-         && ! probe_obstack (saveable_obstack, tmp_token.yylval.ttype, 2))
-       tmp_token.yylval.ttype = copy_node (tmp_token.yylval.ttype);
+      do_snarf_defarg = 0;
+      yylval.ttype = snarf_defarg ();
+      yychar = DEFARG;
+      got_object = NULL_TREE;
+      timevar_pop (TV_LEX);
+      return DEFARG;
     }
+
+  /* if we've got tokens, send them */
+  else if (num_tokens ())
+    yychr = nth_token (0)->yychar;
   else
-    {
-      /* if not, grab the next one and think about it */
-      tmp_token.yychar = real_yylex ();
-      tmp_token.yylval = yylval;
-      tmp_token.end_of_file = end_of_file;
-      add_token(&tmp_token);
-    }
+    yychr = shift_token ();
 
   /* many tokens just need to be returned. At first glance, all we
-   * have to do is send them back up, but some of them are needed to
-   * figure out local context. */
-  switch(tmp_token.yychar)
+     have to do is send them back up, but some of them are needed to
+     figure out local context.  */
+  switch (yychr)
     {
     case EMPTY:
       /* This is a lexical no-op.  */
-      consume_token ();
-#ifdef SPEW_DEBUG    
+#ifdef SPEW_DEBUG
       if (spew_debug)
-       debug_yychar (tmp_token.yychar);
+       debug_yychar (yychr);
 #endif
+      consume_token ();
       goto retry;
 
-    case IDENTIFIER:
+    case '(':
       scan_tokens (1);
-      if (nth_token (1)->yychar == SCOPE)
-       /* Don't interfere with the setting from an 'aggr' prefix.  */
-       looking_for_typename++;
-      else if (nth_token (1)->yychar == '<')
-       looking_for_template = 1;
-
-      trrr = lookup_name (tmp_token.yylval.ttype, -2);
-
-      if (trrr)
+      if (nth_token (1)->yychar == ')')
        {
-         tmp_token.yychar = identifier_type (trrr);
-         switch (tmp_token.yychar)
-           {
-           case TYPENAME:
-             lastiddecl = identifier_typedecl_value (tmp_token.yylval.ttype);
-             if (lastiddecl != trrr)
-               {
-                 lastiddecl = trrr;
-                 if (got_scope || got_object)
-                   tmp_token.yylval.ttype = DECL_NESTED_TYPENAME (trrr);
-               }
-             break;
-           case IDENTIFIER:
-             lastiddecl = trrr;
-             break;
-           case PTYPENAME:
-             lastiddecl = NULL_TREE;
-             break;
-           default:
-             my_friendly_abort (101);
-           }
+         consume_token ();
+         yychr = LEFT_RIGHT;
        }
-      else
-       lastiddecl = trrr;
-      got_scope = NULL_TREE;
-      /* and fall through to... */
+      break;
+
+    case IDENTIFIER:
+    {
+      int peek;
+
+      scan_tokens (1);
+      peek = nth_token (1)->yychar;
+      yychr = frob_id (yychr, peek, &nth_token (0)->yylval.ttype);
+      break;
+    }
     case IDENTIFIER_DEFN:
-    case TYPENAME:
+    case tTYPENAME:
     case TYPENAME_DEFN:
     case PTYPENAME:
     case PTYPENAME_DEFN:
-      consume_token ();
-      if (looking_for_typename > 0)
-       looking_for_typename--;
+      /* If we see a SCOPE next, restore the old value.
+        Otherwise, we got what we want. */
+      looking_for_typename = old_looking_for_typename;
       looking_for_template = 0;
       break;
 
     case SCSPEC:
-      /* do_aggr needs to check if the previous token was RID_FRIEND,
-        so just increment first_token instead of calling consume_token. */
-      first_token++;
+      if (nth_token (0)->yylval.ttype == ridpointers[RID_EXTERN])
+       {
+         scan_tokens (1);
+         if (nth_token (1)->yychar == STRING)
+           {
+             yychr = EXTERN_LANG_STRING;
+             nth_token (1)->yylval.ttype = get_identifier
+               (TREE_STRING_POINTER (nth_token (1)->yylval.ttype));
+             consume_token ();
+           }
+       }
+      /* do_aggr needs to know if the previous token was `friend'.  */
+      else if (nth_token (0)->yylval.ttype == ridpointers[RID_FRIEND])
+       just_saw_friend = 1;
+
+      break;
+
+    case NEW:
+      /* do_aggr needs to know if the previous token was `new'.  */
+      just_saw_new = 1;
       break;
+
     case TYPESPEC:
-      consume_token ();
+    case '{':
+    case ':':
+    case ';':
+      /* If this provides a type for us, then revert lexical
+        state to standard state.  */
+      looking_for_typename = 0;
       break;
 
     case AGGR:
-      *nth_token(0) = tmp_token;
       do_aggr ();
-      /* fall through to output... */
+      break;
+
     case ENUM:
       /* Set this again, in case we are rescanning.  */
-      looking_for_typename = 1;
-      /* fall through... */
+      looking_for_typename = 2;
+      break;
+
     default:
-      consume_token();
+      break;
     }
 
-  yylval = tmp_token.yylval;
-  yychar = tmp_token.yychar;
-  end_of_file = tmp_token.end_of_file;
-#ifdef SPEW_DEBUG    
+  after_friend = just_saw_friend;
+  after_new = just_saw_new;
+
+  /* class member lookup only applies to the first token after the object
+     expression, except for explicit destructor calls.  */
+  if (yychr != '~')
+    got_object = NULL_TREE;
+
+  yychar = yychr;
+  {
+    struct token *tok = nth_token (0);
+
+    yylval = tok->yylval;
+    if (tok->lineno)
+      lineno = tok->lineno;
+  }
+
+#ifdef SPEW_DEBUG
   if (spew_debug)
-    debug_yychar(yychar);
+    debug_yychar (yychr);
 #endif
-  return yychar;
+  consume_token ();
+
+  timevar_pop (TV_LEX);
+  return yychr;
 }
 
-/* token[0] == AGGR (struct/union/enum)
- * Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN.
- * If token[2] == '{' or ':' then it's TYPENAME_DEFN.
- * It's also a definition if it's a forward declaration (as in 'struct Foo;')
- * which we can tell lf token[2] == ';' *and* token[-1] != FRIEND.
- */
+/* Unget character CH from the input stream.
+   If RESCAN is non-zero, then we want to `see' this
+   character as the next input token.  */
+
+void
+yyungetc (ch, rescan)
+     int ch;
+     int rescan;
+{
+  /* Unget a character from the input stream.  */
+  if (yychar == YYEMPTY || rescan == 0)
+    {
+      struct token fake;
+
+      fake.yychar = ch;
+      fake.yylval.ttype = 0;
+      fake.lineno = lineno;
+
+      push_token (&fake);
+    }
+  else
+    {
+      yychar = ch;
+    }
+}
+
+/* Lexer hackery to determine what *IDP really is.  */
+
 static int
-do_aggr ()
+frob_id (yyc, peek, idp)
+     int yyc;
+     int peek;
+     tree *idp;
 {
-  int yc1, yc2;
-  
-  scan_tokens (2);
-  yc1 = nth_token (1)->yychar;
-  if (yc1 != TYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
-    return 0;
-  yc2 = nth_token (2)->yychar;
-  if (yc2 == ';')
+  tree trrr;
+  int old_looking_for_typename = 0;
+
+  if (peek == SCOPE)
     {
-      /* It's a forward declaration iff we were not preceded by 'friend'. */
-      if (first_token > 0 && nth_token (-1)->yychar == SCSPEC
-         && nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND])
-       return 0;
+      /* Don't interfere with the setting from an 'aggr' prefix.  */
+      old_looking_for_typename = looking_for_typename;
+      looking_for_typename = 1;
     }
-  else if (yc2 != '{' && yc2 != ':')
-    return 0;
+  else if (peek == '<')
+    looking_for_template = 1;
+  trrr = lookup_name (*idp, -2);
+  if (trrr)
+    {
+      yyc = identifier_type (trrr);
+      switch(yyc)
+        {
+          case tTYPENAME:
+          case SELFNAME:
+          case NSNAME:
+          case PTYPENAME:
+           /* If this got special lookup, remember it.  In these
+              cases, we know it can't be a declarator-id. */
+            if (got_scope || got_object)
+              *idp = trrr;
+            /* FALLTHROUGH */
+          case PFUNCNAME:
+          case IDENTIFIER:
+            lastiddecl = trrr;
+            break;
+          default:
+            abort ();
+        }
+    }
+  else
+    lastiddecl = NULL_TREE;
+  got_scope = NULL_TREE;
+  looking_for_typename = old_looking_for_typename;
+  looking_for_template = 0;
+  return yyc;
+}
 
-  switch (yc1)
+/* ID is an operator name. Duplicate the hackery in yylex to determine what
+   it really is.  */
+
+tree frob_opname (id)
+     tree id;
+{
+  scan_tokens (0);
+  frob_id (0, nth_token (0)->yychar, &id);
+  got_object = NULL_TREE;
+  return id;
+}
+
+/* Set up the state required to correctly handle the definition of the
+   inline function whose preparsed state has been saved in PI.  */
+
+static void
+begin_parsing_inclass_inline (pi)
+     struct unparsed_text *pi;
+{
+  tree context;
+
+  /* Record that we are processing the chain of inlines starting at
+     PI for GC.  */
+  if (cfun)
+    cp_function_chain->unparsed_inlines = pi;
+  else
+    processing_these_inlines = pi;
+
+  ggc_collect ();
+
+  /* If this is an inline function in a local class, we must make sure
+     that we save all pertinent information about the function
+     surrounding the local class.  */
+  context = decl_function_context (pi->decl);
+  if (context)
+    push_function_context_to (context);
+
+  feed_input (pi);
+  interface_unknown = pi->interface == 1;
+  interface_only  = pi->interface == 0;
+  DECL_PENDING_INLINE_P (pi->decl) = 0;
+  DECL_PENDING_INLINE_INFO (pi->decl) = 0;
+
+  /* Pass back a handle to the rest of the inline functions, so that they
+     can be processed later.  */
+  yychar = PRE_PARSED_FUNCTION_DECL;
+  yylval.pi = pi;
+
+  start_function (NULL_TREE, pi->decl, NULL_TREE,
+                 (SF_DEFAULT | SF_PRE_PARSED | SF_INCLASS_INLINE));
+}
+
+/* Called from the top level: if there are any pending inlines to
+   do, set up to process them now.  This function sets up the first function
+   to be parsed; after it has been, the rule for fndef in parse.y will
+   call process_next_inline to start working on the next one.  */
+
+void
+do_pending_inlines ()
+{
+  /* Oops, we're still dealing with the last batch.  */
+  if (yychar == PRE_PARSED_FUNCTION_DECL)
+    return;
+
+  if (pending_inlines)
     {
-    case TYPENAME:
-      nth_token (1)->yychar = TYPENAME_DEFN;
-      break;
-    case PTYPENAME:
-      nth_token (1)->yychar = PTYPENAME_DEFN;
-      break;
-    case IDENTIFIER:
-      nth_token (1)->yychar = IDENTIFIER_DEFN;
-      break;
-    default:
-      my_friendly_abort (102);
+      /* Clear the chain, so that any inlines nested inside the batch
+        we're to process now don't refer to this batch.  See e.g.
+        g++.other/lookup6.C.  */
+      struct unparsed_text *first = pending_inlines;
+      pending_inlines = pending_inlines_tail = 0;
+
+      begin_parsing_inclass_inline (first);
     }
-  return 0;
-}  
-  
-#ifdef SPEW_DEBUG    
-/* debug_yychar takes a yychar (token number) value and prints its name. */
-static int
+}
+
+/* Called from the fndecl rule in the parser when the function just parsed
+   was declared using a PRE_PARSED_FUNCTION_DECL (i.e. came from
+   do_pending_inlines).  */
+
+void
+process_next_inline (i)
+     struct unparsed_text *i;
+{
+  tree decl = i->decl;
+  tree context = decl_function_context (decl);
+
+  if (context)
+    pop_function_context_from (context);
+  if (yychar == YYEMPTY)
+    yychar = yylex ();
+  if (yychar != END_OF_SAVED_INPUT)
+    error ("parse error at end of saved function text");
+  end_input ();
+
+  i = i->next;
+  if (i)
+    begin_parsing_inclass_inline (i);
+  else
+    {
+      if (cfun)
+       cp_function_chain->unparsed_inlines = 0;
+      else
+       processing_these_inlines = 0;
+      extract_interface_info ();
+    }
+}
+\f
+/* Create a new token at the end of the token list in T.  */
+static SPEW_INLINE struct token *
+space_for_token (t)
+     struct unparsed_text *t;
+{
+  if (t->last_pos != TOKEN_CHUNK_SIZE)
+    return t->last_chunk->toks + (t->last_pos++);
+
+  t->last_chunk->next = ggc_alloc_cleared (sizeof (*t->last_chunk->next));
+  t->last_chunk = t->last_chunk->next;
+  t->last_chunk->next = NULL;
+
+  t->last_pos = 1;
+  return t->last_chunk->toks;
+}
+
+/* Shrink the token list in T by one token.  */
+static SPEW_INLINE struct token *
+remove_last_token (t)
+     struct unparsed_text *t;
+{
+  struct token *result = t->last_chunk->toks + t->last_pos - 1;
+  if (t->last_pos == 0)
+    abort ();
+  t->last_pos--;
+  if (t->last_pos == 0 && t->last_chunk != t->tokens)
+    {
+      struct token_chunk **tc;
+      for (tc = &t->tokens; (*tc)->next != NULL; tc = &(*tc)->next)
+       ;
+      *tc = NULL;
+      t->last_pos = ARRAY_SIZE ((*tc)->toks);
+    }
+  return result;
+}
+
+/* Allocate an 'unparsed_text' structure, ready to use space_for_token.  */
+static struct unparsed_text *
+alloc_unparsed_text (locus, decl, interface)
+     const location_t *locus;
+     tree decl;
+     int interface;
+{
+  struct unparsed_text *r;
+  r = ggc_alloc_cleared (sizeof (*r));
+  r->decl = decl;
+  r->locus = *locus;
+  r->interface = interface;
+  r->tokens = r->last_chunk = ggc_alloc_cleared (sizeof (*r->tokens));
+  return r;
+}
+
+/* Subroutine of snarf_method, deals with actual absorption of the block.  */
+
+static void
+snarf_block (t)
+     struct unparsed_text *t;
+{
+  int blev = 1;
+  int look_for_semicolon = 0;
+  int look_for_lbrac = 0;
+  int look_for_catch = 0;
+  int yyc;
+  struct token *current;
+
+  if (yychar == '{')
+    ;
+  else if (yychar == '=')
+    look_for_semicolon = 1;
+  else if (yychar == ':' || yychar == RETURN_KEYWORD || yychar == TRY)
+    {
+      if (yychar == TRY)
+       look_for_catch = 1;
+      look_for_lbrac = 1;
+      blev = 0;
+    }
+  else
+    yyerror ("parse error in method specification");
+
+  /* The current token is the first one to be recorded.  */
+  current = space_for_token (t);
+  current->yychar = yychar;
+  current->yylval = yylval;
+  current->lineno = lineno;
+
+  for (;;)
+    {
+      yyc = next_token (space_for_token (t));
+
+      if (yyc == '{')
+       {
+         look_for_lbrac = 0;
+         blev++;
+       }
+      else if (yyc == '}')
+       {
+         blev--;
+         if (blev == 0 && !look_for_semicolon)
+           {
+             if (!look_for_catch)
+               break;
+
+             if (next_token (space_for_token (t)) != CATCH)
+               {
+                 push_token (remove_last_token (t));
+                 break;
+               }
+
+             look_for_lbrac = 1;
+           }
+       }
+      else if (yyc == ';')
+       {
+         if (look_for_lbrac)
+           {
+             struct token *fake;
+
+             error ("function body for constructor missing");
+             /* fake a { } to avoid further errors */
+             fake = space_for_token (t);
+             fake->yylval.ttype = 0;
+             fake->yychar = '{';
+             fake = space_for_token (t);
+             fake->yylval.ttype = 0;
+             fake->yychar = '}';
+             break;
+           }
+         else if (look_for_semicolon && blev == 0)
+           break;
+       }
+      else if (yyc == 0)
+       {
+         error ("%Hend of file read inside definition", &t->locus);
+         break;
+       }
+    }
+}
+
+/* This function stores away the text for an inline function that should
+   be processed later (by do_pending_inlines).  */
+void
+snarf_method (decl)
+     tree decl;
+{
+  struct unparsed_text *meth;
+  location_t starting;
+  starting.file = input_filename;
+  starting.line = lineno;
+
+  meth = alloc_unparsed_text (&starting, decl, (interface_unknown ? 1
+                                               : (interface_only ? 0 : 2)));
+
+  snarf_block (meth);
+
+  /* Happens when we get two declarations of the same function in the
+     same scope.  */
+  if (decl == void_type_node
+      || (current_class_type && TYPE_REDEFINED (current_class_type)))
+    return;
+
+#ifdef SPEW_DEBUG
+  if (spew_debug)
+    fprintf (stderr, "\tsaved method of %d tokens from %s:%d\n",
+            meth->limit, starting.file, starting.line);
+#endif
+
+  DECL_PENDING_INLINE_INFO (decl) = meth;
+  DECL_PENDING_INLINE_P (decl) = 1;
+
+  if (pending_inlines_tail)
+    pending_inlines_tail->next = meth;
+  else
+    pending_inlines = meth;
+  pending_inlines_tail = meth;
+}
+
+/* Consume a no-commas expression - a default argument - and return
+   a DEFAULT_ARG tree node.  */
+
+static tree
+snarf_defarg ()
+{
+  int yyc;
+  int plev = 0;
+  struct unparsed_text *buf;
+  tree arg;
+  location_t starting;
+  starting.file = input_filename;
+  starting.line = lineno;
+
+  buf = alloc_unparsed_text (&starting, 0, 0);
+
+  for (;;)
+    {
+      yyc = next_token (space_for_token (buf));
+
+      if (plev <= 0 && (yyc == ')' || yyc == ','))
+       break;
+      else if (yyc == '(' || yyc == '[')
+       ++plev;
+      else if (yyc == ']' || yyc == ')')
+       --plev;
+      else if (yyc == 0)
+       {
+         error ("%Hend of file read inside default argument", &starting);
+         goto done;
+       }
+    }
+
+  /* Unget the last token.  */
+  push_token (remove_last_token (buf));
+
+ done:
+#ifdef SPEW_DEBUG
+  if (spew_debug)
+    fprintf (stderr, "\tsaved defarg of %d tokens from %s:%d\n",
+            buf->limit, starting.file, starting.line);
+#endif
+
+  arg = make_node (DEFAULT_ARG);
+  DEFARG_POINTER (arg) = (char *)buf;
+
+  return arg;
+}
+
+/* Decide whether the default argument we are about to see should be
+   gobbled up as text for later parsing.  */
+
+void
+maybe_snarf_defarg ()
+{
+  if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
+    do_snarf_defarg = 1;
+}
+
+/* Called from grokfndecl to note a function decl with unparsed default
+   arguments for later processing.  Also called from grokdeclarator
+   for function types with unparsed defargs; the call from grokfndecl
+   will always come second, so we can overwrite the entry from the type.  */
+
+void
+add_defarg_fn (decl)
+     tree decl;
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    TREE_VALUE (defarg_fns) = decl;
+  else
+    {
+      defarg_fns = tree_cons (NULL_TREE, decl, defarg_fns);
+      TREE_TYPE (defarg_fns) = current_class_type;
+    }
+}
+
+/* Helper for do_pending_defargs.  Starts the parsing of a default arg.  */
+
+static void
+feed_defarg (p)
+     tree p;
+{
+  tree d = TREE_PURPOSE (p);
+
+  feed_input ((struct unparsed_text *)DEFARG_POINTER (d));
+  yychar = DEFARG_MARKER;
+  yylval.ttype = p;
+}
+
+/* Helper for do_pending_defargs.  Ends the parsing of a default arg.  */
+
+static void
+finish_defarg ()
+{
+  if (yychar == YYEMPTY)
+    yychar = yylex ();
+  if (yychar != END_OF_SAVED_INPUT)
+    error ("parse error at end of saved function text");
+
+  end_input ();
+}
+
+/* Main function for deferred parsing of default arguments.  Called from
+   the parser.  */
+
+void
+do_pending_defargs ()
+{
+  if (defarg_parm)
+    finish_defarg ();
+
+  for (; defarg_fns;)
+    {
+      tree current = defarg_fns;
+
+      tree defarg_fn = TREE_VALUE (defarg_fns);
+      if (defarg_parm == NULL_TREE)
+       {
+         push_nested_class (TREE_TYPE (defarg_fns), 1);
+         pushlevel (0);
+         if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+           maybe_begin_member_template_processing (defarg_fn);
+
+         if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+           defarg_parm = TYPE_ARG_TYPES (TREE_TYPE (defarg_fn));
+         else
+           defarg_parm = TYPE_ARG_TYPES (defarg_fn);
+       }
+      else
+       defarg_parm = TREE_CHAIN (defarg_parm);
+
+      for (; defarg_parm; defarg_parm = TREE_CHAIN (defarg_parm))
+       if (!TREE_PURPOSE (defarg_parm)
+           || TREE_CODE (TREE_PURPOSE (defarg_parm)) != DEFAULT_ARG)
+         ;/* OK */
+       else if (TREE_PURPOSE (current) == error_mark_node)
+         DEFARG_POINTER (TREE_PURPOSE (defarg_parm)) = NULL;
+       else
+         {
+           feed_defarg (defarg_parm);
+
+           /* Return to the parser, which will process this defarg
+              and call us again.  */
+           return;
+         }
+
+      if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+       {
+         maybe_end_member_template_processing ();
+         check_default_args (defarg_fn);
+       }
+
+      poplevel (0, 0, 0);
+      pop_nested_class ();
+
+      defarg_fns = TREE_CHAIN (defarg_fns);
+      if (defarg_depfns)
+        {
+          /* This function's default args depend on unprocessed default args
+             of defarg_fns. We will need to reprocess this function, and
+             check for circular dependencies.  */
+          tree a, b;
+
+          for (a = defarg_depfns, b = TREE_PURPOSE (current); a && b;
+               a = TREE_CHAIN (a), b = TREE_CHAIN (b))
+            if (TREE_VALUE (a) != TREE_VALUE (b))
+              goto different;
+          if (a || b)
+            {
+            different:;
+              TREE_CHAIN (current) = NULL_TREE;
+              defarg_fns = chainon (defarg_fns, current);
+              TREE_PURPOSE (current) = defarg_depfns;
+            }
+          else
+            {
+              cp_warning_at ("circular dependency in default args of `%#D'", defarg_fn);
+              /* No need to say what else is dependent, as they will be
+                 picked up in another pass.  */
+
+              /* Immediately repeat, but marked so that we break the loop. */
+              defarg_fns = current;
+              TREE_PURPOSE (current) = error_mark_node;
+            }
+          defarg_depfns = NULL_TREE;
+        }
+      else if (TREE_PURPOSE (current) == error_mark_node)
+        defarg_fnsdone = tree_cons (NULL_TREE, defarg_fn, defarg_fnsdone);
+    }
+}
+
+/* After parsing all the default arguments, we must clear any that remain,
+   which will be part of a circular dependency. */
+void
+done_pending_defargs ()
+{
+  for (; defarg_fnsdone; defarg_fnsdone = TREE_CHAIN (defarg_fnsdone))
+    {
+      tree fn = TREE_VALUE (defarg_fnsdone);
+      tree parms;
+
+      if (TREE_CODE (fn) == FUNCTION_DECL)
+        parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      else
+        parms = TYPE_ARG_TYPES (fn);
+      for (; parms; parms = TREE_CHAIN (parms))
+       if (TREE_PURPOSE (parms)
+           && TREE_CODE (TREE_PURPOSE (parms)) == DEFAULT_ARG)
+         {
+            my_friendly_assert (!DEFARG_POINTER (TREE_PURPOSE (parms)), 20010107);
+           TREE_PURPOSE (parms) = NULL_TREE;
+         }
+    }
+}
+
+/* In processing the current default arg, we called FN, but that call
+   required a default argument of FN, and that had not yet been processed.
+   Remember FN.  */
+
+void
+unprocessed_defarg_fn (fn)
+     tree fn;
+{
+  defarg_depfns = tree_cons (NULL_TREE, fn, defarg_depfns);
+}
+
+/* Called from the parser to update an element of TYPE_ARG_TYPES for some
+   FUNCTION_TYPE with the newly parsed version of its default argument, which
+   was previously digested as text.  */
+
+void
+replace_defarg (arg, init)
+     tree arg, init;
+{
+  if (init == error_mark_node)
+    TREE_PURPOSE (arg) = error_mark_node;
+  else
+    {
+      if (! processing_template_decl
+          && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
+        pedwarn ("invalid type `%T' for default argument to `%T'",
+                   TREE_TYPE (init), TREE_VALUE (arg));
+      if (!defarg_depfns)
+        TREE_PURPOSE (arg) = init;
+    }
+}
+
+#ifdef SPEW_DEBUG
+/* debug_yychar takes a yychar (token number) value and prints its name.  */
+
+static void
 debug_yychar (yy)
      int yy;
 {
-  /* In parse.y: */
-  extern char *debug_yytranslate ();
-  
-  int i;
-  
-  if(yy<256) {
-    fprintf (stderr, "<%d: %c >\n", yy, yy);
-    return 0;
-  }
-  fprintf (stderr, "<%d:%s>\n", yy, debug_yytranslate (yy));
-  return 1;
+  if (yy<256)
+    fprintf (stderr, "->%d < %c >\n", lineno, yy);
+  else if (yy == IDENTIFIER || yy == tTYPENAME)
+    {
+      const char *id;
+      if (TREE_CODE (yylval.ttype) == IDENTIFIER_NODE)
+       id = IDENTIFIER_POINTER (yylval.ttype);
+      else if (TREE_CODE_CLASS (TREE_CODE (yylval.ttype)) == 'd')
+       id = IDENTIFIER_POINTER (DECL_NAME (yylval.ttype));
+      else
+       id = "";
+      fprintf (stderr, "->%d <%s `%s'>\n", lineno, debug_yytranslate (yy), id);
+    }
+  else
+    fprintf (stderr, "->%d <%s>\n", lineno, debug_yytranslate (yy));
 }
 
 #endif
+
+#define NAME(TYPE) cpp_type2name (TYPE)
+
+void
+yyerror (msgid)
+     const char *msgid;
+{
+  const char *string = _(msgid);
+
+  if (last_token == CPP_EOF)
+    error ("%s at end of input", string);
+  else if (last_token == CPP_CHAR || last_token == CPP_WCHAR)
+    {
+      unsigned int val = TREE_INT_CST_LOW (yylval.ttype);
+      const char *const ell = (last_token == CPP_CHAR) ? "" : "L";
+      if (val <= UCHAR_MAX && ISGRAPH (val))
+       error ("%s before %s'%c'", string, ell, val);
+      else
+       error ("%s before %s'\\x%x'", string, ell, val);
+    }
+  else if (last_token == CPP_STRING
+          || last_token == CPP_WSTRING)
+    error ("%s before string constant", string);
+  else if (last_token == CPP_NUMBER)
+    error ("%s before numeric constant", string);
+  else if (last_token == CPP_NAME)
+    {
+      if (TREE_CODE (last_token_id) == IDENTIFIER_NODE)
+        error ("%s before `%s'", string, IDENTIFIER_POINTER (last_token_id));
+      else if (ISGRAPH (yychar))
+        error ("%s before `%c'", string, yychar);
+      else
+       error ("%s before `\%o'", string, yychar);
+    }
+  else
+    error ("%s before `%s' token", string, NAME (last_token));
+}
+
+#include "gt-cp-spew.h"