OSDN Git Service

update copyrights
[pf3gnuchains/gcc-fork.git] / gcc / cpplib.c
index b0008af..c915f77 100644 (file)
@@ -1,4 +1,4 @@
-/* CPP Library.
+/* CPP Library. (Directive handling.)
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
@@ -28,9 +28,13 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "obstack.h"
 #include "symcat.h"
 
-#ifdef HAVE_MMAP_FILE
-# include <sys/mman.h>
-#endif
+/* Chained list of answers to an assertion.  */
+struct answer
+{
+  struct answer *next;
+  unsigned int count;
+  cpp_token first[1];
+};
 
 /* Stack of conditionals currently in progress
    (including both successful and failing conditionals).  */
@@ -38,48 +42,102 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 struct if_stack
 {
   struct if_stack *next;
-  unsigned int lineno;         /* line number where condition started */
-  unsigned int colno;          /* and column */
-  int was_skipping;            /* value of pfile->skipping before this if */
-  const cpp_hashnode *cmacro;  /* macro name for #ifndef around entire file */
+  cpp_lexer_pos pos;           /* line and column where condition started */
+  const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
+  unsigned char was_skipping;  /* Value of pfile->skipping before this if.  */
   int type;                    /* type of last directive seen in this group */
 };
 
+/* Values for the origin field of struct directive.  KANDR directives
+   come from traditional (K&R) C.  STDC89 directives come from the
+   1989 C standard.  EXTENSION directives are extensions.  */
+#define KANDR          0
+#define STDC89         1
+#define EXTENSION      2
+
+/* Values for the flags field of struct directive.  COND indicates a
+   conditional; IF_COND an opening conditional.  INCL means to treat
+   "..." and <...> as q-char and h-char sequences respectively.  IN_I
+   means this directive should be handled even if -fpreprocessed is in
+   effect (these are the directives with callback hooks).  */
+#define COND           (1 << 0)
+#define IF_COND                (1 << 1)
+#define INCL           (1 << 2)
+#define IN_I           (1 << 3)
+
+/* Defines one #-directive, including how to handle it.  */
+typedef void (*directive_handler) PARAMS ((cpp_reader *));
+typedef struct directive directive;
+struct directive
+{
+  directive_handler handler;   /* Function to handle directive.  */
+  const U_CHAR *name;          /* Name of directive.  */
+  unsigned short length;       /* Length of name.  */
+  unsigned char origin;                /* Origin of directive.  */
+  unsigned char flags;         /* Flags describing this directive.  */
+};
+
 /* Forward declarations.  */
 
-static void validate_else      PARAMS ((cpp_reader *, const U_CHAR *));
-static int  parse_include      PARAMS ((cpp_reader *, const U_CHAR *, int,
-                                        const U_CHAR **, unsigned int *,
-                                        int *));
+static void skip_rest_of_line  PARAMS ((cpp_reader *));
+static void check_eol          PARAMS ((cpp_reader *));
+static void start_directive    PARAMS ((cpp_reader *));
+static void end_directive      PARAMS ((cpp_reader *, int));
+static void run_directive      PARAMS ((cpp_reader *, int,
+                                        enum cpp_buffer_type,
+                                        const char *, size_t));
+static int glue_header_name    PARAMS ((cpp_reader *, cpp_token *));
+static int  parse_include      PARAMS ((cpp_reader *, cpp_token *));
 static void push_conditional   PARAMS ((cpp_reader *, int, int,
                                         const cpp_hashnode *));
-static void pass_thru_directive        PARAMS ((cpp_reader *));
-static int  read_line_number   PARAMS ((cpp_reader *, int *));
+static unsigned int read_flag  PARAMS ((cpp_reader *, unsigned int));
 static int  strtoul_for_line   PARAMS ((const U_CHAR *, unsigned int,
                                         unsigned long *));
-
-static const cpp_hashnode *
-           parse_ifdef         PARAMS ((cpp_reader *, const U_CHAR *));
-static const cpp_hashnode *
-           detect_if_not_defined PARAMS ((cpp_reader *));
-static cpp_hashnode *
-           get_define_node     PARAMS ((cpp_reader *));
-static void dump_macro_name    PARAMS ((cpp_reader *, cpp_hashnode *));
-static void unwind_if_stack    PARAMS ((cpp_reader *, cpp_buffer *));
-
-/* Utility.  */
-#define str_match(sym, len, str) \
-((len) == (sizeof (str) - 1) && !ustrncmp ((sym), U(str), sizeof (str) - 1))
+static void do_diagnostic      PARAMS ((cpp_reader *, enum error_type, int));
+static cpp_hashnode *lex_macro_node    PARAMS ((cpp_reader *));
+static void do_pragma_once     PARAMS ((cpp_reader *));
+static void do_pragma_poison   PARAMS ((cpp_reader *));
+static void do_pragma_system_header    PARAMS ((cpp_reader *));
+static void do_pragma_dependency       PARAMS ((cpp_reader *));
+static int get__Pragma_string  PARAMS ((cpp_reader *, cpp_token *));
+static unsigned char *destringize      PARAMS ((const cpp_string *,
+                                                unsigned int *));
+static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
+static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **,
+                                             int));
+static struct answer ** find_answer PARAMS ((cpp_hashnode *,
+                                            const struct answer *));
+static void handle_assertion   PARAMS ((cpp_reader *, const char *, int));
 
 /* This is the table of directive handlers.  It 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).
+   pcmcia-cs-3.0.9).  This is no longer important as directive lookup
+   is now O(1).  All extensions other than #warning and #include_next
+   are deprecated.  The name is where the extension appears to have
+   come from.  */
 
-   The entries with a dash and a name after the count are extensions,
-   of which all but #warning and #include_next are deprecated.  The name
-   is where the extension appears to have come from.  */
+#define DIRECTIVE_TABLE                                                        \
+D(define,      T_DEFINE = 0,   KANDR,     IN_I)           /* 270554 */ \
+D(include,     T_INCLUDE,      KANDR,     INCL)           /*  52262 */ \
+D(endif,       T_ENDIF,        KANDR,     COND)           /*  45855 */ \
+D(ifdef,       T_IFDEF,        KANDR,     COND | IF_COND) /*  22000 */ \
+D(if,          T_IF,           KANDR,     COND | IF_COND) /*  18162 */ \
+D(else,                T_ELSE,         KANDR,     COND)           /*   9863 */ \
+D(ifndef,      T_IFNDEF,       KANDR,     COND | IF_COND) /*   9675 */ \
+D(undef,       T_UNDEF,        KANDR,     IN_I)           /*   4837 */ \
+D(line,                T_LINE,         KANDR,     IN_I)           /*   2465 */ \
+D(elif,                T_ELIF,         KANDR,     COND)           /*    610 */ \
+D(error,       T_ERROR,        STDC89,    0)              /*    475 */ \
+D(pragma,      T_PRAGMA,       STDC89,    IN_I)           /*    195 */ \
+D(warning,     T_WARNING,      EXTENSION, 0)              /*     22 */ \
+D(include_next,        T_INCLUDE_NEXT, EXTENSION, INCL)           /*     19 */ \
+D(ident,       T_IDENT,        EXTENSION, IN_I)           /*     11 */ \
+D(import,      T_IMPORT,       EXTENSION, INCL)           /* 0 ObjC */ \
+D(assert,      T_ASSERT,       EXTENSION, 0)              /* 0 SVR4 */ \
+D(unassert,    T_UNASSERT,     EXTENSION, 0)              /* 0 SVR4 */ \
+SCCS_ENTRY                                                /* 0 SVR4? */
 
 /* #sccs is not always recognized.  */
 #ifdef SCCS_DIRECTIVE
@@ -88,27 +146,6 @@ static void unwind_if_stack PARAMS ((cpp_reader *, cpp_buffer *));
 # define SCCS_ENTRY /* nothing */
 #endif
 
-#define DIRECTIVE_TABLE                                                        \
-D(define,      T_DEFINE = 0,   KANDR,     COMMENTS)       /* 270554 */ \
-D(include,     T_INCLUDE,      KANDR,     EXPAND | INCL)  /*  52262 */ \
-D(endif,       T_ENDIF,        KANDR,     COND)           /*  45855 */ \
-D(ifdef,       T_IFDEF,        KANDR,     COND)           /*  22000 */ \
-D(if,          T_IF,           KANDR,     COND | EXPAND)  /*  18162 */ \
-D(else,                T_ELSE,         KANDR,     COND)           /*   9863 */ \
-D(ifndef,      T_IFNDEF,       KANDR,     COND)           /*   9675 */ \
-D(undef,       T_UNDEF,        KANDR,     0)              /*   4837 */ \
-D(line,                T_LINE,         KANDR,     EXPAND)         /*   2465 */ \
-D(elif,                T_ELIF,         KANDR,     COND | EXPAND)  /*    610 */ \
-D(error,       T_ERROR,        STDC89,    0)              /*    475 */ \
-D(pragma,      T_PRAGMA,       STDC89,    0)              /*    195 */ \
-D(warning,     T_WARNING,      EXTENSION, 0)              /*     22 GNU   */ \
-D(include_next,        T_INCLUDE_NEXT, EXTENSION, EXPAND | INCL)  /*     19 GNU   */ \
-D(ident,       T_IDENT,        EXTENSION, 0)              /*     11 SVR4  */ \
-D(import,      T_IMPORT,       EXTENSION, EXPAND | INCL)  /*      0 ObjC  */ \
-D(assert,      T_ASSERT,       EXTENSION, 0)              /*      0 SVR4  */ \
-D(unassert,    T_UNASSERT,     EXTENSION, 0)              /*      0 SVR4  */ \
-SCCS_ENTRY                                                /*      0 SVR2? */
-
 /* Use the table to generate a series of prototypes, an enum for the
    directive names, and an array of directive handlers.  */
 
@@ -117,13 +154,14 @@ SCCS_ENTRY                                                   /*      0 SVR2? */
    pointers to functions returning void.  */
 
 /* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */
-#define D(name, t, o, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *));
+#define D(name, t, o, f) static void CONCAT2(do_,name) PARAMS ((cpp_reader *));
 DIRECTIVE_TABLE
 #undef D
 
 #define D(n, tag, o, f) tag,
 enum
 {
+  T_BAD_DIRECTIVE,
   DIRECTIVE_TABLE
   N_DIRECTIVES
 };
@@ -133,358 +171,485 @@ enum
 #define D(name, t, origin, flags) \
 { CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \
   sizeof STRINGX(name) - 1, origin, flags },
-static const struct directive dtable[] =
+static const directive dtable[] =
 {
 DIRECTIVE_TABLE
 };
 #undef D
 #undef DIRECTIVE_TABLE
 
-/* Check if a token's name matches that of a known directive.  Put in
-   this file to save exporting dtable and other unneeded information.  */
-const struct directive *
-_cpp_check_directive (pfile, token, bol)
+/* Skip any remaining tokens in a directive.  */
+static void
+skip_rest_of_line (pfile)
      cpp_reader *pfile;
