Disentangling control flow inside the macro expander

Zack Weinberg zack@wolery.cumb.org
Tue Jul 11 16:16:00 GMT 2000


This patch shuffles the control flow around a bit inside the macro
expander.  Formerly we had six core routines engaged in mutual
recursion, plus all the directive handlers and their subroutines.  So
you would get this huge cycle in profiling output:

  [4]     91.5  0.94   14.47 1094600+8143500 <cycle 1 as a whole> [4]
                0.25    8.51 3120900      cpp_get_token <cycle 1> [5]
                0.01    0.42  126000      push_macro_context <cycle 1> [36]
                0.19    0.02 3087800      maybe_paste_with_next <cycle 1> [55]
                0.01    0.22   78500      parse_arg <cycle 1> [51]
                0.01    0.00  129900      is_macro_disabled <cycle 1> [125]
                0.01    0.00   46600      parse_args <cycle 1> [133]

                0.15    0.11  563100      process_directive <cycle 1> [46]
                0.00    1.57    9700      do_include <cycle 1> [18]
                0.03    0.02   81400      do_ifndef <cycle 1> [81]
                0.02    0.01   55900      do_if <cycle 1> [91]
                0.03    0.00  149700      do_define <cycle 1> [95]
                0.00    0.01   22100      do_undef <cycle 1> [121]
                0.00    0.01   46700      do_ifdef <cycle 1> [127]
                0.00    0.00     300      do_elif <cycle 1> [198]

                0.03    0.04  780400      _cpp_get_raw_token <cycle 1> [72]
                0.01    3.49  149700      parse_define <cycle 1> [12]
                0.06    0.00   37900      _cpp_parse_expr <cycle 1> [77]
                0.04    0.00   89700      parse_defined <cycle 1> [85]
                0.03    0.00  171800      get_define_node <cycle 1> [94]
                0.02    0.00  149700      _cpp_create_definition <cycle 1> [99]
                0.02    0.00  273800      lex <cycle 1> [105]
                0.02    0.00   56400      parse_ifdef <cycle 1> [107]
                0.00    0.00    9900      parse_include <cycle 1> [192]

I've shuffled this around - the top block is the lexer proper, the
second block is the directives, and the third their subroutines.  You
can imagine how confusing it was when it was all one big thing sorted
by time in "children".

With this patch, the cycle is limited to the code that actually needs
mutual recursion.  Hopefully we can get rid of a bit more in the
future.

[6]     56.6    0.37    4.08 1483184+3901043 <cycle 1 as a whole> [6]
                0.13    3.74 2019716      get_raw_token <cycle 1> [7]
                0.02    0.21   56363      push_macro_context <cycle 1> [43]
                0.13    0.01 1707945      _cpp_get_token <cycle 1> [54]
                0.01    0.10   35304      parse_arg <cycle 1> [60]
                0.07    0.01 1485258      maybe_paste_with_next <cycle 1> [71]
                0.01    0.00   21543      parse_args <cycle 1> [115]
                0.00    0.00   58081      is_macro_disabled <cycle 1> [164]

Profiling is easier, reading the code in cpplex.c is easier,
and as a convenient side effect PLACEMARKER tokens are no longer
returned by the public interface.

This patch also includes a modified version of Donn Terry's patch to
initialize the base context properly.

zw

2000-07-11  Zack Weinberg  <zack@wolery.cumb.org>

	* cpplex.c (parse_name): No longer inline (premature optimization).
	(do_pop_context): Fold into pop_context.
	(pop_context): Returns int.
	(lex_next): Hoist test for end of directive into pop_context.
	(push_macro_context): Returns int; takes just reader and token.
	Hoist test for excessive nesting to caller.
	(push_arg_context): Returns void; takes just reader and token.
	Do not call stringify_arg or get_raw_token.
	(get_raw_token): Convert tail recursion through	push_arg_context
	to a loop at this level.  Call stringify_arg here if appropriate.
	(maybe_paste_with_next): Convert tail recursion to a while loop.
	Hoist test of paste_level to caller.

	(stringify_arg): Push arg context at beginning.
	(cpp_get_token): Split out core into _cpp_get_token.  Call
	process_directive here.  Throw away CPP_PLACEMARKER tokens.
	(_cpp_get_token): Convert tail recursion through
	push_macro_context to a loop at this level.
	(_cpp_glue_header_name, is_macro_disabled, stringify_arg,
	_cpp_get_raw_token): Use _cpp_get_token.
	(_cpp_skip_rest_of_line): Drop the context stack directly; do
	not call pop_context.
	(_cpp_run_directive): Call lex_next directly.

	* cpphash.h: Prototype _cpp_get_token.
	* cppexp.c (lex): Use it.
	* cpphash.c (parse_define): Use it.
	* cpplex.c 
	* cpplib.c (get_define_node, do_undef, parse_include,
	read_line_number, do_line, do_ident, do_pragma, do_pragma_gcc,
	do_pragma_implementation, do_pragma_poison, do_pragma_dependency,
	parse_ifdef, validate_else): Use it.
	(cpp_push_buffer): Tweak error message; abort if anyone tries
	to push a buffer while macro expansions are stacked.

