OSDN Git Service

* cppexp.c: Don't include cpphash.h.
[pf3gnuchains/gcc-fork.git] / gcc / cpplib.c
index 1c85ba7..c64e682 100644 (file)
@@ -1,5 +1,5 @@
 /* CPP Library.
-   Copyright (C) 1986, 87, 89, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1986, 87, 89, 92-99, 2000 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -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))
@@ -36,19 +35,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
    (Note that it is false while we're expanding macro *arguments*.) */
 #define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
 
-/* Forward declarations.  */
-
-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,
-                                               enum node_type, U_CHAR *));
-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 *));
+/* ACTIVE_MARK_P is true if there's a live mark in the buffer, in which
+   case CPP_BUMP_LINE must not be called.  */
+#define ACTIVE_MARK_P() (CPP_BUFFER (pfile)->mark != -1)
 
 /* External declarations.  */
 
@@ -86,24 +75,38 @@ static int do_sccs PARAMS ((cpp_reader *, const struct directive *));
 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 *));
+
+/* Forward declarations.  */
+
+static void validate_else              PARAMS ((cpp_reader *, const char *));
+static HOST_WIDEST_INT eval_if_expression PARAMS ((cpp_reader *));
+static void conditional_skip           PARAMS ((cpp_reader *, int,
+                                               enum node_type, U_CHAR *));
+static void skip_if_group              PARAMS ((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 *));
+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 void skip_rest_of_line          PARAMS ((cpp_reader *));
+static void cpp_skip_hspace            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 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_FRAME *));
+static void skip_block_comment         PARAMS ((cpp_reader *));
+static void skip_line_comment          PARAMS ((cpp_reader *));
+static void parse_set_mark             PARAMS ((cpp_reader *));
+static void parse_goto_mark            PARAMS ((cpp_reader *));
 
 /* Here is the actual list of #-directives.
    This table is ordered by frequency of occurrence; the numbers
@@ -190,7 +193,7 @@ cpp_grow_buffer (pfile, n)
   CPP_SET_WRITTEN (pfile, old_written);
 }
 
-/* Process the string STR as if it appeared as the body of a #define
+/* Process the string STR as if it appeared as the body of a #define.
    If STR is just an identifier, define it with value 1.
    If STR has anything after the identifier, then it should
    be identifier=definition. */
@@ -203,21 +206,28 @@ cpp_define (pfile, str)
   U_CHAR *buf, *p;
   size_t count;
 
-  /* Copy the entire option so we can modify it.  */
-  count = strlen (str) + 3;
-  buf = (U_CHAR *) alloca (count);
-  memcpy (buf, str, count - 2);
-  /* Change the first "=" in the string to a space.  If there is none,
-     tack " 1" on the end. */
-  p = (U_CHAR *) strchr (buf, '=');
+  p = strchr (str, '=');
+  /* Copy the entire option so we can modify it. 
+     Change the first "=" in the string to a space.  If there is none,
+     tack " 1" on the end.  Then add a newline and a NUL.  */
+  
   if (p)
     {
-      *p = ' ';
-      count -= 2;
+      count = strlen (str) + 2;
+      buf = (U_CHAR *) alloca (count);
+      memcpy (buf, str, count - 2);
+      buf[p - str] = ' ';
+      buf[count - 2] = '\n';
+      buf[count - 1] = '\0';
     }
   else
-      strcpy (&buf[count-3], " 1");
-  
+    {
+      count = strlen (str) + 4;
+      buf = (U_CHAR *) alloca (count);
+      memcpy (buf, str, count - 4);
+      strcpy (&buf[count-4], " 1\n");
+    }
+
   if (cpp_push_buffer (pfile, buf, count - 1) != NULL)
     {
       do_define (pfile, NULL);
@@ -238,6 +248,21 @@ cpp_assert (pfile, str)
     }
 }
 
+/* Determine whether the identifier ID, of length LEN, is a defined macro.  */
+int
+cpp_defined (pfile, id, len)
+     cpp_reader *pfile;
+     const U_CHAR *id;
+     int len;
+{
+  HASHNODE *hp = cpp_lookup (pfile, id, len);
+  if (hp && hp->type == T_POISON)
+    {
+      cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
+      return 0;
+    }
+  return (hp != NULL);
+}
 
 static enum cpp_token
 null_underflow (pfile)
@@ -254,152 +279,146 @@ null_cleanup (pbuf, pfile)
   return 0;
 }
 
-/* Skip a comment - C, C++, or Chill style.  M is the first character
-   of the comment marker.  If this really is a comment, skip to its
-   end and return ' '.  If we hit end-of-file before end-of-comment,
-   return EOF.  If this is not a comment, return M (which will be
-   '/' or '-').  */
-
-static int
-skip_comment (pfile, m)
+/* Skip a C-style block comment.  We know it's a comment, and point is
+   at the second character of the starter.  */
+static void
+skip_block_comment (pfile)
      cpp_reader *pfile;