-     const cpp_token *token;
-     int bol;
 {
-  const U_CHAR *name = token->val.name.text;
-  size_t len = token->val.name.len;
-  unsigned int i;
+  cpp_token token;
 
-  /* If we are rescanning preprocessed input, don't obey any directives
-     other than # nnn.  */
-  if (CPP_OPTION (pfile, preprocessed))
-    return 0;
-
-  for (i = 0; i < N_DIRECTIVES; i++)
-    if (dtable[i].length == len && !memcmp (dtable[i].name, name, len))
-      {
-       /* If we are skipping a failed conditional group, all non-conditional
-          directives are ignored.  */
-       if (pfile->skipping && !(dtable[i].flags & COND))
-         return 0;
-
-       /* In -traditional mode, a directive is ignored unless its #
-          is in column 1.  */
-       if (!bol && dtable[i].origin == KANDR && CPP_WTRADITIONAL (pfile))
-         cpp_warning (pfile, "traditional C ignores #%s with the # indented",
-                      dtable[i].name);
-             
-       if (!bol && CPP_TRADITIONAL (pfile))
-         return 0;
-
-       /* Issue -pedantic warnings for extended directives.   */
-       if (CPP_PEDANTIC (pfile) && dtable[i].origin == EXTENSION)
-         cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name);
-
-       /* -Wtraditional gives warnings about directives with inappropriate
-          indentation of #.  */
-       if (bol && dtable[i].origin != KANDR && CPP_WTRADITIONAL (pfile))
-         cpp_warning (pfile,
-                   "suggest hiding #%s from traditional C with an indented #",
-                      dtable[i].name);
-
-       return &dtable[i];
-      }
+  /* Discard all input lookaheads.  */
+  while (pfile->la_read)
+    _cpp_release_lookahead (pfile);
 
-  return 0;
+  /* Discard all stacked contexts.  */
+  while (pfile->context != &pfile->base_context)
+    _cpp_pop_context (pfile);
+
+  /* Sweep up all tokens remaining on the line.  */
+  pfile->state.prevent_expansion++;
+  while (!pfile->state.next_bol)
+    _cpp_lex_token (pfile, &token);
+  pfile->state.prevent_expansion--;
 }
 
-const struct directive *
-_cpp_check_linemarker (pfile, token, bol)
+/* Ensure there are no stray tokens at the end of a directive.  */
+static void
+check_eol (pfile)
      cpp_reader *pfile;
-     const cpp_token *token ATTRIBUTE_UNUSED;
-     int bol;
 {
-  /* # followed by a number is equivalent to #line.  Do not recognize
-     this form in assembly language source files or skipped
-     conditional groups.  Complain about this form if we're being
-     pedantic, but not if this is regurgitated input (preprocessed or
-     fed back in by the C++ frontend).  */
-  if (pfile->skipping || CPP_OPTION (pfile, lang_asm))
-    return 0;
-
-  if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc
-      && ! CPP_OPTION (pfile, preprocessed))
-    cpp_pedwarn (pfile, "# followed by integer");
-
-  /* In -traditional mode, a directive is ignored unless its #
-     is in column 1.  */
-  if (!bol && CPP_WTRADITIONAL (pfile))
-    cpp_warning (pfile, "traditional C ignores #%s with the # indented",
-                dtable[T_LINE].name);
-             
-  if (!bol && CPP_TRADITIONAL (pfile))
-    return 0;
-  
-  return &dtable[T_LINE];
-}  
+  if (!pfile->state.next_bol)
+    {
+      cpp_token token;
 
+      _cpp_lex_token (pfile, &token);
+      if (token.type != CPP_EOF)
+       cpp_pedwarn (pfile, "extra tokens at end of #%s directive",
+                    pfile->directive->name);
+    }
+}
+
+/* Called when entering a directive, _Pragma or command-line directive.  */
 static void
-dump_macro_name (pfile, node)
+start_directive (pfile)
      cpp_reader *pfile;
-     cpp_hashnode *node;
 {
-  CPP_PUTS (pfile, "#define ", sizeof "#define " - 1);
-  CPP_PUTS (pfile, node->name, node->length);
+  cpp_buffer *buffer = pfile->buffer;
+
+  /* Setup in-directive state.  */
+  pfile->state.in_directive = 1;
+  pfile->state.save_comments = 0;
+
+  /* Some handlers need the position of the # for diagnostics.  */
+  pfile->directive_pos = pfile->lexer_pos;
+
+  /* Don't save directive tokens for external clients.  */
+  pfile->la_saved = pfile->la_write;
+  pfile->la_write = 0;
+
+  /* Turn off skipping.  */
+  buffer->was_skipping = pfile->skipping;
+  pfile->skipping = 0;
 }
 
-/* Pass the current directive through to the output file.  */
+/* Called when leaving a directive, _Pragma or command-line directive.  */
 static void
-pass_thru_directive (pfile)
+end_directive (pfile, skip_line)
      cpp_reader *pfile;
+     int skip_line;
 {
-  /* XXX This output may be genuinely needed even when there is no
-     printer.  */
-  if (! pfile->printer)
-    return;
-  /* Flush first (temporary).  */
-  cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line);
-  _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 1);
+  cpp_buffer *buffer = pfile->buffer;
+
+  /* Restore pfile->skipping before skip_rest_of_line, so that e.g.
+     __VA_ARGS__ in the rest of the directive doesn't warn.  */
+  pfile->skipping = buffer->was_skipping;
+
+  /* We don't skip for an assembler #.  */
+  if (skip_line)
+    skip_rest_of_line (pfile);
+
+  /* Restore state.  */
+  pfile->la_write = pfile->la_saved;
+  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
+  pfile->state.in_directive = 0;
+  pfile->state.angled_headers = 0;
+  pfile->state.line_extension = 0;
+  pfile->directive = 0;
 }
 
-static cpp_hashnode *
-get_define_node (pfile)
+/* Check if a token's name matches that of a known directive.  Put in
+   this file to save exporting dtable and other unneeded information.  */
+int
+_cpp_handle_directive (pfile, indented)
      cpp_reader *pfile;
+     int indented;
 {
-  cpp_hashnode *node;
-  const cpp_token *token;
-  const U_CHAR *sym;
-  unsigned int len;
+  cpp_buffer *buffer = pfile->buffer;
+  const directive *dir = 0;
+  cpp_token dname;
+  int skip = 1;
+
+  start_directive (pfile);
 
-  /* Skip any -C comments.  */
-  while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
-    ;
+  /* Lex the directive name directly.  */
+  _cpp_lex_token (pfile, &dname);
 
-  if (token->type != CPP_NAME)
+  if (dname.type == CPP_NAME)
     {
-      cpp_error_with_line (pfile, pfile->token_list.line, token->col,
-                          "macro names must be identifiers");
-      return 0;
+      unsigned int index = dname.val.node->directive_index;
+      if (index)
+       dir = &dtable[index - 1];
+    }
+  else if (dname.type == CPP_NUMBER)
+    {
+      /* # followed by a number is equivalent to #line.  Do not
+        recognize this form in assembly language source files or
+        skipped conditional groups.  Complain about this form if
+        we're being pedantic, but not if this is regurgitated input
+        (preprocessed or fed back in by the C++ frontend).  */
+      if (! buffer->was_skipping && CPP_OPTION (pfile, lang) != CLK_ASM)
+       {
+         dir = &dtable[T_LINE];
+         pfile->state.line_extension = 1;
+         _cpp_push_token (pfile, &dname, &pfile->directive_pos);
+         if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed))
+           cpp_pedwarn (pfile, "# followed by integer");
+       }
     }
 
-  /* That identifier is not allowed to be "defined".  See predefined
-     macro names (6.10.8.4).  */
-  len = token->val.name.len;
-  sym = token->val.name.text;
-  if (str_match (sym, len, "defined"))
+  pfile->directive = dir;
+  if (dir)
     {
-      cpp_error_with_line (pfile, pfile->token_list.line, token->col,
-                          "\"defined\" is not a legal macro name");
-      return 0;
+      /* Make sure we lex headers correctly, whether skipping or not.  */
+      pfile->state.angled_headers = dir->flags & INCL;
+
+      /* If we are rescanning preprocessed input, only directives tagged
+        with IN_I are honored, and the warnings below are suppressed.  */
+      if (! CPP_OPTION (pfile, preprocessed) || dir->flags & IN_I)
+       {
+         /* Traditionally, a directive is ignored unless its # is in
+            column 1.  Therefore in code intended to work with K+R
+            compilers, directives added by C89 must have their #
+            indented, and directives present in traditional C must
+            not.  This is true even of directives in skipped
+            conditional blocks.  */
+         if (CPP_WTRADITIONAL (pfile))
+           {
+             if (indented && dir->origin == KANDR)
+               cpp_warning (pfile,
+                            "traditional C ignores #%s with the # indented",
+                            dir->name);
+             else if (!indented && dir->origin != KANDR)
+               cpp_warning (pfile,
+            "suggest hiding #%s from traditional C with an indented #",
+                            dir->name);
+           }
+
+         /* If we are skipping a failed conditional group, all
+            non-conditional directives are ignored.  */
+         if (! buffer->was_skipping || (dir->flags & COND))
+           {
+             /* Issue -pedantic warnings for extensions.   */
+             if (CPP_PEDANTIC (pfile) && dir->origin == EXTENSION)
+               cpp_pedwarn (pfile, "#%s is a GCC extension", dir->name);
+
+             /* If we have a directive that is not an opening
+                conditional, invalidate any control macro.  */
+             if (! (dir->flags & IF_COND))
+               pfile->mi_state = MI_FAILED;
+
+             (*dir->handler) (pfile);
+           }
+       }
     }
+  else if (dname.type != CPP_EOF && ! pfile->skipping)
+    {
+      /* An unknown directive.  Don't complain about it in assembly
+        source: we don't know where the comments are, and # may
+        introduce assembler pseudo-ops.  Don't complain about invalid
+        directives in skipped conditional groups (6.10 p4).  */
+      if (CPP_OPTION (pfile, lang) == CLK_ASM)
+       {
+         /* Output the # and lookahead token for the assembler.  */
+         _cpp_push_token (pfile, &dname, &pfile->directive_pos);
+         skip = 0;
+       }
+      else
+       cpp_error (pfile, "invalid preprocessing directive #%s",
+                  cpp_token_as_text (pfile, &dname));
+    }
+
+  end_directive (pfile, skip);
+  return skip;
+}
+
+/* Directive handler wrapper used by the command line option
+   processor.  */
+static void
+run_directive (pfile, dir_no, type, buf, count)
+     cpp_reader *pfile;
+     int dir_no;
+     enum cpp_buffer_type type;
+     const char *buf;
+     size_t count;
+{
+  unsigned int output_line = pfile->lexer_pos.output_line;
+  cpp_buffer *buffer;
 
-  node = cpp_lookup (pfile, sym, len);
-  /* Check for poisoned identifiers now.  */
-  if (node->type == T_POISON)
+  buffer = cpp_push_buffer (pfile, (const U_CHAR *) buf, count, type, 0);
+
+  if (dir_no == T_PRAGMA)
     {
-      cpp_error (pfile, "attempt to use poisoned \"%.*s\"", (int) len, sym);
-      return 0;
+      /* A kludge to avoid line markers for _Pragma.  */
+      pfile->lexer_pos.output_line = output_line;
+      /* Avoid interpretation of directives in a _Pragma string.  */
+      pfile->state.next_bol = 0;
     }
 
-  return node;
+  start_directive (pfile);
+  pfile->state.prevent_expansion++;
+  (void) (*dtable[dir_no].handler) (pfile);
+  pfile->state.prevent_expansion--;
+  check_eol (pfile);
+  end_directive (pfile, 1);
+
+  cpp_pop_buffer (pfile);
 }
 
