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]

Conditionals revised


Neil came up with this idea in the context of the new lexer, and I've
applied it to the old one in the interest of shrinking the diff we're
batting around.

Instead of having a separate scanner to skip over failed conditionals,
we use the normal one and throw away the tokens.  The separate scanner
isn't any faster, and it tended to have obscure bugs.  The main
benefit is of course code simplification.  Roughly 200 lines are
deleted.  (This is not immediately obvious because I took the
opportunity to rearrange all the conditional handlers.)

We also save the hash node instead of the string of a control macro,
which avoids looking it up over and over again.

Finally, I got tired of piecemeal updating error messages, so I've
done all of the ones in cpplib.c - the new convention is to not put
`scare quotes' around the names of directives.

Bootstrapped i686-linux.

zw

	* cpplib.h (cpp_reader): Remove if_stack.  Change
	potential_control_macro to a cpp_hashnode *.  Add skipping flag.
	* cpphash.h (struct ihash): Change control_macro to a
	cpp_hashnode * and shorten name to cmacro.
	Add NEVER_REINCLUDE constant.

	* cppfiles.c (redundant_include_p): Drop cpp_reader argument.
	Examine the cmacro node directly, no need to call cpp_defined.
	(_cpp_execute_include, read_include_file): Set cmacro to
	NEVER_REINCLUDE, not U"".
	* cpplex.c (cpp_push_buffer): Don't set new->if_stack.
	(cpp_get_token): If pfile->skipping is true, discard text and
	keep scanning until we hit a directive; don't expand macros.

	* cpplib.c (struct if_stack): Remove if_succeeded, add
	was_skipping. Change control_macro to a cpp_hashnode * and
	shorten name to cmacro.  Remove typedef IF_STACK.
	(parse_ifdef), detect_if_not_defined): Return a cpp_hashnode *.
	(conditional_skip, skip_if_group,
	consider_directive_while_skipping): Delete.
	(push_conditional): New.
	(_cpp_handle_directive): Don't process directives other than
	conditionals if we are skipping.

	(do_ifdef, do_ifndef, do_if, do_else, do_elif, do_endif):
	Update to new scheme.
	(validate_else): Skip rest of line here, unconditionally.
	(_cpp_unwind_if_stack): The stack is per-buffer.  Force
	pfile->skipping off.

	(all): Remove `scare quotes' from error messages.

===================================================================
Index: cpplib.h
--- cpplib.h	2000/05/28 05:56:38	1.98
+++ cpplib.h	2000/05/29 15:41:46
@@ -509,8 +509,7 @@ struct cpp_reader
      for include files.  (Altered as we get more of them.)  */
   unsigned int max_include_len;
 
-  struct if_stack *if_stack;
-  const unsigned char *potential_control_macro;
+  const cpp_hashnode *potential_control_macro;
 
   /* Token column position adjustment owing to tabs in whitespace.  */
   unsigned int col_adjust;
@@ -555,6 +554,9 @@ struct cpp_reader
   /* True after cpp_start_read completes.  Used to inhibit some
      warnings while parsing the command line.  */
   unsigned char done_initializing;
+
+  /* True if we are skipping a failed conditional group.  */
+  unsigned char skipping;
 };
 
 /* struct cpp_printer encapsulates state used to convert the stream of
===================================================================
Index: cpphash.h
--- cpphash.h	2000/05/28 05:56:38	1.52
+++ cpphash.h	2000/05/29 15:41:45
@@ -69,10 +69,11 @@ struct ihash
   unsigned int hash;		/* save hash value for future reference */
   const char *nshort;		/* name of file as referenced in #include;
 				   points into name[]  */
-  const U_CHAR *control_macro;	/* macro, if any, preventing reinclusion.  */
+  const cpp_hashnode *cmacro;	/* macro, if any, preventing reinclusion.  */
   const char name[1];		/* (partial) pathname of file */
 };
 typedef struct ihash IHASH;
+#define NEVER_REINCLUDE ((const cpp_hashnode *)-1)
 
 /* Character classes.
    If the definition of `numchar' looks odd to you, please look up the
===================================================================
Index: cppfiles.c
--- cppfiles.c	2000/05/28 05:56:37	1.62
+++ cppfiles.c	2000/05/29 15:41:45
@@ -39,8 +39,7 @@ Foundation, 59 Temple Place - Suite 330,
 #  define MMAP_THRESHOLD 0
 #endif
 
-static IHASH *redundant_include_p PARAMS ((cpp_reader *, IHASH *,
-					   struct file_name_list *));
+static IHASH *redundant_include_p PARAMS ((IHASH *, struct file_name_list *));
 static IHASH *make_IHASH	PARAMS ((const char *, const char *,
 					 struct file_name_list *,
 					 unsigned int, IHASH **));
@@ -124,8 +123,7 @@ _cpp_init_include_hash (pfile)
    the directories are in fact the same.  */
 
 static IHASH *