-     int m;
 {
-  if (m == '/' && PEEKC() == '*')
+  int c, prev_c = -1;
+  long line, col;
+
+  FORWARD(1);
+  cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
+  for (;;)
     {
-      int c, prev_c = -1;
-      long line, col;
-      
-      FORWARD(1);
-      cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
-      for (;;)
+      c = GETC ();
+      if (c == EOF)
        {
-         c = GETC ();
-         if (c == EOF)
-           {
-             cpp_error_with_line (pfile, line, col, "unterminated comment");
-             return EOF;
-           }
-         else if (c == '\n' || c == '\r')
-           /* \r cannot be a macro escape marker here. */
+         cpp_error_with_line (pfile, line, col, "unterminated comment");
+         return;
+       }
+      else if (c == '\n' || c == '\r')
+       {
+         /* \r cannot be a macro escape marker here. */
+         if (!ACTIVE_MARK_P())
            CPP_BUMP_LINE (pfile);
-         else if (c == '/' && prev_c == '*')
-           return ' ';
-         else if (c == '*' && prev_c == '/'
-                  && CPP_OPTIONS (pfile)->warn_comments)
-           cpp_warning (pfile, "`/*' within comment");
-
-         prev_c = c;
        }
+      else if (c == '/' && prev_c == '*')
+       return;
+      else if (c == '*' && prev_c == '/'
+              && CPP_OPTIONS (pfile)->warn_comments)
+       cpp_warning (pfile, "`/*' within comment");
+
+      prev_c = c;
     }
-  else if ((m == '/' && PEEKC() == '/'
-           && CPP_OPTIONS (pfile)->cplusplus_comments)
-          || (m == '-' && PEEKC() == '-'
-              && CPP_OPTIONS (pfile)->chill))
+}
+
+/* Skip a C++/Chill line comment.  We know it's a comment, and point
+   is at the second character of the initiator.  */
+static void
+skip_line_comment (pfile)
+     cpp_reader *pfile;
+{
+  FORWARD(1);
+  for (;;)
     {
-      FORWARD(1);
-      for (;;)
+      int c = GETC ();
+
+      /* We don't have to worry about EOF in here.  */
+      if (c == '\n')
        {
-         int c = GETC ();
-         if (c == EOF)
-           return ' '; /* Allow // to be terminated by EOF.  */
-             if (c == '\n')
-               {
-                 /* Don't consider final '\n' to be part of comment.  */
-                 FORWARD(-1);
-                 return ' ';
-               }
-             else if (c == '\r')
-               /* \r cannot be a macro escape marker here. */
-               CPP_BUMP_LINE (pfile);
+         /* Don't consider final '\n' to be part of comment.  */
+         FORWARD(-1);
+         return;
+       }
+      else if (c == '\r')
+       {
+         /* \r cannot be a macro escape marker here. */
+         if (!ACTIVE_MARK_P())
+           CPP_BUMP_LINE (pfile);
+         if (CPP_OPTIONS (pfile)->warn_comments)
+           cpp_warning (pfile, "backslash-newline within line comment");
        }
     }
-  else
-    return m;
 }
 
-/* Identical to skip_comment except that it copies the comment into the
-   token_buffer.  This is used if put_out_comments.  */
+/* Skip a comment - C, C++, or Chill style.  M is the first character
+   of the comment marker.  If this really is a comment, skip to its
+   end and return ' '.  If this is not a comment, return M (which will
+   be '/' or '-').  */
+
 static int
-copy_comment (pfile, m)
+skip_comment (pfile, m)
      cpp_reader *pfile;
      int m;
 {
   if (m == '/' && PEEKC() == '*')
     {
-      int c, prev_c = -1;
-      long line, col;
-
-      CPP_PUTC (pfile, '/');
-      CPP_PUTC (pfile, '*');
-      FORWARD(1);
-      cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
-      for (;;)
-       {
-         c = GETC ();
-         if (c == EOF)
-           {
-             cpp_error_with_line (pfile, line, col, "unterminated comment");
-             /* We must pretend this was a legitimate comment, so that the
-                output in token_buffer is not passed back tagged CPP_POP. */
-             return ' ';
-           }
-         else if (c == '\r')
-           {
-             /* \r cannot be a macro escape marker here. */
-             CPP_BUMP_LINE (pfile);
-             continue;
-           }
-
-         CPP_PUTC (pfile, c);
-         if (c == '\n')
-           {
-             pfile->lineno++;
-             CPP_BUMP_LINE (pfile);
-           }
-         else if (c == '/' && prev_c == '*')
-           return ' ';
-         else if (c == '*' && prev_c == '/'
-                  && CPP_OPTIONS (pfile)->warn_comments)
-           cpp_warning (pfile, "`/*' within comment");
-
-         prev_c = c;
-       }
+      skip_block_comment (pfile);
+      return ' ';
     }
-  else if ((m == '/' && PEEKC() == '/'
-           && CPP_OPTIONS (pfile)->cplusplus_comments)
-          || (m == '-' && PEEKC() == '-'
-              && CPP_OPTIONS (pfile)->chill))
+  else if (m == '/' && PEEKC() == '/')
     {
-      CPP_PUTC (pfile, m);
-      CPP_PUTC (pfile, m);
-      FORWARD(1);
-      for (;;)
+      if (CPP_BUFFER (pfile)->system_header_p)
        {
-         int c = GETC ();
-         if (c == EOF)
-           return ' '; /* Allow line comments to be terminated by EOF. */
-         else if (c == '\n')
+         /* We silently allow C++ comments in system headers, irrespective
+            of conformance mode, because lots of busted systems do that
+            and trying to clean it up in fixincludes is a nightmare.  */
+         skip_line_comment (pfile);
+         return ' ';
+       }
+      else if (CPP_OPTIONS (pfile)->cplusplus_comments)
+       {
+         if (CPP_OPTIONS (pfile)->c89
+             && CPP_PEDANTIC (pfile)
+             && ! CPP_BUFFER (pfile)->warned_cplusplus_comments)
            {
-             /* Don't consider final '\n' to be part of comment.  */
-             FORWARD(-1);
-             return ' ';
+             cpp_pedwarn (pfile,
+                          "C++ style comments are not allowed in ISO C89");
+             cpp_pedwarn (pfile,
+                          "(this will be reported only once per input file)");
+             CPP_BUFFER (pfile)->warned_cplusplus_comments = 1;
            }
-         else if (c == '\r')
-           /* \r cannot be a macro escape marker here. */
-           CPP_BUMP_LINE (pfile);
-
-         CPP_PUTC (pfile, c);
+         skip_line_comment (pfile);
+         return ' ';
        }
+      else
+       return m;
+    }
+  else if (m == '-' && PEEKC() == '-'
+          && CPP_OPTIONS (pfile)->chill)
+    {
+      skip_line_comment (pfile);
+      return ' ';
     }
   else
     return m;
 }
 
+/* Identical to skip_comment except that it copies the comment into the
+   token_buffer.  This is used if !discard_comments.  */
+static int
+copy_comment (pfile, m)
+     cpp_reader *pfile;
+     int m;
+{
+  U_CHAR *start = CPP_BUFFER (pfile)->cur;  /* XXX Layering violation */
+  U_CHAR *limit;
+
+  if (skip_comment (pfile, m) == m)
+    return m;
+
+  CPP_PUTC (pfile, m);
+  for (limit = CPP_BUFFER (pfile)->cur; start <= limit; start++)
+    if (*start != '\r')
+      CPP_PUTC (pfile, *start);
+  return ' ';
+}
 
 /* Skip whitespace \-newline and comments.  Does not macro-expand.  */
 