-/* Process a #define command.  */
-static int
-do_define (pfile)
+/* Checks for validity the macro name in #define, #undef, #ifdef and
+   #ifndef directives.  */
+static cpp_hashnode *
+lex_macro_node (pfile)
      cpp_reader *pfile;
 {
-  cpp_hashnode *node;
+  cpp_token token;
+
+  /* Lex the macro name directly.  */
+  _cpp_lex_token (pfile, &token);
+
+  /* The token immediately after #define must be an identifier.  That
+     identifier is not allowed to be "defined".  See predefined macro
+     names (6.10.8.4).  In C++, it is not allowed to be any of the
+     <iso646.h> macro names (which are keywords in C++) either.  */
+
+  if (token.type != CPP_NAME)
+    {
+      if (token.type == CPP_EOF)
+       cpp_error (pfile, "no macro name given in #%s directive",
+                  pfile->directive->name);
+      else if (token.flags & NAMED_OP)
+       cpp_error (pfile,
+                  "\"%s\" cannot be used as a macro name as it is an operator in C++",
+                  token.val.node->name);
+      else
+       cpp_error (pfile, "macro names must be identifiers");
+    }
+  else
+    {
+      cpp_hashnode *node = token.val.node;
+
+      /* In Objective C, some keywords begin with '@', but general
+        identifiers do not, and you're not allowed to #define them.  */
+      if (node == pfile->spec_nodes.n_defined || node->name[0] == '@')
+       cpp_error (pfile, "\"%s\" cannot be used as a macro name", node->name);
+      else if (!(node->flags & NODE_POISONED))
+       return node;
+    }
 
-  if ((node = get_define_node (pfile)))
-    if (_cpp_create_definition (pfile, node))
-      {
-       if (CPP_OPTION (pfile, debug_output)
-           || CPP_OPTION (pfile, dump_macros) == dump_definitions)
-         _cpp_dump_definition (pfile, node);
-       else if (CPP_OPTION (pfile, dump_macros) == dump_names)
-         dump_macro_name (pfile, node);
-      }
   return 0;
 }
 
-/* Remove the definition of a symbol from the symbol table.  */
-static int
-do_undef (pfile)
+/* Process a #define directive.  Most work is done in cppmacro.c.  */
+static void
+do_define (pfile)
      cpp_reader *pfile;
 {
-  cpp_hashnode *node = get_define_node (pfile);  
+  cpp_hashnode *node = lex_macro_node (pfile);
 
-  if (cpp_get_token (pfile)->type != CPP_EOF)
-    cpp_pedwarn (pfile, "junk on line after #undef");
+  if (node)
+    {
+      if (_cpp_create_definition (pfile, node))
+       if (pfile->cb.define)
+         (*pfile->cb.define) (pfile, node);
+    }
+}
+
+/* Handle #undef.  Marks the identifier NT_VOID in the hash table.  */
+static void
+do_undef (pfile)
+     cpp_reader *pfile;
+{
+  cpp_hashnode *node = lex_macro_node (pfile);  
 
   /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
      is not currently defined as a macro name.  */
-  if (node && node->type != T_VOID)
+  if (node && node->type == NT_MACRO)
     {
-      /* If we are generating additional info for debugging (with -g) we
-        need to pass through all effective #undef commands.  */
-      if (CPP_OPTION (pfile, debug_output)
-         || CPP_OPTION (pfile, dump_macros) == dump_definitions
-         || CPP_OPTION (pfile, dump_macros) == dump_names)
-       pass_thru_directive (pfile);
-
-      if (node->type != T_MACRO)
+      if (pfile->cb.undef)
+       (*pfile->cb.undef) (pfile, node);
+
+      if (node->flags & NODE_BUILTIN)
        cpp_warning (pfile, "undefining \"%s\"", node->name);
 
       _cpp_free_definition (node);
-      node->type = T_VOID;
     }
-
-  return 0;
+  check_eol (pfile);
 }
 
+/* Helper routine used by parse_include.  Reinterpret the current line
+   as an h-char-sequence (< ... >); we are looking at the first token
+   after the <.  Returns zero on success.  */
+static int
+glue_header_name (pfile, header)
+     cpp_reader *pfile;
+     cpp_token *header;
+{
+  cpp_token token;
+  unsigned char *buffer, *token_mem;
+  size_t len, total_len = 0, capacity = 1024;
+
+  /* To avoid lexed tokens overwriting our glued name, we can only
+     allocate from the string pool once we've lexed everything.  */
+
+  buffer = (unsigned char *) xmalloc (capacity);
+  for (;;)
+    {
+      cpp_get_token (pfile, &token);
+
+      if (token.type == CPP_GREATER || token.type == CPP_EOF)
+       break;
+
+      len = cpp_token_len (&token);
+      if (total_len + len > capacity)
+       {
+         capacity = (capacity + len) * 2;
+         buffer = (unsigned char *) xrealloc (buffer, capacity);
+       }
+
+      if (token.flags & PREV_WHITE)
+       buffer[total_len++] = ' ';
+
+      total_len = cpp_spell_token (pfile, &token, &buffer[total_len]) - buffer;
+    }
 
-/* Handle #include and #import.  */
+  if (token.type == CPP_EOF)
+    cpp_error (pfile, "missing terminating > character");
+  else
+    {
+      token_mem = _cpp_pool_alloc (&pfile->ident_pool, total_len);
+      memcpy (token_mem, buffer, total_len);
 
+      header->type = CPP_HEADER_NAME;
+      header->flags &= ~PREV_WHITE;
+      header->val.str.len = total_len;
+      header->val.str.text = token_mem;
+    }
+
+  free ((PTR) buffer);
+  return token.type == CPP_EOF;
+}
+
+/* Parse the header name of #include, #include_next, #import and
+   #pragma dependency.  Returns zero on success.  */
 static int
-parse_include (pfile, dir, trail, strp, lenp, abp)
+parse_include (pfile, header)
      cpp_reader *pfile;
-     const U_CHAR *dir;
-     int trail;
-     const U_CHAR **strp;
-     unsigned int *lenp;
-     int *abp;
+     cpp_token *header;
 {
-  const cpp_token *name = cpp_get_token (pfile);
+  int is_pragma = pfile->directive == &dtable[T_PRAGMA];
+  const unsigned char *dir;
+
+  if (is_pragma)
+    dir = U"pragma dependency";
+  else
+    dir = pfile->directive->name;
 
-  if (name->type != CPP_STRING && name->type != CPP_HEADER_NAME)
+  /* Allow macro expansion.  */
+  cpp_get_token (pfile, header);
+  if (header->type != CPP_STRING && header->type != CPP_HEADER_NAME)
     {
-      if (name->type == CPP_LESS)
-       name = _cpp_glue_header_name (pfile);
-      else
+      if (header->type != CPP_LESS)
        {
          cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
          return 1;
        }
+      if (glue_header_name (pfile, header))
+       return 1;
     }
-  if (name->val.name.len == 0)
+
+  if (header->val.str.len == 0)
     {
       cpp_error (pfile, "empty file name in #%s", dir);
       return 1;
     }
 
-  if (!trail && cpp_get_token (pfile)->type != CPP_EOF)
-    cpp_error (pfile, "junk at end of #%s", dir);
+  if (!is_pragma)
+    {
+      check_eol (pfile);
+      /* Get out of macro context, if we are.  */
+      skip_rest_of_line (pfile);
+      if (pfile->cb.include)
+       (*pfile->cb.include) (pfile, dir, header);
+    }
 
-  *lenp = name->val.name.len;
-  *strp = name->val.name.text;
-  *abp = (name->type == CPP_HEADER_NAME);
   return 0;
 }
 
-static int
+static void
 do_include (pfile)
      cpp_reader *pfile;
 {
-  unsigned int len;
-  const U_CHAR *str;
-  int ab;
-
-  if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab))
-    return 0;
+  cpp_token header;
 
-  _cpp_execute_include (pfile, str, len, 0, 0, ab);
-  if (CPP_OPTION (pfile, dump_includes))
-    pass_thru_directive (pfile);
-  return 0;
+  if (!parse_include (pfile, &header))
+    _cpp_execute_include (pfile, &header, 0, 0);
 }
 
-static int
+static void
 do_import (pfile)
      cpp_reader *pfile;
 {
-  unsigned int len;
-  const U_CHAR *str;
-  int ab;
+  cpp_token header;
 
-  if (CPP_OPTION (pfile, warn_import)
-      && !CPP_IN_SYSTEM_HEADER (pfile) && !pfile->import_warning)
+  if (!pfile->import_warning && CPP_OPTION (pfile, warn_import))
     {
       pfile->import_warning = 1;
       cpp_warning (pfile,
           "#import is obsolete, use an #ifndef wrapper in the header file");
     }
 
-  if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab))
-    return 0;
-
-  _cpp_execute_include (pfile, str, len, 1, 0, ab);
-  if (CPP_OPTION (pfile, dump_includes))
-    pass_thru_directive (pfile);
-  return 0;
+  if (!parse_include (pfile, &header))
+    _cpp_execute_include (pfile, &header, 1, 0);
 }
 
-static int
+static void
 do_include_next (pfile)
      cpp_reader *pfile;
 {
-  unsigned int len;
-  const U_CHAR *str;
-  struct file_name_list *search_start = 0;
-  int ab;
-
-  if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab))
-    return 0;
-
-  /* For #include_next, skip in the search path past the dir in which
-     the current file was found.  If this is the last directory in the
-     search path, don't include anything.  If the current file was
-     specified with an absolute path, use the normal search logic.  If
-     this is the primary source file, use the normal search logic and
-     generate a warning.  */
-  if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)))
-    {
-      if (CPP_BUFFER (pfile)->inc->foundhere)
-       {
-         search_start = CPP_BUFFER (pfile)->inc->foundhere->next;
-         if (!search_start)
-           return 0;
-       }
-    }
-  else
-    cpp_warning (pfile, "#include_next in primary source file");
-
-  _cpp_execute_include (pfile, str, len, 0, search_start, ab);
-  if (CPP_OPTION (pfile, dump_includes))
-    pass_thru_directive (pfile);
+  cpp_token header;
 
-  return 0;
+  if (!parse_include (pfile, &header))
+    _cpp_execute_include (pfile, &header, 0, 1);
 }
 
-/* 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.  */
+/* Subroutine of do_line.  Read possible flags after file name.  LAST
+   is the last flag seen; 0 if this is the first flag. Return the flag
+   if it is valid, 0 at the end of the directive. Otherwise complain.  */
 
-static int
-read_line_number (pfile, num)
+static unsigned int
+read_flag (pfile, last)
      cpp_reader *pfile;
-     int *num;
+     unsigned int last;
 {
-  const cpp_token *tok = cpp_get_token (pfile);
-  enum cpp_ttype type = tok->type;
-  const U_CHAR *p = tok->val.name.text;
-  unsigned int len = tok->val.name.len;
+  cpp_token token;
 
-  if (type == CPP_NUMBER && len == 1 && p[0] >= '1' && p[0] <= '4')
-    {
-      *num = p[0] - '0';
-      return 1;
-    }
-  else
+  _cpp_lex_token (pfile, &token);
+  if (token.type == CPP_NUMBER && token.val.str.len == 1)
     {
-      if (type != CPP_VSPACE && type != CPP_EOF)
-       cpp_error (pfile, "invalid format #line");
-      return 0;
+      unsigned int flag = token.val.str.text[0] - '0';
+
+      if (flag > last && flag <= 4
+         && (flag != 4 || last == 3)
+         && (flag != 2 || last == 0))
+       return flag;
     }
+
+  if (token.type != CPP_EOF)
+    cpp_error (pfile, "invalid flag \"%s\" in line directive",
+              cpp_token_as_text (pfile, &token));
+  return 0;
 }
 
 /* Another subroutine of do_line.  Convert a number in STR, of length
    LEN, to binary; store it in NUMP, and return 0 if the number was
-   legal, 1 if not.  Temporary, hopefully.  */
+   well-formed, 1 if not.  Temporary, hopefully.  */
 static int
 strtoul_for_line (str, len, nump)
      const U_CHAR *str;
@@ -509,346 +674,409 @@ strtoul_for_line (str, len, nump)
    Note that the filename string (if any) is treated as if it were an
    include filename.  That means no escape handling.  */
 