2000-07-11  Donn Terry  <donnte@microsoft.com>

	* cpplex.c (free_macro_args, save_token): Cast arg of free
	and/or xrealloc to PTR.
	(_cpp_init_input_buffer): Clear all fields of the base context.

===================================================================
Index: cppexp.c
--- cppexp.c	2000/07/09 20:44:51	1.65
+++ cppexp.c	2000/07/11 22:42:26
@@ -392,7 +392,7 @@ lex (pfile, skip_evaluation)
   const cpp_token *tok;
 
  retry:
-  tok = cpp_get_token (pfile);
+  tok = _cpp_get_token (pfile);
 
   switch (tok->type)
     {
===================================================================
Index: cpphash.c
--- cpphash.c	2000/07/08 19:00:38	1.97
+++ cpphash.c	2000/07/11 22:42:26
@@ -354,7 +354,7 @@ parse_define (pfile)
   int prev_white = 0;
 
   /* The first token after the macro's name.  */
-  token = cpp_get_token (pfile);
+  token = _cpp_get_token (pfile);
 
   /* Constraint 6.10.3.5  */
   if (is__va_args__ (pfile, token - 1))
===================================================================
Index: cpphash.h
--- cpphash.h	2000/07/09 09:19:44	1.61
+++ cpphash.h	2000/07/11 22:42:26
@@ -256,6 +256,7 @@ extern void _cpp_run_directive		PARAMS (
 						 const char *, size_t));
 extern unsigned int _cpp_get_line	PARAMS ((cpp_reader *,
 						 unsigned int *));
+extern const cpp_token *_cpp_get_token PARAMS ((cpp_reader *));
 extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *));
 extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*));
 extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *));
===================================================================
Index: cpplex.c
--- cpplex.c	2000/07/11 14:28:09	1.68
+++ cpplex.c	2000/07/11 22:42:27
@@ -417,7 +417,7 @@ _cpp_glue_header_name (pfile)
 
   for (;;)
     {
-      t = cpp_get_token (pfile);
+      t = _cpp_get_token (pfile);
       if (t->type == CPP_GREATER || t->type == CPP_EOF)
 	break;
 
@@ -947,7 +947,7 @@ skip_whitespace (pfile, in_directive)
 }
 
 /* Parse (append) an identifier.  */
-static inline const U_CHAR *
+static const U_CHAR *
 parse_name (pfile, tok, cur, rlimit)
      cpp_reader *pfile;
      cpp_token *tok;
@@ -1960,7 +1960,7 @@ struct cpp_context
     const cpp_token **arg;	/* Used for arg contexts only.  */
   } u;
 
-  /* Pushed token to be returned by next call to cpp_get_token.  */
+  /* Pushed token to be returned by next call to get_raw_token.  */
   const cpp_token *pushed_token;
 
   struct macro_args *args;	/* 0 for arguments and object-like macros.  */
@@ -1985,13 +1985,9 @@ static const cpp_token *parse_arg PARAMS
 					   macro_args *, unsigned int *));
 static int parse_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_args *));
 static void save_token PARAMS ((macro_args *, const cpp_token *));
-static const cpp_token *push_arg_context PARAMS ((cpp_reader *,
-						  const cpp_token *));
-static int do_pop_context PARAMS ((cpp_reader *));
-static const cpp_token *pop_context PARAMS ((cpp_reader *));
-static const cpp_token *push_macro_context PARAMS ((cpp_reader *,
-						    cpp_hashnode *,
-						    const cpp_token *));
+static int pop_context PARAMS ((cpp_reader *));
+static int push_macro_context PARAMS ((cpp_reader *, const cpp_token *));
+static void push_arg_context PARAMS ((cpp_reader *, const cpp_token *));
 static void free_macro_args PARAMS ((macro_args *));
 
 /* Free the storage allocated for macro arguments.  */
@@ -2000,7 +1996,7 @@ free_macro_args (args)
      macro_args *args;
 {
   if (args->tokens)
-    free (args->tokens);
+    free ((PTR) args->tokens);
   free (args->ends);
   free (args);
 }