-void
+static void
 cpp_skip_hspace (pfile)
      cpp_reader *pfile;
 {
@@ -409,7 +428,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",
@@ -432,9 +451,7 @@ cpp_skip_hspace (pfile)
       else if (c == '/' || c == '-')
        {
          c = skip_comment (pfile, c);
-         if (c == EOF)
-           return;
-         else if (c != ' ')
+         if (c  != ' ')
            break;
        }
       else
@@ -474,10 +491,11 @@ copy_rest_of_line (pfile)
          parse_string (pfile, c);
          continue;
        case '/':
-         if (PEEKC() == '*' && CPP_TRADITIONAL (pfile))
+         if (PEEKC() == '*')
            {
-             CPP_PUTS (pfile, "/**/", 4);
-             skip_comment (pfile, c);
+             if (CPP_TRADITIONAL (pfile))
+               CPP_PUTS (pfile, "/**/", 4);
+             skip_block_comment (pfile);
              continue;
            }
          /* else fall through */
@@ -501,7 +519,7 @@ copy_rest_of_line (pfile)
    the scan itself.  >75% of calls to copy_r_o_l are from here or
    skip_if_group, which means the common case is to copy stuff into the
    token_buffer only to discard it.  */
-void
+static void
 skip_rest_of_line (pfile)
      cpp_reader *pfile;
 {
@@ -526,15 +544,28 @@ 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)
+       return 0;
+
+      if (CPP_PEDANTIC (pfile)
+         && ! CPP_PREPROCESSED (pfile)
+         && ! CPP_BUFFER (pfile)->manual_pop)
        cpp_pedwarn (pfile, "`#' followed by integer");
       do_line (pfile, NULL);
       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());
@@ -542,28 +573,35 @@ handle_directive (pfile)
   ident_length = CPP_PWRITTEN (pfile) - ident;
   if (ident_length == 0)
     {
-      /* A line of just `#' becomes blank.  */
-      if (PEEKC() == '\n')
-       return 1;
-      else
-       return 0;
+      /* A line of just `#' becomes blank.  A line with something
+        other than an identifier after the # is reparsed as a non-
+        directive line.  */
+      CPP_SET_WRITTEN (pfile, old_written);
+      return (PEEKC() == '\n');
     }
 
-  /*
-   * Decode the keyword and call the appropriate expansion
-   * routine, after moving the input pointer up to the next line.
-   */
+  /* Decode the keyword and call the appropriate expansion routine.  */
   for (kt = directive_table; ; kt++)
     {
       if (kt->length <= 0)
-       return 0;
+       /* # identifier, but not a legit directive.  Pass onward as a
+          CPP_DIRECTIVE token anyway - let the consumer worry about it.  */
+       return 1;
       if (kt->length == ident_length
          && !strncmp (kt->name, ident, ident_length)) 
        break;
     }
 
   CPP_SET_WRITTEN (pfile, old_written);
-  (*kt->func) (pfile, kt);
+
+  if (pfile->no_directives)
+    {
+      cpp_error (pfile, "`#%s' may not be used inside a macro argument",
+                kt->name);
+      skip_rest_of_line (pfile);
+    }
+  else
+    (*kt->func) (pfile, kt);
 
   return 1;
 }
@@ -590,103 +628,107 @@ pass_thru_directive (buf, len, pfile, keyword)
   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;
      const U_CHAR *symname;
-     int assertion;
 {
   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;
      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 = (U_CHAR *) alloca (end - buf + 1);
-  bcopy (buf, macro, end - buf + 1);
+  memcpy (macro, buf, end - buf + 1);
   end = macro + (end - buf);
 
   CPP_SET_WRITTEN (pfile, here);
 
-  mdef = create_definition (macro, end, pfile, keyword == NULL);
+  mdef = create_definition (macro, end, pfile);
   if (mdef.defn == 0)
     return 0;
 
-  hashcode = hashf (mdef.symnam, mdef.symlen, HASHSIZE);
-
-  if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen, hashcode)) != NULL)
+  if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen)) != NULL)
     {
       int ok = 0;
-      /* Redefining a precompiled key is ok.  */
-      if (hp->type == T_PCSTRING)
-       ok = 1;
+      /* Redefining a poisoned identifier is even worse than `not ok'.  */
+      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)
        {
-         cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
-         if (hp->type == T_MACRO)
+         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_OPTIONS (pfile)->done_initializing)
            cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
-                                           hp->value.defn->line,
+                                           hp->value.defn->line, -1,
                        "this is the location of the previous definition");
        }
-      /* Replace the old definition.  */
-      hp->type = T_MACRO;
-      hp->value.defn = mdef.defn;
+      if (hp->type != T_POISON)
+       {
+         /* Replace the old definition.  */
+         hp->type = new_type;
+         free_definition (hp->value.defn);
+         hp->value.defn = mdef.defn;
+       }
     }
   else
-    cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO,
-                (char *) mdef.defn, hashcode);
+    cpp_install (pfile, mdef.symnam, mdef.symlen, new_type, (char *)mdef.defn);
 