-redundant_include_p (pfile, ihash, ilist)
-     cpp_reader *pfile;
+redundant_include_p (ihash, ilist)
      IHASH *ihash;
      struct file_name_list *ilist;
 {
@@ -138,14 +136,14 @@ redundant_include_p (pfile, ihash, ilist
   for (i = ihash; i; i = i->next_this_file)
     for (l = ilist; l; l = l->next)
        if (i->foundhere == l)
-	 /* The control_macro works like this: If it's NULL, the file
-	    is to be included again.  If it's "", the file is never to
-	    be included again.  If it's a string, the file is not to be
-	    included again if the string is the name of a defined macro. */
-	 return (i->control_macro
-		 && (i->control_macro[0] == '\0'
-		     || cpp_defined (pfile, i->control_macro, 
-				     ustrlen (i->control_macro))))
+	 /* The cmacro works like this: If it's NULL, the file is to
+	    be included again.  If it's NEVER_REINCLUDE, the file is
+	    never to be included again.  Otherwise it is a macro
+	    hashnode, and the file is to be included again if the
+	    macro is not defined.  */
+	 return (i->cmacro
+		 && (i->cmacro == NEVER_REINCLUDE
+		     || i->cmacro->type != T_VOID))
 	     ? (IHASH *)-1 : i;
 
   return 0;
@@ -199,7 +197,7 @@ make_IHASH (name, fname, path, hash, slo
     }
   strcpy ((char *)ih->name, name);
   ih->foundhere = path;
-  ih->control_macro = NULL;
+  ih->cmacro = NULL;
   ih->hash = hash;
   ih->next_this_file = *slot;
   *slot = ih;
@@ -256,7 +254,7 @@ find_include_file (pfile, fname, search_
 					      (const void *) &dummy,
 					      dummy.hash, INSERT);
 
-  if (*slot && (ih = redundant_include_p (pfile, *slot, path)))
+  if (*slot && (ih = redundant_include_p (*slot, path)))
     {
       if (ih == (IHASH *)-1)
 	return -2;
@@ -629,7 +627,7 @@ _cpp_execute_include (pfile, f, len, no_
 
   /* Actually process the file.  */
   if (no_reinclude)
-    ihash->control_macro = U"";
+    ihash->cmacro = NEVER_REINCLUDE;
   
   if (read_include_file (pfile, fd, ihash))
     {
@@ -662,7 +660,7 @@ cpp_read_file (pfile, fname)
   slot = (IHASH **) htab_find_slot_with_hash (pfile->all_include_files,
 					      (const void *) &dummy,
 					      dummy.hash, INSERT);
-  if (*slot && (ih = redundant_include_p (pfile, *slot, ABSOLUTE_PATH)))
+  if (*slot && (ih = redundant_include_p (*slot, ABSOLUTE_PATH)))
     {
       if (ih == (IHASH *) -1)
 	return 1;  /* Already included.  */
@@ -759,7 +757,7 @@ read_include_file (pfile, fd, ihash)
   fp->nominal_fname = ihash->name;
   
   if (length == 0)
-    ihash->control_macro = U"";  /* never re-include */
+    ihash->cmacro = NEVER_REINCLUDE;
   else
     /* Temporary - I hope.  */
     length = _cpp_prescan (pfile, fp, length);
===================================================================
Index: cpplex.c
--- cpplex.c	2000/05/28 05:56:38	1.51
+++ cpplex.c	2000/05/29 15:41:46
@@ -193,7 +193,6 @@ cpp_push_buffer (pfile, buffer, length)
 
   new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
 
-  new->if_stack = pfile->if_stack;
   new->buf = new->cur = buffer;
   new->rlimit = buffer + length;
   new->prev = buf;
@@ -221,7 +220,7 @@ cpp_pop_buffer (pfile)
 	pfile->system_include_depth--;
       if (pfile->potential_control_macro)
 	{
-	  buf->ihash->control_macro = pfile->potential_control_macro;
+	  buf->ihash->cmacro = pfile->potential_control_macro;
 	  pfile->potential_control_macro = 0;
 	}
       pfile->input_stack_listing_current = 0;
@@ -1743,6 +1742,7 @@ cpp_get_token (pfile)
 {
   enum cpp_ttype token;
   long written = CPP_WRITTEN (pfile);
+  int macro_buffer;
 
  get_next:
   token = _cpp_lex_token (pfile);
@@ -1750,24 +1750,26 @@ cpp_get_token (pfile)
   switch (token)
     {
     default:
+      if (pfile->skipping)
+	break;
       pfile->potential_control_macro = 0;
       pfile->only_seen_white = 0;
-      return token;
+      break;
 
+    case CPP_HSPACE:
+    case CPP_COMMENT:
+      break;
+
     case CPP_VSPACE:
       if (pfile->only_seen_white == 0)
 	pfile->only_seen_white = 1;
       CPP_BUMP_LINE (pfile);
-      return token;
+      break;
 
-    case CPP_HSPACE:
-    case CPP_COMMENT:
-      return token;
-
     case CPP_HASH:
       pfile->potential_control_macro = 0;
       if (!pfile->only_seen_white)
-	return CPP_HASH;
+	break;
       /* XXX shouldn't have to do this - remove the hash or %: from
 	 the token buffer.  */
       if (CPP_PWRITTEN (pfile)[-1] == '#')
@@ -1776,30 +1778,43 @@ cpp_get_token (pfile)
 	CPP_ADJUST_WRITTEN (pfile, -2);
 
       if (_cpp_handle_directive (pfile))
-	return CPP_DIRECTIVE; 
+	{
+	  token = CPP_DIRECTIVE;
+	  break;
+	}
       pfile->only_seen_white = 0;
       CPP_PUTC (pfile, '#');
-      return CPP_HASH;
+      break;
 
     case CPP_MACRO:
+      if (pfile->skipping)
+	break;
       pfile->potential_control_macro = 0;
       pfile->only_seen_white = 0;
       if (! pfile->no_macro_expand
 	  && maybe_macroexpand (pfile, written))
 	goto get_next;
-      return CPP_NAME;
+      token = CPP_NAME;
+      break;
 
+      /* Do not run this case through the 'skipping' logic.  */
     case CPP_EOF:
       if (CPP_BUFFER (pfile) == NULL)
 	return CPP_EOF;
-      if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
-	{
-	  cpp_pop_buffer (pfile);
-	  goto get_next;
-	}
+      macro_buffer = CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile));
+
       cpp_pop_buffer (pfile);
+      if (macro_buffer)
+	goto get_next;
       return CPP_EOF;
     }
+  
+  if (pfile->skipping)
+    {
+      CPP_SET_WRITTEN (pfile, written);
+      goto get_next;
+    }
+  return token;
 }
 
 /* Like cpp_get_token, but skip spaces and comments.  */
===================================================================
Index: cpplib.c
--- cpplib.c	2000/05/28 05:56:38	1.170
+++ cpplib.c	2000/05/29 15:41:46
@@ -44,26 +44,22 @@ struct if_stack
 {
   struct if_stack *next;
   int lineno;			/* line number where condition started */
-  int if_succeeded;		/* truth of last condition in this group */
-  const U_CHAR *control_macro;	/* macro name for #ifndef around entire file */
+  int was_skipping;		/* value of pfile->skipping before this if */
+  const cpp_hashnode *cmacro;	/* macro name for #ifndef around entire file */
   int type;			/* type of last directive seen in this group */
 };
-typedef struct if_stack IF_STACK;
 
 /* Forward declarations.  */
 
 static void validate_else		PARAMS ((cpp_reader *, const U_CHAR *));
-static int parse_ifdef			PARAMS ((cpp_reader *, const U_CHAR *));
 static unsigned int parse_include	PARAMS ((cpp_reader *, const U_CHAR *));
-static int conditional_skip		PARAMS ((cpp_reader *, int, int,
-						 U_CHAR *));
-static int skip_if_group		PARAMS ((cpp_reader *));
+static void push_conditional		PARAMS ((cpp_reader *, int, int,
+						 const cpp_hashnode *));
 static void pass_thru_directive		PARAMS ((const U_CHAR *, size_t,
 						 cpp_reader *, int));
 static int read_line_number		PARAMS ((cpp_reader *, int *));
-static U_CHAR *detect_if_not_defined	PARAMS ((cpp_reader *));
-static int consider_directive_while_skipping
-					PARAMS ((cpp_reader *, IF_STACK *));
+static const cpp_hashnode *parse_ifdef	PARAMS ((cpp_reader *, const U_CHAR *));
+static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *));
 
 /* Values for the flags field of the table below.  KANDR and COND
    directives come from traditional (K&R) C.  The difference is, if we
@@ -208,12 +204,13 @@ _cpp_handle_directive (pfile)
   CPP_GOTO_MARK (pfile);
 
   /* # followed by a number is equivalent to #line.  Do not recognize
-     this form in assembly language source files.  Complain about this
-     form if we're being pedantic, but not if this is regurgitated
-     input (preprocessed or fed back in by the C++ frontend).  */
+     this form in assembly language source files or skipped
+     conditional groups.  Complain about this form if we're being
+     pedantic, but not if this is regurgitated input (preprocessed or
+     fed back in by the C++ frontend).  */
   if (tok == CPP_NUMBER)
     {
-      if (CPP_OPTION (pfile, lang_asm))
+      if (pfile->skipping || CPP_OPTION (pfile, lang_asm))
 	return 0;
 
       if (CPP_PEDANTIC (pfile)
@@ -244,8 +241,9 @@ _cpp_handle_directive (pfile)
 	}
       /* Don't complain about invalid directives in assembly source,
 	 we don't know where the comments are, and # may introduce
-	 assembler pseudo-ops.  */
-      if (!CPP_OPTION (pfile, lang_asm))
+	 assembler pseudo-ops.  Don't complain about invalid directives
+	 in skipped conditional groups (6.10 p4). */
+      if (!pfile->skipping && !CPP_OPTION (pfile, lang_asm))
 	cpp_error (pfile, "invalid preprocessing directive #%s", ident);
       return 0;
     }
@@ -255,6 +253,11 @@ _cpp_handle_directive (pfile)
 
  real_directive:
 
+  /* If we are skipping a failed conditional group, all non-conditional
+     directives are ignored.  */
+  if (pfile->skipping && ORIGIN (dtable[i].flags) != COND)
+    return 0;
+
   /* In -traditional mode, a directive is ignored unless its # is in
      column 1.  */
   if (CPP_TRADITIONAL (pfile) && !hash_at_bol)
@@ -302,11 +305,7 @@ _cpp_handle_directive (pfile)
   CPP_SET_WRITTEN (pfile, old_written);
 
  process_directive:
-  /* Some directives (e.g. #if) may return a request to execute
-     another directive handler immediately.  No directive ever
-     requests that #define be executed immediately, so it is safe for
-     the loop to terminate when some function returns 0 (== T_DEFINE).  */
-  while ((i = dtable[i].func (pfile)));
+  (void) (*dtable[i].func) (pfile);
   return 1;
 }
 
@@ -434,7 +433,7 @@ parse_include (pfile, name)
 #endif
   else
     {
-      cpp_error (pfile, "`#%s' expects \"FILENAME\" or <FILENAME>", name);
+      cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", name);
       CPP_SET_WRITTEN (pfile, old_written);
       _cpp_skip_rest_of_line (pfile);
       return 0;
@@ -442,14 +441,14 @@ parse_include (pfile, name)
 
   if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
     {
-      cpp_error (pfile, "junk at end of `#%s'", name);
+      cpp_error (pfile, "junk at end of #%s", name);
       _cpp_skip_rest_of_line (pfile);
     }
 
   CPP_SET_WRITTEN (pfile, old_written);
 
   if (len == 0)
-    cpp_error (pfile, "empty file name in `#%s'", name);
+    cpp_error (pfile, "empty file name in #%s", name);
 
   return len;
 }
@@ -563,7 +562,7 @@ read_line_number (pfile, num)
   else
     {
       if (token != CPP_VSPACE && token != CPP_EOF)
-	cpp_error (pfile, "invalid format `#line' command");
+	cpp_error (pfile, "invalid format #line");
       CPP_SET_WRITTEN (pfile, save_written);
       return 0;
     }
@@ -587,7 +586,7 @@ do_line (pfile)
 
   if (token != CPP_NUMBER)
     {
-      cpp_error (pfile, "token after `#line' is not an integer");
+      cpp_error (pfile, "token after #line is not an integer");
       goto bad_line_directive;
     }
 
@@ -596,13 +595,13 @@ do_line (pfile)
 			&x, 10);
   if (x[0] != '\0')
     {
-      cpp_error (pfile, "token after `#line' is not an integer");
+      cpp_error (pfile, "token after #line is not an integer");
       goto bad_line_directive;
     }      
   CPP_SET_WRITTEN (pfile, old_written);
 
   if (CPP_PEDANTIC (pfile) && (new_lineno <= 0 || new_lineno > 32767))