-static int
+static void
 do_line (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-  unsigned long new_lineno, old_lineno;
-  /* C99 raised the minimum limit on #line numbers.  */
-  unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
-  int action_number = 0;
-  enum cpp_ttype type;
-  const U_CHAR *str;
-  char *fname;
-  unsigned int len;
-  const cpp_token *tok;
+  cpp_buffer *buffer = pfile->buffer;
+  const char *filename = buffer->nominal_fname;
+  unsigned int lineno = buffer->lineno;
+  enum cpp_fc_reason reason = FC_RENAME;
+  unsigned long new_lineno;
+  unsigned int cap;
+  cpp_token token;
 
-  tok = cpp_get_token (pfile);
-  type = tok->type;
-  str = tok->val.name.text;
-  len = tok->val.name.len;
+  /* C99 raised the minimum limit on #line numbers.  */
+  cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
 
-  if (type != CPP_NUMBER || strtoul_for_line (str, len, &new_lineno))
+  /* #line commands expand macros.  */
+  cpp_get_token (pfile, &token);
+  if (token.type != CPP_NUMBER
+      || strtoul_for_line (token.val.str.text, token.val.str.len, &new_lineno))
     {
-      cpp_error (pfile, "token after #line is not a positive integer");
-      goto done;
+      cpp_error (pfile, "\"%s\" after #line is not a positive integer",
+                cpp_token_as_text (pfile, &token));
+      return;
     }      
 
   if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
     cpp_pedwarn (pfile, "line number out of range");
 
-  old_lineno = ip->lineno;
-  ip->lineno = new_lineno;
-  tok = cpp_get_token (pfile);
-  type = tok->type;
-  str = tok->val.name.text;
-  len = tok->val.name.len;
-
-  if (type == CPP_VSPACE || type == CPP_EOF)
-    goto done;
-  else if (type != CPP_STRING)
+  cpp_get_token (pfile, &token);
+  if (token.type == CPP_STRING)
     {
-      cpp_error (pfile, "second token after #line is not a string");
-      ip->lineno = old_lineno;  /* malformed #line should have no effect */
-      goto done;
-    }
-
-  fname = alloca (len + 1);
-  memcpy (fname, str, len);
-  fname[len] = '\0';
+      char *fname;
+      unsigned int len;
+
+      /* FIXME: memory leak.  */
+      len = token.val.str.len;
+      fname = xmalloc (len + 1);
+      memcpy (fname, token.val.str.text, len);
+      fname[len] = '\0';
     
-  if (strcmp (fname, ip->nominal_fname))
-    {
-      if (!strcmp (fname, ip->inc->name))
-       ip->nominal_fname = ip->inc->name;
-      else
-       ip->nominal_fname = _cpp_fake_include (pfile, fname);
-    }
+      _cpp_simplify_pathname (fname);
 
-  if (read_line_number (pfile, &action_number) == 0)
-    return 0;
+      if (! pfile->state.line_extension)
+       check_eol (pfile);
+      else
+       {
+         int flag = 0, sysp = 0;
 
-  if (CPP_PEDANTIC (pfile))
-    cpp_pedwarn (pfile, "garbage at end of #line");
+         flag = read_flag (pfile, flag);
+         if (flag == 1)
+           {
+             reason = FC_ENTER;
+             flag = read_flag (pfile, flag);
+           }
+         else if (flag == 2)
+           {
+             reason = FC_LEAVE;
+             flag = read_flag (pfile, flag);
+           }
+         if (flag == 3)
+           {
+             sysp = 1;
+             flag = read_flag (pfile, flag);
+             if (flag == 4)
+               sysp = 2, read_flag (pfile, flag);
+           }
 
-  /* This is somewhat questionable: change the buffer stack
-     depth so that output_line_command thinks we've stacked
-     another buffer. */
-  if (action_number == 1)
-    {
-      pfile->buffer_stack_depth++;
-      cpp_make_system_header (pfile, ip, 0);
-      read_line_number (pfile, &action_number);
-    }
-  else if (action_number == 2)
-    {
-      pfile->buffer_stack_depth--;
-      cpp_make_system_header (pfile, ip, 0);
-      read_line_number (pfile, &action_number);
-    }
-  if (action_number == 3)
-    {
-      cpp_make_system_header (pfile, ip, 1);
-      read_line_number (pfile, &action_number);
+         if (reason == FC_ENTER)
+           {
+             cpp_push_buffer (pfile, 0, 0, BUF_FAKE, fname);
+             buffer = pfile->buffer;
+           }
+         else if (reason == FC_LEAVE)
+           {
+             if (buffer->type != BUF_FAKE)
+               cpp_warning (pfile, "file \"%s\" left but not entered",
+                            buffer->nominal_fname);
+             else
+               {
+                 cpp_pop_buffer (pfile);
+                 buffer = pfile->buffer;
+                 if (strcmp (buffer->nominal_fname, fname))
+                   cpp_warning (pfile, "expected to return to file \"%s\"",
+                                buffer->nominal_fname);
+                 if (buffer->lineno + 1 != new_lineno)
+                   cpp_warning (pfile, "expected to return to line number %u",
+                                buffer->lineno + 1);
+                 if (buffer->sysp != sysp)
+                   cpp_warning (pfile, "header flags for \"%s\" have changed",
+                                buffer->nominal_fname);
+               }
+           }
+         buffer->sysp = sysp;
+       }
+      buffer->nominal_fname = fname;
     }
-  if (action_number == 4)
+  else if (token.type != CPP_EOF)
     {
-      cpp_make_system_header (pfile, ip, 2);
-      read_line_number (pfile, &action_number);
+      cpp_error (pfile, "\"%s\" is not a valid filename",
+                cpp_token_as_text (pfile, &token));
+      return;
     }
-   return 0;
 
- done:
-  return 0;
+  /* Our line number is incremented after the directive is processed.  */
+  buffer->lineno = new_lineno - 1;
+  _cpp_do_file_change (pfile, reason, filename, lineno);
 }
 
-/*
- * Report an error detected by the program we are processing.
- * Use the text of the line in the error message.
- * (We use error because it prints the filename & line#.)
- */
-
-static int
-do_error (pfile)
+/* Arrange the file_change callback.  */
+void
+_cpp_do_file_change (pfile, reason, from_file, from_lineno)
      cpp_reader *pfile;
+     enum cpp_fc_reason reason;
+     const char *from_file;
+     unsigned int from_lineno;
 {
-  U_CHAR *text, *limit;
+  if (pfile->cb.file_change)
+    {
+      cpp_file_change fc;
+      cpp_buffer *buffer = pfile->buffer;
 
-  text = pfile->limit;
-  _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0);
-  limit = pfile->limit;
-  pfile->limit = text;
-  cpp_error (pfile, "%.*s", (int)(limit - text), text);
+      fc.reason = reason;
+      fc.to.filename = buffer->nominal_fname;
+      fc.to.lineno = buffer->lineno + 1;
+      fc.sysp = buffer->sysp;
+      fc.externc = CPP_OPTION (pfile, cplusplus) && buffer->sysp == 2;
 
-  return 0;
+      /* Caller doesn't need to handle FC_ENTER.  */
+      if (reason == FC_ENTER)
+       {
+         if (buffer->prev)
+           {
+             from_file = buffer->prev->nominal_fname;
+             from_lineno = buffer->prev->lineno;
+           }
+         else
+           from_file = 0;
+       }
+      /* Special case for file "foo.i" with "# 1 foo.c" on first line.  */
+      else if (reason == FC_RENAME && ! buffer->prev
+              && pfile->directive_pos.line == 1)
+       from_file = 0;
+
+      fc.from.filename = from_file;
+      fc.from.lineno = from_lineno;
+      pfile->cb.file_change (pfile, &fc);
+    }
 }
 
 /*
- * Report a warning detected by the program we are processing.
- * Use the text of the line in the warning message, then continue.
+ * Report a warning or error detected by the program we are
+ * processing.  Use the directive's tokens in the error message.
  */
 
-static int
-do_warning (pfile)
+static void
+do_diagnostic (pfile, code, print_dir)
      cpp_reader *pfile;
+     enum error_type code;
+     int print_dir;
 {
-  U_CHAR *text, *limit;
+  if (_cpp_begin_message (pfile, code, NULL, 0))
+    {
+      if (print_dir)
+       fprintf (stderr, "#%s ", pfile->directive->name);
+      pfile->state.prevent_expansion++;
+      cpp_output_line (pfile, stderr);
+      pfile->state.prevent_expansion--;
+    }
+}
 
-  text = pfile->limit;
-  _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0);
-  limit = pfile->limit;
-  pfile->limit = text;
-  cpp_warning (pfile, "%.*s", (int)(limit - text), text);
-  return 0;
+static void
+do_error (pfile)
+     cpp_reader *pfile;
+{
+  do_diagnostic (pfile, ERROR, 1);
+}
+
+static void
+do_warning (pfile)
+     cpp_reader *pfile;
+{
+  do_diagnostic (pfile, WARNING, 1);
 }
 
 /* Report program identification.  */
 
-static int
+static void
 do_ident (pfile)
      cpp_reader *pfile;
 {
-  /* Next token should be a string constant.  */
-  if (cpp_get_token (pfile)->type == CPP_STRING)
-    /* And then a newline.  */
-    if (cpp_get_token (pfile)->type == CPP_EOF)
-      {
-       /* Good - ship it.  */
-       pass_thru_directive (pfile);
-       return 0;
-      }
+  cpp_token str;
 
-  cpp_error (pfile, "invalid #ident");
-  return 0;
+  cpp_get_token (pfile, &str);
+  if (str.type != CPP_STRING)
+    cpp_error (pfile, "invalid #ident");
+  else if (pfile->cb.ident)
+    (*pfile->cb.ident) (pfile, &str.val.str);
+
+  check_eol (pfile);
 }
 
 /* Pragmata handling.  We handle some of these, and pass the rest on
    to the front end.  C99 defines three pragmas and says that no macro
    expansion is to be performed on them; whether or not macro
    expansion happens for other pragmas is implementation defined.
-   This implementation never macro-expands the text after #pragma.
-
-   We currently do not support the _Pragma operator.  Support for that
-   has to be coordinated with the front end.  Proposed implementation:
-   both #pragma blah blah and _Pragma("blah blah") become
-   __builtin_pragma(blah blah) and we teach the parser about that.  */
+   This implementation never macro-expands the text after #pragma.  */
 
 /* Sub-handlers for the pragmas needing treatment here.
    They return 1 if the token buffer is to be popped, 0 if not. */
 struct pragma_entry
 {
+  struct pragma_entry *next;
   const char *name;
-  int (*handler) PARAMS ((cpp_reader *));
+  size_t len;
+  int isnspace;
+  union {
+    void (*handler) PARAMS ((cpp_reader *));
+    struct pragma_entry *space;
+  } u;
 };
 
-static int pragma_dispatch             
-    PARAMS ((cpp_reader *, const struct pragma_entry *,
-            const U_CHAR *, size_t));
-static int do_pragma_once              PARAMS ((cpp_reader *));
-static int do_pragma_implementation    PARAMS ((cpp_reader *));
-static int do_pragma_poison            PARAMS ((cpp_reader *));
-static int do_pragma_system_header     PARAMS ((cpp_reader *));
-static int do_pragma_gcc                PARAMS ((cpp_reader *));
-static int do_pragma_dependency         PARAMS ((cpp_reader *));
-
-static const struct pragma_entry top_pragmas[] =
+void
+cpp_register_pragma (pfile, space, name, handler)
+     cpp_reader *pfile;
+     const char *space;
+     const char *name;
+     void (*handler) PARAMS ((cpp_reader *));
 {
-  {"once", do_pragma_once},
-  {"implementation", do_pragma_implementation},
-  {"poison", do_pragma_poison},
-  {"GCC", do_pragma_gcc},
-  {NULL, NULL}
-};
+  struct pragma_entry **x, *new;
+  size_t len;
 