@@ -2069,7 +2065,7 @@ is_macro_disabled (pfile, expansion, tok
 
       prev_nme = pfile->no_expand_level;
       pfile->no_expand_level = context - pfile->contexts;
-      next = cpp_get_token (pfile);
+      next = _cpp_get_token (pfile);
       restore_macro_expansion (pfile, prev_nme);
       if (next->type != CPP_OPEN_PAREN)
 	{
@@ -2096,7 +2092,8 @@ save_token (args, token)
     {
       args->capacity += args->capacity + 100;
       args->tokens = (const cpp_token **)
-	xrealloc (args->tokens, args->capacity * sizeof (const cpp_token *));
+	xrealloc ((PTR) args->tokens,
+		  args->capacity * sizeof (const cpp_token *));
     }
   args->tokens[args->used++] = token;
 }
@@ -2117,7 +2114,7 @@ parse_arg (pfile, var_args, paren_contex
   
   for (count = 0;; count++)
     {
-      token = cpp_get_token (pfile);
+      token = _cpp_get_token (pfile);
 
       switch (token->type)
 	{
@@ -2511,97 +2508,100 @@ maybe_paste_with_next (pfile, token)
   cpp_context *context = CURRENT_CONTEXT (pfile);
 
   /* Is this token on the LHS of ## ? */
-  if (!((context->flags & CONTEXT_PASTEL) && context->posn == context->count)
-      && !(token->flags & PASTE_LEFT))
-    return token;
 
-  /* Prevent recursion, and possibly pushing back more than one token.  */
-  if (pfile->paste_level)
-    return token;
-  
-  /* Suppress macro expansion for next token, but don't conflict with
-     the other method of suppression.  If it is an argument, macro
-     expansion within the argument will still occur.  */
-  pfile->paste_level = pfile->cur_context;
-  second = cpp_get_token (pfile);
-  pfile->paste_level = 0;
-
-  /* Ignore placemarker argument tokens (cannot be from an empty macro
-     since macros are not expanded).  */
-  if (token->type == CPP_PLACEMARKER)
-     pasted = duplicate_token (pfile, second);
-  else if (second->type == CPP_PLACEMARKER)
-    {
-      cpp_context *mac_context = CURRENT_CONTEXT (pfile) - 1;
-      /* GCC has special extended semantics for a ## b where b is a
-	 varargs parameter: a disappears if b consists of no tokens.
-	 This extension is deprecated.  */
-      if ((mac_context->u.list->flags & GNU_REST_ARGS)
-	  && (mac_context->u.list->tokens[mac_context->posn - 1].val.aux + 1
-	      == (unsigned) mac_context->u.list->paramc))
+  while ((token->flags & PASTE_LEFT)
+	 || ((context->flags & CONTEXT_PASTEL)
+	     && context->posn == context->count))
+    {
+      /* Suppress macro expansion for next token, but don't conflict
+	 with the other method of suppression.  If it is an argument,
+	 macro expansion within the argument will still occur.  */
+      pfile->paste_level = pfile->cur_context;
+      second = _cpp_get_token (pfile);
+      pfile->paste_level = 0;
+
+      /* Ignore placemarker argument tokens (cannot be from an empty
+	 macro since macros are not expanded).  */
+      if (token->type == CPP_PLACEMARKER)
+	pasted = duplicate_token (pfile, second);
+      else if (second->type == CPP_PLACEMARKER)
 	{
-	  cpp_warning (pfile, "deprecated GNU ## extension used");
-	  pasted = duplicate_token (pfile, second);
+	  cpp_context *mac_context = CURRENT_CONTEXT (pfile) - 1;
+	  /* GCC has special extended semantics for a ## b where b is
+	     a varargs parameter: a disappears if b consists of no
+	     tokens.  This extension is deprecated.  */
+	  if ((mac_context->u.list->flags & GNU_REST_ARGS)
+	      && (mac_context->u.list->tokens[mac_context->posn-1].val.aux + 1
+		  == (unsigned) mac_context->u.list->paramc))
+	    {
+	      cpp_warning (pfile, "deprecated GNU ## extension used");
+	      pasted = duplicate_token (pfile, second);
+	    }
+	  else
+	    pasted = duplicate_token (pfile, token);
 	}
       else
-	pasted = duplicate_token (pfile, token);
-    }
-  else
-    {
-      int digraph = 0;
-      enum cpp_ttype type = can_paste (pfile, token, second, &digraph);
-
-      if (type == CPP_EOF)
 	{
-	  if (CPP_OPTION (pfile, warn_paste))
-	    cpp_warning (pfile,
-			 "pasting would not give a valid preprocessing token");
-	  _cpp_push_token (pfile, second);
-	  return token;
-	}
+	  int digraph = 0;
+	  enum cpp_ttype type = can_paste (pfile, token, second, &digraph);
 
-      if (type == CPP_NAME || type == CPP_NUMBER)
-	{
-	  /* Join spellings.  */
-	  U_CHAR *buf, *end;
+	  if (type == CPP_EOF)
+	    {
+	      if (CPP_OPTION (pfile, warn_paste))
+		cpp_warning (pfile,
+			"pasting would not give a valid preprocessing token");
+	      _cpp_push_token (pfile, second);
+	      return token;
+	    }
+
+	  if (type == CPP_NAME || type == CPP_NUMBER)
+	    {
+	      /* Join spellings.  */
+	      U_CHAR *buf, *end;
 
-	  pasted = get_temp_token (pfile);
-	  buf = (U_CHAR *) alloca (TOKEN_LEN (token) + TOKEN_LEN (second));
-	  end = spell_token (pfile, token, buf);
-	  end = spell_token (pfile, second, end);
-	  *end = '\0';
+	      pasted = get_temp_token (pfile);
+	      buf = (U_CHAR *) alloca (TOKEN_LEN (token) + TOKEN_LEN (second));
+	      end = spell_token (pfile, token, buf);
+	      end = spell_token (pfile, second, end);
+	      *end = '\0';
 
-	  if (type == CPP_NAME)
-	    pasted->val.node = cpp_lookup (pfile, buf, end - buf);
+	      if (type == CPP_NAME)
+		pasted->val.node = cpp_lookup (pfile, buf, end - buf);
+	      else
+		{
+		  pasted->val.str.text = uxstrdup (buf);
+		  pasted->val.str.len = end - buf;
+		}
+	    }
+	  else if (type == CPP_WCHAR || type == CPP_WSTRING)
+	    pasted = duplicate_token (pfile, second);
 	  else
 	    {
-	      pasted->val.str.text = uxstrdup (buf);
-	      pasted->val.str.len = end - buf;
+	      pasted = get_temp_token (pfile);
+	      pasted->val.integer = 0;
 	    }
-	}
-      else if (type == CPP_WCHAR || type == CPP_WSTRING)
-	pasted = duplicate_token (pfile, second);
-      else
-	{
-	  pasted = get_temp_token (pfile);
-	  pasted->val.integer = 0;
+
+	  pasted->type = type;
+	  pasted->flags = digraph ? DIGRAPH : 0;
 	}
 
-      pasted->type = type;
-      pasted->flags = digraph ? DIGRAPH : 0;
+      /* The pasted token gets the whitespace flags and position of the
+	 first token, the PASTE_LEFT flag of the second token, plus the
+	 PASTED flag to indicate it is the result of a paste.  However, we
+	 want to preserve the DIGRAPH flag.  */
+      pasted->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT);
+      pasted->flags |= ((token->flags & (PREV_WHITE | BOL))
+			| (second->flags & PASTE_LEFT) | PASTED);
+      pasted->col = token->col;
+      pasted->line = token->line;
+
+      /* See if there is another token to be pasted onto the one we just
+	 constructed.  */
+      token = pasted;
+      context = CURRENT_CONTEXT (pfile);
+      /* and loop */
     }
-
-  /* The pasted token gets the whitespace flags and position of the
-     first token, the PASTE_LEFT flag of the second token, plus the
-     PASTED flag to indicate it is the result of a paste.  However, we
-     want to preserve the DIGRAPH flag.  */
-  pasted->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT);
-  pasted->flags |= ((token->flags & (PREV_WHITE | BOL))
-		    | (second->flags & PASTE_LEFT) | PASTED);
-  pasted->col = token->col;
-  pasted->line = token->line;
-
-  return maybe_paste_with_next (pfile, pasted);
+  return token;
 }
 
 /* Convert a token sequence to a single string token according to the
@@ -2617,13 +2617,14 @@ stringify_arg (pfile, token)
   unsigned int prev_value, backslash_count = 0;
   unsigned int buf_used = 0, whitespace = 0, buf_cap = INIT_SIZE;
 
+  push_arg_context (pfile, token);
   prev_value  = prevent_macro_expansion (pfile);
   main_buf = (unsigned char *) xmalloc (buf_cap);
 
   result = get_temp_token (pfile);
   ASSIGN_FLAGS_AND_POS (result, token);
 
-  for (; (token = cpp_get_token (pfile))->type != CPP_EOF; )
+  for (; (token = _cpp_get_token (pfile))->type != CPP_EOF; )
     {
       int escape;
       unsigned char *buf;
@@ -2690,22 +2691,16 @@ expand_context_stack (pfile)
 
 /* Push the context of macro NODE onto the context stack.  TOKEN is
    the CPP_NAME token invoking the macro.  */
-static const cpp_token *
-push_macro_context (pfile, node, token)
+static int
+push_macro_context (pfile, token)
      cpp_reader *pfile;
-     cpp_hashnode *node;
      const cpp_token *token;
 {
   unsigned char orig_flags;
   macro_args *args;
   cpp_context *context;
+  cpp_hashnode *node = token->val.node;
 
-  if (pfile->cur_context > CPP_STACK_MAX)
-    {
-      cpp_error (pfile, "infinite macro recursion invoking '%s'", node->name);
-      return token;
-    }
-
   /* Token's flags may change when parsing args containing a nested
      invocation of this macro.  */
   orig_flags = token->flags & (PREV_WHITE | BOL);
@@ -2731,7 +2726,7 @@ push_macro_context (pfile, node, token)
       if (error)
 	{
 	  free_macro_args (args);
-	  return token;
+	  return 1;
 	}
     }
 
@@ -2753,12 +2748,12 @@ push_macro_context (pfile, node, token)
      be one, empty macros are a single placemarker token.  */
   MODIFY_FLAGS_AND_POS (&context->u.list->tokens[0], token, orig_flags);
 
-  return cpp_get_token (pfile);
+  return 0;
 }
 
 /* Push an argument to the current macro onto the context stack.
    TOKEN is the MACRO_ARG token representing the argument expansion.  */
-static const cpp_token *
+static void
 push_arg_context (pfile, token)
      cpp_reader *pfile;
      const cpp_token *token;
@@ -2792,15 +2787,10 @@ push_arg_context (pfile, token)
 			  token->flags & (PREV_WHITE | BOL));
   }
 
