This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

cpplib: Simplify multiple-include optimisation


In particular, the part that handles

#if !defined foo

which is naturally awkward to handle because you either have to look
ahead, or figure out during expression parsing whether you saw an
expression of that form and nothing more.  I was making it a little
more complicated than need be previously.

This is another part of my trying to make cpplib more robust to
changes in lexing and directive handling.  The main object of this was
to remove an unnecessary token lookahead.

Also, a small documentation update.

Neil.

	* cppexp.c (parse_defined): Always record the macro name.
	(lex): Don't worry about identifiers, or special-case
	CPP_NOT here.
	(_cpp_parse_expr): Figure out at the end of the routine
	whether we saw a valid !defined() expression.
	* cppfiles.c (stack_include_file): Update for mi_valid.
	(_cpp_pop_file_buffer): Similarly.
	* cpplex.c (_cpp_lex_token): Similarly.
	* cpphash.h (enum mi_state, enum mi_ind, mi_state,
	mi_if_not_defined, mi_lexed): Remove.
	(mi_valid): New.
	* cpplib.c (do_if): Simplify.
	(do_endif, push_conditional, _cpp_handle_directive): Update
	for renaming of mi_state to mi_valid.

	* cpp.texi: Add index entries for digraphs, and add comment
	that C++ refers to them as alternative tokens.

============================================================
Index: gcc/cppexp.c
--- gcc/cppexp.c	2001/07/19 06:12:48	1.93
+++ gcc/cppexp.c	2001/07/29 12:39:15
@@ -267,16 +267,9 @@ parse_defined (pfile)
       op.unsignedp = 0;
       op.op = CPP_NUMBER;
 
-      /* No macros?  At top of file?  */
-      if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0
-	  && pfile->mi_if_not_defined == MI_IND_NOT && pfile->mi_lexed == 1)
-	{
-	  cpp_start_lookahead (pfile);
-	  cpp_get_token (pfile, &token);
-	  if (token.type == CPP_EOF)
-	    pfile->mi_ind_cmacro = node;
-	  cpp_stop_lookahead (pfile, 0);
-	}
+      /* A possible controlling macro of the form #if !defined ().
+	 _cpp_parse_expr checks there was no other junk on the line.  */
+      pfile->mi_ind_cmacro = node;
     }
 
   pfile->state.prevent_expansion--;
@@ -351,10 +344,6 @@ lex (pfile, skip_evaluation, token)
 	}
       else
 	{
-	  /* Controlling #if expressions cannot contain identifiers (they
-	     could become macros in the future).  */
-	  pfile->mi_state = MI_FAILED;
-
 	  op.op = CPP_NUMBER;
 	  op.unsignedp = 0;
 	  op.value = 0;
@@ -377,11 +366,6 @@ lex (pfile, skip_evaluation, token)
 	return op;
       }
 
-    case CPP_NOT:
-      /* We don't worry about its position here.  */
-      pfile->mi_if_not_defined = MI_IND_NOT;
-      /* Fall through.  */
-
     default:
       if (((int) token->type > (int) CPP_EQ
 	   && (int) token->type < (int) CPP_PLUS_EQ)
@@ -598,10 +582,12 @@ _cpp_parse_expr (pfile)
   register struct op *top = stack + 1;
   int skip_evaluation = 0;
   int result;
+  unsigned int lex_count, saw_leading_not;
 
   /* Set up detection of #if ! defined().  */
-  pfile->mi_lexed = 0;
-  pfile->mi_if_not_defined = MI_IND_NONE;
+  pfile->mi_ind_cmacro = 0;
+  saw_leading_not = 0;
+  lex_count = 0;
 
   /* We've finished when we try to reduce this.  */
   top->op = CPP_EOF;
@@ -618,7 +604,7 @@ _cpp_parse_expr (pfile)
 
       /* Read a token */
       op = lex (pfile, skip_evaluation, &token);
-      pfile->mi_lexed++;
+      lex_count++;
 
       /* If the token is an operand, push its value and get next
 	 token.  If it is an operator, get its priority and flags, and
@@ -638,6 +624,11 @@ _cpp_parse_expr (pfile)
 	  continue;
 
 	case CPP_EOF:	prio = FORCE_REDUCE_PRIO;	break;
+
+	case CPP_NOT:
+	  saw_leading_not = lex_count == 1;
+	  prio = op_to_prio[op.op];
+	  break;
 	case CPP_PLUS:
 	case CPP_MINUS: prio = PLUS_PRIO;  if (top->flags & HAVE_VALUE) break;
           /* else unary; fall through */
@@ -869,7 +860,14 @@ _cpp_parse_expr (pfile)
     }
 
  done:
+  /* The controlling macro expression is only valid if we called lex 3
+     times: <!> <defined expression> and <EOF>.  push_conditional ()
+     checks that we are at top-of-file.  */
+  if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
+    pfile->mi_ind_cmacro = 0;
+
   result = (top[1].value != 0);
+
   if (top != stack)
     CPP_ICE ("unbalanced stack in #if");
   else if (!(top[1].flags & HAVE_VALUE))
============================================================
Index: gcc/cppfiles.c
--- gcc/cppfiles.c	2001/05/22 11:57:21	1.118
+++ gcc/cppfiles.c	2001/07/29 12:39:22
@@ -332,7 +332,7 @@ stack_include_file (pfile, inc)
   fp->sysp = sysp;
 
   /* Initialise controlling macro state.  */
-  pfile->mi_state = MI_OUTSIDE;
+  pfile->mi_valid = true;
   pfile->mi_cmacro = 0;
   pfile->include_depth++;
 
@@ -748,12 +748,12 @@ _cpp_pop_file_buffer (pfile, buf)
     pfile->include_depth--;
 
   /* Record the inclusion-preventing macro, which could be NULL
-     meaning no controlling macro, if we haven't got it already.  */
-  if (pfile->mi_state == MI_OUTSIDE && inc->cmacro == NULL)
+     meaning no controlling macro.  */
+  if (pfile->mi_valid)
     inc->cmacro = pfile->mi_cmacro;
 
   /* Invalidate control macros in the #including file.  */
-  pfile->mi_state = MI_FAILED;
+  pfile->mi_valid = false;
 
   inc->refcnt--;
   if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
============================================================
Index: gcc/cpphash.h
--- gcc/cpphash.h	2001/07/26 06:02:47	1.106
+++ gcc/cpphash.h	2001/07/29 12:39:22
@@ -93,10 +93,6 @@ struct search_path
   struct file_name_map *name_map;
 };
 
-/* Multiple-include optimisation.  */
-enum mi_state {MI_FAILED = 0, MI_OUTSIDE};
-enum mi_ind {MI_IND_NONE = 0, MI_IND_NOT};
-
 /* #include types.  */
 enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
 
@@ -268,11 +264,9 @@ struct cpp_reader
   const struct directive *directive;
 
   /* Multiple inlcude optimisation.  */
-  enum mi_state mi_state;
-  enum mi_ind mi_if_not_defined;
-  unsigned int mi_lexed;
   const cpp_hashnode *mi_cmacro;
   const cpp_hashnode *mi_ind_cmacro;
+  bool mi_valid;
 
   /* Token lookahead.  */
   struct cpp_lookahead *la_read;	/* Read from this lookahead.  */
============================================================
Index: gcc/cpplex.c
--- gcc/cpplex.c	2001/07/26 06:02:47	1.146
+++ gcc/cpplex.c	2001/07/29 12:39:28
@@ -1266,7 +1266,7 @@ _cpp_lex_token (pfile, result)
 
   /* If not in a directive, this token invalidates controlling macros.  */
   if (!pfile->state.in_directive)
-    pfile->mi_state = MI_FAILED;
+    pfile->mi_valid = false;
 }
 
 /* An upper bound on the number of bytes needed to spell a token,
============================================================
Index: gcc/cpplib.c
--- gcc/cpplib.c	2001/07/26 06:02:47	1.255
+++ gcc/cpplib.c	2001/07/29 12:39:31
@@ -358,7 +358,7 @@ _cpp_handle_directive (pfile, indented)
 	      /* If we have a directive that is not an opening
 		 conditional, invalidate any control macro.  */
 	      if (! (dir->flags & IF_COND))
-		pfile->mi_state = MI_FAILED;
+		pfile->mi_valid = false;
 
 	      (*dir->handler) (pfile);
 	    }
@@ -1278,27 +1278,22 @@ do_ifndef (pfile)
   push_conditional (pfile, skip, T_IFNDEF, node);
 }
 
