OSDN Git Service

fix compile time warnings about unused epilogue instructions
[pf3gnuchains/gcc-fork.git] / gcc / cpplib.c
index eb43e3b..90f6c80 100644 (file)
@@ -25,8 +25,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "cpphash.h"
 #include "intl.h"
 
-#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
-#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
+#define SKIP_WHITE_SPACE(p) do { while (is_hspace(*p)) p++; } while (0)
 
 #define PEEKN(N) (CPP_BUFFER (pfile)->rlimit - CPP_BUFFER (pfile)->cur >= (N) ? CPP_BUFFER (pfile)->cur[N] : EOF)
 #define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
@@ -38,8 +37,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* Forward declarations.  */
 
-static char *my_strerror               PROTO ((int));
-static void validate_else              PROTO ((cpp_reader *, char *));
+static const char *my_strerror         PROTO ((int));
+static void validate_else              PROTO ((cpp_reader *, const char *));
 static HOST_WIDEST_INT eval_if_expression      PROTO ((cpp_reader *));
 
 static void conditional_skip           PROTO ((cpp_reader *, int,
@@ -49,6 +48,8 @@ static void skip_if_group             PROTO ((cpp_reader *));
 static void parse_name                 PARAMS ((cpp_reader *, int));
 static void parse_string               PARAMS ((cpp_reader *, int));
 static int parse_assertion             PARAMS ((cpp_reader *));
+static const char *if_directive_name   PARAMS ((cpp_reader *,
+                                                struct if_stack *));
 
 /* External declarations.  */
 
@@ -59,8 +60,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
 struct directive {
   int length;                  /* Length of name */
   int (*func)                  /* Function to handle directive */
-    PARAMS ((cpp_reader *, struct directive *));
-  char *name;                  /* Name of directive */
+    PARAMS ((cpp_reader *, const struct directive *));
+  const char *name;            /* Name of directive */
   enum node_type type;         /* Code which describes which directive.  */
 };
 
@@ -68,53 +69,74 @@ struct directive {
    are going to be placed in a table and some old compilers have trouble with
    pointers to functions returning void.  */
 
-static int do_define PARAMS ((cpp_reader *, struct directive *));
-static int do_line PARAMS ((cpp_reader *, struct directive *));
-static int do_include PARAMS ((cpp_reader *, struct directive *));
-static int do_undef PARAMS ((cpp_reader *, struct directive *));
-static int do_error PARAMS ((cpp_reader *, struct directive *));
-static int do_pragma PARAMS ((cpp_reader *, struct directive *));
-static int do_ident PARAMS ((cpp_reader *, struct directive *));
-static int do_if PARAMS ((cpp_reader *, struct directive *));
-static int do_xifdef PARAMS ((cpp_reader *, struct directive *));
-static int do_else PARAMS ((cpp_reader *, struct directive *));
-static int do_elif PARAMS ((cpp_reader *, struct directive *));
-static int do_endif PARAMS ((cpp_reader *, struct directive *));
+static int do_define PARAMS ((cpp_reader *, const struct directive *));
+static int do_line PARAMS ((cpp_reader *, const struct directive *));
+static int do_include PARAMS ((cpp_reader *, const struct directive *));
+static int do_undef PARAMS ((cpp_reader *, const struct directive *));
+static int do_error PARAMS ((cpp_reader *, const struct directive *));
+static int do_pragma PARAMS ((cpp_reader *, const struct directive *));
+static int do_ident PARAMS ((cpp_reader *, const struct directive *));
+static int do_if PARAMS ((cpp_reader *, const struct directive *));
+static int do_xifdef PARAMS ((cpp_reader *, const struct directive *));
+static int do_else PARAMS ((cpp_reader *, const struct directive *));
+static int do_elif PARAMS ((cpp_reader *, const struct directive *));
+static int do_endif PARAMS ((cpp_reader *, const struct directive *));
 #ifdef SCCS_DIRECTIVE
-static int do_sccs PARAMS ((cpp_reader *, struct directive *));
+static int do_sccs PARAMS ((cpp_reader *, const struct directive *));
 #endif
-static int do_assert PARAMS ((cpp_reader *, struct directive *));
-static int do_unassert PARAMS ((cpp_reader *, struct directive *));
-static int do_warning PARAMS ((cpp_reader *, struct directive *));
-
-#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
-((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
-
-/* Here is the actual list of #-directives, most-often-used first.
-   The initialize_builtins function assumes #define is the very first.  */
-
-static struct directive directive_table[] = {
-  {  6, do_define,   "define",       T_DEFINE },
-  {  5, do_xifdef,   "ifdef",        T_IFDEF },
-  {  6, do_xifdef,   "ifndef",       T_IFNDEF },
-  {  7, do_include,  "include",      T_INCLUDE },
-  { 12, do_include,  "include_next", T_INCLUDE_NEXT },
-  {  6, do_include,  "import",       T_IMPORT },
-  {  5, do_endif,    "endif",        T_ENDIF },
-  {  4, do_else,     "else",         T_ELSE },
-  {  2, do_if,       "if",           T_IF },
-  {  4, do_elif,     "elif",         T_ELIF },
-  {  5, do_undef,    "undef",        T_UNDEF },
-  {  5, do_error,    "error",        T_ERROR },
-  {  7, do_warning,  "warning",      T_WARNING },
-  {  6, do_pragma,   "pragma",       T_PRAGMA },
-  {  4, do_line,     "line",         T_LINE },
-  {  5, do_ident,    "ident",        T_IDENT },
+static int do_assert PARAMS ((cpp_reader *, const struct directive *));
+static int do_unassert PARAMS ((cpp_reader *, const struct directive *));
+static int do_warning PARAMS ((cpp_reader *, const struct directive *));
+static enum cpp_token null_underflow PARAMS ((cpp_reader *));
+static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
+static int skip_comment PARAMS ((cpp_reader *, int));
+static int copy_comment PARAMS ((cpp_reader *, int));
+static void copy_rest_of_line PARAMS ((cpp_reader *));
+static int handle_directive PARAMS ((cpp_reader *));
+static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, cpp_reader *,
+                                        const struct directive *));
+static enum cpp_token get_directive_token PARAMS ((cpp_reader *));
+static int read_line_number PARAMS ((cpp_reader *, int *));
+static void cpp_print_file_and_line PARAMS ((cpp_reader *));
+static void v_cpp_error PARAMS ((cpp_reader *, const char *, va_list));
+static void v_cpp_warning PARAMS ((cpp_reader *, const char *, va_list));
+static void v_cpp_error_with_line PARAMS ((cpp_reader *, int, int,
+                                          const char *, va_list));
+static void v_cpp_warning_with_line PARAMS ((cpp_reader *, int, int, const char *, va_list));
+static U_CHAR *detect_if_not_defined PARAMS ((cpp_reader *));
+static int consider_directive_while_skipping PARAMS ((cpp_reader *, IF_STACK_FRAME *));
+
+/* Here is the actual list of #-directives.
+   This table is ordered by frequency of occurrence; the numbers
+   at the end are directive counts from all the source code I have
+   lying around (egcs and libc CVS as of 1999-05-18, plus grub-0.5.91,
+   linux-2.2.9, and pcmcia-cs-3.0.9).  */
+
+static const struct directive directive_table[] = {
+  /* In C89 */
+  {  6, do_define,   "define",       T_DEFINE },       /* 270554 */
+  {  7, do_include,  "include",      T_INCLUDE },      /*  52262 */
+  {  5, do_endif,    "endif",        T_ENDIF },                /*  45855 */
+  {  5, do_xifdef,   "ifdef",        T_IFDEF },                /*  22000 */
+  {  2, do_if,       "if",           T_IF },           /*  18162 */
+  {  4, do_else,     "else",         T_ELSE },         /*   9863 */
+  {  6, do_xifdef,   "ifndef",       T_IFNDEF },       /*   9675 */
+  {  5, do_undef,    "undef",        T_UNDEF },                /*   4837 */
+  {  4, do_line,     "line",         T_LINE },         /*   2465 */
+  {  4, do_elif,     "elif",         T_ELIF },         /*    610 */
+  {  5, do_error,    "error",        T_ERROR },                /*    475 */
+  {  6, do_pragma,   "pragma",       T_PRAGMA },       /*    195 */
+
+  /* Extensions.  All deprecated except #warning and #include_next.  */
+  {  7, do_warning,  "warning",      T_WARNING },      /*     22 - GNU   */
+  { 12, do_include,  "include_next", T_INCLUDE_NEXT }, /*     19 - GNU   */
+  {  5, do_ident,    "ident",        T_IDENT },                /*     11 - SVR4  */
+  {  6, do_include,  "import",       T_IMPORT },       /*      0 - ObjC  */
+  {  6, do_assert,   "assert",       T_ASSERT },       /*      0 - SVR4  */
+  {  8, do_unassert, "unassert",     T_UNASSERT },     /*      0 - SVR4  */
 #ifdef SCCS_DIRECTIVE
-  {  4, do_sccs,     "sccs",         T_SCCS },
+  {  4, do_sccs,     "sccs",         T_SCCS },         /*      0 - SVR2? */
 #endif
-  {  6, do_assert,   "assert",       T_ASSERT },
-  {  8, do_unassert, "unassert",     T_UNASSERT },
   {  -1, 0, "", T_UNUSED }
 };
 
@@ -388,7 +410,7 @@ cpp_skip_hspace (pfile)
       c = GETC();
       if (c == EOF)
        return;
-      else if (is_hor_space[c])
+      else if (is_hspace(c))
        {
          if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
            cpp_pedwarn (pfile, "%s in preprocessing directive",
@@ -497,7 +519,7 @@ handle_directive (pfile)
      cpp_reader *pfile;
 {
   int c;
-  register struct directive *kt;
+  register const struct directive *kt;
   int ident_length;
   U_CHAR *ident;
   long old_written = CPP_WRITTEN (pfile);
@@ -505,196 +527,150 @@ handle_directive (pfile)
   cpp_skip_hspace (pfile);
 
   c = PEEKC ();
+  /* # 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).  */
   if (c >= '0' && c <= '9')
     {
-      /* Handle # followed by a line number.  */
-      if (CPP_PEDANTIC (pfile))
+      if (CPP_OPTIONS (pfile)->lang_asm)
+       {
+         skip_rest_of_line (pfile);
+         return 1;
+       }
+
+      if (CPP_PEDANTIC (pfile)
+         && ! CPP_PREPROCESSED (pfile)
+         && ! CPP_BUFFER (pfile)->manual_pop)
        cpp_pedwarn (pfile, "`#' followed by integer");
       do_line (pfile, NULL);
-      goto done_a_directive;
+      return 1;
     }
 
+  /* If we are rescanning preprocessed input, don't obey any directives
+     other than # nnn.  */
+  if (CPP_PREPROCESSED (pfile))
+    return 0;
+
   /* Now find the directive name.  */
   CPP_PUTC (pfile, '#');
   parse_name (pfile, GETC());
   ident = pfile->token_buffer + old_written + 1;
   ident_length = CPP_PWRITTEN (pfile) - ident;
-  if (ident_length == 0 && PEEKC() == '\n')
+  if (ident_length == 0)
     {
       /* A line of just `#' becomes blank.  */
-      goto done_a_directive;
-    }
-
-#if 0
-  if (ident_length == 0 || !is_idstart[*ident]) {
-    U_CHAR *p = ident;
-    while (is_idchar[*p]) {
-      if (*p < '0' || *p > '9')
-       break;
-      p++;
-    }
-    /* Avoid error for `###' and similar cases unless -pedantic.  */
-    if (p == ident) {
-      while (*p == '#' || is_hor_space[*p]) p++;
-      if (*p == '\n') {
-       if (pedantic && !lang_asm)
-         cpp_warning (pfile, "invalid preprocessor directive");
+      if (PEEKC() == '\n')
+       return 1;
+      else
        return 0;
-      }
     }
 
-    if (!lang_asm)
-      cpp_error (pfile, "invalid preprocessor directive name");
-
-    return 0;
-  }
-#endif
   /*
    * Decode the keyword and call the appropriate expansion
    * routine, after moving the input pointer up to the next line.
    */
-  for (kt = directive_table; ; kt++) {
-    if (kt->length <= 0)
-      goto not_a_directive;
-    if (kt->length == ident_length
-       && !strncmp (kt->name, ident, ident_length)) 
-      break;
-  }
-
-  /* We may want to pass through #define, #undef, #pragma, and #include.
-     Other directives may create output, but we don't want the directive
-     itself out, so we pop it now.  For example conditionals may emit
-     #failed ... #endfailed stuff.  */
-
-  if (! (kt->type == T_DEFINE
-        || kt->type == T_PRAGMA
-        || (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)
-            && CPP_OPTIONS (pfile)->dump_includes)))
-    CPP_SET_WRITTEN (pfile, old_written);
-
-  (*kt->func) (pfile, kt);
-
-  if (kt->type == T_DEFINE)
+  for (kt = directive_table; ; kt++)
     {
-      if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
-       {
-         /* Skip "#define". */
-         U_CHAR *p = pfile->token_buffer + old_written + 7;
-
-         SKIP_WHITE_SPACE (p);
-         while (is_idchar[*p]) p++;
-         pfile->limit = p;
-         CPP_PUTC (pfile, '\n');
-       }
-      else if (CPP_OPTIONS (pfile)->dump_macros != dump_definitions)
-       CPP_SET_WRITTEN (pfile, old_written);
+      if (kt->length <= 0)
+       return 0;
+      if (kt->length == ident_length
+         && !strncmp (kt->name, ident, ident_length)) 
+       break;
     }
 
- done_a_directive:
-  return 1;
+  CPP_SET_WRITTEN (pfile, old_written);
+  (*kt->func) (pfile, kt);
 
- not_a_directive:
-  return 0;
+  return 1;
 }
 
 /* Pass a directive through to the output file.
    BUF points to the contents of the directive, as a contiguous string.
-m   LIMIT points to the first character past the end of the directive.
+   LEN is the length of the string pointed to by BUF.
    KEYWORD is the keyword-table entry for the directive.  */
 
 static void
-pass_thru_directive (buf, limit, pfile, keyword)
-     U_CHAR *buf, *limit;
+pass_thru_directive (buf, len, pfile, keyword)
+     const U_CHAR *buf;
+     size_t len;
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   register unsigned keyword_length = keyword->length;
 
-  CPP_RESERVE (pfile, 1 + keyword_length + (limit - buf));
+  CPP_RESERVE (pfile, 1 + keyword_length + len);
   CPP_PUTC_Q (pfile, '#');
   CPP_PUTS_Q (pfile, keyword->name, keyword_length);
-  if (limit != buf && buf[0] != ' ')
+  if (len != 0 && buf[0] != ' ')
     CPP_PUTC_Q (pfile, ' ');
-  CPP_PUTS_Q (pfile, buf, limit - buf);
-#if 0
-  CPP_PUTS_Q (pfile, '\n');
-  /* Count the line we have just made in the output,
-     to get in sync properly.  */
-  pfile->lineno++;
-#endif
+  CPP_PUTS_Q (pfile, buf, len);
 }
 
-/* Check a purported macro name SYMNAME, and yield its length.
-   ASSERTION is nonzero if this is really for an assertion name.  */
+/* Check a purported macro name SYMNAME, and yield its length.  */
 
 int
-check_macro_name (pfile, symname, assertion)
+check_macro_name (pfile, symname)
      cpp_reader *pfile;
-     U_CHAR *symname;
-     int assertion;
+     const U_CHAR *symname;
 {
-  U_CHAR *p;
+  const U_CHAR *p;
   int sym_length;
 
-  for (p = symname; is_idchar[*p]; p++)
+  for (p = symname; is_idchar(*p); p++)
     ;
   sym_length = p - symname;
   if (sym_length == 0
       || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
-    cpp_error (pfile,
-              assertion ? "invalid assertion name" : "invalid macro name");
-  else if (!is_idstart[*symname]
+    cpp_error (pfile, "invalid macro name");
+  else if (!is_idstart(*symname)
           || (! strncmp (symname, "defined", 7) && sym_length == 7)) {
     U_CHAR *msg;                       /* what pain...  */
     msg = (U_CHAR *) alloca (sym_length + 1);
     bcopy (symname, msg, sym_length);
     msg[sym_length] = 0;
-    cpp_error (pfile,
-              (assertion
-               ? "invalid assertion name `%s'"
-               : "invalid macro name `%s'"),
-              msg);
+    cpp_error (pfile, "invalid macro name `%s'", msg);
   }
   return sym_length;
 }
 
-
 /* Process a #define command.
-KEYWORD is the keyword-table entry for #define,
-or NULL for a "predefined" macro.  */
+   KEYWORD is the keyword-table entry for #define,
+   or NULL for a "predefined" macro,
+   or the keyword-table entry for #pragma in the case of a #pragma poison.  */
 
 static int
 do_define (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int hashcode;
   MACRODEF mdef;
   HASHNODE *hp;
   long here;
   U_CHAR *macro, *buf, *end;
+  enum node_type new_type;
 
   here = CPP_WRITTEN (pfile);
   copy_rest_of_line (pfile);
 
+  if (keyword == NULL || keyword->type == T_DEFINE)
+    new_type = T_MACRO;
+  else
+    new_type = T_POISON;
+
   /* Copy out the line so we can pop the token buffer. */
   buf = pfile->token_buffer + here;
   end = CPP_PWRITTEN (pfile);
-  macro = alloca (end - buf + 1);
+  macro = (U_CHAR *) alloca (end - buf + 1);
   bcopy (buf, macro, end - buf + 1);
   end = macro + (end - buf);
 
   CPP_SET_WRITTEN (pfile, here);
 
-#if 0
-  /* If this is a precompiler run (with -pcp) pass thru #define commands.  */
-  if (pcp_outfile && keyword)
-    pass_thru_directive (macro, end, pfile, keyword);
-#endif
-
   mdef = create_definition (macro, end, pfile, keyword == NULL);
   if (mdef.defn == 0)
-    goto nope;
+    return 0;
 
   hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE);
 
@@ -704,44 +680,49 @@ do_define (pfile, keyword)
       /* Redefining a precompiled key is ok.  */
       if (hp->type == T_PCSTRING)
        ok = 1;
+      /* Redefining a poisoned identifier is even worse than `not ok'.  */
+      else if (hp->type == T_POISON)
+       ok = -1;
       /* Redefining a macro is ok if the definitions are the same.  */
       else if (hp->type == T_MACRO)
        ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
       /* Redefining a constant is ok with -D.  */
       else if (hp->type == T_CONST || hp->type == T_STDC)
         ok = ! CPP_OPTIONS (pfile)->done_initializing;
-      /* Print the warning if it's not ok.  */
-      if (!ok)
+      /* Print the warning or error if it's not ok.  */
+      if (ok <= 0)
        {
-         /* If we are passing through #define and #undef directives, do
-            that for this re-definition now.  */
-         if (CPP_OPTIONS (pfile)->debug_output && keyword)
-           pass_thru_directive (macro, end, pfile, keyword);
-
-         cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
+         if (hp->type == T_POISON)
+           cpp_error (pfile, "redefining poisoned `%.*s'", 
+                      mdef.symlen, mdef.symnam);
+         else
+           cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
          if (hp->type == T_MACRO)
-           cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line,
-                                     "this is the location of the previous definition");
+           cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
+                                           hp->value.defn->line,
+                       "this is the location of the previous definition");
+       }
+      if (hp->type != T_POISON)
+       {
+         /* Replace the old definition.  */
+         hp->type = new_type;
+         hp->value.defn = mdef.defn;
        }
-      /* Replace the old definition.  */
-      hp->type = T_MACRO;
-      hp->value.defn = mdef.defn;
     }
   else
+    cpp_install (pfile, mdef.symnam, mdef.symlen, new_type,
+                (char *) mdef.defn, hashcode);
+
+  if (keyword != NULL && keyword->type == T_DEFINE)
     {
-      /* If we are passing through #define and #undef directives, do
-        that for this new definition now.  */
-      if (CPP_OPTIONS (pfile)->debug_output && keyword)
-       pass_thru_directive (macro, end, pfile, keyword);
-      cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO,
-                  (char *) mdef.defn, hashcode);
+      if (CPP_OPTIONS (pfile)->debug_output
+         || CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
+       dump_definition (pfile, mdef);
+      else if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
+       pass_thru_directive (mdef.symnam, mdef.symlen, pfile, keyword);
     }
 
   return 0;
-
-nope:
-
-  return 1;
 }
 
 
@@ -764,7 +745,7 @@ cpp_push_buffer (pfile, buffer, length)
       return NULL;
     }
 
-  new = (cpp_buffer *) xcalloc (sizeof (cpp_buffer), 1);
+  new = (cpp_buffer *) xcalloc (1, sizeof (cpp_buffer));
 
   new->if_stack = pfile->if_stack;
   new->cleanup = null_cleanup;
@@ -798,15 +779,42 @@ cpp_scan_buffer (pfile)
      cpp_reader *pfile;
 {
   cpp_buffer *buffer = CPP_BUFFER (pfile);
-  for (;;)
+  enum cpp_token token;
+  if (CPP_OPTIONS (pfile)->no_output)
     {
-      enum cpp_token token = cpp_get_token (pfile);
-      if (token == CPP_EOF) /* Should not happen ...  */
-       break;
-      if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
+      long old_written = CPP_WRITTEN (pfile);
+      /* In no-output mode, we can ignore everything but directives.  */
+      for (;;)
        {
-         cpp_pop_buffer (pfile);
-         break;
+         if (! pfile->only_seen_white)
+           skip_rest_of_line (pfile);
+         token = cpp_get_token (pfile);
+         if (token == CPP_EOF) /* Should not happen ...  */
+           break;
+         if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
+           {
+             if (CPP_PREV_BUFFER (CPP_BUFFER (pfile))
+                 != CPP_NULL_BUFFER (pfile))
+               cpp_pop_buffer (pfile);
+             break;
+           }
+       }
+      CPP_SET_WRITTEN (pfile, old_written);
+    }
+  else
+    {
+      for (;;)
+       {
+         token = cpp_get_token (pfile);
+         if (token == CPP_EOF) /* Should not happen ...  */
+           break;
+         if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
+           {
+             if (CPP_PREV_BUFFER (CPP_BUFFER (pfile))
+                 != CPP_NULL_BUFFER (pfile))
+               cpp_pop_buffer (pfile);
+             break;
+           }
        }
     }
 }
@@ -823,17 +831,12 @@ cpp_scan_buffer (pfile)
 void
 cpp_expand_to_buffer (pfile, buf, length)
      cpp_reader *pfile;
-     U_CHAR *buf;
+     const U_CHAR *buf;
      int length;
 {
   register cpp_buffer *ip;
-#if 0
-  cpp_buffer obuf;
-#endif
   U_CHAR *buf1;
-#if 0
-  int odepth = indepth;
-#endif
+  int save_no_output;
 
   if (length < 0)
     {
@@ -851,12 +854,12 @@ cpp_expand_to_buffer (pfile, buf, length)
   if (ip == NULL)
     return;
   ip->has_escapes = 1;
-#if 0
-  ip->lineno = obuf.lineno = 1;
-#endif
 
   /* Scan the input, create the output.  */
+  save_no_output = CPP_OPTIONS (pfile)->no_output;
+  CPP_OPTIONS (pfile)->no_output = 0;
   cpp_scan_buffer (pfile);
+  CPP_OPTIONS (pfile)->no_output = save_no_output;
 
   CPP_NUL_TERMINATE (pfile);
 }
@@ -1013,14 +1016,14 @@ get_directive_token (pfile)
 static int
 do_include (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int importing = (keyword->type == T_IMPORT);
   int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
   int angle_brackets = 0;      /* 0 for "...", 1 for <...> */
   int before;  /* included before? */
   long flen;
-  unsigned char *fbeg, *fend;
+  unsigned char *ftok;
   cpp_buffer *fp;
 
   enum cpp_token token;
@@ -1046,7 +1049,8 @@ do_include (pfile, keyword)
       && !CPP_BUFFER (pfile)->system_header_p && !pfile->import_warning)
     {
       pfile->import_warning = 1;
-      cpp_warning (pfile, "`#import' is obsolete, use an #ifndef wrapper in the header file");
+      cpp_warning (pfile,
+          "#import is obsolete, use an #ifndef wrapper in the header file");
     }
 
   pfile->parsing_include_directive++;
@@ -1055,28 +1059,20 @@ do_include (pfile, keyword)
 
   if (token == CPP_STRING)
     {
-      fbeg = pfile->token_buffer + old_written + 1;
-      fend = CPP_PWRITTEN (pfile) - 1;
-      *fend = '\0';
-      if (fbeg[-1] == '<')
-         angle_brackets = 1;
+      if (pfile->token_buffer[old_written] == '<')
+       angle_brackets = 1;
     }
 #ifdef VMS
   else if (token == CPP_NAME)
     {
-      /* Support '#include xyz' like VAX-C to allow for easy use of
-       * all the decwindow include files. It defaults to '#include
-       * <xyz.h>' and generates a warning.  */
+      /* Support '#include xyz' like VAX-C.  It is taken as
+         '#include <xyz.h>' and generates a warning.  */
       cpp_warning (pfile,
-                  "VAX-C-style include specification found, use '#include <filename.h>' !");
+              "`#include filename' is obsolete, use `#include <filename.h>'");
       angle_brackets = 1;
 
       /* Append the missing `.h' to the name. */
-      CPP_PUTS (pfile, ".h", 3)
-      CPP_NUL_TERMINATE_Q (pfile);
-
-      fbeg = pfile->token_buffer + old_written;
-      fend = CPP_PWRITTEN (pfile);
+      CPP_PUTS (pfile, ".h", 2);
     }
 #endif
   else
@@ -1088,8 +1084,12 @@ do_include (pfile, keyword)
       return 0;
     }
 