-    cpp_pedwarn (pfile, "line number out of range in `#line' command");
+    cpp_pedwarn (pfile, "line number out of range in #line");
 
   token = _cpp_get_directive_token (pfile);
 
@@ -615,7 +614,7 @@ do_line (pfile)
       if (read_line_number (pfile, &action_number))
 	{
 	  if (CPP_PEDANTIC (pfile))
-	    cpp_pedwarn (pfile, "garbage at end of `#line' command");
+	    cpp_pedwarn (pfile, "garbage at end of #line");
 
 	  /* This is somewhat questionable: change the buffer stack
 	     depth so that output_line_command thinks we've stacked
@@ -656,7 +655,7 @@ do_line (pfile)
     }
   else if (token != CPP_VSPACE && token != CPP_EOF)
     {
-      cpp_error (pfile, "token after `#line %d' is not a string", new_lineno);
+      cpp_error (pfile, "second token after #line is not a string");
       goto bad_line_directive;
     }
 
@@ -889,12 +888,12 @@ do_pragma_once (pfile)
   /* Allow #pragma once in system headers, since that's not the user's
      fault.  */
   if (!ip->system_header_p)
-    cpp_warning (pfile, "`#pragma once' is obsolete");
+    cpp_warning (pfile, "#pragma once is obsolete");
       
   if (CPP_PREV_BUFFER (ip) == NULL)
-    cpp_warning (pfile, "`#pragma once' outside include file");
+    cpp_warning (pfile, "#pragma once outside include file");
   else
-    ip->ihash->control_macro = U"";  /* never repeat */
+    ip->ihash->cmacro = NEVER_REINCLUDE;
 
   return 1;
 }