-static const struct pragma_entry gcc_pragmas[] =
-{
-  {"implementation", do_pragma_implementation},
-  {"poison", do_pragma_poison},
-  {"system_header", do_pragma_system_header},
-  {"dependency", do_pragma_dependency},
-  {NULL, NULL}
-};
+  x = &pfile->pragmas;
+  if (space)
+    {
+      struct pragma_entry *p = pfile->pragmas;
+      len = strlen (space);
+      while (p)
+       {
+         if (p->isnspace && p->len == len && !memcmp (p->name, space, len))
+           {
+             x = &p->u.space;
+             goto found;
+           }
+         p = p->next;
+       }
+      cpp_ice (pfile, "unknown #pragma namespace %s", space);
+      return;
+    }
 
-static int pragma_dispatch (pfile, table, p, len)
-     cpp_reader *pfile;
-     const struct pragma_entry *table;
-     const U_CHAR *p;
-     size_t len;
-{
-  for (; table->name; table++)
-    if (strlen (table->name) == len && !memcmp (p, table->name, len))
-      return (*table->handler) (pfile);
-  return 0;
+ found:
+  new = xnew (struct pragma_entry);
+  new->name = name;
+  new->len = strlen (name);
+  new->isnspace = 0;
+  new->u.handler = handler;
+
+  new->next = *x;
+  *x = new;
 }
 
-static int
-do_pragma (pfile)
+void
+cpp_register_pragma_space (pfile, space)
      cpp_reader *pfile;
+     const char *space;
 {
-  const cpp_token *tok;
-  int pop;
+  struct pragma_entry *new;
+  const struct pragma_entry *p = pfile->pragmas;
+  size_t len = strlen (space);
 
-  tok = cpp_get_token (pfile);
-  if (tok->type == CPP_EOF)
-    return 0;
-  else if (tok->type != CPP_NAME)
+  while (p)
     {
-      cpp_error (pfile, "malformed #pragma directive");
-      return 0;
+      if (p->isnspace && p->len == len && !memcmp (p->name, space, len))
+       /* Multiple different callers are allowed to register the same
+          namespace.  */
+       return;
+      p = p->next;
     }
 
-  pop = pragma_dispatch (pfile, top_pragmas,
-                        tok->val.name.text, tok->val.name.len);
-  if (!pop)
-    pass_thru_directive (pfile);
-  return 0;
-}
+  new = xnew (struct pragma_entry);
+  new->name = space;
+  new->len = len;
+  new->isnspace = 1;
+  new->u.space = 0;
 
-static int
-do_pragma_gcc (pfile)
+  new->next = pfile->pragmas;
+  pfile->pragmas = new;
+}
+  
+void
+_cpp_init_internal_pragmas (pfile)
      cpp_reader *pfile;
 {
-  const cpp_token *tok;
+  /* top level */
+  cpp_register_pragma (pfile, 0, "poison", do_pragma_poison);
+  cpp_register_pragma (pfile, 0, "once", do_pragma_once);
 
-  tok = cpp_get_token (pfile);
-  if (tok->type == CPP_EOF)
-    return 1;
-  else if (tok->type != CPP_NAME)
-    return 0;
-  
-  return pragma_dispatch (pfile, gcc_pragmas,
-                         tok->val.name.text, tok->val.name.len);
+  /* GCC namespace */
+  cpp_register_pragma_space (pfile, "GCC");
+
+  cpp_register_pragma (pfile, "GCC", "poison", do_pragma_poison);
+  cpp_register_pragma (pfile, "GCC", "system_header", do_pragma_system_header);
+  cpp_register_pragma (pfile, "GCC", "dependency", do_pragma_dependency);
 }
 
-static int
-do_pragma_once (pfile)
+static void
+do_pragma (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-
-  /* Allow #pragma once in system headers, since that's not the user's
-     fault.  */
-  if (!CPP_IN_SYSTEM_HEADER (pfile))
-    cpp_warning (pfile, "#pragma once is obsolete");
-      
-  if (CPP_PREV_BUFFER (ip) == NULL)
-    cpp_warning (pfile, "#pragma once outside include file");
-  else
-    ip->inc->cmacro = NEVER_REREAD;
+  const struct pragma_entry *p;
+  cpp_token tok;
+  const cpp_hashnode *node;
+  const U_CHAR *name;
+  size_t len;
+  int drop = 0;
+
+  p = pfile->pragmas;
+  pfile->state.prevent_expansion++;
+  cpp_start_lookahead (pfile);
+
+ new_space:
+  cpp_get_token (pfile, &tok);
+  if (tok.type == CPP_NAME)
+    {
+      node = tok.val.node;
+      name = node->name;
+      len = node->length;
+      while (p)
+       {
+         if (strlen (p->name) == len && !memcmp (p->name, name, len))
+           {
+             if (p->isnspace)
+               {
+                 p = p->u.space;
+                 goto new_space;
+               }
+             else
+               {
+                 (*p->u.handler) (pfile);
+                 drop = 1;
+                 break;
+               }
+           }
+         p = p->next;
+       }
+    }
 
-  return 1;
+  cpp_stop_lookahead (pfile, drop);
+  pfile->state.prevent_expansion--;
+
+  if (!drop && pfile->cb.def_pragma)
+    (*pfile->cb.def_pragma) (pfile);
 }
 
-static int
-do_pragma_implementation (pfile)
+static void
+do_pragma_once (pfile)
      cpp_reader *pfile;
 {
-  /* Be quiet about `#pragma implementation' for a file only if it hasn't
-     been included yet.  */
-  const cpp_token *tok = cpp_get_token (pfile);
-  char *copy;
-
-  if (tok->type == CPP_EOF)
-    return 0;
-  else if (tok->type != CPP_STRING
-          || cpp_get_token (pfile)->type != CPP_EOF)
-    {
-      cpp_error (pfile, "malformed #pragma implementation");
-      return 1;
-    }
+  cpp_warning (pfile, "#pragma once is obsolete");
+  if (pfile->buffer->prev == NULL)
+    cpp_warning (pfile, "#pragma once in main file");
+  else
+    _cpp_never_reread (pfile->buffer->inc);
 
-  /* Make a NUL-terminated copy of the string.  */
-  copy = alloca (tok->val.name.len + 1);
-  memcpy (copy, tok->val.name.text, tok->val.name.len);
-  copy[tok->val.name.len] = '\0';
-  
-  if (cpp_included (pfile, copy))
-    cpp_warning (pfile,
-        "#pragma implementation for %s appears after file is included",
-                copy);
-  return 0;
+  check_eol (pfile);
 }
 
-static int
+static void
 do_pragma_poison (pfile)
      cpp_reader *pfile;
 {
   /* Poison these symbols so that all subsequent usage produces an
      error message.  */
-  const cpp_token *tok;
+  cpp_token tok;
   cpp_hashnode *hp;
-  int writeit;
-
-  /* As a rule, don't include #pragma poison commands in output,  
-     unless the user asks for them.  */
-  writeit = (CPP_OPTION (pfile, debug_output)
-            || CPP_OPTION (pfile, dump_macros) == dump_definitions
-            || CPP_OPTION (pfile, dump_macros) == dump_names);
 
+  pfile->state.poisoned_ok = 1;
   for (;;)
     {
-      tok = cpp_get_token (pfile);
-      if (tok->type == CPP_EOF)
+      _cpp_lex_token (pfile, &tok);
+      if (tok.type == CPP_EOF)
        break;
-      if (tok->type != CPP_NAME)
+      if (tok.type != CPP_NAME)
        {
-         cpp_error (pfile, "invalid #pragma poison directive");
-         return 1;
+         cpp_error (pfile, "invalid #pragma GCC poison directive");
+         break;
        }
 
-      hp = cpp_lookup (pfile, tok->val.name.text, tok->val.name.len);
-      if (hp->type == T_POISON)
-       ;  /* It is allowed to poison the same identifier twice.  */
-      else
-       {
-         if (hp->type != T_VOID)
-           cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name);
-         _cpp_free_definition (hp);
-         hp->type = T_POISON;
-       }
+      hp = tok.val.node;
+      if (hp->flags & NODE_POISONED)
+       continue;
+
+      if (hp->type == NT_MACRO)
+       cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name);
+      _cpp_free_definition (hp);
+      hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
     }
-  return !writeit;
+  pfile->state.poisoned_ok = 0;
+
+#if 0                          /* Doesn't quite work yet.  */
+  if (tok.type == CPP_EOF && pfile->cb.poison)
+    (*pfile->cb.poison) (pfile);
+#endif
 }
 
 /* Mark the current header as a system header.  This will suppress
@@ -857,312 +1085,283 @@ do_pragma_poison (pfile)
    conforming C, but cannot be certain that their headers appear in a
    system include directory.  To prevent abuse, it is rejected in the
    primary source file.  */
-static int
+static void
 do_pragma_system_header (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-  if (CPP_PREV_BUFFER (ip) == NULL)
-    cpp_warning (pfile, "#pragma system_header outside include file");
+  cpp_buffer *buffer = pfile->buffer;
+
+  if (buffer->prev == 0)
+    cpp_warning (pfile, "#pragma system_header ignored outside include file");
   else
-    cpp_make_system_header (pfile, ip, 1);
+    cpp_make_system_header (pfile, 1, 0);
 
-  return 1;
+  check_eol (pfile);
 }
 
 /* Check the modified date of the current include file against a specified
    file. Issue a diagnostic, if the specified file is newer. We use this to
    determine if a fixed header should be refixed.  */
-static int
+static void
 do_pragma_dependency (pfile)
      cpp_reader *pfile;
 {
-  const U_CHAR *name;
-  unsigned int len;
-  int ordering, ab;
-  char left, right;
+  cpp_token header, msg;
+  int ordering;
  
-  if (parse_include (pfile, U"pragma dependency", 1, &name, &len, &ab))
-    return 1;
+  if (parse_include (pfile, &header))
+    return;
 
-  left = ab ? '<' : '"';
-  right = ab ? '>' : '"';
-  ordering = _cpp_compare_file_date (pfile, name, len, ab);
+  ordering = _cpp_compare_file_date (pfile, &header);
   if (ordering < 0)
-    cpp_warning (pfile, "cannot find source %c%s%c", left, name, right);
+    cpp_warning (pfile, "cannot find source %s",
+                cpp_token_as_text (pfile, &header));
   else if (ordering > 0)
     {
-      const cpp_token *msg = cpp_get_token (pfile);
-      
-      cpp_warning (pfile, "current file is older than %c%s%c",
-                  left, name, right);
-      if (msg->type != CPP_EOF)
-       {
-         U_CHAR *text, *limit;
-
-         text = pfile->limit;
-         _cpp_dump_list (pfile, &pfile->token_list, msg, 0);
-         limit = pfile->limit;
-         pfile->limit = text;
-         cpp_warning (pfile, "%.*s", (int)(limit - text), text);
-       }
+      cpp_warning (pfile, "current file is older than %s",
+                  cpp_token_as_text (pfile, &header));
+      cpp_start_lookahead (pfile);
+      cpp_get_token (pfile, &msg);
+      cpp_stop_lookahead (pfile, msg.type == CPP_EOF);
+      if (msg.type != CPP_EOF)
+       do_diagnostic (pfile, WARNING, 0);
     }
-  return 1;
 }
 
-/* Just ignore #sccs, on systems where we define it at all.  */
-#ifdef SCCS_DIRECTIVE
+/* Check syntax is "(string-literal)".  Returns 0 on success.  */
 static int
-do_sccs (pfile)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-{
-  return 0;
-}
-#endif
-
-/* 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 the
-   hash node for SYMBOL.  Otherwise, return NULL.  */
-
-static const cpp_hashnode *
-detect_if_not_defined (pfile)
+get__Pragma_string (pfile, string)
      cpp_reader *pfile;