-  if (token->flags & STRINGIFY_ARG)
-    return stringify_arg (pfile, token);
-
   if (token->flags & PASTE_LEFT)
     context->flags |= CONTEXT_PASTEL;
   if (pfile->paste_level)
     context->flags |= CONTEXT_PASTER;
-
-  return get_raw_token (pfile);
 }
 
 /* "Unget" a token.  It is effectively inserted in the token queue and
@@ -2859,58 +2849,92 @@ cpp_get_token (pfile)
      cpp_reader *pfile;
 {
   const cpp_token *token;
-  cpp_hashnode *node;
-
-  /* Loop till we hit a non-directive, non-skipped, non-placemarker token.  */
+  /* Loop till we hit a non-directive, non-placemarker token.  */
   for (;;)
     {
-      token = get_raw_token (pfile);
-      if (token->flags & BOL && token->type == CPP_HASH
+      token = _cpp_get_token (pfile);
+
+      if (token->type == CPP_PLACEMARKER)
+	continue;
+
+      if (token->type == CPP_HASH && token->flags & BOL
 	  && pfile->token_list.directive)
 	{
 	  process_directive (pfile, token);
 	  continue;
 	}
 
+      return token;
+    }
+}
+
+/* The internal interface to return the next token.  There are two
+   differences between the internal and external interfaces: the
+   internal interface may return a PLACEMARKER token, and it does not
+   process directives.  */
+const cpp_token *
+_cpp_get_token (pfile)
+     cpp_reader *pfile;
+{
+  const cpp_token *token;
+  cpp_hashnode *node;
+
+  /* Loop until we hit a non-macro token.  */
+  for (;;)
+    {
+      token = get_raw_token (pfile);
+
       /* Short circuit EOF. */
       if (token->type == CPP_EOF)
 	return token;
-      
-      if (pfile->skipping && ! pfile->token_list.directive)
+
+      /* If we are skipping... */
+      if (pfile->skipping)
 	{
+	  /* we still have to process directives,  */
+	  if (pfile->token_list.directive)
+	    return token;
+
+	  /* but everything else is ignored.  */
 	  _cpp_skip_rest_of_line (pfile);
 	  continue;
 	}
-      break;
-    }
-
-  /* If there's a potential control macro and we get here, then that
-     #ifndef didn't cover the entire file and its argument shouldn't
-     be taken as a control macro.  */
-  pfile->potential_control_macro = 0;
-
-  token = maybe_paste_with_next (pfile, token);
 
-  if (token->type != CPP_NAME)
-    return token;
+      /* If there's a potential control macro and we get here, then that
+	 #ifndef didn't cover the entire file and its argument shouldn't
+	 be taken as a control macro.  */
+      pfile->potential_control_macro = 0;
+
+      /* See if there's a token to paste with this one.  */
+      if (!pfile->paste_level)
+	token = maybe_paste_with_next (pfile, token);
+
+      /* If it isn't a macro, return it now.  */
+      if (token->type != CPP_NAME
+	  || token->val.node->type == T_VOID)
+	return token;
 
-  /* Is macro expansion disabled in general?  */
-  if (pfile->no_expand_level == pfile->cur_context || pfile->paste_level)
-    return token;
+      /* Is macro expansion disabled in general?  */
+      if (pfile->no_expand_level == pfile->cur_context || pfile->paste_level)
+	return token;
  
-  node = token->val.node;
-  if (node->type == T_VOID)
-    return token;
+      node = token->val.node;
+      if (node->type != T_MACRO)
+	return special_symbol (pfile, node, token);
 
-  if (node->type == T_MACRO)
-    {
       if (is_macro_disabled (pfile, node->value.expansion, token))
 	return token;
 
-      return push_macro_context (pfile, node, token);
+      if (pfile->cur_context > CPP_STACK_MAX)
+	{
+	  cpp_error (pfile, "macros nested too deep invoking '%s'", node->name);
+	  return token;
+	}
+
+      if (push_macro_context (pfile, token))
+	return token;
+      /* else loop */
     }
-  else
-    return special_symbol (pfile, node, token);
 }
 
 /* Returns the next raw token, i.e. without performing macro
@@ -2920,33 +2944,45 @@ get_raw_token (pfile)
      cpp_reader *pfile;
 {
   const cpp_token *result;
-  cpp_context *context = CURRENT_CONTEXT (pfile);
+  cpp_context *context;
 
-  if (context->pushed_token)
-    {
-      result = context->pushed_token;
-      context->pushed_token = 0;
-    }
-  else if (context->posn == context->count)
-    result = pop_context (pfile);
-  else
+  for (;;)
     {
-      if (IS_ARG_CONTEXT (context))
+      context = CURRENT_CONTEXT (pfile);
+      if (context->pushed_token)
 	{
-	  result = context->u.arg[context->posn++];
-	  if (result == 0)
+	  result = context->pushed_token;
+	  context->pushed_token = 0;
+	}
+      else if (context->posn == context->count)
+	{
+	  if (pop_context (pfile))
+	    return &eof_token;
+	  continue;
+	}
+      else
+	{
+	  if (IS_ARG_CONTEXT (context))
 	    {
-	      context->flags ^= CONTEXT_RAW;
 	      result = context->u.arg[context->posn++];
+	      if (result == 0)
+		{
+		  context->flags ^= CONTEXT_RAW;
+		  result = context->u.arg[context->posn++];
+		}
+	      return result;	/* Cannot be a CPP_MACRO_ARG */
 	    }