-  if (keyword)
+  if (keyword != NULL && keyword->type == T_DEFINE)
     {
       if (CPP_OPTIONS (pfile)->debug_output
          || CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
@@ -718,7 +760,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;
@@ -737,6 +779,8 @@ cpp_pop_buffer (pfile)
      cpp_reader *pfile;
 {
   cpp_buffer *buf = CPP_BUFFER (pfile);
+  if (ACTIVE_MARK_P())
+    cpp_ice (pfile, "mark active in cpp_pop_buffer");
   (*buf->cleanup) (buf, pfile);
   CPP_BUFFER (pfile) = CPP_PREV_BUFFER (buf);
   free (buf);
@@ -813,7 +857,7 @@ cpp_expand_to_buffer (pfile, buf, length)
 
   if (length < 0)
     {
-      cpp_fatal (pfile, "internal error: length < 0 in cpp_expand_to_buffer");
+      cpp_ice (pfile, "length < 0 in cpp_expand_to_buffer");
       return;
     }
 
@@ -951,30 +995,47 @@ output_line_command (pfile, file_change)
 /* Like cpp_get_token, except that it does not read past end-of-line.
    Also, horizontal space is skipped, and macros are popped.  */
 
-static enum cpp_token
+enum cpp_token
 get_directive_token (pfile)
      cpp_reader *pfile;
 {
+  long old_written = CPP_WRITTEN (pfile);
+  enum cpp_token token;
+
   for (;;)
     {
-      long old_written = CPP_WRITTEN (pfile);
-      enum cpp_token token;
       cpp_skip_hspace (pfile);
       if (PEEKC () == '\n')
-         return CPP_VSPACE;
+       return CPP_VSPACE;
+
       token = cpp_get_token (pfile);
-      switch (token)
-      {
-      case CPP_POP:
-         if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
-             return token;
-         /* ... else fall though ...  */
-      case CPP_HSPACE:  case CPP_COMMENT:
+      /* token could be hspace at the beginning of a macro.  */
+      if (token == CPP_HSPACE || token == CPP_COMMENT)
+       {
          CPP_SET_WRITTEN (pfile, old_written);
-         break;
-      default:
+         continue;
+       }
+
+      /* token cannot be vspace, it would have been caught above.  */
+      if (token == CPP_VSPACE)
+       {
+         cpp_ice (pfile, "VSPACE in get_directive_token");
          return token;
-      }
+       }
+
+      /* token cannot be POP unless the buffer is a macro buffer.  */
+      if (token != CPP_POP)
+       return token;
+
+      if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
+       {
+         cpp_ice (pfile, "POP of file buffer in get_directive_token");
+         return token;
+       }
+
+      /* We must pop the buffer by hand, or else cpp_get_token might
+        hand us white space or newline on the next invocation.  */
+      cpp_pop_buffer (pfile);
     }
 }
 \f
@@ -1103,7 +1164,7 @@ do_include (pfile, keyword)
 
   if (fp == CPP_NULL_BUFFER (pfile))
     {
-      cpp_fatal (pfile, "cpp internal error: fp == NULL_BUFFER in do_include");
+      cpp_ice (pfile, "fp == NULL_BUFFER in do_include");
       return 0;
     }
   
@@ -1331,7 +1392,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
@@ -1347,7 +1408,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;
@@ -1392,7 +1453,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);
@@ -1417,17 +1478,22 @@ do_undef (pfile, keyword)
 
   CPP_SET_WRITTEN (pfile, here);
 
-  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)
+  while ((hp = cpp_lookup (pfile, name, sym_length)) != 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, sym_length, pfile, keyword);
-      if (hp->type != T_MACRO)
-       cpp_warning (pfile, "undefining `%s'", hp->name);
-      delete_macro (hp);
+      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;
@@ -1439,14 +1505,19 @@ cpp_undef (pfile, macro)
      cpp_reader *pfile;
      U_CHAR *macro;
 {
-  if (cpp_push_buffer (pfile, macro, strlen (macro)))
+  /* Copy the string so we can append a newline.  */
+  size_t len = strlen (macro);
+  U_CHAR *buf = alloca (len + 2);
+  memcpy (buf, macro, len);
+  buf[len]     = '\n';
+  buf[len + 1] = '\0';
+  if (cpp_push_buffer (pfile, buf, len + 1))
     {
       do_undef (pfile, NULL);
       cpp_pop_buffer (pfile);
     }
 }
 
-\f
 /*
  * Report an error detected by the program we are processing.
  * Use the text of the line in the error message.
@@ -1579,6 +1650,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;
 }
@@ -1707,35 +1837,35 @@ do_elif (pfile, keyword)
      cpp_reader *pfile;
      const struct directive *keyword ATTRIBUTE_UNUSED;
 {
-  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_IF && pfile->if_stack->type != T_ELIF) {
-      cpp_error (pfile, "`#elif' after `#else'");
-#if 0
-      fprintf (stderr, " (matches line %d", pfile->if_stack->lineno);
-#endif
-      if (pfile->if_stack->fname != NULL && CPP_BUFFER (pfile)->fname != NULL
-         && strcmp (pfile->if_stack->fname,
-                    CPP_BUFFER (pfile)->nominal_fname) != 0)
-       fprintf (stderr, ", file %s", pfile->if_stack->fname);
-      fprintf (stderr, ")\n");
+  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_IF && pfile->if_stack->type != T_ELIF)
+       {
+         cpp_error (pfile, "`#elif' after `#else'");
+         cpp_error_with_line (pfile, pfile->if_stack->lineno, -1,
+                              "the conditional began here");
+       }
+      pfile->if_stack->type = T_ELIF;
     }
-    pfile->if_stack->type = T_ELIF;
-  }
 
   if (pfile->if_stack->if_succeeded)
     skip_if_group (pfile);
-  else {
-    HOST_WIDEST_INT value = eval_if_expression (pfile);
-    if (value == 0)
-      skip_if_group (pfile);
-    else {
-      ++pfile->if_stack->if_succeeded; /* continue processing input */
-      output_line_command (pfile, same_file);
+  else
+    {
+      HOST_WIDEST_INT value = eval_if_expression (pfile);
+      if (value == 0)
+       skip_if_group (pfile);
+      else
+       {
+         ++pfile->if_stack->if_succeeded;      /* continue processing input */
+         output_line_command (pfile, same_file);
+       }
     }
-  }
   return 0;
 }
 
@@ -1751,10 +1881,13 @@ eval_if_expression (pfile)
   HOST_WIDEST_INT value;
   long old_written = CPP_WRITTEN (pfile);
 
-  pfile->pcp_inside_if = 1;
+  /* Work around bug in cpp_get_token where it may mistake an
+     assertion for a directive.  */
+  pfile->only_seen_white = 0;
+
   value = cpp_parse_expr (pfile);
-  pfile->pcp_inside_if = 0;
 
+  skip_rest_of_line (pfile);
   CPP_SET_WRITTEN (pfile, old_written); /* Pop */
 
   return value;