-/* #if cooperates with parse_defined to handle multiple-include
-   optimisations.  If macro expansions or identifiers appear in the
-   expression, we cannot treat it as a controlling conditional, since
-   their values could change in the future.  */
+/* _cpp_parse_expr puts a macro in a "#if !defined ()" expression in
+   pfile->mi_ind_cmacro so we can handle multiple-include
+   optimisations.  If macro expansion occurs in the expression, we
+   cannot treat it as a controlling conditional, since the expansion
+   could change in the future.  That is handled by cpp_get_token.  */
 
 static void
 do_if (pfile)
      cpp_reader *pfile;
 {
   int skip = 1;
-  const cpp_hashnode *cmacro = 0;
 
   if (! pfile->state.skipping)
-    {
-      /* Controlling macro of #if ! defined ()  */
-      pfile->mi_ind_cmacro = 0;
-      skip = _cpp_parse_expr (pfile) == 0;
-      cmacro = pfile->mi_ind_cmacro;
-    }
+    skip = _cpp_parse_expr (pfile) == 0;
 
-  push_conditional (pfile, skip, T_IF, cmacro);
+  push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro);
 }
 
 /* Flip skipping state if appropriate and continue without changing
@@ -1395,7 +1390,7 @@ do_endif (pfile)
       /* If potential control macro, we go back outside again.  */
       if (ifs->next == 0 && ifs->mi_cmacro)
 	{
-	  pfile->mi_state = MI_OUTSIDE;
+	  pfile->mi_valid = true;
 	  pfile->mi_cmacro = ifs->mi_cmacro;
 	}
 
@@ -1406,8 +1401,8 @@ do_endif (pfile)
 }
 
 /* Push an if_stack entry and set pfile->state.skipping accordingly.
-   If this is a #ifndef starting at the beginning of a file,
-   CMACRO is the macro name tested by the #ifndef.  */
+   If this is a #if or #ifndef, CMACRO is a potentially controlling
+   macro - we need to check here that we are at the top of the file.  */
 
 static void
 push_conditional (pfile, skip, type, cmacro)
@@ -1425,7 +1420,8 @@ push_conditional (pfile, skip, type, cma
   ifs->skip_elses = pfile->state.skipping || !skip;
   ifs->was_skipping = pfile->state.skipping;
   ifs->type = type;
-  if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0)
+  /* This condition is effectively a test for top-of-file.  */
+  if (pfile->mi_valid && pfile->mi_cmacro == 0)
     ifs->mi_cmacro = cmacro;
   else
     ifs->mi_cmacro = 0;
============================================================
Index: gcc/cppmacro.c
--- gcc/cppmacro.c	2001/06/23 11:34:41	1.54
+++ gcc/cppmacro.c	2001/07/29 12:39:43
@@ -953,7 +953,7 @@ cpp_get_token (pfile, token)
 	  cpp_hashnode *node = token->val.node;
 
 	  /* Macros invalidate controlling macros.  */
-	  pfile->mi_state = MI_FAILED;
+	  pfile->mi_valid = false;
 
 	  if (node->flags & NODE_BUILTIN)
 	    {
============================================================
Index: gcc/doc/cpp.texi
--- gcc/doc/cpp.texi	2001/07/04 20:06:27	1.11
+++ gcc/doc/cpp.texi	2001/07/29 12:39:51
@@ -536,15 +536,18 @@ be removed in GCC 3.1.  You may use cont
 constant concatenation.  @xref{Differences from previous versions}.
 
 @cindex punctuators
+@cindex digraphs
+@cindex alternative tokens
 @dfn{Punctuators} are all the usual bits of punctuation which are
 meaningful to C and C++.  All but three of the punctuation characters in
 ASCII are C punctuators.  The exceptions are @samp{@@}, @samp{$}, and
 @samp{`}.  In addition, all the two- and three-character operators are
-punctuators.  There are also six @dfn{digraphs}, which are merely
-alternate ways to spell other punctuators.  This is a second attempt to
-work around missing punctuation in obsolete systems.  It has no negative
-side effects, unlike trigraphs, but does not cover as much ground.  The
-digraphs and their corresponding normal punctuators are:
+punctuators.  There are also six @dfn{digraphs}, which the C++ standard
+calls @dfn{alternative tokens}, which are merely alternate ways to spell
+other punctuators.  This is a second attempt to work around missing
+punctuation in obsolete systems.  It has no negative side effects,
+unlike trigraphs, but does not cover as much ground.  The digraphs and
+their corresponding normal punctuators are:
 
 @example
 Digraph:        <%  %>  <:  :>  %:  %:%:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]