-	  return result;	/* Cannot be a CPP_MACRO_ARG */
+	  result = &context->u.list->tokens[context->posn++];
 	}
-      result = &context->u.list->tokens[context->posn++];
-    }
 
-  if (result->type == CPP_MACRO_ARG)
-    result = push_arg_context (pfile, result);
-  return result;
+      if (result->type != CPP_MACRO_ARG)
+	return result;
+
+      if (result->flags & STRINGIFY_ARG)
+	return stringify_arg (pfile, result);
+
+      push_arg_context (pfile, result);
+    }
 }
 
 /* Internal interface to get the token without macro expanding.  */
@@ -2955,7 +2991,7 @@ _cpp_get_raw_token (pfile)
      cpp_reader *pfile;
 {
   int prev_nme = prevent_macro_expansion (pfile);
-  const cpp_token *result = cpp_get_token (pfile);
+  const cpp_token *result = _cpp_get_token (pfile);
   restore_macro_expansion (pfile, prev_nme);
   return result;
 }
@@ -2973,16 +3009,6 @@ lex_next (pfile, clear)
   const cpp_token *old_list = list->tokens;
   unsigned int old_used = list->tokens_used;
 
-  /* If we are currently processing a directive, do not advance.  6.10
-     paragraph 2: A new-line character ends the directive even if it
-     occurs within what would otherwise be an invocation of a
-     function-like macro.
-
-     It is possible that clear == 1 too; e.g. "#if funlike_macro ("
-     since parse_args swallowed the directive's EOF.  */
-  if (list->directive)
-    return 1;
-
   if (clear)
     {
       /* Release all temporary tokens.  */
@@ -3034,18 +3060,27 @@ lex_next (pfile, clear)
   return 0;
 }
 