+     cpp_token *string;
 {
-  const cpp_token *token;
-  cpp_hashnode *cmacro = 0;
-
-  /* We are guaranteed that tokens are consecutive and end in CPP_EOF.  */
-  token = pfile->first_directive_token + 2;
-
-  if (token->type != CPP_NOT)
-    return 0;
+  cpp_token paren;
 
-  token++;
-  if (token->type != CPP_NAME
-      || !str_match (token->val.name.text, token->val.name.len, "defined"))
-    return 0;
+  cpp_get_token (pfile, &paren);
+  if (paren.type != CPP_OPEN_PAREN)
+    return 1;
 
-  token++;
-  if (token->type == CPP_OPEN_PAREN)
-    token++;
+  cpp_get_token (pfile, string);
+  if (string->type != CPP_STRING && string->type != CPP_WSTRING)
+    return 1;
 
-  if (token->type != CPP_NAME)
-    return 0;
+  cpp_get_token (pfile, &paren);
+  return paren.type != CPP_CLOSE_PAREN;
+}
 
-  cmacro = cpp_lookup (pfile, token->val.name.text, token->val.name.len);
+/* Returns a malloced buffer containing a destringized cpp_string by
+   removing the first \ of \" and \\ sequences.  */
+static unsigned char *
+destringize (in, len)
+     const cpp_string *in;
+     unsigned int *len;
+{
+  const unsigned char *src, *limit;
+  unsigned char *dest, *result;
 
-  if (token[-1].type == CPP_OPEN_PAREN)
+  dest = result = (unsigned char *) xmalloc (in->len);
+  for (src = in->text, limit = src + in->len; src < limit;)
     {
-      token++;
-      if (token->type != CPP_CLOSE_PAREN)
-       return 0;
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+       src++;
+      *dest++ = *src++;
     }
 
-  token++;
-  if (token->type != CPP_EOF)
-    return 0;
-
-  return cmacro;
+  *len = dest - result;
+  return result;
 }
 
-/* Parse an #ifdef or #ifndef directive.  Returns the hash node of the
-   macro being tested, and issues various error messages.  */
-
-static const cpp_hashnode *
-parse_ifdef (pfile, name)
+void
+_cpp_do__Pragma (pfile)
      cpp_reader *pfile;
-     const U_CHAR *name;
 {
-  const U_CHAR *ident;
+  cpp_token string;
+  unsigned char *buffer;
   unsigned int len;
-  enum cpp_ttype type;
-  const cpp_hashnode *node = 0;
 
-  const cpp_token *token = cpp_get_token (pfile);
-  type = token->type;
-  ident = token->val.name.text;
-  len = token->val.name.len;
-
-  if (!CPP_TRADITIONAL (pfile))
+  if (get__Pragma_string (pfile, &string))
     {
-      if (type == CPP_EOF)
-       cpp_pedwarn (pfile, "#%s with no argument", name);
-      else if (type != CPP_NAME)
-       cpp_pedwarn (pfile, "#%s with invalid argument", name);
-      else if (cpp_get_token (pfile)->type != CPP_EOF)
-       cpp_pedwarn (pfile, "garbage at end of #%s", name);
+      cpp_error (pfile, "_Pragma takes a parenthesized string literal");
+      return;
     }
 
-  if (type == CPP_NAME)
-    node = cpp_lookup (pfile, ident, len);
-  if (node && node->type == T_POISON)
-    cpp_error (pfile, "attempt to use poisoned identifier \"%s\"", node->name);
-    
-  return node;
+  buffer = destringize (&string.val.str, &len);
+  run_directive (pfile, T_PRAGMA, BUF_PRAGMA, (char *) buffer, len);
+  free ((PTR) buffer);
 }
 
-/* #ifdef is dead simple.  */
+/* Just ignore #sccs, on systems where we define it at all.  */
+#ifdef SCCS_DIRECTIVE
+static void
+do_sccs (pfile)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+{
+}
+#endif
 
-static int
+static void
 do_ifdef (pfile)
      cpp_reader *pfile;
 {
-  int def = 0;
-  const cpp_hashnode *node = 0;
+  int skip = 1;
 
-  if (! pfile->skipping)
+  if (! pfile->buffer->was_skipping)
     {
-      node = parse_ifdef (pfile, dtable[T_IFDEF].name);
+      const cpp_hashnode *node = lex_macro_node (pfile);
+
       if (node)
-       def = (node->type != T_VOID && node->type != T_POISON);
+       skip = node->type != NT_MACRO;
+
+      if (node)
+       check_eol (pfile);
     }
 
-  push_conditional (pfile, !def, T_IFDEF, 0);
-  return 0;
+  push_conditional (pfile, skip, T_IFDEF, 0);
 }
 
-/* #ifndef is a tad more complex, because we need to check for a
-   no-reinclusion wrapper.  */
-
-static int
+static void
 do_ifndef (pfile)
      cpp_reader *pfile;
 {
-  int start_of_file = 0;
-  int def = 0;
-  const cpp_hashnode *cmacro = 0;
+  int skip = 1;
+  const cpp_hashnode *node = 0;
 
-  if (! pfile->skipping)
+  if (! pfile->buffer->was_skipping)
     {
-      start_of_file = (pfile->token_list.flags & BEG_OF_FILE);
-      cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
-      if (cmacro)
-       def = cmacro->type != T_VOID;
+      node = lex_macro_node (pfile);
+      if (node)
+       skip = node->type == NT_MACRO;
+
+      if (node)
+       check_eol (pfile);
     }
 
-  push_conditional (pfile, def, T_IFNDEF, start_of_file ? cmacro : 0);
-  return 0;
+  push_conditional (pfile, skip, T_IFNDEF, node);
 }
 
-/* #if is straightforward; just call _cpp_parse_expr, then conditional_skip.
-   Also, check for a reinclude preventer of the form #if !defined (MACRO).  */
+/* #if cooperates with parse_defined to handle multiple-include
+   optimisations.  If macro expansions or identifiers appear in the
+   expression, we cannot treat it as a controlling conditional, since
+   their values could change in the future.  */
 
-static int
+static void
 do_if (pfile)
      cpp_reader *pfile;
 {
+  int skip = 1;
   const cpp_hashnode *cmacro = 0;
-  int value = 0;
 
-  if (! pfile->skipping)
+  if (! pfile->buffer->was_skipping)
     {
-      cmacro = detect_if_not_defined (pfile);  
-      value = _cpp_parse_expr (pfile);
+      /* Controlling macro of #if ! defined ()  */
+      pfile->mi_ind_cmacro = 0;
+      skip = _cpp_parse_expr (pfile) == 0;
+      cmacro = pfile->mi_ind_cmacro;
     }
-  push_conditional (pfile, value == 0, T_IF, cmacro);
-  return 0;
+
+  push_conditional (pfile, skip, T_IF, cmacro);
 }
 
-/* #else flips pfile->skipping and continues without changing
+/* Flip skipping state if appropriate and continue without changing
    if_stack; this is so that the error message for missing #endif's
    etc. will point to the original #if.  */
 
-static int
+static void
 do_else (pfile)
      cpp_reader *pfile;
 {
-  struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
-  validate_else (pfile, dtable[T_ELSE].name);
+  cpp_buffer *buffer = pfile->buffer;
+  struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
+    cpp_error (pfile, "#else without #if");
+  else
     {
-      cpp_error (pfile, "#else without #if");
-      return 0;
-    }
-  if (ifs->type == T_ELSE)
-    {
-      cpp_error (pfile, "#else after #else");
-      cpp_error_with_line (pfile, ifs->lineno, ifs->colno,
-                          "the conditional began here");
-    }
+      if (ifs->type == T_ELSE)
+       {
+         cpp_error (pfile, "#else after #else");
+         cpp_error_with_line (pfile, ifs->pos.line, ifs->pos.col,
+                              "the conditional began here");
+       }
+      ifs->type = T_ELSE;
 
-  /* #ifndef can't have its special treatment for containing the whole file
-     if it has a #else clause.  */
-  ifs->cmacro = 0;
-  ifs->type = T_ELSE;
-  if (! ifs->was_skipping)
-    {
-      /* If pfile->skipping is 2, one of the blocks in an #if/#elif/... chain
-        succeeded, so we mustn't do the else block.  */
-      if (pfile->skipping < 2)
-       pfile->skipping = ! pfile->skipping;
+      /* Buffer->was_skipping is 1 if all conditionals in this chain
+        have been false, 2 if a conditional has been true.  */
+      if (! ifs->was_skipping && buffer->was_skipping != 2)
+       buffer->was_skipping = ! buffer->was_skipping;
+
+      /* Invalidate any controlling macro.  */
+      ifs->mi_cmacro = 0;
     }
-  return 0;
+
+  check_eol (pfile);
 }
 
-/*
- * handle a #elif directive by not changing if_stack either.
- * see the comment above do_else.
- */
+/* handle a #elif directive by not changing if_stack either.  see the
+   comment above do_else.  */
 
-static int
+static void
 do_elif (pfile)
      cpp_reader *pfile;
 {
-  struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
+  cpp_buffer *buffer = pfile->buffer;
+  struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
+    cpp_error (pfile, "#elif without #if");
+  else
     {
-      cpp_error (pfile, "#elif without #if");
-      return 0;
-    }
-  if (ifs->type == T_ELSE)
-    {
-      cpp_error (pfile, "#elif after #else");
-      cpp_error_with_line (pfile, ifs->lineno, ifs->colno,
-                          "the conditional began here");
-    }
+      if (ifs->type == T_ELSE)
+       {
+         cpp_error (pfile, "#elif after #else");
+         cpp_error_with_line (pfile, ifs->pos.line, ifs->pos.col,
+                              "the conditional began here");
+       }
+      ifs->type = T_ELIF;
 
-  ifs->type = T_ELIF;
-  if (ifs->was_skipping)
-    return 0;  /* Don't evaluate a nested #if */
+      /* Don't evaluate #elif if our higher level is skipping.  */
+      if (! ifs->was_skipping)
+       {
+         /* Buffer->was_skipping is 1 if all conditionals in this
+            chain have been false, 2 if a conditional has been true.  */
+         if (buffer->was_skipping == 1)
+           buffer->was_skipping = ! _cpp_parse_expr (pfile);
+         else
+           buffer->was_skipping = 2;
 
-  if (pfile->skipping != 1)
-    {
-      pfile->skipping = 2;  /* one block succeeded, so don't do any others */
-      return 0;
+         /* Invalidate any controlling macro.  */
+         ifs->mi_cmacro = 0;
+       }
     }
-
-  pfile->skipping = ! _cpp_parse_expr (pfile);
-  return 0;
 }
 
 /* #endif pops the if stack and resets pfile->skipping.  */
 
-static int
+static void
 do_endif (pfile)
      cpp_reader *pfile;
 {
-  struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
-
-  validate_else (pfile, dtable[T_ENDIF].name);
+  cpp_buffer *buffer = pfile->buffer;
+  struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
     cpp_error (pfile, "#endif without #if");
   else
     {
-      CPP_BUFFER (pfile)->if_stack = ifs->next;
-      pfile->skipping = ifs->was_skipping;
-      pfile->potential_control_macro = ifs->cmacro;
+      /* If potential control macro, we go back outside again.  */
+      if (ifs->next == 0 && ifs->mi_cmacro)
+       {
+         pfile->mi_state = MI_OUTSIDE;
+         pfile->mi_cmacro = ifs->mi_cmacro;
+       }
+
+      buffer->if_stack = ifs->next;
+      buffer->was_skipping = ifs->was_skipping;
       obstack_free (pfile->buffer_ob, ifs);
     }
-  return 0;
-}
 