@@ -929,7 +928,7 @@ do_pragma_implementation (pfile)
   
   if (cpp_included (pfile, copy))
     cpp_warning (pfile,
-	 "`#pragma implementation' for `%s' appears after file is included",
+	 "#pragma implementation for %s appears after file is included",
 		 copy);
   return 0;
 }
@@ -1018,21 +1017,21 @@ do_sccs (pfile)
    this file is white space, and if it is of the form
    `#if ! defined SYMBOL', then SYMBOL is a possible controlling macro
    for inclusion of this file.  (See redundant_include_p in cppfiles.c
-   for an explanation of controlling macros.)  If so, return a
-   malloced copy of SYMBOL.  Otherwise, return NULL.  */
+   for an explanation of controlling macros.)  If so, return the
+   hash node for SYMBOL.  Otherwise, return NULL.  */
 
-static U_CHAR *
+static const cpp_hashnode *
 detect_if_not_defined (pfile)
      cpp_reader *pfile;
 {
-  U_CHAR *control_macro = 0;
+  const cpp_hashnode *cmacro = 0;
   enum cpp_ttype token;
   unsigned int base_offset;
   unsigned int token_offset;
   unsigned int need_rparen = 0;
   unsigned int token_len;
 
-  if (pfile->only_seen_white != 2)
+  if (pfile->skipping || pfile->only_seen_white != 2)
     return NULL;
 
   /* Save state required for restore.  */
@@ -1077,82 +1076,21 @@ detect_if_not_defined (pfile)
     goto restore;
 
   /* We have a legitimate controlling macro for this header.  */
-  control_macro = (U_CHAR *) xmalloc (token_len + 1);
-  memcpy (control_macro, pfile->token_buffer + token_offset, token_len);
-  control_macro[token_len] = '\0';
+  cmacro = cpp_lookup (pfile, pfile->token_buffer + token_offset, token_len);
 
  restore:
   CPP_SET_WRITTEN (pfile, base_offset);
   pfile->no_macro_expand--;
   CPP_GOTO_MARK (pfile);
 
-  return control_macro;
+  return cmacro;
 }
 
-/*
- * #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
- * Also, check for a reinclude preventer of the form #if !defined (MACRO).
- */
-
-static int
-do_if (pfile)
-     cpp_reader *pfile;
-{
-  U_CHAR *control_macro;
-  int value;
-  int save_only_seen_white = pfile->only_seen_white;
-
-  control_macro = detect_if_not_defined (pfile);  
-
-  pfile->only_seen_white = 0;
-  value = _cpp_parse_expr (pfile);
-  pfile->only_seen_white = save_only_seen_white;
-
-  return conditional_skip (pfile, value == 0, T_IF, control_macro);
-}
-
-/*
- * handle a #elif directive by not changing  if_stack  either.
- * see the comment above do_else.
- */
-
-static int
-do_elif (pfile)
-     cpp_reader *pfile;
-{
-  if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
-    {
-      cpp_error (pfile, "`#elif' not within a conditional");
-      return 0;
-    }
-  else
-    {
-      if (pfile->if_stack->type == T_ELSE)
-	{
-	  cpp_error (pfile, "`#elif' after `#else'");
-	  cpp_error_with_line (pfile, pfile->if_stack->lineno, 0,
-			       "the conditional began here");
-	}
-      pfile->if_stack->type = T_ELIF;
-    }
-
-  if (pfile->if_stack->if_succeeded)
-    {
-      _cpp_skip_rest_of_line (pfile);
-      return skip_if_group (pfile);
-    }
-  if (_cpp_parse_expr (pfile) == 0)
-    return skip_if_group (pfile);
-
-  ++pfile->if_stack->if_succeeded;	/* continue processing input */
-  return 0;
-}
-
 /* Parse an #ifdef or #ifndef directive.  Returns 1 for defined, 0 for
    not defined; the macro tested is left in the token buffer (but
    popped).  */
 