-/* Pops a context of the context stack.  If we're at the bottom, lexes
-   the next logical line.  Returns 1 if we're at the end of the
+/* Pops a context off the context stack.  If we're at the bottom, lexes
+   the next logical line.  Returns EOF if we're at the end of the
    argument list to the # operator, or if it is illegal to "overflow"
    into the rest of the file (e.g. 6.10.3.1.1).  */
 static int
-do_pop_context (pfile)
+pop_context (pfile)
      cpp_reader *pfile;
 {
   cpp_context *context;
 
   if (pfile->cur_context == 0)
-    return lex_next (pfile, pfile->no_expand_level == UINT_MAX);
+    {
+      /* If we are currently processing a directive, do not advance.  6.10
+	 paragraph 2: A new-line character ends the directive even if it
+	 occurs within what would otherwise be an invocation of a
+	 function-like macro.  */
+      if (pfile->token_list.directive)
+	return 1;
+
+      return lex_next (pfile, pfile->no_expand_level == UINT_MAX);
+    }
 
   /* Argument contexts, when parsing args or handling # operator
      return CPP_EOF at the end.  */
@@ -3064,16 +3099,6 @@ do_pop_context (pfile)
   return 0;
 }
 
-/* Move down the context stack, and return the next raw token.  */
-static const cpp_token *
-pop_context (pfile)
-     cpp_reader *pfile;
-{
-  if (do_pop_context (pfile))
-    return &eof_token;
-  return get_raw_token (pfile);
-}
-
 /* Turn off macro expansion at the current context level.  */
 static unsigned int
 prevent_macro_expansion (pfile)