@@ -1800,13 +1933,18 @@ do_xifdef (pfile, keyword)
     }
   else if (token == CPP_NAME)
     {
-      HASHNODE *hp = cpp_lookup (pfile, ident, ident_length, -1);
+      HASHNODE *hp = cpp_lookup (pfile, ident, ident_length);
       skip = (hp == NULL) ^ (keyword->type == T_IFNDEF);
       if (start_of_file && !skip)
        {
          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
     {
@@ -1824,20 +1962,6 @@ do_xifdef (pfile, keyword)
     }
   skip_rest_of_line (pfile);
 
-#if 0
-    if (pcp_outfile) {
-      /* Output a precondition for this macro.  */
-      if (hp && hp->value.defn->predefined)
-       fprintf (pcp_outfile, "#define %s\n", hp->name);
-      else {
-       U_CHAR *cp = buf;
-       fprintf (pcp_outfile, "#undef ");
-       while (is_idchar[*cp]) /* Ick! */
-         fputc (*cp++, pcp_outfile);
-       putc ('\n', pcp_outfile);
-      }
-#endif
-
   conditional_skip (pfile, skip, T_IF, control_macro);
   return 0;
 }
@@ -1858,9 +1982,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;
@@ -1914,13 +2036,10 @@ consider_directive_while_skipping (pfile, stack)
            return 0;
 
        case T_ELSE:
-           if (CPP_PEDANTIC (pfile) && pfile->if_stack != stack)
+           if (pfile->if_stack != stack)
              validate_else (pfile, "#else");
            /* fall through */
        case T_ELIF:
-           if (pfile->if_stack->type == T_ELSE)
-             cpp_error (pfile, "`%s' after `#else'", kt->name);
-           
            if (pfile->if_stack == stack)
              return 1;
            else
@@ -1930,7 +2049,7 @@ consider_directive_while_skipping (pfile, stack)
              }
 
            case T_ENDIF:
-               if (CPP_PEDANTIC (pfile) && pfile->if_stack != stack)
+               if (pfile->if_stack != stack)
                  validate_else (pfile, "#endif");
 
                if (pfile->if_stack == stack)
@@ -2044,36 +2163,36 @@ do_else (pfile, keyword)
      cpp_reader *pfile;
      const struct directive *keyword ATTRIBUTE_UNUSED;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-
-  if (CPP_PEDANTIC (pfile))
-    validate_else (pfile, "#else");
+  validate_else (pfile, "#else");
   skip_rest_of_line (pfile);
 
-  if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) {
-    cpp_error (pfile, "`#else' not within a conditional");
-    return 0;
-  } 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;
-
-    if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF) {
-      cpp_error (pfile, "`#else' after `#else'");
-      fprintf (stderr, " (matches line %d", pfile->if_stack->lineno);
-      if (strcmp (pfile->if_stack->fname, ip->nominal_fname) != 0)
-       fprintf (stderr, ", file %s", pfile->if_stack->fname);
-      fprintf (stderr, ")\n");
-    }
-    pfile->if_stack->type = T_ELSE;
-  }
+  if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack)
+    {
+      cpp_error (pfile, "`#else' not within a conditional");
+      return 0;
+    }
+  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;
+
+      if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF)
+       {
+         cpp_error (pfile, "`#else' after `#else'");
+         cpp_error_with_line (pfile, pfile->if_stack->lineno, -1,
+                              "the conditional began here");
+       }
+      pfile->if_stack->type = T_ELSE;
+    }
 
   if (pfile->if_stack->if_succeeded)
     skip_if_group (pfile);
-  else {
-    ++pfile->if_stack->if_succeeded;   /* continue processing input */
-    output_line_command (pfile, same_file);
-  }
+  else
+    {
+      ++pfile->if_stack->if_succeeded; /* continue processing input */
+      output_line_command (pfile, same_file);
+    }
   return 0;
 }
 
@@ -2086,12 +2205,11 @@ do_endif (pfile, keyword)
      cpp_reader *pfile;
      const struct directive *keyword ATTRIBUTE_UNUSED;
 {
-  if (CPP_PEDANTIC (pfile))
-    validate_else (pfile, "#endif");
+  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;
@@ -2132,26 +2250,46 @@ do_endif (pfile, keyword)
   return 0;
 }
 
-/* When an #else or #endif is found while skipping failed conditional,
-   if -pedantic was specified, this is called to warn about text after
-   the command name.  P points to the first char after the command name.  */
+/* 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.  */
 
 static void
 validate_else (pfile, directive)
      cpp_reader *pfile;
      const char *directive;
 {
-  int c;
+  if (! CPP_PEDANTIC (pfile) || CPP_BUFFER (pfile)->system_header_p)
+    return;
+
   cpp_skip_hspace (pfile);
-  c = PEEKC ();
-  if (c != EOF && c != '\n')
+  if (PEEKC () != '\n')
     cpp_pedwarn (pfile,
                 "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_ice (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.  */
-  
+
 enum cpp_token
 cpp_get_token (pfile)
      cpp_reader *pfile;
@@ -2164,7 +2302,6 @@ cpp_get_token (pfile)
   c = GETC();
   if (c == EOF)
     {
-    handle_eof:
       if (CPP_BUFFER (pfile)->manual_pop)
        /* If we've been reading from redirected input, the
           frontend will pop the buffer.  */
@@ -2179,9 +2316,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))
            {
@@ -2194,6 +2345,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;
        }
     }
@@ -2206,75 +2359,36 @@ cpp_get_token (pfile)
            goto op2;
 
        comment:
-         if (opts->put_out_comments)
-           c = copy_comment (pfile, c);
-         else
+         if (opts->discard_comments)
            c = skip_comment (pfile, c);
-         if (c == EOF)
-           goto handle_eof;
-         else if (c != ' ')
+         else
+           c = copy_comment (pfile, c);
+         if (c != ' ')
            goto randomchar;
          
          /* Comments are equivalent to spaces.
             For -traditional, a comment is equivalent to nothing.  */
-         if (opts->traditional || opts->put_out_comments)
+         if (opts->traditional || !opts->discard_comments)
            return CPP_COMMENT;
          else
            {
              CPP_PUTC (pfile, c);
              return CPP_HSPACE;
            }