-static int
+static const cpp_hashnode *
 parse_ifdef (pfile, name)
      cpp_reader *pfile;
      const U_CHAR *name;
@@ -1161,7 +1099,7 @@ parse_ifdef (pfile, name)
   unsigned int len;
   enum cpp_ttype token;
   long old_written = CPP_WRITTEN (pfile);
-  int defined;
+  const cpp_hashnode *node = 0;
 
   pfile->no_macro_expand++;
   token = _cpp_get_directive_token (pfile);
@@ -1173,20 +1111,17 @@ parse_ifdef (pfile, name)
   if (token == CPP_VSPACE)
     {
       if (! CPP_TRADITIONAL (pfile))
-	cpp_pedwarn (pfile, "`#%s' with no argument", name);
-      defined = 0;
+	cpp_pedwarn (pfile, "#%s with no argument", name);
       goto done;
     }
   else if (token == CPP_NAME)
     {
-      defined = cpp_defined (pfile, ident, len);
-      CPP_PUTC (pfile, '\0');  /* so it can be copied with xstrdup */
+      node = cpp_lookup (pfile, ident, len);
     }
   else
     {
-      defined = 0;
       if (! CPP_TRADITIONAL (pfile))
-	cpp_error (pfile, "`#%s' with invalid argument", name);
+	cpp_error (pfile, "#%s with invalid argument", name);
     }
 
   if (!CPP_TRADITIONAL (pfile))
@@ -1194,13 +1129,13 @@ parse_ifdef (pfile, name)
       if (_cpp_get_directive_token (pfile) == CPP_VSPACE)
 	goto done;
       
-      cpp_pedwarn (pfile, "garbage at end of `#%s' argument", name);
+      cpp_pedwarn (pfile, "garbage at end of #%s", name);
     }
   _cpp_skip_rest_of_line (pfile);
   
  done:
   CPP_SET_WRITTEN (pfile, old_written); /* Pop */