@@ -3286,18 +3311,26 @@ void
 _cpp_init_input_buffer (pfile)
      cpp_reader *pfile;
 {
+  cpp_context *base;
+
   init_trigraph_map ();
+  _cpp_init_toklist (&pfile->token_list, DUMMY_TOKEN);
+  pfile->no_expand_level = UINT_MAX;
   pfile->context_cap = 20;
-  pfile->contexts = (cpp_context *)
-    xmalloc (pfile->context_cap * sizeof (cpp_context));
   pfile->cur_context = 0;
-  pfile->contexts[0].u.list = &pfile->token_list;
 
-  pfile->contexts[0].posn = 0;
-  pfile->contexts[0].count = 0;
-  pfile->no_expand_level = UINT_MAX;
+  pfile->contexts = (cpp_context *)
+    xmalloc (pfile->context_cap * sizeof (cpp_context));
 
-  _cpp_init_toklist (&pfile->token_list, DUMMY_TOKEN);
+  /* Clear the base context.  */
+  base = &pfile->contexts[0];
+  base->u.list = &pfile->token_list;
+  base->posn = 0;
+  base->count = 0;
+  base->args = 0;
+  base->level = 0;
+  base->flags = 0;
+  base->pushed_token = 0;
 }
 
 /* Moves to the end of the directive line, popping contexts as
@@ -3306,17 +3339,20 @@ void
 _cpp_skip_rest_of_line (pfile)
      cpp_reader *pfile;
 {
-  /* Get to base context.  Clear parsing args and each contexts flags,
-     since these can cause pop_context to return without popping.  */
-  pfile->no_expand_level = UINT_MAX;
-  while (pfile->cur_context != 0)
-    {
-      pfile->contexts[pfile->cur_context].flags = 0;
-      do_pop_context (pfile);
-    }
+  /* Discard all stacked contexts.  */
+  int i;
+  for (i = pfile->cur_context; i > 0; i--)
+    if (pfile->contexts[i].args)
+      free_macro_args (pfile->contexts[i].args);
+
+  if (pfile->no_expand_level <= pfile->cur_context)
+    pfile->no_expand_level = 0;
+  pfile->cur_context = 0;
 
-  pfile->contexts[pfile->cur_context].count = 0;
-  pfile->contexts[pfile->cur_context].posn = 0;
+  /* Clear the base context, and clear the directive pointer so that
+     get_raw_token will advance to the next line.  */
+  pfile->contexts[0].count = 0;
+  pfile->contexts[0].posn = 0;
   pfile->token_list.directive = 0;
 }
 