+  check_eol (pfile);
+}
 
 /* Push an if_stack entry and set pfile->skipping accordingly.
    If this is a #ifndef starting at the beginning of a file,
@@ -1176,257 +1375,246 @@ push_conditional (pfile, skip, type, cmacro)
      const cpp_hashnode *cmacro;
 {
   struct if_stack *ifs;
+  cpp_buffer *buffer = pfile->buffer;
 
   ifs = xobnew (pfile->buffer_ob, struct if_stack);
-  ifs->lineno = _cpp_get_line (pfile, &ifs->colno);
-  ifs->next = CPP_BUFFER (pfile)->if_stack;
-  ifs->cmacro = cmacro;
-  ifs->was_skipping = pfile->skipping;
+  ifs->pos = pfile->directive_pos;
+  ifs->next = buffer->if_stack;
+  ifs->was_skipping = buffer->was_skipping;
   ifs->type = type;
+  if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0)
+    ifs->mi_cmacro = cmacro;
+  else
+    ifs->mi_cmacro = 0;
 
-  if (!pfile->skipping)
-    pfile->skipping = skip;
-
-  CPP_BUFFER (pfile)->if_stack = ifs;
-}
-
-/* Issue -pedantic warning for text which is not a comment following
-   an #else or #endif.  */
-
-static void
-validate_else (pfile, directive)
-     cpp_reader *pfile;
-     const U_CHAR *directive;
-{
-  if (CPP_PEDANTIC (pfile) && cpp_get_token (pfile)->type != CPP_EOF)
-    cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
+  buffer->was_skipping = skip;
+  buffer->if_stack = ifs;
 }
 
-/* Called when we reach the end of a file.  Walk back up the
-   conditional stack till we reach its level at entry to this file,
-   issuing error messages.  Then force skipping off.  */
-static void
-unwind_if_stack (pfile, pbuf)
-     cpp_reader *pfile;
-     cpp_buffer *pbuf;
-{
-  struct if_stack *ifs, *nifs;
-
-  for (ifs = pbuf->if_stack; ifs; ifs = nifs)
-    {
-      cpp_error_with_line (pfile, ifs->lineno, ifs->colno, "unterminated #%s",
-                          dtable[ifs->type].name);
-      nifs = ifs->next;
-      /* No need to free - they'll all go away with the buffer.  */
-    }
-  pfile->skipping = 0;
-}
+/* Read the tokens of the answer into the macro pool.  Only commit the
+   memory if we intend it as permanent storage, i.e. the #assert case.
+   Returns 0 on success.  */
 
-/* Parses an assertion, returning a pointer to the hash node of the
-   predicate, or 0 on error.  If an answer was supplied, it is
-   allocated and placed in ANSWERP, otherwise it is set to 0.  We use
-   _cpp_get_raw_token, since we cannot assume tokens are consecutive
-   in a #if statement (we may be in a macro), and we don't want to
-   macro expand.  */
-cpp_hashnode *
-_cpp_parse_assertion (pfile, answerp)
+static int
+parse_answer (pfile, answerp, type)
      cpp_reader *pfile;
      struct answer **answerp;
+     int type;
 {
-  struct answer *answer = 0;
-  cpp_toklist *list;
-  U_CHAR *sym;
-  const cpp_token *token, *predicate;
-  const struct directive *d = pfile->token_list.directive;
-  unsigned int len = 0;
-
-  predicate = _cpp_get_raw_token (pfile);
-  if (predicate->type == CPP_EOF)
+  cpp_token paren, *token;
+  struct answer *answer;
+
+  if (POOL_FRONT (&pfile->macro_pool) + sizeof (struct answer) >
+      POOL_LIMIT (&pfile->macro_pool))
+    _cpp_next_chunk (&pfile->macro_pool, sizeof (struct answer), 0);
+  answer = (struct answer *) POOL_FRONT (&pfile->macro_pool);
+  answer->count = 0;
+
+  /* In a conditional, it is legal to not have an open paren.  We
+     should save the following token in this case.  */
+  if (type == T_IF)
+    cpp_start_lookahead (pfile);
+  cpp_get_token (pfile, &paren);
+  if (type == T_IF)
+    cpp_stop_lookahead (pfile, paren.type == CPP_OPEN_PAREN);
+
+  /* If not a paren, see if we're OK.  */
+  if (paren.type != CPP_OPEN_PAREN)
     {
-      cpp_error (pfile, "assertion without predicate");
-      return 0;
-    }
-  else if (predicate->type != CPP_NAME)
-    {
-      cpp_error (pfile, "predicate must be an identifier");
-      return 0;
-    }
+      /* In a conditional no answer is a test for any answer.  It
+         could be followed by any token.  */
+      if (type == T_IF)
+       return 0;
+
+      /* #unassert with no answer is valid - it removes all answers.  */
+      if (type == T_UNASSERT && paren.type == CPP_EOF)
+       return 0;
 
-  token = _cpp_get_raw_token (pfile);
-  if (token->type != CPP_OPEN_PAREN)
-    {
-      /* #unassert and #if are OK without predicate.  */
-      if (d == &dtable[T_UNASSERT])
-       {
-         if (token->type == CPP_EOF)
-           goto lookup_node;
-       }
-      else if (d != &dtable[T_ASSERT])
-       {
-         _cpp_push_token (pfile, token);
-         goto lookup_node;
-       }
       cpp_error (pfile, "missing '(' after predicate");
-      return 0;
+      return 1;
     }
 
-  /* Allocate a struct answer, and copy the answer to it.  */
-  answer = (struct answer *) xmalloc (sizeof (struct answer));
-  list = &answer->list;
-  _cpp_init_toklist (list, NO_DUMMY_TOKEN);
-
   for (;;)
     {
-      cpp_token *dest;
-
-      token = _cpp_get_raw_token (pfile);
-
-      if (token->type == CPP_EOF)
+      token = &answer->first[answer->count];
+      /* Check we have room for the token.  */
+      if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
        {
-         cpp_error (pfile, "missing ')' to complete answer");
-         goto error;
+         _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_token),
+                          (unsigned char **) &answer);
+         token = &answer->first[answer->count];
        }
+
+      cpp_get_token (pfile, token);
       if (token->type == CPP_CLOSE_PAREN)
        break;
 
-      /* Copy the token.  */
-      _cpp_expand_token_space (list, 1);
-      dest = &list->tokens[list->tokens_used++];
-      *dest = *token;
-
-      if (token_spellings[token->type].type > SPELL_NONE)
+      if (token->type == CPP_EOF)
        {
-         _cpp_expand_name_space (list, token->val.name.len);
-         dest->val.name.text = list->namebuf + list->name_used;
-         memcpy (list->namebuf + list->name_used,
-                 token->val.name.text, token->val.name.len);
-         list->name_used += token->val.name.len;
+         cpp_error (pfile, "missing ')' to complete answer");
+         return 1;
        }
+      answer->count++;
     }
 
-  if (list->tokens_used == 0)
+  if (answer->count == 0)
     {
       cpp_error (pfile, "predicate's answer is empty");
-      goto error;
+      return 1;
     }
 
   /* Drop whitespace at start.  */
-  list->tokens[0].flags &= ~PREV_WHITE;
+  answer->first->flags &= ~PREV_WHITE;
+  *answerp = answer;
 
-  if ((d == &dtable[T_ASSERT] || d == &dtable[T_UNASSERT])
-      && token[1].type != CPP_EOF)
-    {
-      cpp_error (pfile, "junk at end of assertion");
-      goto error;
-    }
+  if (type == T_ASSERT || type == T_UNASSERT)
+    check_eol (pfile);
+  return 0;
+}
 
- lookup_node:
-  *answerp = answer;
-  len = predicate->val.name.len;
-  sym = alloca (len + 1);
+/* Parses an assertion, returning a pointer to the hash node of the
+   predicate, or 0 on error.  If an answer was supplied, it is placed
+   in ANSWERP, otherwise it is set to 0.  */
+static cpp_hashnode *
+parse_assertion (pfile, answerp, type)
+     cpp_reader *pfile;
+     struct answer **answerp;
+     int type;
+{
+  cpp_hashnode *result = 0;
+  cpp_token predicate;
+
+  /* We don't expand predicates or answers.  */
+  pfile->state.prevent_expansion++;
+
+  *answerp = 0;
+  cpp_get_token (pfile, &predicate);
+  if (predicate.type == CPP_EOF)
+    cpp_error (pfile, "assertion without predicate");
+  else if (predicate.type != CPP_NAME)
+    cpp_error (pfile, "predicate must be an identifier");
+  else if (parse_answer (pfile, answerp, type) == 0)
+    {
+      unsigned int len = predicate.val.node->length;
+      unsigned char *sym = alloca (len + 1);
 
-  /* Prefix '#' to get it out of macro namespace.  */
-  sym[0] = '#';
-  memcpy (sym + 1, predicate->val.name.text, len);
-  return cpp_lookup (pfile, sym, len);
+      /* Prefix '#' to get it out of macro namespace.  */
+      sym[0] = '#';
+      memcpy (sym + 1, predicate.val.node->name, len);
+      result = cpp_lookup (pfile, sym, len + 1);
+    }
 
- error:
-  FREE_ANSWER (answer);
-  return 0;
+  pfile->state.prevent_expansion--;
+  return result;
 }
 
 /* Returns a pointer to the pointer to the answer in the answer chain,
    or a pointer to NULL if the answer is not in the chain.  */
-struct answer **
-_cpp_find_answer (node, candidate)
+static struct answer **
+find_answer (node, candidate)
      cpp_hashnode *node;
-     const cpp_toklist *candidate;
+     const struct answer *candidate;
 {
+  unsigned int i;
   struct answer **result;
 
   for (result = &node->value.answers; *result; result = &(*result)->next)
-    if (_cpp_equiv_toklists (&(*result)->list, candidate))
-      break;
+    {
+      struct answer *answer = *result;
+
+      if (answer->count == candidate->count)
+       {
+         for (i = 0; i < answer->count; i++)
+           if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i]))
+             break;
+
+         if (i == answer->count)
+           break;
+       }
+    }
 
   return result;
 }
 
-#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
-#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0)
-#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0)
-static int
+/* Test an assertion within a preprocessor conditional.  Returns
+   non-zero on failure, zero on success.  On success, the result of
+   the test is written into VALUE.  */
+int
+_cpp_test_assertion (pfile, value)
+     cpp_reader *pfile;
+     int *value;
+{
+  struct answer *answer;
+  cpp_hashnode *node;
+
+  node = parse_assertion (pfile, &answer, T_IF);
+  if (node)
+    *value = (node->type == NT_ASSERTION &&
+             (answer == 0 || *find_answer (node, answer) != 0));
+
+  /* We don't commit the memory for the answer - it's temporary only.  */
+  return node == 0;
+}
+
+static void
 do_assert (pfile)
      cpp_reader *pfile;
 {
   struct answer *new_answer;
   cpp_hashnode *node;
   
-  node = _cpp_parse_assertion (pfile, &new_answer);
+  node = parse_assertion (pfile, &new_answer, T_ASSERT);
   if (node)
     {
+      /* Place the new answer in the answer list.  First check there
+         is not a duplicate.  */
       new_answer->next = 0;
-      new_answer->list.line = pfile->token_list.line;
-      new_answer->list.file = pfile->token_list.file;
-
-      if (node->type == T_ASSERTION)
+      if (node->type == NT_ASSERTION)
        {
-         if (*_cpp_find_answer (node, &new_answer->list))
-           goto err;
+         if (*find_answer (node, new_answer))
+           {
+             cpp_warning (pfile, "\"%s\" re-asserted", node->name + 1);
+             return;
+           }
          new_answer->next = node->value.answers;
        }
-      node->type = T_ASSERTION;
+      node->type = NT_ASSERTION;
       node->value.answers = new_answer;
+      POOL_COMMIT (&pfile->macro_pool, (sizeof (struct answer)
+                                       + (new_answer->count - 1)
+                                       * sizeof (cpp_token)));
     }
-  return 0;
-
- err:
-  cpp_warning (pfile, "\"%.*s\" re-asserted",
-              node->length - 1, node->name + 1);
-  FREE_ANSWER (new_answer);
-  return 0;
 }
 