-  return defined;
+  return node;
 }
 
 /* #ifdef is dead simple.  */
@@ -1209,8 +1144,14 @@ static int
 do_ifdef (pfile)
      cpp_reader *pfile;
 {
-  int skip = ! parse_ifdef (pfile, dtable[T_IFDEF].name);
-  return conditional_skip (pfile, skip, T_IFDEF, 0);
+  int def = 0;
+  const cpp_hashnode *node = parse_ifdef (pfile, dtable[T_IFDEF].name);
+  if (node->type == T_POISON)
+    cpp_error (pfile, "attempt to use poisoned `%s'", node->name);
+  else
+    def = (node->type != T_VOID);
+  push_conditional (pfile, !def, T_IFDEF, 0);
+  return 0;
 }
 
 /* #ifndef is a tad more complex, because we need to check for a
@@ -1220,283 +1161,191 @@ static int
 do_ifndef (pfile)
      cpp_reader *pfile;
 {
-  int start_of_file, skip;
-  U_CHAR *control_macro = 0;
+  int start_of_file;
+  int def = 0;
+  const cpp_hashnode *cmacro;
 
   start_of_file = pfile->only_seen_white == 2;
-  skip = parse_ifdef (pfile, dtable[T_IFNDEF].name);
-
-  if (start_of_file && !skip)
-    control_macro = uxstrdup (CPP_PWRITTEN (pfile));
+  cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
+  if (cmacro->type == T_POISON)
+    cpp_error (pfile, "attempt to use poisoned `%s'", cmacro->name);
+  else
+    def = (cmacro->type != T_VOID);
 
-  return conditional_skip (pfile, skip, T_IFNDEF, control_macro);
+  push_conditional (pfile, def, T_IFNDEF,
+		    start_of_file ? cmacro : 0);
+  return 0;
 }
 
-/* Push TYPE on stack; then, if SKIP is nonzero, skip ahead.
-   If this is a #ifndef starting at the beginning of a file,
-   CONTROL_MACRO is the macro name tested by the #ifndef.
-   Otherwise, CONTROL_MACRO is 0.  */
+/* #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
+   Also, check for a reinclude preventer of the form #if !defined (MACRO).  */
 
 static int
-conditional_skip (pfile, skip, type, control_macro)
+do_if (pfile)
      cpp_reader *pfile;
-     int skip;
-     int type;
-     U_CHAR *control_macro;
 {
-  IF_STACK *temp;
-
-  temp = (IF_STACK *) xcalloc (1, sizeof (IF_STACK));
-  temp->lineno = CPP_BUFFER (pfile)->lineno;
-  temp->next = pfile->if_stack;
-  temp->control_macro = control_macro;
-  pfile->if_stack = temp;
-
-  pfile->if_stack->type = type;
+  const cpp_hashnode *cmacro = 0;
+  int value = 0;
+  int save_only_seen_white = pfile->only_seen_white;
 
-  if (skip != 0)
-    return skip_if_group (pfile);
+  if (! pfile->skipping)
+    {
+      cmacro = detect_if_not_defined (pfile);  
 
-  ++pfile->if_stack->if_succeeded;
+      pfile->only_seen_white = 0;
+      value = _cpp_parse_expr (pfile);
+      pfile->only_seen_white = save_only_seen_white;
+    }
+  push_conditional (pfile, value == 0, T_IF, cmacro);
   return 0;
 }
 
-/* Subroutine of skip_if_group.  Examine one preprocessing directive
-   and return 0 if skipping should continue, or the directive number
-   of the directive that ends the block if it should halt.
+/* #else flips pfile->skipping and continues without changing
+   if_stack; this is so that the error message for missing #endif's
+   etc. will point to the original #if.  */
 