-#if 0
-         if (opts->for_lint) {
-           U_CHAR *argbp;
-           int cmdlen, arglen;
-           char *lintcmd = get_lintcmd (ibp, limit, &argbp, &arglen, &cmdlen);
-           
-           if (lintcmd != NULL) {
-             /* I believe it is always safe to emit this newline: */
-             obp[-1] = '\n';
-             bcopy ("#pragma lint ", (char *) obp, 13);
-             obp += 13;
-             bcopy (lintcmd, (char *) obp, cmdlen);
-             obp += cmdlen;
-
-             if (arglen != 0) {
-               *(obp++) = ' ';
-               bcopy (argbp, (char *) obp, arglen);
-               obp += arglen;
-             }
-
-             /* OK, now bring us back to the state we were in before we entered
-                this branch.  We need #line because the newline for the pragma
-                could mess things up.  */
-             output_line_command (pfile, same_file);
-             *(obp++) = ' ';   /* just in case, if comments are copied thru */
-             *(obp++) = '/';
-           }
-         }
-#endif
 
        case '#':
-#if 0
-         /* If this is expanding a macro definition, don't recognize
-            preprocessor directives.  */
-         if (ip->macro != 0)
-           goto randomchar;
-         /* If this is expand_into_temp_buffer, recognize them
-            only after an actual newline at this level,
-            not at the beginning of the input level.  */
-         if (ip->fname == 0 && beg_of_line == ip->buf)
-           goto randomchar;
-         if (ident_length)
-           goto specialchar;
-#endif
-
          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;
-         return CPP_OTHER;
+         goto randomchar;
 
        case '\"':
        case '\'':
@@ -2363,9 +2477,7 @@ cpp_get_token (pfile)
                             here.  Just delete 'em. */
                          int d = GETC();
                          if (d != '-' && d != ' ')
-                           cpp_fatal (pfile,
-                                 "internal error: unrecognized escape \\r%c",
-                                      d);
+                           cpp_ice (pfile, "unrecognized escape \\r%c", d);
                          CPP_ADJUST_WRITTEN (pfile, -1);
                        }                         
                    }
@@ -2448,7 +2560,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 != '-')))
@@ -2473,7 +2585,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);
                }
@@ -2515,7 +2627,7 @@ cpp_get_token (pfile)
              return CPP_NAME;
            ident = pfile->token_buffer + before_name_written;
            ident_len = CPP_PWRITTEN (pfile) - ident;
-           hp = cpp_lookup (pfile, ident, ident_len, -1);
+           hp = cpp_lookup (pfile, ident, ident_len);
            if (!hp)
              return CPP_NAME;
            if (hp->type == T_DISABLED)
@@ -2533,55 +2645,53 @@ cpp_get_token (pfile)
                return CPP_NAME;
              }
 
-           /* If macro wants an arglist, verify that a '(' follows.
-              first skip all whitespace, copying it to the output
-              after the macro name.  Then, if there is no '(',
-              decide this is not a macro call and leave things that way.  */
+           /* If macro wants an arglist, verify that a '(' follows.  */
            if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
            {
-             int is_macro_call, macbuf_whitespace = 0;
+             int macbuf_whitespace = 0;
+
+             while (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
+               {
+                 U_CHAR *point = CPP_BUFFER (pfile)->cur;
+                 for (;;)
+                   {
+                     cpp_skip_hspace (pfile);
+                     c = PEEKC ();
+                     if (c == '\n')
+                       FORWARD(1);
+                     else
+                       break;
+                   }
+                 if (point != CPP_BUFFER (pfile)->cur)
+                   macbuf_whitespace = 1;
+                 if (c == '(')
+                   goto is_macro_call;
+                 else if (c != EOF)
+                   goto not_macro_call;
+                 cpp_pop_buffer (pfile);
+               }
 
              parse_set_mark (pfile);
              for (;;)
                {
                  cpp_skip_hspace (pfile);
                  c = PEEKC ();
-                 is_macro_call = c == '(';
-                 if (c != EOF)
-                   {
-                     if (c != '\n')
-                       break;
-                     FORWARD (1);
-                   }
-                  else
-                    {
-                      if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
-                        {
-                          if (CPP_BUFFER (pfile)->mark !=
-                              (CPP_BUFFER (pfile)->cur
-                               - CPP_BUFFER (pfile)->buf))
-                             macbuf_whitespace = 1;
-
-                         /* The mark goes away automatically when
-                            the buffer is popped. */
-                          cpp_pop_buffer (pfile);
-                          parse_set_mark (pfile);
-                        }
-                      else
-                        break;
-                    }
+                 if (c == '\n')
+                   FORWARD(1);
+                 else
+                   break;
                }
-             if (!is_macro_call)
-                {
-                  parse_goto_mark (pfile);
-                  if (macbuf_whitespace)
-                    CPP_PUTC (pfile, ' ');
-                }
-             else
-               parse_clear_mark (pfile);
-             if (!is_macro_call)
-               return CPP_NAME;
+             parse_goto_mark (pfile);
+
+             if (c == '(')
+               goto is_macro_call;
+
+           not_macro_call:
+             if (macbuf_whitespace)
+               CPP_PUTC (pfile, ' ');
+             return CPP_NAME;
            }
+         is_macro_call:
            /* This is now known to be a macro call.
               Expand the macro, reading arguments as needed,
               and push the expansion on the input stack.  */
@@ -2595,7 +2705,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);
            }
@@ -2622,8 +2732,7 @@ cpp_get_token (pfile)
                }
              else
                {
-                 cpp_fatal (pfile,
-                            "internal error: unrecognized escape \\r%c", c);
+                 cpp_ice (pfile, "unrecognized escape \\r%c", c);
                  goto get_next;
                }
            }