-static int
+static void
 do_unassert (pfile)
      cpp_reader *pfile;
 {
   cpp_hashnode *node;
-  struct answer *answer, *temp, *next;
+  struct answer *answer;
   
-  node = _cpp_parse_assertion (pfile, &answer);
-  if (node)
+  node = parse_assertion (pfile, &answer, T_UNASSERT);
+  /* It isn't an error to #unassert something that isn't asserted.  */
+  if (node && node->type == NT_ASSERTION)
     {
-      /* It isn't an error to #unassert something that isn't asserted.  */
-      if (node->type == T_ASSERTION)
+      if (answer)
        {
-         if (answer)
-           {
-             struct answer **p = _cpp_find_answer (node, &answer->list);
+         struct answer **p = find_answer (node, answer), *temp;
 
-             temp = *p;
-             if (temp)
-               {
-                 *p = temp->next;
-                 FREE_ANSWER (temp);
-               }
-             if (node->value.answers == 0)
-               node->type = T_VOID;
-           }
-         else
-           {
-             for (temp = node->value.answers; temp; temp = next)
-               {
-                 next = temp->next;
-                 FREE_ANSWER (temp);
-               }
-             node->type = T_VOID;
-           }
-       }
+         /* Remove the answer from the list.  */
+         temp = *p;
+         if (temp)
+           *p = temp->next;
 
-      if (answer)
-       FREE_ANSWER (answer);
+         /* Did we free the last answer?  */
+         if (node->value.answers == 0)
+           node->type = NT_VOID;
+       }
+      else
+       _cpp_free_definition (node);
     }
-  return 0;
+
+  /* We don't commit the memory for the answer - it's temporary only.  */
 }
 
 /* These are for -D, -U, -A.  */
@@ -1444,29 +1632,34 @@ cpp_define (pfile, str)
   char *buf, *p;
   size_t count;
 
-  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.  */
-  
+     tack " 1" on the end.  */
+
+  /* Length including the null.  */  
+  count = strlen (str);
+  buf = (char *) alloca (count + 2);
+  memcpy (buf, str, count);
+
+  p = strchr (str, '=');
   if (p)
-    {
-      count = strlen (str) + 2;
-      buf = (char *) alloca (count);
-      memcpy (buf, str, count - 2);
-      buf[p - str] = ' ';
-      buf[count - 2] = '\n';
-      buf[count - 1] = '\0';
-    }
+    buf[p - str] = ' ';
   else
     {
-      count = strlen (str) + 4;
-      buf = (char *) alloca (count);
-      memcpy (buf, str, count - 4);
-      strcpy (&buf[count-4], " 1\n");
+      buf[count++] = ' ';
+      buf[count++] = '1';
     }
 
-  _cpp_run_directive (pfile, &dtable[T_DEFINE], buf, count - 1);
+  run_directive (pfile, T_DEFINE, BUF_CL_OPTION, buf, count);
+}
+
+/* Slight variant of the above for use by initialize_builtins.  */
+void
+_cpp_define_builtin (pfile, str)
+     cpp_reader *pfile;
+     const char *str;
+{
+  run_directive (pfile, T_DEFINE, BUF_BUILTIN, str, strlen (str));
 }
 
 /* Process MACRO as if it appeared as the body of an #undef.  */
@@ -1475,7 +1668,7 @@ cpp_undef (pfile, macro)
      cpp_reader *pfile;
      const char *macro;
 {
-  _cpp_run_directive (pfile, &dtable[T_UNDEF], macro, strlen (macro));
+  run_directive (pfile, T_UNDEF, BUF_CL_OPTION, macro, strlen (macro));
 }
 
 /* Process the string STR as if it appeared as the body of a #assert. */
@@ -1484,7 +1677,7 @@ cpp_assert (pfile, str)
      cpp_reader *pfile;
      const char *str;
 {
-  _cpp_run_directive (pfile, &dtable[T_ASSERT], str, strlen (str));
+  handle_assertion (pfile, str, T_ASSERT);
 }
 
 /* Process STR as if it appeared as the body of an #unassert. */
@@ -1493,95 +1686,145 @@ cpp_unassert (pfile, str)
      cpp_reader *pfile;
      const char *str;
 {
-  _cpp_run_directive (pfile, &dtable[T_UNASSERT], str, strlen (str));
+  handle_assertion (pfile, str, T_UNASSERT);
 }  
 
-/* Determine whether the identifier ID, of length LEN, is a defined macro.  */
-int
-cpp_defined (pfile, id, len)
+/* Common code for cpp_assert (-A) and cpp_unassert (-A-).  */
+static void
+handle_assertion (pfile, str, type)
      cpp_reader *pfile;
-     const U_CHAR *id;
-     int len;
+     const char *str;
+     int type;
 {
-  cpp_hashnode *hp = cpp_lookup (pfile, id, len);
-  if (hp->type == T_POISON)
+  size_t count = strlen (str);
+  const char *p = strchr (str, '=');
+
+  if (p)
     {
-      cpp_error (pfile, "attempt to use poisoned \"%s\"", hp->name);
-      return 0;
+      /* Copy the entire option so we can modify it.  Change the first
+        "=" in the string to a '(', and tack a ')' on the end.  */
+      char *buf = (char *) alloca (count + 1);
+
+      memcpy (buf, str, count);
+      buf[p - str] = '(';
+      buf[count++] = ')';
+      str = buf;
     }
-  return (hp->type != T_VOID);
-}
 
-/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack.
-   If BUFFER != NULL, then use the LENGTH characters in BUFFER
-   as the new input buffer.
-   Return the new buffer, or NULL on failure.  */
+  run_directive (pfile, type, BUF_CL_OPTION, str, count);
+}
 
+/* Push a new buffer on the buffer stack.  Returns the new buffer; it
+   doesn't fail.  It does not generate a file change call back; that
+   is the responsibility of the caller.  */
 cpp_buffer *
-cpp_push_buffer (pfile, buffer, length)
+cpp_push_buffer (pfile, buffer, len, type, filename)
      cpp_reader *pfile;
      const U_CHAR *buffer;
-     long length;
+     size_t len;
+     enum cpp_buffer_type type;
+     const char *filename;
 {
-  cpp_buffer *buf = CPP_BUFFER (pfile);
-  cpp_buffer *new;
-  if (++pfile->buffer_stack_depth == CPP_STACK_MAX)
+  cpp_buffer *new = xobnew (pfile->buffer_ob, cpp_buffer);
+
+  if (type == BUF_FAKE)
+    {
+      /* A copy of the current buffer, just with a new name and type.  */
+      memcpy (new, pfile->buffer, sizeof (cpp_buffer));
+      new->type = BUF_FAKE;
+    }
+  else
     {
-      cpp_fatal (pfile, "#include recursion too deep");
-      return NULL;
+      if (type == BUF_BUILTIN)
+       filename = _("<builtin>");
+      else if (type == BUF_CL_OPTION)
+       filename = _("<command line>");
+      else if (type == BUF_PRAGMA)
+       filename = "<_Pragma>";
+
+      /* Clears, amongst other things, if_stack and mi_cmacro.  */
+      memset (new, 0, sizeof (cpp_buffer));
+
+      new->line_base = new->buf = new->cur = buffer;
+      new->rlimit = buffer + len;
+      new->sysp = 0;
+
+      /* No read ahead or extra char initially.  */
+      new->read_ahead = EOF;
+      new->extra_char = EOF;
+
+      /* Preprocessed files, builtins, _Pragma and command line
+        options don't do trigraph and escaped newline processing.  */
+      new->from_stage3 = type != BUF_FILE || CPP_OPTION (pfile, preprocessed);
+
+      pfile->lexer_pos.output_line = 1;
     }
 
-  new = xobnew (pfile->buffer_ob, cpp_buffer);
-  memset (new, 0, sizeof (cpp_buffer));
+  new->nominal_fname = filename;
+  new->type = type;
+  new->prev = pfile->buffer;
+  new->pfile = pfile;
+  new->include_stack_listed = 0;
+  new->lineno = 1;
 
-  new->buf = new->cur = buffer;
-  new->rlimit = buffer + length;
-  new->prev = buf;
+  pfile->state.next_bol = 1;
+  pfile->buffer_stack_depth++;
+  pfile->buffer = new;
 
-  CPP_BUFFER (pfile) = new;
   return new;
 }
 
+/* If called from do_line, pops a single buffer.  Otherwise pops all
+   buffers until a real file is reached.  Generates appropriate
+   call-backs.  */
 cpp_buffer *
 cpp_pop_buffer (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *buf = CPP_BUFFER (pfile);
-
-  unwind_if_stack (pfile, buf);
-#ifdef HAVE_MMAP_FILE
-  if (buf->mapped)
-    munmap ((caddr_t) buf->buf, buf->rlimit - buf->buf);
-  else
-#endif
-    if (buf->inc)
-      free ((PTR) buf->buf);
+  cpp_buffer *buffer;
+  struct if_stack *ifs;
 
-  if (buf->inc)
+  for (;;)
     {
-      if (pfile->system_include_depth)
-       pfile->system_include_depth--;
-      if (pfile->include_depth)
-       pfile->include_depth--;
-      if (pfile->potential_control_macro)
-       {
-         if (buf->inc->cmacro != NEVER_REREAD)
-           buf->inc->cmacro = pfile->potential_control_macro;
-         pfile->potential_control_macro = 0;
-       }
-      pfile->input_stack_listing_current = 0;
-      /* If the file will not be included again, then close it.  */
-      if (DO_NOT_REREAD (buf->inc))
-       {
-         close (buf->inc->fd);
-         buf->inc->fd = -1;
-       }
+      buffer = pfile->buffer;
+      /* Walk back up the conditional stack till we reach its level at
+        entry to this file, issuing error messages.  */
+      for (ifs = buffer->if_stack; ifs; ifs = ifs->next)
+       cpp_error_with_line (pfile, ifs->pos.line, ifs->pos.col,
+                            "unterminated #%s", dtable[ifs->type].name);
+
+      if (buffer->type == BUF_FAKE)
+       buffer->prev->cur = buffer->cur;
+      else if (buffer->type == BUF_FILE)
+       _cpp_pop_file_buffer (pfile, buffer);
+
+      pfile->buffer = buffer->prev;
+      pfile->buffer_stack_depth--;
+
+      /* Callbacks only generated for faked or real files.  */
+      if (buffer->type != BUF_FILE && buffer->type != BUF_FAKE)
+       break;
+         
+      /* No callback for EOF of last file.  */
+      if (!pfile->buffer)
+       break;
+
+      /* do_line does its own call backs.  */
+      pfile->buffer->include_stack_listed = 0;
+      if (pfile->directive == &dtable[T_LINE])
+       break;
+
+      _cpp_do_file_change (pfile, FC_LEAVE, buffer->nominal_fname,
+                          buffer->lineno);
+      if (pfile->buffer->type == BUF_FILE)
+       break;
+
+      cpp_warning (pfile, "file \"%s\" entered but not left",
+                  buffer->nominal_fname);
     }
 
-  CPP_BUFFER (pfile) = CPP_PREV_BUFFER (buf);
-  obstack_free (pfile->buffer_ob, buf);
-  pfile->buffer_stack_depth--;
-  return CPP_BUFFER (pfile);
+  obstack_free (pfile->buffer_ob, buffer);
+  return pfile->buffer;
 }
 
 #define obstack_chunk_alloc xmalloc
@@ -1590,8 +1833,18 @@ void
 _cpp_init_stacks (pfile)
      cpp_reader *pfile;
 {
+  int i;
+  cpp_hashnode *node;
+
   pfile->buffer_ob = xnew (struct obstack);
   obstack_init (pfile->buffer_ob);
+
+  /* Register the directives.  */
+  for (i = 1; i < N_DIRECTIVES; i++)
+    {
+      node = cpp_lookup (pfile, dtable[i - 1].name, dtable[i - 1].length);
+      node->directive_index = i;
+    }
 }
 
 void