-   Also adjusts the if_stack as appropriate.  The `#' has been read,
-   but not the identifier. */
-
 static int
-consider_directive_while_skipping (pfile, stack)
-    cpp_reader *pfile;
-    IF_STACK *stack; 
+do_else (pfile)
+     cpp_reader *pfile;
 {
-  long ident;
-  int i, hash_at_bol;
-  unsigned int len;
-  IF_STACK *temp;
-
-  /* -traditional directives are recognized only with the # in column 1.  */
-  hash_at_bol = CPP_IN_COLUMN_1 (pfile);
-
-  ident = CPP_WRITTEN (pfile);
-  if (_cpp_get_directive_token (pfile) != CPP_NAME)
-    return 0;
-  len = CPP_WRITTEN (pfile) - ident;
-
-  for (i = 0; i < N_DIRECTIVES; i++)
-    {
-      if (dtable[i].length == len
-	  && !ustrncmp (dtable[i].name, pfile->token_buffer + ident, len)) 
-	goto real_directive;
-    }
-  return 0;
-
- real_directive:
-
-  /* If it's not a directive of interest to us, return now.  */
-  if (ORIGIN (dtable[i].flags) != COND)
-    return 0;
+  struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
 
-  /* First, deal with -traditional and -Wtraditional.
-     All COND directives are from K+R.  */
+  validate_else (pfile, dtable[T_ELSE].name);
 
-  if (! hash_at_bol)
+  if (ifs == NULL)
     {
-      if (CPP_TRADITIONAL (pfile))
-	{
-	  if (CPP_WTRADITIONAL (pfile))
-	    cpp_warning (pfile, "ignoring #%s because of its indented #",
-			 dtable[i].name);
-	  return 0;
-	}
-      if (CPP_WTRADITIONAL (pfile))
-	cpp_warning (pfile, "traditional C ignores %s with the # indented",
-		     dtable[i].name);
+      cpp_error (pfile, "#else without #if");
+      return 0;
     }
-  
-  switch (i)
+  if (ifs->type == T_ELSE)
     {
-    default:
-      cpp_ice (pfile, "non COND directive in switch in c_d_w_s");
-      return 0;
-
-    case T_IF:
-    case T_IFDEF:
-    case T_IFNDEF:
-      temp = (IF_STACK *) xcalloc (1, sizeof (IF_STACK));
-      temp->lineno = CPP_BUFFER (pfile)->lineno;
-      temp->next = pfile->if_stack;
-      temp->type = i;
-      pfile->if_stack = temp;
-      return 0;
-
-    case T_ELSE:
-      if (pfile->if_stack != stack)
-	validate_else (pfile, dtable[i].name);
-      /* fall through */
-    case T_ELIF:
-      if (pfile->if_stack == stack)
-	return i;
-
-      pfile->if_stack->type = i;
-      return 0;
-
-    case T_ENDIF:
-      if (pfile->if_stack != stack)
-	validate_else (pfile, dtable[i].name);
-
-      if (pfile->if_stack == stack)
-	return i;
-		    
-      temp = pfile->if_stack;
-      pfile->if_stack = temp->next;
-      free (temp);
-      return 0;
+      cpp_error (pfile, "#else after #else");
+      cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here");
     }
-}
 
-/* Skip to #endif, #else, or #elif.  Consumes the directive that
-   causes it to stop, but not its argument.  Returns the number of
-   that directive, which must be passed back up to
-   _cpp_handle_directive, which will execute it.  */
-static int
-skip_if_group (pfile)
-    cpp_reader *pfile;
-{
-  enum cpp_ttype token;
-  IF_STACK *save_if_stack = pfile->if_stack; /* don't pop past here */
-  long old_written;
-  int ret = 0;
+  /* #ifndef can't have its special treatment for containing the whole file
+     if it has a #else clause.  */
+  ifs->cmacro = 0;
 
-  /* We are no longer at the start of the file.  */
-  pfile->only_seen_white = 0;
-
-  old_written = CPP_WRITTEN (pfile);
-  pfile->no_macro_expand++;
-  for (;;)
+  ifs->type = T_ELSE;
+  if (! ifs->was_skipping)
     {
-      /* We are at the end of a line.
-	 XXX Serious layering violation here.  */
-      int c = CPP_BUF_PEEK (CPP_BUFFER (pfile));
-      if (c == EOF)
-	break;  /* Caller will issue error.  */
-      else if (c != '\n')
-	cpp_ice (pfile, "character %c at end of line in skip_if_group", c);
-      CPP_BUFFER (pfile)->cur++;
-      CPP_BUMP_LINE (pfile);
-      CPP_SET_WRITTEN (pfile, old_written);
-      pfile->only_seen_white = 1;
-
-      token = _cpp_get_directive_token (pfile);
-
-      if (token == CPP_HASH)
-	{
-	  ret = consider_directive_while_skipping (pfile, save_if_stack);
-	  if (ret)
-	    break;
-	}
-
-      if (token != CPP_VSPACE)
-	_cpp_skip_rest_of_line (pfile);
+      /* If pfile->skipping is 2, one of the blocks in an #if/#elif/... chain
+	 succeeded, so we mustn't do the else block.  */
+      if (pfile->skipping < 2)
+	pfile->skipping = ! pfile->skipping;
     }
-  CPP_SET_WRITTEN (pfile, old_written);
-  pfile->no_macro_expand--;
-  return ret;
+  return 0;
 }
 
 /*
- * handle a #else directive.  Do this by just continuing processing
- * without changing  if_stack ;  this is so that the error message
- * for missing #endif's etc. will point to the original #if.  It
- * is possible that something different would be better.
+ * handle a #elif directive by not changing if_stack either.
+ * see the comment above do_else.
  */
 
 static int
-do_else (pfile)
+do_elif (pfile)
      cpp_reader *pfile;
 {
-  validate_else (pfile, dtable[T_ELSE].name);
-  _cpp_skip_rest_of_line (pfile);
+  struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
 
-  if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
+  if (ifs == NULL)
     {
-      cpp_error (pfile, "`#else' not within a conditional");
+      cpp_error (pfile, "#elif without #if");
       return 0;
     }
-  else
+  if (ifs->type == T_ELSE)
     {
-      /* #ifndef can't have its special treatment for containing the whole file
-	 if it has a #else clause.  */
-      pfile->if_stack->control_macro = 0;
+      cpp_error (pfile, "#elif after #else");
+      cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here");
+    }
 