-  token = get_directive_token (pfile);
-  if (token != CPP_VSPACE)
+  flen = CPP_WRITTEN (pfile) - old_written;
+  ftok = (unsigned char *) alloca (flen + 1);
+  memcpy (ftok, pfile->token_buffer + old_written, flen);
+  ftok[flen] = '\0';
+
+  if (get_directive_token (pfile) != CPP_VSPACE)
     {
       cpp_error (pfile, "junk at end of `#include'");
       skip_rest_of_line (pfile);
@@ -1097,14 +1097,29 @@ do_include (pfile, keyword)
 
   CPP_SET_WRITTEN (pfile, old_written);
 
-  flen = fend - fbeg;
-
   if (flen == 0)
     {
       cpp_error (pfile, "empty file name in `#%s'", keyword->name);
       return 0;
     }
 
+  if (CPP_OPTIONS (pfile)->dump_includes)
+    pass_thru_directive (ftok,
+                        flen
+#ifdef VMS
+         - ((token == CPP_NAME) ? 2 : 0)
+#endif
+                        , pfile, keyword);
+
+#ifdef VMS
+  if (token == CPP_STRING)
+#endif
+    {
+      ftok++;
+      flen -= 2;
+      ftok[flen] = '\0';
+    }
+
   search_start = 0;
 
   for (fp = CPP_BUFFER (pfile);
@@ -1116,7 +1131,7 @@ do_include (pfile, keyword)
   if (fp == CPP_NULL_BUFFER (pfile))
     {
       cpp_fatal (pfile, "cpp internal error: fp == NULL_BUFFER in do_include");
-      return 1;
+      return 0;
     }
   
   /* For #include_next, skip in the search path past the dir in which the
@@ -1149,11 +1164,11 @@ do_include (pfile, keyword)
 
   if (!search_start)
     {
-      cpp_error (pfile, "No include path in which to find %s", fbeg);
+      cpp_error (pfile, "No include path in which to find %s", ftok);
       return 0;
     }
 
-  fd = find_include_file (pfile, fbeg, search_start, &ihash, &before);
+  fd = find_include_file (pfile, ftok, search_start, &ihash, &before);
 
   if (fd == -2)
     return 0;
@@ -1165,7 +1180,7 @@ do_include (pfile, keyword)
                                       (pfile->system_include_depth > 0)))
         {
          if (!angle_brackets)
-           deps_output (pfile, fbeg, ' ');
+           deps_output (pfile, ftok, ' ');
          else
            {
              char *p;
@@ -1178,13 +1193,13 @@ do_include (pfile, keyword)
                ptr = CPP_OPTIONS (pfile)->quote_include;
 
              p = (char *) alloca (strlen (ptr->name)
-                                  + strlen (fbeg) + 2);
+                                  + strlen (ftok) + 2);
              if (*ptr->name != '\0')
                {
                  strcpy (p, ptr->name);
                  strcat (p, "/");
                }
-             strcat (p, fbeg);
+             strcat (p, ftok);
              deps_output (pfile, p, ' ');
            }
        }
@@ -1197,9 +1212,9 @@ do_include (pfile, keyword)
       else if (CPP_PRINT_DEPS (pfile)
               && (CPP_PRINT_DEPS (pfile)
                   <= (angle_brackets || (pfile->system_include_depth > 0))))
-       cpp_warning (pfile, "No include path in which to find %s", fbeg);
+       cpp_warning (pfile, "No include path in which to find %s", ftok);
       else
-       cpp_error_from_errno (pfile, fbeg);
+       cpp_error_from_errno (pfile, ftok);
 
       return 0;
     }
@@ -1241,6 +1256,34 @@ do_include (pfile, keyword)
   return 0;
 }
 
+/* Subroutine of do_line.  Read next token from PFILE without adding it to
+   the output buffer.  If it is a number between 1 and 4, store it in *NUM
+   and return 1; otherwise, return 0 and complain if we aren't at the end
+   of the directive.  */
+
+static int
+read_line_number (pfile, num)
+     cpp_reader *pfile;
+     int *num;
+{
+  long save_written = CPP_WRITTEN (pfile);
+  U_CHAR *p = pfile->token_buffer + save_written;
+  enum cpp_token token = get_directive_token (pfile);
+  CPP_SET_WRITTEN (pfile, save_written);
+
+  if (token == CPP_NUMBER && *p >= '1' && *p <= '4' && p[1] == '\0')
+    {
+      *num = p[0] - '0';
+      return 1;
+    }
+  else
+    {
+      if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
+       cpp_error (pfile, "invalid format `#line' command");
+      return 0;
+    }
+}
+
 /* Interpret #line command.
    Note that the filename string (if any) is treated as if it were an
    include filename.  That means no escape handling.  */
@@ -1248,7 +1291,7 @@ do_include (pfile, keyword)
 static int
 do_line (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
   int new_lineno;
@@ -1282,41 +1325,32 @@ do_line (pfile, keyword)
     {
       U_CHAR *fname = pfile->token_buffer + old_written + 1;
       U_CHAR *end_name = CPP_PWRITTEN (pfile) - 1;
-      long num_start = CPP_WRITTEN (pfile);
+      int action_number = 0;
 
-      token = get_directive_token (pfile);
-      if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
+      if (read_line_number (pfile, &action_number))
        {
-         U_CHAR *p = pfile->token_buffer + num_start;
          if (CPP_PEDANTIC (pfile))
            cpp_pedwarn (pfile, "garbage at end of `#line' command");
 
-         if (token != CPP_NUMBER || *p < '0' || *p > '4' || p[1] != '\0')
+         if (action_number == 1)
            {
-             cpp_error (pfile, "invalid format `#line' command");
-             goto bad_line_directive;
+             file_change = enter_file;
+             read_line_number (pfile, &action_number);
            }
-         if (*p == '1')
-           file_change = enter_file;
-         else if (*p == '2')
-           file_change = leave_file;
-         else if (*p == '3')
-           ip->system_header_p = 1;
-         else /* if (*p == '4') */
-           ip->system_header_p = 2;
-
-         CPP_SET_WRITTEN (pfile, num_start);
-         token = get_directive_token (pfile);
-         p = pfile->token_buffer + num_start;
-         if (token == CPP_NUMBER && p[1] == '\0' && (*p == '3' || *p== '4'))
+         else if (action_number == 2)
            {
-             ip->system_header_p = *p == '3' ? 1 : 2;
-             token = get_directive_token (pfile);
+             file_change = leave_file;
+             read_line_number (pfile, &action_number);
            }
-         if (token != CPP_VSPACE)
+         if (action_number == 3)
            {
-             cpp_error (pfile, "invalid format `#line' command");
-             goto bad_line_directive;
+             ip->system_header_p = 1;
+             read_line_number (pfile, &action_number);
+           }
+         if (action_number == 4)
+           {
+             ip->system_header_p = 2;
+             read_line_number (pfile, &action_number);
            }
        }
       
@@ -1324,7 +1358,7 @@ do_line (pfile, keyword)
       
       if (strcmp (fname, ip->nominal_fname))
        {
-         char *newname, *oldname;
+         const char *newname, *oldname;
          if (!strcmp (fname, ip->fname))
            newname = ip->fname;
          else if (ip->last_nominal_fname
@@ -1340,7 +1374,7 @@ do_line (pfile, keyword)
              && ip->last_nominal_fname != oldname
              && ip->last_nominal_fname != newname
              && ip->last_nominal_fname != ip->fname)
-           free (ip->last_nominal_fname);
+           free ((void *) ip->last_nominal_fname);
 
          if (newname == ip->fname)
            ip->last_nominal_fname = NULL;
@@ -1374,7 +1408,7 @@ do_line (pfile, keyword)
 static int
 do_undef (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int sym_length;
   HASHNODE *hp;
@@ -1385,7 +1419,7 @@ do_undef (pfile, keyword)
 
   cpp_skip_hspace (pfile);
   c = GETC();
-  if (! is_idstart[c])
+  if (! is_idstart(c))
   {
       cpp_error (pfile, "token after #undef is not an identifier");
       skip_rest_of_line (pfile);
@@ -1397,7 +1431,7 @@ do_undef (pfile, keyword)
   limit = CPP_PWRITTEN(pfile);
 
   /* Copy out the token so we can pop the token buffer. */
-  name = alloca (limit - buf + 1);
+  name = (U_CHAR *) alloca (limit - buf + 1);
   bcopy(buf, name, limit - buf);
   name[limit - buf] = '\0';
 
@@ -1410,23 +1444,22 @@ do_undef (pfile, keyword)
 
   CPP_SET_WRITTEN (pfile, here);
 
-#if 0
-  /* If this is a precompiler run (with -pcp) pass thru #undef commands.  */
-  if (pcp_outfile && keyword)
-    pass_thru_directive (buf, limit, pfile, keyword);
-#endif
-
-  sym_length = check_macro_name (pfile, buf, 0);
+  sym_length = check_macro_name (pfile, buf);
 
   while ((hp = cpp_lookup (pfile, name, sym_length, -1)) != NULL)
     {
       /* If we are generating additional info for debugging (with -g) we
         need to pass through all effective #undef commands.  */
       if (CPP_OPTIONS (pfile)->debug_output && keyword)
-       pass_thru_directive (name, name+sym_length, pfile, keyword);
-      if (hp->type != T_MACRO)
-       cpp_warning (pfile, "undefining `%s'", hp->name);
-      delete_macro (hp);
+       pass_thru_directive (name, sym_length, pfile, keyword);
+      if (hp->type == T_POISON)
+       cpp_error (pfile, "cannot undefine poisoned `%s'", hp->name);
+      else 
+       {
+         if (hp->type != T_MACRO)
+           cpp_warning (pfile, "undefining `%s'", hp->name);
+         delete_macro (hp);
+       }
     }
 
   return 0;
@@ -1455,7 +1488,7 @@ cpp_undef (pfile, macro)
 static int
 do_error (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   long here = CPP_WRITTEN (pfile);
   U_CHAR *text;
@@ -1476,7 +1509,7 @@ do_error (pfile, keyword)
 static int
 do_warning (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   U_CHAR *text;
   long here = CPP_WRITTEN(pfile);
@@ -1494,18 +1527,23 @@ do_warning (pfile, keyword)
   return 0;
 }
 
-/* Report program identification.  */
+/* Report program identification.
+   This is not precisely what cccp does with #ident, however I believe
+   it matches `closely enough' (behavior is identical as long as there
+   are no macros on the #ident line, which is pathological in my opinion).  */
 
 static int
 do_ident (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   /* Allow #ident in system headers, since that's not user's fault.  */
   if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
     cpp_pedwarn (pfile, "ANSI C does not allow `#ident'");
 
-  skip_rest_of_line (pfile);  /* Correct?  Appears to match cccp.  */
+  CPP_PUTS (pfile, "#ident ", 7);
+  cpp_skip_hspace (pfile);
+  copy_rest_of_line (pfile);
 
   return 0;
 }
@@ -1516,14 +1554,17 @@ do_ident (pfile, keyword)
 static int
 do_pragma (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
-  long here = CPP_WRITTEN (pfile);
+  long here;
   U_CHAR *buf;
+
+  CPP_PUTS (pfile, "#pragma ", 8);
+  cpp_skip_hspace (pfile);
   
+  here = CPP_WRITTEN (pfile);
   copy_rest_of_line (pfile);
   buf = pfile->token_buffer + here;
-  SKIP_WHITE_SPACE (buf);
   
   if (!strncmp (buf, "once", 4))
     {
@@ -1547,8 +1588,7 @@ do_pragma (pfile, keyword)
       else
        ip->ihash->control_macro = "";  /* never repeat */
     }
-
-  if (!strncmp (buf, "implementation", 14))
+  else if (!strncmp (buf, "implementation", 14))
     {
       /* Be quiet about `#pragma implementation' for a file only if it hasn't
         been included yet.  */
@@ -1561,7 +1601,7 @@ do_pragma (pfile, keyword)
       fname = p + 1;
       p = (U_CHAR *) index (fname, '\"');
 
-      fcopy = alloca (p - fname + 1);
+      fcopy = (U_CHAR *) alloca (p - fname + 1);
       bcopy (fname, fcopy, p - fname);
       fcopy[p-fname] = '\0';
 
@@ -1571,6 +1611,65 @@ do_pragma (pfile, keyword)
          "`#pragma implementation' for `%s' appears after file is included",
                     fcopy);
     }
+  else if (!strncmp (buf, "poison", 6))
+    {
+      /* Poison these symbols so that all subsequent usage produces an
+        error message.  */
+      U_CHAR *p = buf + 6;
+      size_t plen;
+      U_CHAR *syms;
+      int writeit;
+
+      SKIP_WHITE_SPACE (p);
+      plen = strlen(p) + 1;
+
+      syms = (U_CHAR *) alloca (plen);
+      memcpy (syms, p, plen);
+
+      /* As a rule, don't include #pragma poison commands in output,  
+         unless the user asks for them.  */
+      writeit = (CPP_OPTIONS (pfile)->debug_output
+                || CPP_OPTIONS (pfile)->dump_macros == dump_definitions
+                || CPP_OPTIONS (pfile)->dump_macros == dump_names);
+
+      if (writeit)
+       CPP_SET_WRITTEN (pfile, here);
+      else
+       CPP_SET_WRITTEN (pfile, here-8);
+
+      if (writeit)
+       {
+         CPP_RESERVE (pfile, plen + 7);
+         CPP_PUTS_Q (pfile, "poison", 7);
+       }
+
+      while (*syms != '\0')
+       {
+         U_CHAR *end = syms;
+         
+         while (is_idchar(*end))
+           end++;
+
+         if (!is_hspace(*end) && *end != '\0')
+           {
+             cpp_error (pfile, "invalid #pragma poison directive");
+             return 1;
+           }
+
+         if (cpp_push_buffer (pfile, syms, end - syms) != NULL)
+           {
+             do_define (pfile, keyword);
+             cpp_pop_buffer (pfile);
+           }
+         if (writeit)
+           {
+             CPP_PUTC_Q (pfile, ' ');
+             CPP_PUTS_Q (pfile, syms, end - syms);
+           }
+         syms = end;
+         SKIP_WHITE_SPACE (syms);
+       }
+    }
 
   return 0;
 }
@@ -1581,7 +1680,7 @@ do_pragma (pfile, keyword)
 static int
 do_sccs (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (CPP_PEDANTIC (pfile))
     cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'");
@@ -1590,6 +1689,81 @@ do_sccs (pfile, keyword)
 }
 #endif
 \f
+
+/* We've found an `#if' directive.  If the only thing before it in
+   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
+   malloc'd copy of SYMBOL.  Otherwise, return NULL.  */
+
+static U_CHAR *
+detect_if_not_defined (pfile)
+     cpp_reader *pfile;
+{
+  U_CHAR *control_macro = 0;
+
+  if (pfile->only_seen_white == 2)
+    {
+      char *ident;
+      enum cpp_token token;
+      int base_offset;
+      int token_offset;
+      int need_rparen = 0;
+
+      /* Save state required for restore.  */
+      pfile->no_macro_expand++;
+      parse_set_mark (pfile);
+      base_offset = CPP_WRITTEN (pfile);
+
+      /* Look for `!', */
+      if (get_directive_token (pfile) != CPP_OTHER
+         || CPP_WRITTEN (pfile) != (size_t) base_offset + 1
+         || CPP_PWRITTEN (pfile)[-1] != '!')
+       goto restore;
+
+      /* ...then `defined', */
+      token_offset = CPP_WRITTEN (pfile);
+      token = get_directive_token (pfile);
+      if (token != CPP_NAME)
+       goto restore;
+      ident = pfile->token_buffer + token_offset;
+      CPP_NUL_TERMINATE (pfile);
+      if (strcmp (ident, "defined"))
+       goto restore;
+
+      /* ...then an optional '(' and the name, */
+      token_offset = CPP_WRITTEN (pfile);
+      token = get_directive_token (pfile);
+      if (token == CPP_LPAREN)
+       {
+         token_offset = CPP_WRITTEN (pfile);
+         token = get_directive_token (pfile);
+         if (token != CPP_NAME)
+           goto restore;
+         need_rparen = 1;
+       }
+      else if (token != CPP_NAME)
+       goto restore;
+
+      ident = pfile->token_buffer + token_offset;
+      CPP_NUL_TERMINATE (pfile);
+
+      /* ...then the ')', if necessary, */
+      if ((!need_rparen || get_directive_token (pfile) == CPP_RPAREN)
+         /* ...and make sure there's nothing else on the line.  */
+         && get_directive_token (pfile) == CPP_VSPACE)
+       control_macro = xstrdup (ident);
+
+    restore:
+      CPP_SET_WRITTEN (pfile, base_offset);
+      pfile->no_macro_expand--;
+      parse_goto_mark (pfile);
+    }
+
+  return control_macro;
+}
+
 /*
  * handle #if command by
  *   1) inserting special `defined' keyword into the hash table
@@ -1606,10 +1780,11 @@ do_sccs (pfile, keyword)
 static int
 do_if (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
+  U_CHAR *control_macro = detect_if_not_defined (pfile);
   HOST_WIDEST_INT value = eval_if_expression (pfile);
-  conditional_skip (pfile, value == 0, T_IF, NULL_PTR);
+  conditional_skip (pfile, value == 0, T_IF, control_macro);
   return 0;
 }
 
@@ -1621,7 +1796,7 @@ do_if (pfile, keyword)
 static int
 do_elif (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) {
     cpp_error (pfile, "`#elif' not within a conditional");
@@ -1685,7 +1860,7 @@ eval_if_expression (pfile)
 static int
 do_xifdef (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword;
+     const struct directive *keyword;
 {
   int skip;
   cpp_buffer *ip = CPP_BUFFER (pfile);
@@ -1723,6 +1898,11 @@ do_xifdef (pfile, keyword)
          control_macro = (U_CHAR *) xmalloc (ident_length + 1);
          bcopy (ident, control_macro, ident_length + 1);
        }
+      if (hp != NULL && hp->type == T_POISON)
+       {
+         cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
+         skip = !skip;
+       }
     }
   else
     {
@@ -1748,7 +1928,7 @@ do_xifdef (pfile, keyword)
       else {
        U_CHAR *cp = buf;
        fprintf (pcp_outfile, "#undef ");
-       while (is_idchar[*cp]) /* Ick! */
+       while (is_idchar(*cp)) /* Ick! */
          fputc (*cp++, pcp_outfile);
        putc ('\n', pcp_outfile);
       }
@@ -1774,9 +1954,7 @@ conditional_skip (pfile, skip, type, control_macro)
 
   temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
   temp->fname = CPP_BUFFER (pfile)->nominal_fname;
-#if 0
   temp->lineno = CPP_BUFFER (pfile)->lineno;
-#endif
   temp->next = pfile->if_stack;
   temp->control_macro = control_macro;
   pfile->if_stack = temp;
@@ -1803,7 +1981,7 @@ consider_directive_while_skipping (pfile, stack)
     IF_STACK_FRAME *stack; 
 {
   long ident_len, ident;
-  struct directive *kt;
+  const struct directive *kt;
   IF_STACK_FRAME *temp;
     
   cpp_skip_hspace (pfile);
@@ -1958,7 +2136,7 @@ skip_if_group (pfile)
 static int
 do_else (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
 
@@ -2000,14 +2178,14 @@ do_else (pfile, keyword)
 static int
 do_endif (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (CPP_PEDANTIC (pfile))
     validate_else (pfile, "#endif");
   skip_rest_of_line (pfile);
 
   if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
-    cpp_error (pfile, "unbalanced `#endif'");
+    cpp_error (pfile, "`#endif' not within a conditional");
   else
     {
       IF_STACK_FRAME *temp = pfile->if_stack;
@@ -2055,7 +2233,7 @@ do_endif (pfile, keyword)
 static void
 validate_else (pfile, directive)
      cpp_reader *pfile;
-     char *directive;
+     const char *directive;
 {
   int c;
   cpp_skip_hspace (pfile);
@@ -2065,6 +2243,25 @@ validate_else (pfile, directive)
                 "text following `%s' violates ANSI standard", directive);
 }
 
+/* Convert T_IF, etc. to a string.   Used in error messages.  */
+static const char *
+if_directive_name (pfile, ifs)
+     cpp_reader *pfile;
+     struct if_stack *ifs;
+{
+  switch (ifs->type)
+    {
+    case T_IF:     return "#if";
+    case T_IFDEF:   return "#ifdef";
+    case T_IFNDEF:  return "#ifndef";
+    case T_ELIF:    return "#elif";
+    case T_ELSE:    return "#else";
+    default:
+      cpp_fatal (pfile, "impossible if_stack->type value %d", ifs->type);
+      return "unknown";
+    }
+}
+
 /* Get the next token, and add it to the text in pfile->token_buffer.
    Return the kind of token we got.  */
   
@@ -2081,7 +2278,11 @@ cpp_get_token (pfile)
   if (c == EOF)
     {
     handle_eof:
-      if (CPP_BUFFER (pfile)->seen_eof)
+      if (CPP_BUFFER (pfile)->manual_pop)
+       /* If we've been reading from redirected input, the
+          frontend will pop the buffer.  */
+       return CPP_EOF;
+      else if (CPP_BUFFER (pfile)->seen_eof)
        {
          if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)) == CPP_NULL_BUFFER (pfile))
            return CPP_EOF;
@@ -2091,9 +2292,23 @@ cpp_get_token (pfile)
        }
       else
        {
-         cpp_buffer *next_buf
-           = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
-         CPP_BUFFER (pfile)->seen_eof = 1;
+         cpp_buffer *next_buf = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
+         struct if_stack *ifs, *nifs;
+
+         /* Unwind the conditional stack and generate error messages.  */
+         for (ifs = pfile->if_stack;
+              ifs != CPP_BUFFER (pfile)->if_stack;
+              ifs = nifs)
+           {
+             cpp_error_with_line (pfile, ifs->lineno, -1,
+                                  "unterminated `%s' conditional",
+                                  if_directive_name (pfile, ifs));
+
+             nifs = ifs->next;
+             free (ifs);
+           }
+         pfile->if_stack = ifs;
+
          if (CPP_BUFFER (pfile)->nominal_fname
              && next_buf != CPP_NULL_BUFFER (pfile))
            {
@@ -2106,6 +2321,8 @@ cpp_get_token (pfile)
              output_line_command (pfile, leave_file);
              CPP_BUFFER (pfile) = cur_buffer;
            }
+
+         CPP_BUFFER (pfile)->seen_eof = 1;
          return CPP_POP;
        }
     }
@@ -2183,6 +2400,12 @@ cpp_get_token (pfile)
 
          if (!pfile->only_seen_white)
            goto randomchar;
+         /* -traditional directives are recognized only with the # in
+            column 1.
+            XXX Layering violation.  */
+         if (CPP_TRADITIONAL (pfile)
+             && CPP_BUFFER (pfile)->cur - CPP_BUFFER (pfile)->line_base != 1)
+           goto randomchar;
          if (handle_directive (pfile))
            return CPP_DIRECTIVE;
          pfile->only_seen_white = 0;
@@ -2226,8 +2449,24 @@ cpp_get_token (pfile)
          c2 = PEEKC ();
          if (c2 == '-' && opts->chill)
            goto comment;  /* Chill style comment */
-         if (c2 == '-' || c2 == '=' || c2 == '>')
+         if (c2 == '-' || c2 == '=')
            goto op2;
+         if (c2 == '>')
+           {
+             if (opts->cplusplus && PEEKN (1) == '*')
+               {
+                 /* In C++, there's a ->* operator.  */
+                 token = CPP_OTHER;
+                 pfile->only_seen_white = 0;
+                 CPP_RESERVE (pfile, 4);
+                 CPP_PUTC_Q (pfile, c);
+                 CPP_PUTC_Q (pfile, GETC ());
+                 CPP_PUTC_Q (pfile, GETC ());
+                 CPP_NUL_TERMINATE_Q (pfile);
+                 return token;
+               }
+             goto op2;
+           }
          goto randomchar;
 
        case '<':
@@ -2273,7 +2512,8 @@ cpp_get_token (pfile)
          c2 = PEEKC ();
          if (c2 == '=')
            goto op2;
-         if (c2 != c)
+         /* GNU C++ supports MIN and MAX operators <? and >?.  */
+         if (c2 != c && (!opts->cplusplus || c2 != '?'))
            goto randomchar;
          FORWARD(1);
          CPP_RESERVE (pfile, 4);
@@ -2295,6 +2535,11 @@ cpp_get_token (pfile)
              c = GETC ();
              goto number;
            }
+
+         /* In C++ there's a .* operator.  */
+         if (opts->cplusplus && c2 == '*')
+           goto op2;
+
          if (c2 == '.' && PEEKN(1) == '.')
            {
              CPP_RESERVE(pfile, 4);
@@ -2338,7 +2583,7 @@ cpp_get_token (pfile)
              c = PEEKC ();
              if (c == EOF)
                break;
-             if (!is_idchar[c] && c != '.'
+             if (!is_idchar(c) && c != '.'
                  && ((c2 != 'e' && c2 != 'E'
                       && ((c2 != 'p' && c2 != 'P') || CPP_C89 (pfile)))
                      || (c != '+' && c != '-')))
@@ -2363,7 +2608,7 @@ cpp_get_token (pfile)
                  c = GETC();
                  if (c == EOF)
                    goto chill_number_eof;
-                 if (!is_idchar[c])
+                 if (!is_idchar(c))
                    break;
                  CPP_PUTC (pfile, c);
                }
@@ -2485,7 +2730,7 @@ cpp_get_token (pfile)
            {
              CPP_PUTC (pfile, c);
              c = PEEKC ();
-             if (c == EOF || !is_hor_space[c])
+             if (c == EOF || !is_hspace(c))
                break;
              FORWARD(1);
            }
@@ -2581,7 +2826,7 @@ parse_name (pfile, c)
 {
   for (;;)
   {
-      if (! is_idchar[c])
+      if (! is_idchar(c))
       {
          FORWARD (-1);
          break;
@@ -2603,7 +2848,7 @@ parse_name (pfile, c)
 /* Parse a string starting with C.  A single quoted string is treated
    like a double -- some programs (e.g., troff) are perverse this way.
    (However, a single quoted string is not allowed to extend over
-   multiple lines.  */
+   multiple lines.)  */
 static void
 parse_string (pfile, c)
      cpp_reader *pfile;
@@ -2628,17 +2873,15 @@ parse_string (pfile, c)
              cpp_pop_buffer (pfile);
              continue;
            }
-         if (!CPP_TRADITIONAL (pfile))
-           {
-             cpp_error_with_line (pfile, start_line, start_column,
-                                "unterminated string or character constant");
-             if (pfile->multiline_string_line != start_line
-                 && pfile->multiline_string_line != 0)
-               cpp_error_with_line (pfile,
-                                    pfile->multiline_string_line, -1,
-                              "possible real start of unterminated constant");
-             pfile->multiline_string_line = 0;
-           }
+
+         cpp_error_with_line (pfile, start_line, start_column,
+                              "unterminated string or character constant");
+         if (pfile->multiline_string_line != start_line
+             && pfile->multiline_string_line != 0)
+           cpp_error_with_line (pfile,
+                                pfile->multiline_string_line, -1,
+                        "possible real start of unterminated constant");
+         pfile->multiline_string_line = 0;
          break;
        }
       CPP_PUTC (pfile, cc);
@@ -2647,11 +2890,17 @@ parse_string (pfile, c)
        case '\n':
          CPP_BUMP_LINE (pfile);
          pfile->lineno++;
-         /* Traditionally, end of line ends a string constant with
-            no error.  */
-         if (CPP_TRADITIONAL (pfile))
+
+         /* In Fortran and assembly language, silently terminate
+            strings of either variety at end of line.  This is a
+            kludge around not knowing where comments are in these
+            languages.  */
+         if (CPP_OPTIONS (pfile)->lang_fortran
+             || CPP_OPTIONS (pfile)->lang_asm)
            return;
-         /* Character constants may not extend over multiple lines.  */
+         /* Character constants may not extend over multiple lines.
+            In Standard C, neither may strings.  We accept multiline
+            strings as an extension.  */
          if (c == '\'')
            {
              cpp_error_with_line (pfile, start_line, start_column,
@@ -2659,10 +2908,8 @@ parse_string (pfile, c)
              return;
            }
          if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
-           {
-             cpp_pedwarn_with_line (pfile, start_line, start_column,
-                                    "string constant runs past end of line");
-           }
+           cpp_pedwarn_with_line (pfile, start_line, start_column,
+                                  "string constant runs past end of line");
          if (pfile->multiline_string_line == 0)
            pfile->multiline_string_line = start_line;
          break;
@@ -2708,7 +2955,7 @@ parse_assertion (pfile)
   int c, dropwhite;
   cpp_skip_hspace (pfile);
   c = PEEKC();
-  if (! is_idstart[c])
+  if (! is_idstart(c))
     {
       cpp_error (pfile, "assertion predicate is not an identifier");
       return 0;
@@ -2720,7 +2967,7 @@ parse_assertion (pfile)
   c = PEEKC();
   if (c != '(')
     {
-      if (is_hor_space[c] || c == '\r')
+      if (is_hspace(c) || c == '\r')
        cpp_skip_hspace (pfile);
       c = PEEKC();
     }
@@ -2732,7 +2979,7 @@ parse_assertion (pfile)
   dropwhite = 1;
   while ((c = GETC()) != ')')
     {
-      if (is_hor_space[c])
+      if (is_space(c))
        {
          if (! dropwhite)
            {
@@ -2773,7 +3020,7 @@ parse_assertion (pfile)
 static int
 do_assert (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   char *sym;
   int ret, c;
@@ -2831,15 +3078,15 @@ do_assert (pfile, keyword)
   return 0;
 
  error:
-  pfile->limit = (unsigned char *) sym; /* Pop */
   skip_rest_of_line (pfile);
-  return 1;
+  pfile->limit = (unsigned char *) sym; /* Pop */
+  return 0;
 }
 
 static int
 do_unassert (pfile, keyword)
      cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
+     const struct directive *keyword ATTRIBUTE_UNUSED;
 {
   int c, ret;
   char *sym;
@@ -2900,9 +3147,9 @@ do_unassert (pfile, keyword)
   pfile->limit = (unsigned char *) sym; /* Pop */
   return 0;
  error:
-  pfile->limit = (unsigned char *) sym; /* Pop */
   skip_rest_of_line (pfile);
-  return 1;
+  pfile->limit = (unsigned char *) sym; /* Pop */
+  return 0;
 }
 
 /* Process STR as if it appeared as the body of an #unassert. */
@@ -2984,7 +3231,7 @@ parse_goto_mark (pfile)
   ip->mark = -1;
 }
 
-void
+static void
 cpp_print_file_and_line (pfile)
      cpp_reader *pfile;
 {
@@ -3220,12 +3467,12 @@ cpp_pedwarn_with_line VPROTO ((cpp_reader * pfile, int line, int column,
    giving specified file name and line number, not current.  */
 
 void
-cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
-                                       const char *msgid, ...))
+cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, const char *file,
+                                       int line, const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
   cpp_reader *pfile;
-  char *file;
+  const char *file;
   int line;
   const char *msgid;
 #endif
@@ -3235,7 +3482,7 @@ cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
 
 #ifndef ANSI_PROTOTYPES
   pfile = va_arg (ap, cpp_reader *);
-  file = va_arg (ap, char *);
+  file = va_arg (ap, const char *);
   line = va_arg (ap, int);
   msgid = va_arg (ap, const char *);
 #endif
@@ -3252,11 +3499,11 @@ cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line,
 /* my_strerror - return the descriptive text associated with an
    `errno' code.  */
 
-static char *
+static const char *
 my_strerror (errnum)
      int errnum;
 {
-  char *result;
+  const char *result;
 
 #ifndef VMS
 #ifndef HAVE_STRERROR