@@ -2691,7 +2800,7 @@ parse_name (pfile, c)
 {
   for (;;)
   {
-      if (! is_idchar[c])
+      if (! is_idchar(c))
       {
          FORWARD (-1);
          break;
@@ -2738,17 +2847,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);
@@ -2757,11 +2864,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,
@@ -2769,10 +2882,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;
@@ -2781,8 +2892,7 @@ parse_string (pfile, c)
          CPP_ADJUST_WRITTEN (pfile, -1);
          if (CPP_BUFFER (pfile)->has_escapes)
            {
-             cpp_fatal (pfile,
-                        "internal error: \\r escape inside string constant");
+             cpp_ice (pfile, "\\r escape inside string constant");
              FORWARD(1);
            }
          else
@@ -2818,7 +2928,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;
@@ -2830,7 +2940,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();
     }
@@ -2842,7 +2952,7 @@ parse_assertion (pfile)
   dropwhite = 1;
   while ((c = GETC()) != ')')
     {
-      if (is_hor_space[c])
+      if (is_space(c))
        {
          if (! dropwhite)
            {
@@ -2915,26 +3025,25 @@ do_assert (pfile, keyword)
 
   thislen = strlen (sym);
   baselen = index (sym, '(') - sym;
-  this = cpp_lookup (pfile, sym, thislen, -1);
+  this = cpp_lookup (pfile, sym, thislen);
   if (this)
     {
       cpp_warning (pfile, "`%s' re-asserted", sym);
       goto error;
     }
 
-  base = cpp_lookup (pfile, sym, baselen, -1);
+  base = cpp_lookup (pfile, sym, baselen);
   if (! base)
-    base = cpp_install (pfile, sym, baselen, T_ASSERT, 0, -1);
+    base = cpp_install (pfile, sym, baselen, T_ASSERT, 0);
   else if (base->type != T_ASSERT)
   {
     /* Token clash - but with what?! */
-    cpp_fatal (pfile,
-              "cpp internal error: base->type != T_ASSERT in do_assert");
+    cpp_ice (pfile, "base->type != T_ASSERT in do_assert");
     goto error;
   }
 
   this = cpp_install (pfile, sym, thislen, T_ASSERT,
-                     (char *)base->value.aschain, -1);
+                     (char *)base->value.aschain);
   base->value.aschain = this;
   
   pfile->limit = (unsigned char *) sym; /* Pop */
@@ -2975,7 +3084,7 @@ do_unassert (pfile, keyword)
   thislen = strlen (sym);
   if (ret == 1)
     {
-      base = cpp_lookup (pfile, sym, thislen, -1);
+      base = cpp_lookup (pfile, sym, thislen);
       if (! base)
        goto error;  /* It isn't an error to #undef what isn't #defined,
                        so it isn't an error to #unassert what isn't
@@ -2991,9 +3100,9 @@ do_unassert (pfile, keyword)
   else
     {
       baselen = index (sym, '(') - sym;
-      base = cpp_lookup (pfile, sym, baselen, -1);
+      base = cpp_lookup (pfile, sym, baselen);
       if (! base) goto error;
-      this = cpp_lookup (pfile, sym, thislen, -1);
+      this = cpp_lookup (pfile, sym, thislen);
       if (! this) goto error;
 
       next = base;
@@ -3032,9 +3141,9 @@ int
 cpp_read_check_assertion (pfile)
      cpp_reader *pfile;
 {
-  U_CHAR *name = CPP_PWRITTEN (pfile);
+  U_CHAR *name;
   int result;
-  HASHNODE *hp;
+  long written = CPP_WRITTEN (pfile);
   
   FORWARD (1);  /* Skip '#' */
   cpp_skip_hspace (pfile);
@@ -3042,398 +3151,44 @@ cpp_read_check_assertion (pfile)
     result = 0;
   else
     {
-      hp = cpp_lookup (pfile, name, CPP_PWRITTEN (pfile) - name, -1);
-      result = (hp != 0);
+      name = pfile->token_buffer + written;
+      result = cpp_defined (pfile, name, CPP_PWRITTEN (pfile) - name);
     }
 
-  pfile->limit = name;
+  CPP_SET_WRITTEN (pfile, written);
   return result;
 }
 
-/* Remember the current position of PFILE.  */
+/* Remember the current position of PFILE so it may be returned to
+   after looking ahead a bit.
 
-void
+   Note that when you set a mark, you _must_ return to that mark.  You
+   may not forget about it and continue parsing.  You may not pop a
+   buffer with an active mark.  You may not call CPP_BUMP_LINE while a
+   mark is active.  */
+
+static void
 parse_set_mark (pfile)
      cpp_reader *pfile;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
-  if (ip->mark != -1)
-      cpp_fatal (pfile,
-                "cpp internal error: ip->mark != -1 in parse_set_mark");
+  if (ACTIVE_MARK_P())
+      cpp_ice (pfile, "mark active in parse_set_mark");
 
   ip->mark = ip->cur - ip->buf;
 }
 
-/* Clear the current mark - we no longer need it.  */
-
-void
-parse_clear_mark (pfile)
-     cpp_reader *pfile;
-{
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-  if (ip->mark == -1)
-      cpp_fatal (pfile,
-                "cpp internal error: ip->mark == -1 in parse_clear_mark");
-
-  ip->mark = -1;
-}
-
 /* Backup the current position of PFILE to that saved in its mark,
    and clear the mark.  */
 
-void
+static void
 parse_goto_mark (pfile)
      cpp_reader *pfile;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
-  if (ip->mark == -1)
-      cpp_fatal (pfile,
-                "cpp internal error: ip->mark == -1 in parse_goto_mark");
+  if (!ACTIVE_MARK_P())
+      cpp_ice (pfile, "mark not active in parse_goto_mark");
 
   ip->cur = ip->buf + ip->mark;
   ip->mark = -1;
 }
-
-static void
-cpp_print_file_and_line (pfile)
-     cpp_reader *pfile;
-{
-  cpp_buffer *ip = cpp_file_buffer (pfile);
-
-  if (ip != NULL)
-    {
-      long line, col;
-      cpp_buf_line_and_col (ip, &line, &col);
-      cpp_file_line_for_message (pfile, ip->nominal_fname,
-                                line, pfile->show_column ? col : -1);
-    }
-}
-
-static void
-v_cpp_error (pfile, msgid, ap)
-  cpp_reader *pfile;
-  const char *msgid;
-  va_list ap;
-{
-  cpp_print_containing_files (pfile);
-  cpp_print_file_and_line (pfile);
-  v_cpp_message (pfile, 1, msgid, ap);
-}
-
-void
-cpp_error VPROTO ((cpp_reader * pfile, const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  const char *msgid;
-#endif
-  va_list ap;
-
-  VA_START(ap, msgid);
-  
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  v_cpp_error (pfile, msgid, ap);
-  va_end(ap);
-}
-
-/* Print error message but don't count it.  */
-
-static void
-v_cpp_warning (pfile, msgid, ap)
-  cpp_reader *pfile;
-  const char *msgid;
-  va_list ap;
-{
-  if (CPP_OPTIONS (pfile)->inhibit_warnings)
-    return;
-
-  if (CPP_OPTIONS (pfile)->warnings_are_errors)
-    pfile->errors++;
-
-  cpp_print_containing_files (pfile);
-  cpp_print_file_and_line (pfile);
-  v_cpp_message (pfile, 0, msgid, ap);
-}
-
-void
-cpp_warning VPROTO ((cpp_reader * pfile, const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  const char *msgid;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msgid);
-  
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  v_cpp_warning (pfile, msgid, ap);
-  va_end(ap);
-}
-
-/* Print an error message and maybe count it.  */
-
-void
-cpp_pedwarn VPROTO ((cpp_reader * pfile, const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  const char *msgid;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msgid);
-  
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  if (CPP_OPTIONS (pfile)->pedantic_errors)
-    v_cpp_error (pfile, msgid, ap);
-  else
-    v_cpp_warning (pfile, msgid, ap);
-  va_end(ap);
-}
-
-static void
-v_cpp_error_with_line (pfile, line, column, msgid, ap)
-  cpp_reader * pfile;
-  int line;
-  int column;
-  const char * msgid;
-  va_list ap;
-{
-  cpp_buffer *ip = cpp_file_buffer (pfile);
-
-  cpp_print_containing_files (pfile);
-
-  if (ip != NULL)
-    cpp_file_line_for_message (pfile, ip->nominal_fname, line, column);
-
-  v_cpp_message (pfile, 1, msgid, ap);
-}
-
-void
-cpp_error_with_line VPROTO ((cpp_reader * pfile, int line, int column,
-                            const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  int line;
-  int column;
-  const char *msgid;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msgid);
-  
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  line = va_arg (ap, int);
-  column = va_arg (ap, int);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  v_cpp_error_with_line(pfile, line, column, msgid, ap);
-  va_end(ap);
-}
-
-static void
-v_cpp_warning_with_line (pfile, line, column, msgid, ap)
-  cpp_reader * pfile;
-  int line;
-  int column;
-  const char *msgid;
-  va_list ap;
-{
-  cpp_buffer *ip;
-
-  if (CPP_OPTIONS (pfile)->inhibit_warnings)
-    return;
-
-  if (CPP_OPTIONS (pfile)->warnings_are_errors)
-    pfile->errors++;
-
-  cpp_print_containing_files (pfile);
-
-  ip = cpp_file_buffer (pfile);
-
-  if (ip != NULL)
-    cpp_file_line_for_message (pfile, ip->nominal_fname, line, column);
-
-  v_cpp_message (pfile, 0, msgid, ap);
-}  
-
-void
-cpp_warning_with_line VPROTO ((cpp_reader * pfile, int line, int column,
-                              const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  int line;
-  int column;
-  const char *msgid;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msgid);
-  
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  line = va_arg (ap, int);
-  column = va_arg (ap, int);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  v_cpp_warning_with_line (pfile, line, column, msgid, ap);
-  va_end(ap);
-}
-
-void
-cpp_pedwarn_with_line VPROTO ((cpp_reader * pfile, int line, int column,
-                              const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  int line;
-  int column;
-  const char *msgid;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msgid);
-  
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  line = va_arg (ap, int);
-  column = va_arg (ap, int);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  if (CPP_OPTIONS (pfile)->pedantic_errors)
-    v_cpp_error_with_line (pfile, column, line, msgid, ap);
-  else
-    v_cpp_warning_with_line (pfile, line, column, msgid, ap);
-  va_end(ap);
-}
-
-/* Report a warning (or an error if pedantic_errors)
-   giving specified file name and line number, not current.  */
-
-void
-cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, const char *file,
-                                       int line, const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  const char *file;
-  int line;
-  const char *msgid;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msgid);
-
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  file = va_arg (ap, const char *);
-  line = va_arg (ap, int);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  if (!CPP_OPTIONS (pfile)->pedantic_errors
-      && CPP_OPTIONS (pfile)->inhibit_warnings)
-    return;
-  if (file != NULL)
-    cpp_file_line_for_message (pfile, file, line, -1);
-  v_cpp_message (pfile, CPP_OPTIONS (pfile)->pedantic_errors, msgid, ap);
-  va_end(ap);
-}
-
-/* my_strerror - return the descriptive text associated with an
-   `errno' code.  */
-
-static const char *
-my_strerror (errnum)
-     int errnum;
-{
-  const char *result;
-
-#ifndef VMS
-#ifndef HAVE_STRERROR
-  result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0);
-#else
-  result = strerror (errnum);
-#endif
-#else  /* VMS */
-  /* VAXCRTL's strerror() takes an optional second argument, which only
-     matters when the first argument is EVMSERR.  However, it's simplest
-     just to pass it unconditionally.  `vaxc$errno' is declared in
-     <errno.h>, and maintained by the library in parallel with `errno'.
-     We assume that caller's `errnum' either matches the last setting of
-     `errno' by the library or else does not have the value `EVMSERR'.  */
-
-  result = strerror (errnum, vaxc$errno);
-#endif
-
-  if (!result)
-    result = "errno = ?";
-
-  return result;
-}
-
-/* Error including a message from `errno'.  */
-
-void
-cpp_error_from_errno (pfile, name)
-     cpp_reader *pfile;
-     const char *name;
-{
-  cpp_message_from_errno (pfile, 1, name);
-}
-
-void
-cpp_message_from_errno (pfile, is_error, name)
-     cpp_reader *pfile;
-     int is_error;
-     const char *name;
-{
-  int e = errno;
-  cpp_buffer *ip = cpp_file_buffer (pfile);
-
-  cpp_print_containing_files (pfile);
-
-  if (ip != NULL)
-    cpp_file_line_for_message (pfile, ip->nominal_fname, ip->lineno, -1);
-
-  cpp_message (pfile, is_error, "%s: %s", name, my_strerror (e));
-}
-
-void
-cpp_perror_with_name (pfile, name)
-     cpp_reader *pfile;
-     const char *name;
-{
-  cpp_message (pfile, 1, "%s: %s: %s", progname, name, my_strerror (errno));
-}
-
-/* TODO:
- * No pre-compiled header file support.
- *
- * Possibly different enum token codes for each C/C++ token.
- *
- * Find and cleanup remaining uses of static variables,
- *
- * Support -dM flag (dump_all_macros).
- *
- * Support for_lint flag.
- */