-      if (pfile->if_stack->type == T_ELSE)
-	{
-	  cpp_error (pfile, "`#else' after `#else'");
-	  cpp_error_with_line (pfile, pfile->if_stack->lineno, 0,
-			       "the conditional began here");
-	}
-      pfile->if_stack->type = T_ELSE;
+  ifs->type = T_ELIF;
+  if (ifs->was_skipping)
+    _cpp_skip_rest_of_line (pfile);
+  else if (pfile->skipping != 1)
+    {
+      _cpp_skip_rest_of_line (pfile);
+      pfile->skipping = 2;  /* one block succeeded, so don't do any others */
     }
+  else
+    pfile->skipping = ! _cpp_parse_expr (pfile);
 
-  if (pfile->if_stack->if_succeeded)
-    return skip_if_group (pfile);
-  
-  ++pfile->if_stack->if_succeeded;	/* continue processing input */
   return 0;
 }
 
-/*
- * unstack after #endif command
- */
+
+/* #endif pops the if stack and resets pfile->skipping.  */
 
 static int
 do_endif (pfile)
      cpp_reader *pfile;
 {
+  struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
+
   validate_else (pfile, dtable[T_ENDIF].name);
-  _cpp_skip_rest_of_line (pfile);
 
-  if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
-    cpp_error (pfile, "`#endif' not within a conditional");
+  if (ifs == NULL)
+    cpp_error (pfile, "#endif without #if");
   else
     {
-      IF_STACK *temp = pfile->if_stack;
-      pfile->if_stack = temp->next;
-      if (temp->control_macro != 0)
-	pfile->potential_control_macro = temp->control_macro;
-      free (temp);
+      CPP_BUFFER (pfile)->if_stack = ifs->next;
+      pfile->skipping = ifs->was_skipping;
+      pfile->potential_control_macro = ifs->cmacro;
+      free (ifs);
     }
   return 0;
 }
 
+/* Push an if_stack entry and set pfile->skipping accordingly.
+   If this is a #ifndef starting at the beginning of a file,
+   CMACRO is the macro name tested by the #ifndef.  */
+
+static void
+push_conditional (pfile, skip, type, cmacro)
+     cpp_reader *pfile;
+     int skip;
+     int type;
+     const cpp_hashnode *cmacro;
+{
+  struct if_stack *ifs;
+
+  ifs = (struct if_stack *) xmalloc (sizeof (struct if_stack));
+  ifs->lineno = CPP_BUFFER (pfile)->lineno;
+  ifs->next = CPP_BUFFER (pfile)->if_stack;
+  ifs->cmacro = cmacro;
+  ifs->was_skipping = pfile->skipping;
+  ifs->type = type;
+
+  if (!pfile->skipping)
+    pfile->skipping = skip;
+
+  CPP_BUFFER (pfile)->if_stack = ifs;
+}
+
 /* Issue -pedantic warning for text which is not a comment following
-   an #else or #endif.  Do not warn in system headers, as this is harmless
-   and very common on old systems.  */
+   an #else or #endif.  */
 
 static void
 validate_else (pfile, directive)
      cpp_reader *pfile;
      const U_CHAR *directive;
 {
-  long old_written;
-  if (! CPP_PEDANTIC (pfile))
-    return;
-
-  old_written = CPP_WRITTEN (pfile);
-  pfile->no_macro_expand++;
-  if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
-    cpp_pedwarn (pfile,
-		 "text following `#%s' violates ANSI standard", directive);
-  CPP_SET_WRITTEN (pfile, old_written);
-  pfile->no_macro_expand--;
+  if (CPP_PEDANTIC (pfile))
+    {
+      long old_written = CPP_WRITTEN (pfile);
+      pfile->no_macro_expand++;
+      if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
+	cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
+      CPP_SET_WRITTEN (pfile, old_written);
+      pfile->no_macro_expand--;
+    }
+  _cpp_skip_rest_of_line (pfile);
 }
 
 /* Called when we reach the end of a macro buffer.  Walk back up the
    conditional stack till we reach its level at entry to this file,
-   issuing error messages.  */
+   issuing error messages.  Then force skipping off.  */
 void
 _cpp_unwind_if_stack (pfile, pbuf)
      cpp_reader *pfile;
@@ -1504,18 +1353,14 @@ _cpp_unwind_if_stack (pfile, pbuf)
 {
   struct if_stack *ifs, *nifs;
 
-  for (ifs = pfile->if_stack;
-       ifs != pbuf->if_stack;
-       ifs = nifs)
+  for (ifs = pbuf->if_stack; ifs; ifs = nifs)
     {
-      cpp_error_with_line (pfile, ifs->lineno, 0,
-			   "unterminated `#%s' conditional",
+      cpp_error_with_line (pfile, ifs->lineno, 1, "unterminated #%s",
 			   dtable[ifs->type].name);
-
       nifs = ifs->next;
       free (ifs);
     }
-  pfile->if_stack = ifs;
+  pfile->skipping = 0;
 }
 
 #define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)

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