@@ -3332,8 +3368,9 @@ _cpp_run_directive (pfile, dir, buf, cou
   if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL)
     {
       unsigned int prev_lvl = 0;
-      /* scan the line now, else prevent_macro_expansion won't work */
-      do_pop_context (pfile);
+
+      /* Scan the line now, else prevent_macro_expansion won't work.  */
+      lex_next (pfile, 1);
       if (! (dir->flags & EXPAND))
 	prev_lvl = prevent_macro_expansion (pfile);
 
===================================================================
Index: cpplib.c
--- cpplib.c	2000/07/08 19:00:39	1.185
+++ cpplib.c	2000/07/11 22:42:27
@@ -250,7 +250,7 @@ get_define_node (pfile)
   const cpp_token *token;
 
   /* Skip any -C comments.  */
-  while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
+  while ((token = _cpp_get_token (pfile))->type == CPP_COMMENT)
     ;
 
   if (token->type != CPP_NAME)
@@ -307,7 +307,7 @@ do_undef (pfile)
 {
   cpp_hashnode *node = get_define_node (pfile);  
 
-  if (cpp_get_token (pfile)->type != CPP_EOF)
+  if (_cpp_get_token (pfile)->type != CPP_EOF)
     cpp_pedwarn (pfile, "junk on line after #undef");
 
   /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
@@ -343,7 +343,7 @@ parse_include (pfile, dir, trail, strp, 
      unsigned int *lenp;
      int *abp;
 {
-  const cpp_token *name = cpp_get_token (pfile);
+  const cpp_token *name = _cpp_get_token (pfile);
 
   if (name->type != CPP_STRING && name->type != CPP_HEADER_NAME)
     {
@@ -361,7 +361,7 @@ parse_include (pfile, dir, trail, strp, 
       return 1;
     }
 
-  if (!trail && cpp_get_token (pfile)->type != CPP_EOF)
+  if (!trail && _cpp_get_token (pfile)->type != CPP_EOF)
     cpp_error (pfile, "junk at end of #%s", dir);
 
   *lenp = name->val.str.len;
@@ -459,7 +459,7 @@ read_line_number (pfile, num)
      cpp_reader *pfile;
      int *num;
 {
-  const cpp_token *tok = cpp_get_token (pfile);
+  const cpp_token *tok = _cpp_get_token (pfile);
   enum cpp_ttype type = tok->type;
   const U_CHAR *p = tok->val.str.text;
   unsigned int len = tok->val.str.len;
@@ -519,7 +519,7 @@ do_line (pfile)
   unsigned int len;
   const cpp_token *tok;
 
-  tok = cpp_get_token (pfile);
+  tok = _cpp_get_token (pfile);
   type = tok->type;
   str = tok->val.str.text;
   len = tok->val.str.len;
@@ -535,7 +535,7 @@ do_line (pfile)
 
   old_lineno = ip->lineno;
   ip->lineno = new_lineno;
-  tok = cpp_get_token (pfile);
+  tok = _cpp_get_token (pfile);
   type = tok->type;
   str = tok->val.str.text;
   len = tok->val.str.len;
@@ -645,9 +645,9 @@ do_ident (pfile)
      cpp_reader *pfile;
 {
   /* Next token should be a string constant.  */
-  if (cpp_get_token (pfile)->type == CPP_STRING)
+  if (_cpp_get_token (pfile)->type == CPP_STRING)
     /* And then a newline.  */
-    if (cpp_get_token (pfile)->type == CPP_EOF)
+    if (_cpp_get_token (pfile)->type == CPP_EOF)
       {
 	/* Good - ship it.  */
 	pass_thru_directive (pfile);
@@ -725,7 +725,7 @@ do_pragma (pfile)
   const cpp_token *tok;
   int pop;
 
-  tok = cpp_get_token (pfile);
+  tok = _cpp_get_token (pfile);
   if (tok->type == CPP_EOF)
     return 0;
   else if (tok->type != CPP_NAME)
@@ -746,7 +746,7 @@ do_pragma_gcc (pfile)
 {
   const cpp_token *tok;
 
-  tok = cpp_get_token (pfile);
+  tok = _cpp_get_token (pfile);
   if (tok->type == CPP_EOF)
     return 1;
   else if (tok->type != CPP_NAME)
@@ -780,13 +780,13 @@ do_pragma_implementation (pfile)
 {
   /* Be quiet about `#pragma implementation' for a file only if it hasn't
      been included yet.  */
-  const cpp_token *tok = cpp_get_token (pfile);
+  const cpp_token *tok = _cpp_get_token (pfile);
   char *copy;
 
   if (tok->type == CPP_EOF)
     return 0;
   else if (tok->type != CPP_STRING
-	   || cpp_get_token (pfile)->type != CPP_EOF)
+	   || _cpp_get_token (pfile)->type != CPP_EOF)
     {
       cpp_error (pfile, "malformed #pragma implementation");
       return 1;
@@ -822,7 +822,7 @@ do_pragma_poison (pfile)
 
   for (;;)
     {
-      tok = cpp_get_token (pfile);
+      tok = _cpp_get_token (pfile);
       if (tok->type == CPP_EOF)
 	break;
       if (tok->type != CPP_NAME)
@@ -887,7 +887,7 @@ do_pragma_dependency (pfile)
     cpp_warning (pfile, "cannot find source %c%s%c", left, name, right);
   else if (ordering > 0)
     {
-      const cpp_token *msg = cpp_get_token (pfile);
+      const cpp_token *msg = _cpp_get_token (pfile);
       
       cpp_warning (pfile, "current file is older than %c%s%c",
 		   left, name, right);
@@ -974,7 +974,7 @@ parse_ifdef (pfile, name)
   enum cpp_ttype type;
   const cpp_hashnode *node = 0;
 
-  const cpp_token *token = cpp_get_token (pfile);
+  const cpp_token *token = _cpp_get_token (pfile);
   type = token->type;
 
   if (!CPP_TRADITIONAL (pfile))
@@ -983,7 +983,7 @@ parse_ifdef (pfile, name)
 	cpp_pedwarn (pfile, "#%s with no argument", name);
       else if (type != CPP_NAME)
 	cpp_pedwarn (pfile, "#%s with invalid argument", name);
-      else if (cpp_get_token (pfile)->type != CPP_EOF)
+      else if (_cpp_get_token (pfile)->type != CPP_EOF)
 	cpp_pedwarn (pfile, "garbage at end of #%s", name);
     }
 
@@ -1186,7 +1186,7 @@ validate_else (pfile, directive)
      cpp_reader *pfile;
      const U_CHAR *directive;
 {
-  if (CPP_PEDANTIC (pfile) && cpp_get_token (pfile)->type != CPP_EOF)
+  if (CPP_PEDANTIC (pfile) && _cpp_get_token (pfile)->type != CPP_EOF)
     cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
 }
 
@@ -1515,8 +1515,13 @@ cpp_push_buffer (pfile, buffer, length)
   cpp_buffer *new;
   if (++pfile->buffer_stack_depth == CPP_STACK_MAX)
     {
-      cpp_fatal (pfile, "#include recursion too deep");
+      cpp_fatal (pfile, "#include nested too deep");
       return NULL;
+    }
+  if (pfile->cur_context > 0)
+    {
+      cpp_ice (pfile, "buffer pushed with contexts stacked");
+      _cpp_skip_rest_of_line (pfile);
     }
 
   new = xobnew (pfile->buffer_ob, cpp_buffer);


More information about the Gcc-patches mailing list