OSDN Git Service

2000-10-28 Neil Booth <neilb@earthling.net>
authorneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Oct 2000 17:59:06 +0000 (17:59 +0000)
committerneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Oct 2000 17:59:06 +0000 (17:59 +0000)
New macro expander.

* cpplib.c (struct answer): New.
(struct if_stack): Use cpp_lexer_pos rather than line and col.
Rename cmacro mi_cmacro.
(struct directive, KANDR, STDC89, EXTENSION, COND, IF_COND, INCL,
IN_I): New directive and flags.
(skip_rest_of_line, check_eol, run_directive, glue_header_name,
parse_answer, parse_assertion, find_answer): New functions.
(parse_ifdef, detect_if_not_defined, validate_else): Remove.
(lex_macro_node): New function to replace parse_ifdef and
get_define_node.

(_cpp_handle_directive): New function, combines _cpp_check_directive
and _cpp_check_linemarker.

(do_define, do_undef, parse_include, do_include, do_import,
do_include_next, read_line_number, do_line, do_ident, do_pragma,
do_pragma_once, do_pragma_poison, do_pragma_dependency):
Update for new token getting interface.

(do_ifdef, do_ifndef, do_if, do_else, do_endif, push_conditional)
: Update for new multiple-include optimisation technique.
(do_elif): Don't forget to invalidate controlling macros.

(unwind_if_stack, cpp_defined, cpp_push_buffer, cpp_pop_buffer): Update.
(parse_assertion, parse_answer, find_answer, _cpp_test_assertion):
Functions to handle assertions with the new token interface.
(do_assert, do_unassert): Use them.

(cpp_define, _cpp_define_builtin, cpp_undef, cpp_assert, cpp_unassert):
Use run_directive.

(_cpp_init_stacks): Register directive names.  Don't register special
nodes.

* cpperror.c (print_containing_files, _cpp_begin_message): Update to
new position recording regime.
(cpp_ice, cpp_fatal, cpp_error, cpp_error_with_line, cpp_warning,
cpp_warning_with_line, cpp_pedwarn, cpp_pedwarn_with_line,
cpp_pedwarn_with_file_and_line): Update for _cpp_begin_message changes.
(cpp_type2name): Move to cpplex.c.

* cppexp.c (parse_charconst): spec_nodes is no longer a pointer.
(parse_defined): Update to handle new multiple include optimisation
method.  Remove poisoned identifier warning.
(parse_assertion, TYPE_NAME): Delete.
(lex): Update for multiple include optimisation, removal of
CPP_DEFINED, to use _cpp_test_assertion for assertions and
cpp_token_as_text.
(_cpp_parse_expr): Update for MI optimisation, and to use op_as_text.
(op_as_text): New function, to wrap cpp_token_as_text.

* cppfiles.c (stack_include_file, _cpp_pop_file_buffer):
Update for MI optimisation.
(_cpp_execute_include): Take a token rather than 3 arguments.  Fix
segfault on diagnostic.
(_cpp_compare_file_date): Take a token rather than 3 args.
(cpp_read_file): Work correctly for zero-length files.

* cpphash.c (_cpp_init_macros, _cpp_cleanup_macros): Rename
_cpp_init_hashtable and _cpp_cleanup_hashtable.
(cpp_lookup): Place identifiers at front of identifier pool
for _cpp_lookup_with_hash.
(_cpp_lookup_with_hash): Require identifiers to be at the front of
the identifier pool.  Commit the memory if not already in the
hash table.

* cppinit.c (cpp_reader_init): Move cpp_init_completed test to top.
Initialise various members of cpp_reader, memory pools, and the
special nodes.
(cpp_printer_init): Delete.
(cpp_cleanup): Update.
(struct builtin, builtin_array, initialize_builtins): Update for new
hashnode definition and builtin handling.
(cpp_start_read, cpp_finish): Don't take or initialise a
printer.  Update.

* cpplib.h (cpp_printer, cpp_toklist, CPP_DEFINED, BOL,
PASTED, VAR_ARGS, BEG_OF_FILE, IN_DIRECTIVE, KNOWN_DIRECTIVE,
T_VOID, T_SPECLINE, T_DATE, T_FILE, T_BASE_FILE, T_INCLUDE_LEVEL,
T_TIME, T_STDC, T_OPERATOR, T_POISON, T_MACRO, T_ASSERTION): Delete.
(struct cpp_pool, struct cpp_macro, struct cpp_lexer_pos,
struct cpp_lookahead, CPP_DHASH, enum mi_state, enum mi_ind,
NO_EXPAND, VARARGS_FIRST, struct cpp_token_with_pos,
struct toklist, struct cpp_context, struct specnodes,
TOKEN_LOOKAHEAD, TOKEN_BUFFSIZE, NODE_OPERATOR, NODE_POISONED,
NODE_BUILTIN, NODE_DIAGNOSTIC, NT_VOID, NT_MACRO, NT_ASSERTION,
enum builtin_type, cpp_can_paste): New.
(struct cpp_token): Delete line and col members.
(struct cpp_buffer): New member output_lineno.
(struct lexer_state): Delete indented, in_lex_line, seen_dot.
Add va_args_ok, poisoned_ok, prevent_expansion, parsing_args.
(struct cpp_reader): New members lexer_pos, macro_pos, directive_pos,
ident_pool, temp_string_pool, macro_pool, argument_pool, string_pool,
base_context, context, directive, mi_state, mi_if_not_defined,
mi_lexed, mi_cmacro, mi_ind_cmacro, la_read, la_write, la_unused,
mlstring_pos, macro_buffer, macro_buffer_len.
Delete members mls_line, mls_column, token_list, potential_control_macro,
temp_tokens, temp_cap, temp_alloced, temp_used, first_directive_token,
context_cap, cur_context, no_expand_level, paste_level, contexts, args,
save_parameter_spellings, need_newline, .
Change type of date, time and spec_nodes members.
Change prototypes for include and ident callbacks.
(struct cpp_hashnode): Change type of name.  Remove union members
expansion and code.  Add members macro, operator and builtin.

(cpp_token_len, cpp_token_as_text, cpp_spell_token, cpp_start_read,
cpp_finish, cpp_avoid_paste, cpp_get_token, cpp_get_line,
cpp_get_output_line, cpp_macro_definition, cpp_start_lookahead,
cpp_stop_lookahead): New prototypes.
(cpp_printer_init, cpp_dump_definition): Delete prototypes.

(U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr, ufputs):
Move from cpphash.h.

* cpphash.h (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr,
ufputs): Move to cpplib.h.
(enum spell_type, struct token_spelling, _cpp_token_spellings, TOKEN_SPELL,
TOKEN_NAME, struct answer, FREE_ANSWER, KANDR, STDC89, EXTENSION,
COND, EXPAND, INCL, COMMENTS, IN_I, struct directive, directive_handler,
struct spec_nodes, _cpp_digraph_spellings, _cpp_free_temp_tokens,
_cpp_init_input_buffer, _cpp_grow_token_buffer, _cpp_init_toklist,
_cpp_clear_toklist, _cpp_expand_token_space, _cpp_expand_name_space,
_cpp_equiv_tokens, _cpp_equiv_toklists, _cpp_process_directive,
_cpp_run_directive, _cpp_get_line, _cpp_get_raw_token, _cpp_glue_header_name,
_cpp_can_paste, _cpp_check_directive, _cpp_check_linemarker,
_cpp_parse_assertion, _cpp_find_answer): Delete.
(VALID_SIGN, ALIGN, POOL_FRONT, POOL_LIMIT, POOL_BASE, POOL_SIZE,
POOL_USED, POOL_COMMIT, struct cpp_chunk, _cpp_lex_token, _cpp_init_pool,
_cpp_free_pool, _cpp_pool_reserve, _cpp_pool_alloc, _cpp_next_chunk,
_cpp_lock_pool, _cpp_unlock_pool, _cpp_test_assertion,
_cpp_handle_directive, DSC): New.
(struct include_file): New member defined.

(DO_NOT_REREAD, _cpp_begin_message, _cpp_execute_include,
_cpp_compare_file_date): Update.
(_cpp_pop_context, _cpp_get_token, _cpp_free_lookaheads, _cpp_push_token): New.
(_cpp_init_macros, _cpp_cleanup_macros): Rename to _cpp_init_hashtable,
_cpp_cleanup_hashtable.

* Makefile.in: Remove cppoutput.c.

* cppoutput.c: Delete

* fixheader.c (read_scan_file): Update for new cpp_get_token
prototype.
(recognized_function): New argument LINE.

* scan-decls.c (skip_to_closing_brace, scan_decls): Update for
new cpp_get_token prototype.

* scan.h (recognized_function): Update prototype.

* po/POTFILES.in: Remove cppoutput.c.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@37098 138bc75d-0d04-0410-961f-82ee72b054a4

18 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/cpperror.c
gcc/cppexp.c
gcc/cppfiles.c
gcc/cpphash.c
gcc/cpphash.h
gcc/cppinit.c
gcc/cpplex.c
gcc/cpplib.c
gcc/cpplib.h
gcc/cppmacro.c
gcc/cppmain.c
gcc/cppoutput.c [deleted file]
gcc/fix-header.c
gcc/po/POTFILES.in
gcc/scan-decls.c
gcc/scan.h

index cebbe87..cd5df85 100644 (file)
@@ -1,3 +1,161 @@
+2000-10-28  Neil Booth  <neilb@earthling.net>
+
+       New macro expander.
+       
+       * cpplib.c (struct answer): New.
+       (struct if_stack): Use cpp_lexer_pos rather than line and col.
+       Rename cmacro mi_cmacro.
+       (struct directive, KANDR, STDC89, EXTENSION, COND, IF_COND, INCL,
+       IN_I): New directive and flags.
+       (skip_rest_of_line, check_eol, run_directive, glue_header_name,
+       parse_answer, parse_assertion, find_answer): New functions.
+       (parse_ifdef, detect_if_not_defined, validate_else): Remove.
+       (lex_macro_node): New function to replace parse_ifdef and
+       get_define_node.
+
+       (_cpp_handle_directive): New function, combines _cpp_check_directive
+       and _cpp_check_linemarker.
+
+       (do_define, do_undef, parse_include, do_include, do_import,
+       do_include_next, read_line_number, do_line, do_ident, do_pragma,
+       do_pragma_once, do_pragma_poison, do_pragma_dependency):
+       Update for new token getting interface.
+
+       (do_ifdef, do_ifndef, do_if, do_else, do_endif, push_conditional)
+       : Update for new multiple-include optimisation technique.
+       (do_elif): Don't forget to invalidate controlling macros.
+
+       (unwind_if_stack, cpp_defined, cpp_push_buffer, cpp_pop_buffer): Update.
+       (parse_assertion, parse_answer, find_answer, _cpp_test_assertion):
+       Functions to handle assertions with the new token interface.
+       (do_assert, do_unassert): Use them.
+
+       (cpp_define, _cpp_define_builtin, cpp_undef, cpp_assert, cpp_unassert):
+       Use run_directive.
+
+       (_cpp_init_stacks): Register directive names.  Don't register special
+       nodes.
+
+       * cpperror.c (print_containing_files, _cpp_begin_message): Update to
+       new position recording regime.
+       (cpp_ice, cpp_fatal, cpp_error, cpp_error_with_line, cpp_warning,
+       cpp_warning_with_line, cpp_pedwarn, cpp_pedwarn_with_line,
+       cpp_pedwarn_with_file_and_line): Update for _cpp_begin_message changes.
+       (cpp_type2name): Move to cpplex.c.
+
+       * cppexp.c (parse_charconst): spec_nodes is no longer a pointer.
+       (parse_defined): Update to handle new multiple include optimisation
+       method.  Remove poisoned identifier warning.
+       (parse_assertion, TYPE_NAME): Delete.
+       (lex): Update for multiple include optimisation, removal of
+       CPP_DEFINED, to use _cpp_test_assertion for assertions and
+       cpp_token_as_text.
+       (_cpp_parse_expr): Update for MI optimisation, and to use op_as_text.
+       (op_as_text): New function, to wrap cpp_token_as_text.
+
+       * cppfiles.c (stack_include_file, _cpp_pop_file_buffer):
+       Update for MI optimisation.
+       (_cpp_execute_include): Take a token rather than 3 arguments.  Fix
+       segfault on diagnostic.
+       (_cpp_compare_file_date): Take a token rather than 3 args.
+       (cpp_read_file): Work correctly for zero-length files.
+
+       * cpphash.c (_cpp_init_macros, _cpp_cleanup_macros): Rename
+       _cpp_init_hashtable and _cpp_cleanup_hashtable.
+       (cpp_lookup): Place identifiers at front of identifier pool
+       for _cpp_lookup_with_hash.
+       (_cpp_lookup_with_hash): Require identifiers to be at the front of
+       the identifier pool.  Commit the memory if not already in the
+       hash table.
+
+       * cppinit.c (cpp_reader_init): Move cpp_init_completed test to top.
+       Initialise various members of cpp_reader, memory pools, and the
+       special nodes.
+       (cpp_printer_init): Delete.
+       (cpp_cleanup): Update.
+       (struct builtin, builtin_array, initialize_builtins): Update for new
+       hashnode definition and builtin handling.
+       (cpp_start_read, cpp_finish): Don't take or initialise a
+       printer.  Update.
+
+       * cpplib.h (cpp_printer, cpp_toklist, CPP_DEFINED, BOL,
+       PASTED, VAR_ARGS, BEG_OF_FILE, IN_DIRECTIVE, KNOWN_DIRECTIVE,
+       T_VOID, T_SPECLINE, T_DATE, T_FILE, T_BASE_FILE, T_INCLUDE_LEVEL,
+       T_TIME, T_STDC, T_OPERATOR, T_POISON, T_MACRO, T_ASSERTION): Delete.
+       (struct cpp_pool, struct cpp_macro, struct cpp_lexer_pos,
+       struct cpp_lookahead, CPP_DHASH, enum mi_state, enum mi_ind,
+       NO_EXPAND, VARARGS_FIRST, struct cpp_token_with_pos,
+       struct toklist, struct cpp_context, struct specnodes,
+       TOKEN_LOOKAHEAD, TOKEN_BUFFSIZE, NODE_OPERATOR, NODE_POISONED,
+       NODE_BUILTIN, NODE_DIAGNOSTIC, NT_VOID, NT_MACRO, NT_ASSERTION,
+       enum builtin_type, cpp_can_paste): New.
+       (struct cpp_token): Delete line and col members.
+       (struct cpp_buffer): New member output_lineno.
+       (struct lexer_state): Delete indented, in_lex_line, seen_dot.
+       Add va_args_ok, poisoned_ok, prevent_expansion, parsing_args.
+       (struct cpp_reader): New members lexer_pos, macro_pos, directive_pos,
+       ident_pool, temp_string_pool, macro_pool, argument_pool, string_pool,
+       base_context, context, directive, mi_state, mi_if_not_defined,
+       mi_lexed, mi_cmacro, mi_ind_cmacro, la_read, la_write, la_unused,
+       mlstring_pos, macro_buffer, macro_buffer_len.
+       Delete members mls_line, mls_column, token_list, potential_control_macro,
+       temp_tokens, temp_cap, temp_alloced, temp_used, first_directive_token,
+       context_cap, cur_context, no_expand_level, paste_level, contexts, args,
+       save_parameter_spellings, need_newline, .
+       Change type of date, time and spec_nodes members.
+       Change prototypes for include and ident callbacks.
+       (struct cpp_hashnode): Change type of name.  Remove union members
+       expansion and code.  Add members macro, operator and builtin.
+
+       (cpp_token_len, cpp_token_as_text, cpp_spell_token, cpp_start_read,
+       cpp_finish, cpp_avoid_paste, cpp_get_token, cpp_get_line,
+       cpp_get_output_line, cpp_macro_definition, cpp_start_lookahead,
+       cpp_stop_lookahead): New prototypes.
+       (cpp_printer_init, cpp_dump_definition): Delete prototypes.
+
+       (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr, ufputs):
+       Move from cpphash.h.
+
+       * cpphash.h (U_CHAR, U, ustrcmp, ustrncmp, ustrlen, uxstrdup, ustrchr,
+       ufputs): Move to cpplib.h.
+       (enum spell_type, struct token_spelling, _cpp_token_spellings, TOKEN_SPELL,
+       TOKEN_NAME, struct answer, FREE_ANSWER, KANDR, STDC89, EXTENSION,
+       COND, EXPAND, INCL, COMMENTS, IN_I, struct directive, directive_handler,
+       struct spec_nodes, _cpp_digraph_spellings, _cpp_free_temp_tokens,
+       _cpp_init_input_buffer, _cpp_grow_token_buffer, _cpp_init_toklist,
+       _cpp_clear_toklist, _cpp_expand_token_space, _cpp_expand_name_space,
+       _cpp_equiv_tokens, _cpp_equiv_toklists, _cpp_process_directive,
+       _cpp_run_directive, _cpp_get_line, _cpp_get_raw_token, _cpp_glue_header_name,
+       _cpp_can_paste, _cpp_check_directive, _cpp_check_linemarker,
+       _cpp_parse_assertion, _cpp_find_answer): Delete.
+       (VALID_SIGN, ALIGN, POOL_FRONT, POOL_LIMIT, POOL_BASE, POOL_SIZE,
+       POOL_USED, POOL_COMMIT, struct cpp_chunk, _cpp_lex_token, _cpp_init_pool,
+       _cpp_free_pool, _cpp_pool_reserve, _cpp_pool_alloc, _cpp_next_chunk,
+       _cpp_lock_pool, _cpp_unlock_pool, _cpp_test_assertion,
+       _cpp_handle_directive, DSC): New.
+       (struct include_file): New member defined.
+
+       (DO_NOT_REREAD, _cpp_begin_message, _cpp_execute_include,
+       _cpp_compare_file_date): Update.
+       (_cpp_pop_context, _cpp_get_token, _cpp_free_lookaheads, _cpp_push_token): New.
+       (_cpp_init_macros, _cpp_cleanup_macros): Rename to _cpp_init_hashtable,
+       _cpp_cleanup_hashtable.
+
+       * Makefile.in: Remove cppoutput.c.
+       
+       * cppoutput.c: Delete
+
+       * fixheader.c (read_scan_file): Update for new cpp_get_token
+       prototype.
+       (recognized_function): New argument LINE.
+
+       * scan-decls.c (skip_to_closing_brace, scan_decls): Update for
+       new cpp_get_token prototype.
+
+       * scan.h (recognized_function): Update prototype.
+
+       * po/POTFILES.in: Remove cppoutput.c.
+       
 2000-10-27  Mark Mitchell  <mark@codesourcery.com>
 
        * c-typeck.c (check_init_type_bitfields): Remove.
index 2ea2ef9..27561cd 100644 (file)
@@ -1841,7 +1841,7 @@ PREPROCESSOR_DEFINES = \
   -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
 
 LIBCPP_OBJS =  cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
-               cpphash.o cpperror.o cppinit.o cppdefault.o cppoutput.o \
+               cpphash.o cpperror.o cppinit.o cppdefault.o \
                mkdeps.o prefix.o version.o mbchar.o
 
 LIBCPP_DEPS =  cpplib.h cpphash.h intl.h system.h
@@ -1863,7 +1863,6 @@ cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
 cppexp.o:   cppexp.c   $(CONFIG_H) $(LIBCPP_DEPS) defaults.h
 cpplex.o:   cpplex.c   $(CONFIG_H) $(LIBCPP_DEPS)
 cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
-cppoutput.o: cppoutput.c $(CONFIG_H) $(LIBCPP_DEPS)
 cpplib.o:   cpplib.c   $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
 cpphash.o:  cpphash.c  $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
 cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
index fa44708..d598fbd 100644 (file)
@@ -57,11 +57,10 @@ print_containing_files (pfile, ip)
       if (first)
        {
          first = 0;
-         /* N.B. The current line in each outer source file is one
-            greater than the line of the #include, so we must
-            subtract one to correct for that.  */
+         /* The current line in each outer source file is now the
+            same as the line of the #include.  */
          fprintf (stderr,  _("In file included from %s:%u"),
-                  ip->nominal_fname, CPP_BUF_LINE (ip) - 1);
+                  ip->nominal_fname, CPP_BUF_LINE (ip));
        }
       else
        /* Translators note: this message is used in conjunction
@@ -107,12 +106,11 @@ print_file_and_line (filename, line, column)
    If it returns 0, this error has been suppressed.  */
 
 int
-_cpp_begin_message (pfile, code, file, line, col)
+_cpp_begin_message (pfile, code, file, pos)
      cpp_reader *pfile;
      enum error_type code;
      const char *file;
-     unsigned int line;
-     unsigned int col;
+     const cpp_lexer_pos *pos;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
   int is_warning = 0;
@@ -177,11 +175,11 @@ _cpp_begin_message (pfile, code, file, line, col)
     {
       if (file == NULL)
        file = ip->nominal_fname;
-      if (line == 0)
-       line = _cpp_get_line (pfile, &col);
+      if (pos == 0)
+       pos = cpp_get_line (pfile);
       print_containing_files (pfile, ip);
-      print_file_and_line (file, line,
-                          CPP_OPTION (pfile, show_column) ? col : 0);
+      print_file_and_line (file, pos->line,
+                          CPP_OPTION (pfile, show_column) ? pos->col : 0);
     }
   else
     fprintf (stderr, "%s: ", progname);
@@ -213,7 +211,7 @@ cpp_ice VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, ICE, NULL, 0, 0))
+  if (_cpp_begin_message (pfile, ICE, NULL, 0))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -240,7 +238,7 @@ cpp_fatal VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, FATAL, NULL, 0, 0))
+  if (_cpp_begin_message (pfile, FATAL, NULL, 0))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -261,7 +259,7 @@ cpp_error VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, ERROR, NULL, 0, 0))
+  if (_cpp_begin_message (pfile, ERROR, NULL, 0))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -277,6 +275,7 @@ cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column,
   const char *msgid;
 #endif
   va_list ap;
+  cpp_lexer_pos pos;
   
   VA_START (ap, msgid);
   
@@ -287,7 +286,9 @@ cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column,
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, ERROR, NULL, line, column))
+  pos.line = line;
+  pos.col = column;
+  if (_cpp_begin_message (pfile, ERROR, NULL, &pos))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -317,7 +318,7 @@ cpp_warning VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, WARNING, NULL, 0, 0))
+  if (_cpp_begin_message (pfile, WARNING, NULL, 0))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -333,6 +334,7 @@ cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
   const char *msgid;
 #endif
   va_list ap;
+  cpp_lexer_pos pos;
   
   VA_START (ap, msgid);
   
@@ -343,7 +345,9 @@ cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, WARNING, NULL, line, column))
+  pos.line = line;
+  pos.col = column;
+  if (_cpp_begin_message (pfile, WARNING, NULL, &pos))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -364,7 +368,7 @@ cpp_pedwarn VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, PEDWARN, NULL, 0, 0))
+  if (_cpp_begin_message (pfile, PEDWARN, NULL, 0))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -380,6 +384,7 @@ cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
   const char *msgid;
 #endif
   va_list ap;
+  cpp_lexer_pos pos;
   
   VA_START (ap, msgid);
   
@@ -390,7 +395,9 @@ cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, PEDWARN, NULL, line, column))
+  pos.line = line;
+  pos.col = column;
+  if (_cpp_begin_message (pfile, PEDWARN, NULL, &pos))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -411,6 +418,7 @@ cpp_pedwarn_with_file_and_line VPARAMS ((cpp_reader *pfile,
   const char *msgid;
 #endif
   va_list ap;
+  cpp_lexer_pos pos;
   
   VA_START (ap, msgid);
 
@@ -422,7 +430,9 @@ cpp_pedwarn_with_file_and_line VPARAMS ((cpp_reader *pfile,
   msgid = va_arg (ap, const char *);
 #endif
 
-  if (_cpp_begin_message (pfile, PEDWARN, file, line, col))
+  pos.line = line;
+  pos.col = col;
+  if (_cpp_begin_message (pfile, PEDWARN, file, &pos))
     v_message (msgid, ap);
   va_end(ap);
 }
@@ -462,11 +472,3 @@ cpp_notice_from_errno (pfile, name)
     name = "stdout";
   cpp_notice (pfile, "%s: %s", name, xstrerror (errno));
 }
-
-const char *
-cpp_type2name (type)
-     enum cpp_ttype type;
-{
-  return (const char *) _cpp_token_spellings[type].name;
-}
-
index 5403dce..566eb15 100644 (file)
@@ -63,10 +63,10 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
 static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
 static struct op parse_charconst PARAMS ((cpp_reader *, const cpp_token *));
 static struct op parse_defined PARAMS ((cpp_reader *));
-static struct op parse_assertion PARAMS ((cpp_reader *));
 static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **,
                                             const U_CHAR *, HOST_WIDEST_INT));
-static struct op lex PARAMS ((cpp_reader *, int));
+static struct op lex PARAMS ((cpp_reader *, int, cpp_token *));
+static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype));
 
 struct op
 {
@@ -291,7 +291,7 @@ parse_charconst (pfile, tok)
   /* If char type is signed, sign-extend the constant.  */
   num_bits = num_chars * width;
       
-  if (pfile->spec_nodes->n__CHAR_UNSIGNED__->type != T_VOID
+  if (pfile->spec_nodes.n__CHAR_UNSIGNED__->type == NT_MACRO
       || ((result >> (num_bits - 1)) & 1) == 0)
     op.value = result & ((unsigned HOST_WIDEST_INT) ~0
                         >> (HOST_BITS_PER_WIDEST_INT - num_bits));
@@ -313,85 +313,85 @@ static struct op
 parse_defined (pfile)
      cpp_reader *pfile;
 {
-  int paren;
-  const cpp_token *tok;
+  int paren = 0;
+  cpp_hashnode *node = 0;
+  cpp_token token;
   struct op op;
 
-  paren = 0;
-  tok = _cpp_get_raw_token (pfile);
-  if (tok->type == CPP_OPEN_PAREN)
+  /* Don't expand macros.  */
+  pfile->state.prevent_expansion++;
+
+  _cpp_get_token (pfile, &token);
+  if (token.type == CPP_OPEN_PAREN)
     {
       paren = 1;
-      tok = _cpp_get_raw_token (pfile);
+      _cpp_get_token (pfile, &token);
     }
 
-  if (tok->type != CPP_NAME)
-    SYNTAX_ERROR ("\"defined\" without an identifier");
-
-  if (paren && _cpp_get_raw_token (pfile)->type != CPP_CLOSE_PAREN)
-    SYNTAX_ERROR ("missing close paren after \"defined\"");
-
-  if (tok->val.node->type == T_POISON)
-    SYNTAX_ERROR2 ("attempt to use poisoned \"%s\"", tok->val.node->name);
-
-  op.value = tok->val.node->type != T_VOID;
-  op.unsignedp = 0;
-  op.op = CPP_INT;
-  return op;
-
- syntax_error:
-  op.op = CPP_ERROR;
-  return op;
-}
-
-static struct op
-parse_assertion (pfile)
-     cpp_reader *pfile;
-{
-  struct op op;
-  struct answer *answer;
-  cpp_hashnode *hp;
+  if (token.type == CPP_NAME)
+    {
+      node = token.val.node;
+      if (paren)
+       {
+         _cpp_get_token (pfile, &token);
+         if (token.type != CPP_CLOSE_PAREN)
+           {
+             cpp_error (pfile, "missing ')' after \"defined\"");
+             node = 0;
+           }
+       }
+    }
+  else
+    cpp_error (pfile, "\"defined\" without an identifier");
 
-  op.op = CPP_ERROR;
-  hp = _cpp_parse_assertion (pfile, &answer);
-  if (hp)
+  if (!node)
+    op.op = CPP_ERROR;
+  else
     {
-      /* If we get here, the syntax is valid.  */
-      op.op = CPP_INT;
+      op.value = node->type == NT_MACRO;
       op.unsignedp = 0;
-      op.value = (hp->type == T_ASSERTION &&
-                 (answer == 0 || *_cpp_find_answer (hp, &answer->list) != 0));
+      op.op = CPP_INT;
 
-      if (answer)
-       FREE_ANSWER (answer);
+      /* No macros?  At top of file?  */
+      if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0
+         && pfile->mi_if_not_defined == MI_IND_NOT && pfile->mi_lexed == 1)
+       {
+         cpp_start_lookahead (pfile);
+         cpp_get_token (pfile, &token);
+         if (token.type == CPP_EOF)
+           pfile->mi_ind_cmacro = node;
+         cpp_stop_lookahead (pfile, 0);
+       }
     }
+
+  pfile->state.prevent_expansion--;
   return op;
 }
 
 /* Read one token.  */
 
 static struct op
-lex (pfile, skip_evaluation)
+lex (pfile, skip_evaluation, token)
      cpp_reader *pfile;
      int skip_evaluation;
+     cpp_token *token;
 {
   struct op op;
-  const cpp_token *tok;
 
  retry:
-  tok = _cpp_get_token (pfile);
+  _cpp_get_token (pfile, token);
 
-  switch (tok->type)
+  switch (token->type)
     {
     case CPP_PLACEMARKER:
       goto retry;
 
     case CPP_INT:
     case CPP_NUMBER:
-      return parse_number (pfile, tok);
+      return parse_number (pfile, token);
     case CPP_CHAR:
     case CPP_WCHAR:
-      return parse_charconst (pfile, tok);
+      return parse_charconst (pfile, token);
 
     case CPP_STRING:
     case CPP_WSTRING:
@@ -401,36 +401,60 @@ lex (pfile, skip_evaluation)
       SYNTAX_ERROR ("floating point numbers are not valid in #if");
 
     case CPP_OTHER:
-      if (ISGRAPH (tok->val.aux))
-       SYNTAX_ERROR2 ("invalid character '%c' in #if", tok->val.aux);
+      if (ISGRAPH (token->val.aux))
+       SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.aux);
       else
-       SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", tok->val.aux);
-
-    case CPP_DEFINED:
-      return parse_defined (pfile);
+       SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.aux);
 
     case CPP_NAME:
+      if (token->val.node == pfile->spec_nodes.n_defined)
+       {
+         if (pfile->context->prev && CPP_PEDANTIC (pfile))
+           cpp_pedwarn (pfile, "\"defined\" operator appears during macro expansion");
+
+         return parse_defined (pfile);
+       }
+      /* Controlling #if expressions cannot contain identifiers (they
+        could become macros in the future).  */
+      pfile->mi_state = MI_FAILED;
+
       op.op = CPP_INT;
       op.unsignedp = 0;
       op.value = 0;
 
       if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
-       cpp_warning (pfile, "\"%s\" is not defined", tok->val.node->name);
+       cpp_warning (pfile, "\"%s\" is not defined", token->val.node->name);
+
       return op;
 
     case CPP_HASH:
-      return parse_assertion (pfile);
+      {
+       int temp;
+
+       op.op = CPP_INT;
+       if (_cpp_test_assertion (pfile, &temp))
+         op.op = CPP_ERROR;
+       op.unsignedp = 0;
+       op.value = temp;
+       return op;
+      }
+
+    case CPP_NOT:
+      /* We don't worry about its position here.  */
+      pfile->mi_if_not_defined = MI_IND_NOT;
+      /* Fall through.  */
 
     default:
-      if ((tok->type > CPP_EQ && tok->type < CPP_PLUS_EQ)
-         || tok->type == CPP_EOF)
+      if ((token->type > CPP_EQ && token->type < CPP_PLUS_EQ)
+         || token->type == CPP_EOF)
        {
-         op.op = tok->type;
+         op.op = token->type;
          return op;
        }
 
-      SYNTAX_ERROR2("'%s' is not valid in #if expressions", TOKEN_NAME (tok));
-  }
+      SYNTAX_ERROR2 ("\"%s\" is not valid in #if expressions",
+                    cpp_token_as_text (pfile, token));
+    }
 
  syntax_error:
   op.op = CPP_ERROR;
@@ -709,8 +733,6 @@ op_to_prio[] =
 /* Parse and evaluate a C expression, reading from PFILE.
    Returns the truth value of the expression.  */
 
-#define TYPE_NAME(t) _cpp_token_spellings[t].name
-
 int
 _cpp_parse_expr (pfile)
      cpp_reader *pfile;
@@ -729,6 +751,7 @@ _cpp_parse_expr (pfile)
   struct op init_stack[INIT_STACK_SIZE];
   struct op *stack = init_stack;
   struct op *limit = stack + INIT_STACK_SIZE;
+  cpp_token token;
   register struct op *top = stack + 1;
   int skip_evaluation = 0;
   int result;
@@ -737,6 +760,10 @@ _cpp_parse_expr (pfile)
   int save_skipping = pfile->skipping;
   pfile->skipping = 0;
 
+  /* Set up detection of #if ! defined().  */
+  pfile->mi_lexed = 0;
+  pfile->mi_if_not_defined = MI_IND_NONE;
+
   /* We've finished when we try to reduce this.  */
   top->op = CPP_EOF;
   /* Nifty way to catch missing '('.  */
@@ -751,7 +778,8 @@ _cpp_parse_expr (pfile)
       struct op op;
 
       /* Read a token */
-      op = lex (pfile, skip_evaluation);
+      op = lex (pfile, skip_evaluation, &token);
+      pfile->mi_lexed++;
 
       /* If the token is an operand, push its value and get next
         token.  If it is an operator, get its priority and flags, and
@@ -797,7 +825,7 @@ _cpp_parse_expr (pfile)
                SYNTAX_ERROR ("void expression between '(' and ')'");
              else
                SYNTAX_ERROR2 ("operator '%s' has no right operand",
-                              TYPE_NAME (top->op));
+                              op_as_text (pfile, top->op));
            }
 
          unsigned2 = top->unsignedp, v2 = top->value;
@@ -808,7 +836,8 @@ _cpp_parse_expr (pfile)
          switch (top[1].op)
            {
            default:
-             cpp_ice (pfile, "impossible operator type %s", TYPE_NAME (op.op));
+             cpp_ice (pfile, "impossible operator '%s'",
+                              op_as_text (pfile, top[1].op));
              goto syntax_error;
 
            case CPP_NOT:        UNARY(!);      break;
@@ -967,13 +996,13 @@ _cpp_parse_expr (pfile)
        {
          if (top->flags & HAVE_VALUE)
            SYNTAX_ERROR2 ("missing binary operator before '%s'",
-                          TYPE_NAME (op.op));
+                          op_as_text (pfile, top->op));
        }
       else
        {
          if (!(top->flags & HAVE_VALUE))
            SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          TYPE_NAME (op.op));
+                          op_as_text (pfile, top->op));
        }
 
       /* Check for and handle stack overflow.  */
@@ -1017,3 +1046,15 @@ _cpp_parse_expr (pfile)
   pfile->skipping = save_skipping;
   return result;
 }
+
+static const unsigned char *
+op_as_text (pfile, op)
+     cpp_reader *pfile;
+     enum cpp_ttype op;
+{
+  cpp_token token;
+
+  token.type = op;
+  token.flags = 0;
+  return cpp_token_as_text (pfile, &token);
+}
index 3110f00..f54fe8a 100644 (file)
@@ -217,6 +217,10 @@ stack_include_file (pfile, inc)
   if (fp == 0)
     return 0;
 
+  /* Initialise controlling macro state.  */
+  pfile->mi_state = MI_OUTSIDE;
+  pfile->mi_cmacro = 0;
+
   fp->inc = inc;
   fp->nominal_fname = inc->name;
   fp->buf = inc->buffer;
@@ -233,8 +237,10 @@ stack_include_file (pfile, inc)
   fp->inc->refcnt++;
   pfile->include_depth++;
   pfile->input_stack_listing_current = 0;
+
   if (pfile->cb.enter_file)
     (*pfile->cb.enter_file) (pfile);
+
   return 1;
 }
 
@@ -562,17 +568,21 @@ report_missing_guard (n, b)
 
 #define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
 void
-_cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets)
+_cpp_execute_include (pfile, header, no_reinclude, search_start)
      cpp_reader *pfile;
-     const U_CHAR *f;
-     unsigned int len;
+     const cpp_token *header;
      int no_reinclude;
      struct file_name_list *search_start;
-     int angle_brackets;
 {
+  unsigned int len = header->val.str.len;
+  unsigned int angle_brackets = header->type == CPP_HEADER_NAME;
   struct include_file *inc;
   char *fname;
 
+  fname = alloca (len + 1);
+  memcpy (fname, header->val.str.text, len);
+  fname[len] = '\0';
+
   if (!search_start)
     {
       if (angle_brackets)
@@ -581,18 +591,14 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets)
        search_start = CPP_OPTION (pfile, quote_include);
       else
        search_start = CPP_BUFFER (pfile)->actual_dir;
-    }
 
-  if (!search_start)
-    {
-      cpp_error (pfile, "No include path in which to find %s", f);
-      return;
+      if (!search_start)
+       {
+         cpp_error (pfile, "No include path in which to find %s", fname);
+         return;
+       }
     }
 
-  fname = alloca (len + 1);
-  memcpy (fname, f, len);
-  fname[len] = '\0';
-
   inc = find_include_file (pfile, fname, search_start);
 
   if (inc)
@@ -666,20 +672,17 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets)
 
 /* Locate file F, and determine whether it is newer than PFILE. Return -1,
    if F cannot be located or dated, 1, if it is newer and 0 if older.  */
-
 int
-_cpp_compare_file_date (pfile, f, len, angle_brackets)
+_cpp_compare_file_date (pfile, f)
      cpp_reader *pfile;
-     const U_CHAR *f;
-     unsigned int len;
-     int angle_brackets;
+     const cpp_token *f;
 {
+  unsigned int len = f->val.str.len;
   char *fname;
   struct file_name_list *search_start;
   struct include_file *inc;
-  struct include_file *current_include = CPP_BUFFER (pfile)->inc;
 
-  if (angle_brackets)
+  if (f->type == CPP_HEADER_NAME)
     search_start = CPP_OPTION (pfile, bracket_include);
   else if (CPP_OPTION (pfile, ignore_srcdir))
     search_start = CPP_OPTION (pfile, quote_include);
@@ -687,7 +690,7 @@ _cpp_compare_file_date (pfile, f, len, angle_brackets)
     search_start = CPP_BUFFER (pfile)->actual_dir;
 
   fname = alloca (len + 1);
-  memcpy (fname, f, len);
+  memcpy (fname, f->val.str.text, len);
   fname[len] = '\0';
   inc = find_include_file (pfile, fname, search_start);
   
@@ -699,7 +702,7 @@ _cpp_compare_file_date (pfile, f, len, angle_brackets)
       inc->fd = -1;
     }
     
-  return inc->st.st_mtime > current_include->st.st_mtime;
+  return inc->st.st_mtime > CPP_BUFFER (pfile)->inc->st.st_mtime;
 }
 
 
@@ -723,6 +726,10 @@ cpp_read_file (pfile, fname)
       return 0;
     }
 
+  /* Return success for zero-length files.  */
+  if (DO_NOT_REREAD (f))
+    return 1;
+
   return stack_include_file (pfile, f);
 }
 
@@ -739,13 +746,18 @@ _cpp_pop_file_buffer (pfile, buf)
     pfile->system_include_depth--;
   if (pfile->include_depth)
     pfile->include_depth--;
-  if (pfile->potential_control_macro)
+  pfile->input_stack_listing_current = 0;
+
+  /* Record the inclusion-preventing macro and its definedness.  */
+  if (pfile->mi_state == MI_OUTSIDE && inc->cmacro != NEVER_REREAD)
     {
-      if (inc->cmacro != NEVER_REREAD)
-       inc->cmacro = pfile->potential_control_macro;
-      pfile->potential_control_macro = 0;
+      /* This could be NULL meaning no controlling macro.  */
+      inc->cmacro = pfile->mi_cmacro;
+      inc->defined = 1;
     }
-  pfile->input_stack_listing_current = 0;
+
+  /* Invalidate control macros in the #including file.  */
+  pfile->mi_state = MI_FAILED;
 
   inc->refcnt--;
   if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
index dee77a9..1c7366d 100644 (file)
@@ -49,7 +49,7 @@ static unsigned long higher_prime_number PARAMS ((unsigned long));
 
 /* Set up and tear down internal structures for macro expansion.  */
 void
-_cpp_init_macros (pfile)
+_cpp_init_hashtable (pfile)
      cpp_reader *pfile;
 {
   pfile->hash_ob = xnew (struct obstack);
@@ -63,7 +63,7 @@ _cpp_init_macros (pfile)
 }
 
 void
-_cpp_cleanup_macros (pfile)
+_cpp_cleanup_hashtable (pfile)
      cpp_reader *pfile;
 {
   cpp_hashnode **p, **limit;
@@ -101,29 +101,32 @@ cpp_lookup (pfile, name, len)
   size_t n = len;
   unsigned int r = 0;
   const U_CHAR *str = name;
+  U_CHAR *dest = _cpp_pool_reserve (&pfile->ident_pool, len + 1);
 
   do
     {
       r = HASHSTEP (r, *str);
-      str++;
+      *dest++ = *str++;
     }
   while (--n);
+  *dest = '\0';
 
-  return _cpp_lookup_with_hash (pfile, name, len, r);
+  return _cpp_lookup_with_hash (pfile, len, r);
 }
 
+/* NAME is a null-terminated identifier of length len.  It is assumed
+   to have been placed at the front of the identifier pool.  */
 cpp_hashnode *
-_cpp_lookup_with_hash (pfile, name, len, hash)
+_cpp_lookup_with_hash (pfile, len, hash)
      cpp_reader *pfile;
-     const U_CHAR *name;
      size_t len;
      unsigned int hash;
 {
   unsigned int index;
-  unsigned int hash2;
   size_t size;
   cpp_hashnode *entry;
   cpp_hashnode **entries;
+  unsigned char *name = POOL_FRONT (&pfile->ident_pool);
 
   entries = pfile->hashtab->entries;
   size = pfile->hashtab->size;
@@ -132,48 +135,49 @@ _cpp_lookup_with_hash (pfile, name, len, hash)
   index = hash % size;
 
   entry = entries[index];
-  if (entry == NULL)
-    goto insert;
-  if (entry->hash == hash && entry->length == len
-      && !memcmp (entry->name, name, len))
-    return entry;
-
-  hash2 = 1 + hash % (size - 2);
-
-  for (;;)
+  if (entry)
     {
-      index += hash2;
-      if (index >= size)
-       index -= size;
-      entry = entries[index];
+      unsigned int hash2;
 
-      if (entry == NULL)
-       goto insert;
       if (entry->hash == hash && entry->length == len
          && !memcmp (entry->name, name, len))
        return entry;
+
+      hash2 = 1 + hash % (size - 2);
+
+      for (;;)
+       {
+         index += hash2;
+         if (index >= size)
+           index -= size;
+         entry = entries[index];
+
+         if (entry == NULL)
+           break;
+         if (entry->hash == hash && entry->length == len
+             && !memcmp (entry->name, name, len))
+           return entry;
+       }
     }
 
- insert:
-  pfile->hashtab->nelts++;
+  /* Commit the memory for the identifier.  */
+  POOL_COMMIT (&pfile->ident_pool, len + 1);
 
-  /* Create a new hash node.  */
-  {
-    U_CHAR *p = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode) + len);
-    entry = (cpp_hashnode *)p;
-    p += offsetof (cpp_hashnode, name);
-    
-    entry->type = T_VOID;
-    entry->fe_value = 0;
-    entry->length = len;
-    entry->hash = hash;
-    entry->value.expansion = NULL;
-    memcpy (p, name, len);
-    p[len] = 0;
-
-    entries[index] = entry;
-  }
+  /* Create a new hash node and insert it in the table.  */
+  entries[index] = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode));
 
+  entry = entries[index];
+  entry->type = NT_VOID;
+  entry->flags = 0;
+  entry->fe_value = 0;
+  entry->directive_index = 0;
+  entry->arg_index = 0;
+  entry->length = len;
+  entry->hash = hash;
+  entry->name = name;
+  entry->value.macro = 0;
+
+  pfile->hashtab->nelts++;
   if (size * 3 <= pfile->hashtab->nelts * 4)
     expand_hash (pfile->hashtab);
 
index 8787a6c..bba1ba9 100644 (file)
@@ -22,68 +22,30 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #ifndef __GCC_CPPHASH__
 #define __GCC_CPPHASH__
 
-typedef unsigned char U_CHAR;
-#define U (const U_CHAR *)  /* Intended use: U"string" */
-
-/* Tokens with SPELL_STRING store their spelling in the token list,
-   and it's length in the token->val.name.len.  */
-enum spell_type
+/* Test if a sign is valid within a preprocessing number.  */
+#define VALID_SIGN(c, prevc) \
+  (((c) == '+' || (c) == '-') && \
+   ((prevc) == 'e' || (prevc) == 'E' \
+    || (((prevc) == 'p' || (prevc) == 'P') && !CPP_OPTION (pfile, c89))))
+
+/* Memory pools.  */
+#define ALIGN(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
+#define POOL_FRONT(p) ((p)->cur->front)
+#define POOL_LIMIT(p) ((p)->cur->limit)
+#define POOL_BASE(p)  ((p)->cur->base)
+#define POOL_SIZE(p)  ((p)->cur->limit - (p)->cur->base)
+#define POOL_ROOM(p)  ((p)->cur->limit - (p)->cur->front)
+#define POOL_USED(p)  ((p)->cur->front - (p)->cur->base)
+#define POOL_COMMIT(p, len) do {((p)->cur->front += ALIGN (len, (p)->align));\
+  if ((p)->cur->front > (p)->cur->limit) abort ();} while (0)
+
+typedef struct cpp_chunk cpp_chunk;
+struct cpp_chunk
 {
-  SPELL_OPERATOR = 0,
-  SPELL_CHAR,
-  SPELL_IDENT,
-  SPELL_STRING,
-  SPELL_NONE
-};
-
-struct token_spelling
-{
-  enum spell_type category;
-  const U_CHAR *name;
-};
-
-extern const struct token_spelling _cpp_token_spellings[];
-#define TOKEN_SPELL(token) (_cpp_token_spellings[(token)->type].category)
-#define TOKEN_NAME(token) (_cpp_token_spellings[(token)->type].name)
-
-/* Chained list of answers to an assertion.  */
-struct answer
-{
-  struct answer *next;
-  cpp_toklist list;
-};
-#define FREE_ANSWER(answer) do {_cpp_free_toklist (&answer->list); \
-                               free (answer); } while (0)
-
-/* 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.  EXPAND means that macros are to be expanded on the
-   directive line.  INCL means to treat "..." and <...> as
-   q-char-sequence and h-char-sequence respectively.  COMMENTS means
-   preserve comments in the directive if -C.  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 EXPAND         (1 << 1)
-#define INCL           (1 << 2)
-#define COMMENTS       (1 << 3)
-#define IN_I           (1 << 4)
-
-/* Defines one #-directive, including how to handle it.  */
-typedef void (*directive_handler) PARAMS ((cpp_reader *));
-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.  */
+  cpp_chunk *next;
+  unsigned char *front;
+  unsigned char *limit;
+  unsigned char *base;
 };
 
 /* List of directories to look for include files in. */
@@ -122,28 +84,18 @@ struct include_file
   unsigned short refcnt;       /* number of stacked buffers using this file */
   unsigned char sysp;          /* file is a system header */
   unsigned char mapped;                /* file buffer is mmapped */
+  unsigned char defined;       /* cmacro prevents inclusion in this state */
 };
 
 /* The cmacro works like this: If it's NULL, the file is to be
    included again.  If it's NEVER_REREAD, the file is never to be
    included again.  Otherwise it is a macro hashnode, and the file is
-   to be included again if the macro is not defined.  */
+   to be included again if the macro is defined or not as specified by
+   DEFINED.  */
 #define NEVER_REREAD ((const cpp_hashnode *)-1)
 #define DO_NOT_REREAD(inc) \
-((inc)->cmacro && \
- ((inc)->cmacro == NEVER_REREAD || (inc)->cmacro->type != T_VOID))
-
-/* Special nodes - identifiers with predefined significance.
-   Note that the array length of dirs[] must be kept in sync with
-   cpplib.c's dtable[].  */
-struct spec_nodes
-{
-  cpp_hashnode *n_L;                   /* L"str" */
-  cpp_hashnode *n__STRICT_ANSI__;      /* STDC_0_IN_SYSTEM_HEADERS */
-  cpp_hashnode *n__CHAR_UNSIGNED__;    /* plain char is unsigned */
-  cpp_hashnode *n__VA_ARGS__;          /* C99 vararg macros */
-  cpp_hashnode *dirs[19];              /* 19 directives counting #sccs */
-};
+((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \
+                  || ((inc)->cmacro->type == NT_MACRO) == (inc)->defined))
 
 /* Character classes.
    If the definition of `numchar' looks odd to you, please look up the
@@ -200,27 +152,30 @@ extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
 /* In cpperror.c  */
 enum error_type { WARNING = 0, PEDWARN, ERROR, FATAL, ICE };
 extern int _cpp_begin_message PARAMS ((cpp_reader *, enum error_type,
-                                      const char *, unsigned int,
-                                      unsigned int));
+                                      const char *, const cpp_lexer_pos *));
 
 /* In cppmacro.c */
 extern void _cpp_free_definition       PARAMS ((cpp_hashnode *));
 extern int _cpp_create_definition      PARAMS ((cpp_reader *, cpp_hashnode *));
+extern void _cpp_pop_context           PARAMS ((cpp_reader *));
+extern void _cpp_get_token             PARAMS ((cpp_reader *, cpp_token *));
+extern void _cpp_free_lookaheads       PARAMS ((cpp_reader *));
+extern void _cpp_push_token            PARAMS ((cpp_reader *, const cpp_token *,
+                                                const cpp_lexer_pos *));
 
 /* In cpphash.c */
-extern void _cpp_init_macros           PARAMS ((cpp_reader *));
-extern void _cpp_cleanup_macros                PARAMS ((cpp_reader *));
-extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, const U_CHAR *,
-                                                   size_t, unsigned int));
+extern void _cpp_init_hashtable                PARAMS ((cpp_reader *));
+extern void _cpp_cleanup_hashtable     PARAMS ((cpp_reader *));
+extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, size_t,
+                                                   unsigned int));
 
 /* In cppfiles.c */
 extern void _cpp_simplify_pathname     PARAMS ((char *));
-extern void _cpp_execute_include       PARAMS ((cpp_reader *, const U_CHAR *,
-                                                unsigned int, int,
-                                                struct file_name_list *,
-                                                int));
-extern int _cpp_compare_file_date       PARAMS ((cpp_reader *, const U_CHAR *,
-                                                 unsigned int, int));
+extern void _cpp_execute_include       PARAMS ((cpp_reader *,
+                                                const cpp_token *, int,
+                                                struct file_name_list *));
+extern int _cpp_compare_file_date       PARAMS ((cpp_reader *,
+                                                const cpp_token *));
 extern void _cpp_report_missing_guards PARAMS ((cpp_reader *));
 extern void _cpp_init_includes         PARAMS ((cpp_reader *));
 extern void _cpp_cleanup_includes      PARAMS ((cpp_reader *));
@@ -231,113 +186,33 @@ extern void _cpp_pop_file_buffer PARAMS ((cpp_reader *, cpp_buffer *));
 extern int _cpp_parse_expr             PARAMS ((cpp_reader *));
 
 /* In cpplex.c */
-extern const unsigned char *_cpp_digraph_spellings[];
-extern void _cpp_skip_rest_of_line     PARAMS ((cpp_reader *));
-extern void _cpp_free_temp_tokens      PARAMS ((cpp_reader *));
-extern void _cpp_init_input_buffer     PARAMS ((cpp_reader *));
-extern void _cpp_grow_token_buffer     PARAMS ((cpp_reader *, long));
-extern void _cpp_init_toklist          PARAMS ((cpp_toklist *, int));
-extern void _cpp_clear_toklist         PARAMS ((cpp_toklist *));
-extern void _cpp_free_toklist          PARAMS ((const cpp_toklist *));
+extern void _cpp_lex_token             PARAMS ((cpp_reader *, cpp_token *));
 extern int _cpp_equiv_tokens           PARAMS ((const cpp_token *,
                                                 const cpp_token *));
-extern int _cpp_equiv_toklists         PARAMS ((const cpp_toklist *,
-                                                const cpp_toklist *));
-extern void _cpp_expand_token_space    PARAMS ((cpp_toklist *, unsigned int));
-extern void _cpp_reserve_name_space    PARAMS ((cpp_toklist *, unsigned int));
-extern void _cpp_expand_name_space     PARAMS ((cpp_toklist *, unsigned int));
-extern int _cpp_equiv_tokens           PARAMS ((const cpp_token *,
-                                                const cpp_token *));
-extern void _cpp_process_directive PARAMS ((cpp_reader *, const cpp_token *));
-extern void _cpp_run_directive         PARAMS ((cpp_reader *,
-                                                const struct directive *,
-                                                const char *, size_t,
-                                                const char *));
-extern unsigned int _cpp_get_line      PARAMS ((cpp_reader *,
-                                                unsigned int *));
-extern const cpp_token *_cpp_get_token PARAMS ((cpp_reader *));
-extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *));
-extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*));
-extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *));
-extern enum cpp_ttype _cpp_can_paste PARAMS ((cpp_reader *, const cpp_token *,
-                                             const cpp_token *, int *));
+extern void _cpp_init_pool             PARAMS ((cpp_pool *, unsigned int,
+                                                 unsigned int, unsigned int));
+extern void _cpp_free_pool             PARAMS ((cpp_pool *));
+extern unsigned char *_cpp_pool_reserve PARAMS ((cpp_pool *, unsigned int));
+extern unsigned char *_cpp_pool_alloc  PARAMS ((cpp_pool *, unsigned int));
+extern unsigned char *_cpp_next_chunk  PARAMS ((cpp_pool *, unsigned int,
+                                                unsigned char **));
+extern void _cpp_lock_pool             PARAMS ((cpp_pool *));
+extern void _cpp_unlock_pool           PARAMS ((cpp_pool *));
 
 /* In cpplib.c */
-extern const struct directive *_cpp_check_directive
-                       PARAMS ((cpp_reader *, const cpp_token *));
-extern const struct directive *_cpp_check_linemarker
-                       PARAMS ((cpp_reader *, const cpp_token *));
-extern cpp_hashnode *_cpp_parse_assertion PARAMS ((cpp_reader *,
-                                                   struct answer **));
-extern struct answer **_cpp_find_answer        PARAMS ((cpp_hashnode *,
-                                                const cpp_toklist *));
-extern void _cpp_define_builtin                PARAMS ((cpp_reader *, const char *));
-
+extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *));
+extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
+extern void _cpp_define_builtin        PARAMS ((cpp_reader *, const char *));
 extern void _cpp_init_stacks   PARAMS ((cpp_reader *));
 extern void _cpp_cleanup_stacks        PARAMS ((cpp_reader *));
 extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));
 
 /* Utility routines and macros.  */
+#define DSC(str) (const U_CHAR *)str, sizeof str - 1
 #define xnew(T)                (T *) xmalloc (sizeof(T))
 #define xcnew(T)       (T *) xcalloc (1, sizeof(T))
 #define xnewvec(T, N)  (T *) xmalloc (sizeof(T) * (N))
 #define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T))
 #define xobnew(O, T)   (T *) obstack_alloc (O, sizeof(T))
 
-/* These are inline functions instead of macros so we can get type
-   checking.  */
-
-static inline int ustrcmp      PARAMS ((const U_CHAR *, const U_CHAR *));
-static inline int ustrncmp     PARAMS ((const U_CHAR *, const U_CHAR *,
-                                        size_t));
-static inline size_t ustrlen   PARAMS ((const U_CHAR *));
-static inline U_CHAR *uxstrdup PARAMS ((const U_CHAR *));
-static inline U_CHAR *ustrchr  PARAMS ((const U_CHAR *, int));
-static inline int ufputs       PARAMS ((const U_CHAR *, FILE *));
-
-static inline int
-ustrcmp (s1, s2)
-     const U_CHAR *s1, *s2;
-{
-  return strcmp ((const char *)s1, (const char *)s2);
-}
-
-static inline int
-ustrncmp (s1, s2, n)
-     const U_CHAR *s1, *s2;
-     size_t n;
-{
-  return strncmp ((const char *)s1, (const char *)s2, n);
-}
-
-static inline size_t
-ustrlen (s1)
-     const U_CHAR *s1;
-{
-  return strlen ((const char *)s1);
-}
-
-static inline U_CHAR *
-uxstrdup (s1)
-     const U_CHAR *s1;
-{
-  return (U_CHAR *) xstrdup ((const char *)s1);
-}
-
-static inline U_CHAR *
-ustrchr (s1, c)
-     const U_CHAR *s1;
-     int c;
-{
-  return (U_CHAR *) strchr ((const char *)s1, c);
-}
-
-static inline int
-ufputs (s, f)
-     const U_CHAR *s;
-     FILE *f;
-{
-  return fputs ((const char *)s, f);
-}
-
 #endif
index 3fbf77e..20dfc63 100644 (file)
@@ -427,8 +427,19 @@ void
 cpp_reader_init (pfile)
      cpp_reader *pfile;
 {
+  struct spec_nodes *s;
+
   memset ((char *) pfile, 0, sizeof (cpp_reader));
 
+  /* If cpp_init hasn't been called, generate a fatal error (by hand)
+     and call it here.  */
+  if (!cpp_init_completed)
+    {
+      fputs ("cpp_reader_init: internal error: cpp_init not called.\n", stderr);
+      pfile->errors = CPP_FATAL_LIMIT;
+      cpp_init ();
+    }
+
   CPP_OPTION (pfile, dollars_in_ident) = 1;
   CPP_OPTION (pfile, cplusplus_comments) = 1;
   CPP_OPTION (pfile, warn_import) = 1;
@@ -441,44 +452,45 @@ cpp_reader_init (pfile)
   CPP_OPTION (pfile, pending) =
     (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
 
-  /* If cpp_init hasn't been called, generate a fatal error (by hand)
-     and call it here.  */
-  if (!cpp_init_completed)
-    {
-      fputs ("cpp_reader_init: internal error: cpp_init not called.\n", stderr);
-      pfile->errors = CPP_FATAL_LIMIT;
-      cpp_init ();
-    }
+  /* Initialize comment saving state.  */
+  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
+
+  /* Indicate date and time not yet calculated.  */
+  pfile->date.type = CPP_EOF;
+
+  /* Initialise the base context.  */
+  pfile->context = &pfile->base_context;
+  pfile->base_context.macro = 0;
+  pfile->base_context.prev = pfile->base_context.next = 0;
+
+  /* Identifier pool initially 8K.  Unaligned, permanent pool.  */
+  _cpp_init_pool (&pfile->ident_pool, 8 * 1024, 1, 0);
+
+  /* String and number pool initially 4K.  Unaligned, temporary pool.  */
+  _cpp_init_pool (&pfile->temp_string_pool, 4 * 1024, 1, 1);
+
+  /* Argument pool initially 8K.  Aligned, temporary pool.  */
+  _cpp_init_pool (&pfile->argument_pool, 8 * 1024, 0, 1);
+
+  /* Macro pool initially 8K.  Aligned, permanent pool.  */
+  _cpp_init_pool (&pfile->macro_pool, 8 * 1024, 0, 0);
 
-  _cpp_init_macros (pfile);
+  /* Start with temporary pool.   */
+  pfile->string_pool = &pfile->temp_string_pool;
+
+  _cpp_init_hashtable (pfile);
   _cpp_init_stacks (pfile);
   _cpp_init_includes (pfile);
   _cpp_init_internal_pragmas (pfile);
-}
 
-/* Initialize a cpp_printer structure.  As a side effect, open the
-   output file.  */
-cpp_printer *
-cpp_printer_init (pfile, print)
-     cpp_reader *pfile;
-     cpp_printer *print;
-{
-  memset (print, '\0', sizeof (cpp_printer));
-  if (CPP_OPTION (pfile, out_fname) == NULL)
-    CPP_OPTION (pfile, out_fname) = "";
-  
-  if (CPP_OPTION (pfile, out_fname)[0] == '\0')
-    print->outf = stdout;
-  else
-    {
-      print->outf = fopen (CPP_OPTION (pfile, out_fname), "w");
-      if (! print->outf)
-       {
-         cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname));
-         return NULL;
-       }
-    }
-  return print;
+  /* Initialize the special nodes.  */
+  s = &pfile->spec_nodes;
+  s->n_L                = cpp_lookup (pfile, DSC("L"));
+  s->n_defined         = cpp_lookup (pfile, DSC("defined"));
+  s->n__STRICT_ANSI__   = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
+  s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
+  s->n__VA_ARGS__       = cpp_lookup (pfile, DSC("__VA_ARGS__"));
+  s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
 }
 
 /* Free resources used by PFILE.
@@ -487,69 +499,84 @@ void
 cpp_cleanup (pfile)
      cpp_reader *pfile;
 {
-  struct file_name_list *dir, *next;
+  struct file_name_list *dir, *dirn;
+  cpp_context *context, *contextn;
 
   while (CPP_BUFFER (pfile) != NULL)
     cpp_pop_buffer (pfile);
 
+  if (pfile->macro_buffer)
+    free ((PTR) pfile->macro_buffer);
+
   if (pfile->deps)
     deps_free (pfile->deps);
 
-  if (pfile->spec_nodes)
-    free (pfile->spec_nodes);
-
-  _cpp_free_temp_tokens (pfile);
   _cpp_cleanup_includes (pfile);
   _cpp_cleanup_stacks (pfile);
-  _cpp_cleanup_macros (pfile);
+  _cpp_cleanup_hashtable (pfile);
+
+  _cpp_free_lookaheads (pfile);
 
-  for (dir = CPP_OPTION (pfile, quote_include); dir; dir = next)
+  _cpp_free_pool (&pfile->ident_pool);
+  _cpp_free_pool (&pfile->temp_string_pool);
+  _cpp_free_pool (&pfile->macro_pool);
+  _cpp_free_pool (&pfile->argument_pool);
+
+  for (dir = CPP_OPTION (pfile, quote_include); dir; dir = dirn)
     {
-      next = dir->next;
+      dirn = dir->next;
       free (dir->name);
       free (dir);
     }
+
+  for (context = pfile->base_context.next; context; context = contextn)
+    {
+      contextn = context->next;
+      free (context);
+    }
 }
 
 
-/* This structure defines one built-in macro.  A node of type TYPE will
-   be entered in the macro hash table under the name NAME, with value
-   VALUE (if any).  If TYPE is T_OPERATOR, the CODE field is used instead.
+/* This structure defines one built-in identifier.  A node will be
+   entered in the hash table under the name NAME, with value VALUE (if
+   any).  If flags has OPERATOR, the node's operator field is used; if
+   flags has BUILTIN the node's builtin field is used.
 
    Two values are not compile time constants, so we tag
    them in the FLAGS field instead:
    VERS                value is the global version_string, quoted
    ULP         value is the global user_label_prefix
 
-   Also, macros with CPLUS set in the flags field are entered only for C++.
- */
+   Also, macros with CPLUS set in the flags field are entered only for C++.  */
 
 struct builtin
 {
   const U_CHAR *name;
   const char *value;
-  unsigned char code;
-  unsigned char type;
+  unsigned char builtin;
+  unsigned char operator;
   unsigned short flags;
-  unsigned int len;
+  unsigned short len;
 };
-#define VERS  0x01
-#define ULP   0x02
-#define CPLUS 0x04
-
-#define B(n, t)       { U n, 0, 0, t,          0, sizeof n - 1 }
-#define C(n, v)       { U n, v, 0, T_MACRO,    0, sizeof n - 1 }
-#define X(n, f)       { U n, 0, 0, T_MACRO,    f, sizeof n - 1 }
-#define O(n, c, f)    { U n, 0, c, T_OPERATOR, f, sizeof n - 1 }
+#define VERS           0x01
+#define ULP            0x02
+#define CPLUS          0x04
+#define BUILTIN                0x08
+#define OPERATOR       0x10
+
+#define B(n, t)       { U n, 0, t, 0, BUILTIN, sizeof n - 1 }
+#define C(n, v)       { U n, v, 0, 0, 0, sizeof n - 1 }
+#define X(n, f)       { U n, 0, 0, 0, f, sizeof n - 1 }
+#define O(n, c, f)    { U n, 0, 0, c, OPERATOR | f, sizeof n - 1 }
 static const struct builtin builtin_array[] =
 {
-  B("__TIME__",                 T_TIME),
-  B("__DATE__",                 T_DATE),
-  B("__FILE__",                 T_FILE),
-  B("__BASE_FILE__",    T_BASE_FILE),
-  B("__LINE__",                 T_SPECLINE),
-  B("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL),
-  B("__STDC__",                 T_STDC),
+  B("__TIME__",                 BT_TIME),
+  B("__DATE__",                 BT_DATE),
+  B("__FILE__",                 BT_FILE),
+  B("__BASE_FILE__",    BT_BASE_FILE),
+  B("__LINE__",                 BT_SPECLINE),
+  B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
+  B("__STDC__",                 BT_STDC),
 
   X("__VERSION__",             VERS),
   X("__USER_LABEL_PREFIX__",   ULP),
@@ -570,9 +597,8 @@ static const struct builtin builtin_array[] =
 
   /* Named operators known to the preprocessor.  These cannot be #defined
      and always have their stated meaning.  They are treated like normal
-     string tokens except for the type code and the meaning.  Most of them
+     identifiers except for the type code and the meaning.  Most of them
      are only for C++ (but see iso646.h).  */
-  O("defined", CPP_DEFINED, 0),
   O("and",     CPP_AND_AND, CPLUS),
   O("and_eq",  CPP_AND_EQ,  CPLUS),
   O("bitand",  CPP_AND,     CPLUS),
@@ -583,7 +609,7 @@ static const struct builtin builtin_array[] =
   O("or",      CPP_OR_OR,   CPLUS),
   O("or_eq",   CPP_OR_EQ,   CPLUS),
   O("xor",     CPP_XOR,     CPLUS),
-  O("xor_eq",  CPP_XOR_EQ,  CPLUS),
+  O("xor_eq",  CPP_XOR_EQ,  CPLUS)
 };
 #undef B
 #undef C
@@ -601,10 +627,25 @@ initialize_builtins (pfile)
 
   for(b = builtin_array; b < builtin_array_end; b++)
     {
-      if (b->flags & CPLUS && ! CPP_OPTION (pfile, cplusplus))
+      if ((b->flags & CPLUS) && ! CPP_OPTION (pfile, cplusplus))
        continue;
 
-      if (b->type == T_MACRO)
+      if (b->flags & (OPERATOR | BUILTIN))
+       {
+         cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
+         if (b->flags & OPERATOR)
+           {
+             hp->flags |= NODE_OPERATOR;
+             hp->value.operator = b->operator;
+           }
+         else
+           {
+             hp->type = NT_MACRO;
+             hp->flags |= NODE_BUILTIN;
+             hp->value.builtin = b->builtin;
+           }
+       }
+      else                     /* A standard macro of some kind.  */
        {
          const char *val;
          char *str;
@@ -629,17 +670,13 @@ initialize_builtins (pfile)
 
          _cpp_define_builtin (pfile, str);
        }
-      else
-       {
-         cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
-         hp->type = b->type;
-         if (b->type == T_OPERATOR)
-           hp->value.code = b->code;
-       }
     }
 }
+#undef BUILTIN
+#undef OPERATOR
 #undef VERS
 #undef ULP
+#undef CPLUS
 #undef builtin_array_end
 
 /* Another subroutine of cpp_start_read.  This one sets up to do
@@ -799,9 +836,8 @@ initialize_standard_includes (pfile)
  */
 
 int
-cpp_start_read (pfile, print, fname)
+cpp_start_read (pfile, fname)
      cpp_reader *pfile;
-     cpp_printer *print;
      const char *fname;
 {
   struct pending_option *p, *q;
@@ -829,19 +865,6 @@ cpp_start_read (pfile, print, fname)
   if (CPP_OPTION (pfile, user_label_prefix) == NULL)
     CPP_OPTION (pfile, user_label_prefix) = USER_LABEL_PREFIX;
 
-  /* Figure out if we need to save function macro parameter spellings.
-     We don't use CPP_PEDANTIC() here because that depends on whether
-     or not the current file is a system header, and there is no
-     current file yet.  */
-  pfile->save_parameter_spellings =
-    CPP_OPTION (pfile, pedantic)
-    || CPP_OPTION (pfile, debug_output)
-    || CPP_OPTION (pfile, dump_macros) == dump_definitions
-    || CPP_OPTION (pfile, dump_macros) == dump_only;
-
-  /* Set up the tables used by read_and_prescan.  */
-  _cpp_init_input_buffer (pfile);
-
   /* Set up the include search path now.  */
   if (! CPP_OPTION (pfile, no_standard_includes))
     initialize_standard_includes (pfile);
@@ -893,13 +916,6 @@ cpp_start_read (pfile, print, fname)
     }
   pfile->done_initializing = 1;
 
-  /* We start at line 1 of the main input file.  */
-  if (print)
-    {
-      print->last_fname = CPP_BUFFER (pfile)->nominal_fname;
-      print->lineno = 1;
-    }
-
   /* The -imacros files can be scanned now, but the -include files
      have to be pushed onto the include stack and processed later,
      in the main loop calling cpp_get_token.  */
@@ -934,9 +950,8 @@ cpp_start_read (pfile, print, fname)
    clear macro definitions, such that you could call cpp_start_read
    with a new filename to restart processing. */
 void
-cpp_finish (pfile, print)
+cpp_finish (pfile)
      cpp_reader *pfile;
-     cpp_printer *print;
 {
   if (CPP_BUFFER (pfile))
     {
@@ -971,15 +986,6 @@ cpp_finish (pfile, print)
        }
     }
 
-  /* Flush any pending output.  */
-  if (print)
-    {
-      if (pfile->need_newline)
-       putc ('\n', print->outf);
-      if (ferror (print->outf) || fclose (print->outf))
-       cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname));
-    }
-
   /* Report on headers that could use multiple include guards.  */
   if (CPP_OPTION (pfile, print_include_names))
     _cpp_report_missing_guards (pfile);
index 426e82d..fa737a9 100644 (file)
@@ -20,79 +20,54 @@ You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-/*
-
-Cleanups to do:-
-
-o Distinguish integers, floats, and 'other' pp-numbers.
-o Store ints and char constants as binary values.
-o New command-line assertion syntax.
-o Comment all functions, and describe macro expansion algorithm.
-o Move as much out of header files as possible.
-o Remove single quote pairs `', and some '', from diagnostics.
-o Correct pastability test for CPP_NAME and CPP_NUMBER.
-
-*/
+/* This lexer works with a single pass of the file.  Recently I
+   re-wrote it to minimize the places where we step backwards in the
+   input stream, to make future changes to support multi-byte
+   character sets fairly straight-forward.
+
+   There is now only one routine where we do step backwards:
+   skip_escaped_newlines.  This routine could probably also be changed
+   so that it doesn't need to step back.  One possibility is to use a
+   trick similar to that used in lex_period and lex_percent.  Two
+   extra characters might be needed, but skip_escaped_newlines itself
+   would probably be the only place that needs to be aware of that,
+   and changes to the remaining routines would probably only be needed
+   if they process a backslash.  */
 
 #include "config.h"
 #include "system.h"
-#include "intl.h"
 #include "cpplib.h"
 #include "cpphash.h"
 #include "symcat.h"
 
-const unsigned char *_cpp_digraph_spellings [] = {U"%:", U"%:%:", U"<:",
-                                                 U":>", U"<%", U"%>"};
-static const cpp_token placemarker_token = {0, 0, CPP_PLACEMARKER,
-                                           0 UNION_INIT_ZERO};
-static const cpp_token eof_token = {0, 0, CPP_EOF, 0 UNION_INIT_ZERO};
-
-/* Flags for cpp_context.  */
-#define CONTEXT_PASTEL (1 << 0) /* An argument context on LHS of ##.  */
-#define CONTEXT_PASTER (1 << 1) /* An argument context on RHS of ##.  */
-#define CONTEXT_RAW    (1 << 2) /* If argument tokens already expanded.  */
-#define CONTEXT_ARG    (1 << 3) /* If an argument context.  */
-#define CONTEXT_VARARGS        (1 << 4) /* If a varargs argument context.  */
-
-typedef struct cpp_context cpp_context;
-struct cpp_context
+/* Tokens with SPELL_STRING store their spelling in the token list,
+   and it's length in the token->val.name.len.  */
+enum spell_type
 {
-  union
-  {
-    const cpp_toklist *list;   /* Used for macro contexts only.  */
-    const cpp_token **arg;     /* Used for arg contexts only.  */
-  } u;
-
-  /* Pushed token to be returned by next call to get_raw_token.  */
-  const cpp_token *pushed_token;
-
-  struct macro_args *args;     /* The arguments for a function-like
-                                  macro.  NULL otherwise.  */
-  unsigned short posn;         /* Current posn, index into u.  */
-  unsigned short count;                /* No. of tokens in u.  */
-  unsigned short level;
-  unsigned char flags;
+  SPELL_OPERATOR = 0,
+  SPELL_CHAR,
+  SPELL_IDENT,
+  SPELL_STRING,
+  SPELL_NONE
 };
 
-typedef struct macro_args macro_args;
-struct macro_args
+struct token_spelling
 {
-  unsigned int *ends;
-  const cpp_token **tokens;
-  unsigned int capacity;
-  unsigned int used;
-  unsigned short level;
+  enum spell_type category;
+  const unsigned char *name;
 };
 
-static const cpp_token *get_raw_token PARAMS ((cpp_reader *));
-static const cpp_token *parse_arg PARAMS ((cpp_reader *, int, unsigned int,
-                                          macro_args *, unsigned int *));
-static int parse_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_args *));
-static void save_token PARAMS ((macro_args *, const cpp_token *));
-static int pop_context PARAMS ((cpp_reader *));
-static int push_macro_context PARAMS ((cpp_reader *, const cpp_token *));
-static void push_arg_context PARAMS ((cpp_reader *, const cpp_token *));
-static void free_macro_args PARAMS ((macro_args *));
+const unsigned char *digraph_spellings [] = {U"%:", U"%:%:", U"<:",
+                                            U":>", U"<%", U"%>"};
+
+#define OP(e, s) { SPELL_OPERATOR, U s           },
+#define TK(e, s) { s,              U STRINGX (e) },
+const struct token_spelling token_spellings [N_TTYPES] = {TTYPE_TABLE };
+#undef OP
+#undef TK
+
+#define TOKEN_SPELL(token) (token_spellings[(token)->type].category)
+#define TOKEN_NAME(token) (token_spellings[(token)->type].name)
 
 static cppchar_t handle_newline PARAMS ((cpp_buffer *, cppchar_t));
 static cppchar_t skip_escaped_newlines PARAMS ((cpp_buffer *, cppchar_t));
@@ -103,278 +78,18 @@ static int skip_line_comment PARAMS ((cpp_reader *));
 static void adjust_column PARAMS ((cpp_reader *));
 static void skip_whitespace PARAMS ((cpp_reader *, cppchar_t));
 static cpp_hashnode *parse_identifier PARAMS ((cpp_reader *, cppchar_t));
-static void parse_number PARAMS ((cpp_reader *, cpp_string *, cppchar_t));
+static void parse_number PARAMS ((cpp_reader *, cpp_string *, cppchar_t, int));
+static int unescaped_terminator_p PARAMS ((cpp_reader *, const U_CHAR *));
 static void parse_string PARAMS ((cpp_reader *, cpp_token *, cppchar_t));
-static void unterminated PARAMS ((cpp_reader *, unsigned int, int));
+static void unterminated PARAMS ((cpp_reader *, int));
 static int trigraph_ok PARAMS ((cpp_reader *, cppchar_t));
 static void save_comment PARAMS ((cpp_reader *, cpp_token *, const U_CHAR *));
 static void lex_percent PARAMS ((cpp_buffer *, cpp_token *));
 static void lex_dot PARAMS ((cpp_reader *, cpp_token *));
-static void lex_line PARAMS ((cpp_reader *, cpp_toklist *));
-static void lex_token PARAMS ((cpp_reader *, cpp_token *));
-static int lex_next PARAMS ((cpp_reader *, int));
-
-static int is_macro_disabled PARAMS ((cpp_reader *, const cpp_toklist *,
-                                     const cpp_token *));
-
-static cpp_token *stringify_arg PARAMS ((cpp_reader *, const cpp_token *));
-static void expand_context_stack PARAMS ((cpp_reader *));
-static unsigned char * spell_token PARAMS ((cpp_reader *, const cpp_token *,
-                                           unsigned char *));
-typedef unsigned int (* speller) PARAMS ((unsigned char *, cpp_toklist *,
-                                         cpp_token *));
-static cpp_token *make_string_token PARAMS ((cpp_token *, const U_CHAR *,
-                                           unsigned int));
-static cpp_token *alloc_number_token PARAMS ((cpp_reader *, int number));
-static const cpp_token *special_symbol PARAMS ((cpp_reader *, cpp_hashnode *,
-                                               const cpp_token *));
-static cpp_token *duplicate_token PARAMS ((cpp_reader *, const cpp_token *));
-static const cpp_token *maybe_paste_with_next PARAMS ((cpp_reader *,
-                                                      const cpp_token *));
-static unsigned int prevent_macro_expansion    PARAMS ((cpp_reader *));
-static void restore_macro_expansion    PARAMS ((cpp_reader *, unsigned int));
-static cpp_token *get_temp_token       PARAMS ((cpp_reader *));
-static void release_temp_tokens                PARAMS ((cpp_reader *));
-static U_CHAR * quote_string PARAMS ((U_CHAR *, const U_CHAR *, unsigned int));
-
-#define VALID_SIGN(c, prevc) \
-  (((c) == '+' || (c) == '-') && \
-   ((prevc) == 'e' || (prevc) == 'E' \
-    || (((prevc) == 'p' || (prevc) == 'P') && !CPP_OPTION (pfile, c89))))
-
-/* An upper bound on the number of bytes needed to spell a token,
-   including preceding whitespace.  */
-static inline size_t TOKEN_LEN PARAMS ((const cpp_token *));
-static inline size_t
-TOKEN_LEN (token)
-     const cpp_token *token;
-{
-  size_t len;
-
-  switch (TOKEN_SPELL (token))
-    {
-    default:           len = 0;                        break;
-    case SPELL_STRING: len = token->val.str.len;       break;
-    case SPELL_IDENT:  len = token->val.node->length;  break;
-    }
-  return len + 5;
-}
-
-#define IS_ARG_CONTEXT(c) ((c)->flags & CONTEXT_ARG)
-#define CURRENT_CONTEXT(pfile) ((pfile)->contexts + (pfile)->cur_context)
-
-#define ASSIGN_FLAGS_AND_POS(d, s) \
-  do {(d)->flags = (s)->flags & (PREV_WHITE | BOL | PASTE_LEFT); \
-      if ((d)->flags & BOL) {(d)->col = (s)->col; (d)->line = (s)->line;} \
-  } while (0)
-
-/* f is flags, just consisting of PREV_WHITE | BOL.  */
-#define MODIFY_FLAGS_AND_POS(d, s, f) \
-  do {(d)->flags &= ~(PREV_WHITE | BOL); (d)->flags |= (f); \
-      if ((f) & BOL) {(d)->col = (s)->col; (d)->line = (s)->line;} \
-  } while (0)
-
-#define OP(e, s) { SPELL_OPERATOR, U s           },
-#define TK(e, s) { s,              U STRINGX (e) },
-
-const struct token_spelling
-_cpp_token_spellings [N_TTYPES] = {TTYPE_TABLE };
-
-#undef OP
-#undef TK
-
-/* Helper routine used by parse_include, which can't see spell_token.
-   Reinterpret the current line as an h-char-sequence (< ... >); we are
-   looking at the first token after the <.  */
-const cpp_token *
-_cpp_glue_header_name (pfile)
-     cpp_reader *pfile;
-{
-  const cpp_token *t;
-  cpp_token *hdr;
-  U_CHAR *buf, *p;
-  size_t len, avail;
-
-  avail = 40;
-  len = 0;
-  buf = xmalloc (avail);
-
-  for (;;)
-    {
-      t = _cpp_get_token (pfile);
-      if (t->type == CPP_GREATER || t->type == CPP_EOF)
-       break;
-
-      if (len + TOKEN_LEN (t) > avail)
-       {
-         avail = len + TOKEN_LEN (t) + 40;
-         buf = xrealloc (buf, avail);
-       }
-
-      if (t->flags & PREV_WHITE)
-       buf[len++] = ' ';
-
-      p = spell_token (pfile, t, buf + len);
-      len = (size_t) (p - buf);  /* p known >= buf */
-    }
-
-  if (t->type == CPP_EOF)
-    cpp_error (pfile, "missing terminating > character");
-
-  buf = xrealloc (buf, len);
-
-  hdr = get_temp_token (pfile);
-  hdr->type = CPP_HEADER_NAME;
-  hdr->flags = 0;
-  hdr->val.str.text = buf;
-  hdr->val.str.len = len;
-  return hdr;
-}
-
-/* Token-buffer helper functions.  */
-
-/* Expand a token list's string space. It is *vital* that
-   list->tokens_used is correct, to get pointer fix-up right.  */
-void
-_cpp_expand_name_space (list, len)
-     cpp_toklist *list;
-     unsigned int len;
-{
-  const U_CHAR *old_namebuf;
-
-  old_namebuf = list->namebuf;
-  list->name_cap += len;
-  list->namebuf = (unsigned char *) xrealloc (list->namebuf, list->name_cap);
-
-  /* Fix up token text pointers.  */
-  if (list->namebuf != old_namebuf)
-    {
-      unsigned int i;
+static int name_p PARAMS ((cpp_reader *, const cpp_string *));
 
-      for (i = 0; i < list->tokens_used; i++)
-       if (TOKEN_SPELL (&list->tokens[i]) == SPELL_STRING)
-         list->tokens[i].val.str.text += (list->namebuf - old_namebuf);
-    }
-}
-
-/* If there is not enough room for LEN more characters, expand the
-   list by just enough to have room for LEN characters.  */
-void
-_cpp_reserve_name_space (list, len)
-     cpp_toklist *list;
-     unsigned int len;
-{
-  unsigned int room = list->name_cap - list->name_used;
-
-  if (room < len)
-    _cpp_expand_name_space (list, len - room);
-}
-
-/* Expand the number of tokens in a list.  */
-void
-_cpp_expand_token_space (list, count)
-     cpp_toklist *list;
-     unsigned int count;
-{
-  list->tokens_cap += count;
-  list->tokens = (cpp_token *)
-    xrealloc (list->tokens, list->tokens_cap * sizeof (cpp_token));
-}
-
-/* Initialize a token list.  If EMPTY is false, some token and name
-   space is provided.  */
-void
-_cpp_init_toklist (list, empty)
-     cpp_toklist *list;
-     int empty;
-{
-  if (empty)
-    {
-      list->tokens_cap = 0;
-      list->tokens = 0;
-      list->name_cap = 0;
-      list->namebuf = 0;
-    }
-  else
-    {
-      /* Initialize token space.  */
-      list->tokens_cap = 256;  /* 4K's worth.  */
-      list->tokens = (cpp_token *)
-       xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token));
-
-      /* Initialize name space.  */
-      list->name_cap = 1024;
-      list->namebuf = (unsigned char *) xmalloc (list->name_cap);
-    }
-
-  _cpp_clear_toklist (list);
-}
-
-/* Clear a token list.  */
-void
-_cpp_clear_toklist (list)
-     cpp_toklist *list;
-{
-  list->tokens_used = 0;
-  list->name_used = 0;
-  list->directive = 0;
-  list->paramc = 0;
-  list->params_len = 0;
-  list->flags = 0;
-}
-
-/* Free a token list.  Does not free the list itself, which may be
-   embedded in a larger structure.  */
-void
-_cpp_free_toklist (list)
-     const cpp_toklist *list;
-{
-  free (list->tokens);
-  free (list->namebuf);
-}
-
-/* Compare two tokens.  */
-int
-_cpp_equiv_tokens (a, b)
-     const cpp_token *a, *b;
-{
-  if (a->type == b->type && a->flags == b->flags)
-    switch (TOKEN_SPELL (a))
-      {
-      default:                 /* Keep compiler happy.  */
-      case SPELL_OPERATOR:
-       return 1;
-      case SPELL_CHAR:
-      case SPELL_NONE:
-       return a->val.aux == b->val.aux; /* arg_no or character.  */
-      case SPELL_IDENT:
-       return a->val.node == b->val.node;
-      case SPELL_STRING:
-       return (a->val.str.len == b->val.str.len
-               && !memcmp (a->val.str.text, b->val.str.text,
-                           a->val.str.len));
-      }
-
-  return 0;
-}
-
-/* Compare two token lists.  */
-int
-_cpp_equiv_toklists (a, b)
-     const cpp_toklist *a, *b;
-{
-  unsigned int i;
-
-  if (a->tokens_used != b->tokens_used
-      || a->flags != b->flags
-      || a->paramc != b->paramc)
-    return 0;
-
-  for (i = 0; i < a->tokens_used; i++)
-    if (! _cpp_equiv_tokens (&a->tokens[i], &b->tokens[i]))
-      return 0;
-  return 1;
-}
+static cpp_chunk *new_chunk PARAMS ((unsigned int));
+static int chunk_suitable PARAMS ((cpp_pool *, cpp_chunk *, unsigned int));
 
 /* Utility routine:
 
@@ -389,7 +104,7 @@ cpp_ideq (token, string)
   if (token->type != CPP_NAME)
     return 0;
 
-  return !ustrcmp (token->val.node->name, (const U_CHAR *)string);
+  return !ustrcmp (token->val.node->name, (const U_CHAR *) string);
 }
 
 /* Call when meeting a newline.  Returns the character after the newline
@@ -578,7 +293,7 @@ skip_block_comment (pfile)
 
     next_char:
       /* FIXME: For speed, create a new character class of characters
-        of no interest inside block comments.  */
+        of interest inside block comments.  */
       if (c == '?' || c == '\\')
        c = skip_escaped_newlines (buffer, c);
 
@@ -692,7 +407,7 @@ skip_whitespace (pfile, c)
              warned = 1;
            }
        }
-      else if (IN_DIRECTIVE (pfile) && CPP_PEDANTIC (pfile))
+      else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
        cpp_pedwarn_with_line (pfile, CPP_BUF_LINE (buffer),
                               CPP_BUF_COL (buffer),
                               "%s in preprocessing directive",
@@ -710,6 +425,22 @@ skip_whitespace (pfile, c)
   buffer->read_ahead = c;
 }
 
+/* See if the characters of a number token are valid in a name (no
+   '.', '+' or '-').  */
+static int
+name_p (pfile, string)
+     cpp_reader *pfile;
+     const cpp_string *string;
+{
+  unsigned int i;
+
+  for (i = 0; i < string->len; i++)
+    if (!is_idchar (string->text[i]))
+      return 0;
+
+  return 1;  
+}
+
 /* Parse an identifier, skipping embedded backslash-newlines.
    Calculate the hash value of the token while parsing, for improved
    performance.  The hashing algorithm *must* match cpp_lookup().  */
@@ -719,18 +450,23 @@ parse_identifier (pfile, c)
      cpp_reader *pfile;
      cppchar_t c;
 {
+  cpp_hashnode *result;
   cpp_buffer *buffer = pfile->buffer;
+  unsigned char *dest, *limit;
   unsigned int r = 0, saw_dollar = 0;
-  unsigned int orig_used = pfile->token_list.name_used;
+
+  dest = POOL_FRONT (&pfile->ident_pool);
+  limit = POOL_LIMIT (&pfile->ident_pool);
 
   do
     {
       do
        {
-         if (pfile->token_list.name_used == pfile->token_list.name_cap)
-           _cpp_expand_name_space (&pfile->token_list,
-                                   pfile->token_list.name_used + 256);
-         pfile->token_list.namebuf[pfile->token_list.name_used++] = c;
+         /* Need room for terminating null.  */
+         if (dest + 1 >= limit)
+           limit = _cpp_next_chunk (&pfile->ident_pool, 0, &dest);
+
+         *dest++ = c;
          r = HASHSTEP (r, c);
 
          if (c == '$')
@@ -751,86 +487,137 @@ parse_identifier (pfile, c)
     }
   while (is_idchar (c));
 
+  /* Remember the next character.  */
+  buffer->read_ahead = c;
+
   /* $ is not a identifier character in the standard, but is commonly
      accepted as an extension.  Don't warn about it in skipped
      conditional blocks.  */
   if (saw_dollar && CPP_PEDANTIC (pfile) && ! pfile->skipping)
     cpp_pedwarn (pfile, "'$' character(s) in identifier");
 
-  /* Remember the next character.  */
-  buffer->read_ahead = c;
-  return _cpp_lookup_with_hash (pfile, &pfile->token_list.namebuf[orig_used],
-                               pfile->token_list.name_used - orig_used, r);
+  /* Identifiers are null-terminated.  */
+  *dest = '\0';
+
+  /* This routine commits the memory if necessary.  */
+  result = _cpp_lookup_with_hash (pfile,
+                                 dest - POOL_FRONT (&pfile->ident_pool), r);
+
+  /* Some identifiers require diagnostics when lexed.  */
+  if (result->flags & NODE_DIAGNOSTIC && !pfile->skipping)
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+       cpp_error (pfile, "attempt to use poisoned \"%s\"", result->name);
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+        replacement list of a variable-arguments macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+         && !pfile->state.va_args_ok)
+       cpp_pedwarn (pfile, "__VA_ARGS__ can only appear in the expansion of a C99 variable-argument macro");
+    }
+
+  return result;
 }
 
 /* Parse a number, skipping embedded backslash-newlines.  */
 static void
-parse_number (pfile, number, c)
+parse_number (pfile, number, c, leading_period)
      cpp_reader *pfile;
      cpp_string *number;
      cppchar_t c;
+     int leading_period;
 {
-  cppchar_t prevc;
   cpp_buffer *buffer = pfile->buffer;
-  unsigned int orig_used = pfile->token_list.name_used;
+  cpp_pool *pool = pfile->string_pool;
+  unsigned char *dest, *limit;
 
-  /* Reserve space for a leading period.  */
-  if (pfile->state.seen_dot)
-    pfile->token_list.name_used++;
+  dest = POOL_FRONT (pool);
+  limit = POOL_LIMIT (pool);
 
+  /* Place a leading period.  */
+  if (leading_period)
+    {
+      if (dest >= limit)
+       limit = _cpp_next_chunk (pool, 0, &dest);
+      *dest++ = '.';
+    }
+  
   do
     {
       do
        {
-         if (pfile->token_list.name_used >= pfile->token_list.name_cap)
-           _cpp_expand_name_space (&pfile->token_list,
-                                   pfile->token_list.name_used + 256);
-         pfile->token_list.namebuf[pfile->token_list.name_used++] = c;
+         /* Need room for terminating null.  */
+         if (dest + 1 >= limit)
+           limit = _cpp_next_chunk (pool, 0, &dest);
+         *dest++ = c;
 
-         prevc = c;
          c = EOF;
          if (buffer->cur == buffer->rlimit)
            break;
 
          c = *buffer->cur++;
        }
-      while (is_numchar (c) || c == '.' || VALID_SIGN (c, prevc));
+      while (is_numchar (c) || c == '.' || VALID_SIGN (c, dest[-1]));
 
       /* Potential escaped newline?  */
       if (c != '?' && c != '\\')
        break;
       c = skip_escaped_newlines (buffer, c);
     }
-  while (is_numchar (c) || c == '.' || VALID_SIGN (c, prevc));
-
-  /* Put any leading period in place, now we have the room.  */
-  if (pfile->state.seen_dot)
-    pfile->token_list.namebuf[orig_used] = '.';
+  while (is_numchar (c) || c == '.' || VALID_SIGN (c, dest[-1]));
 
   /* Remember the next character.  */
   buffer->read_ahead = c;
 
-  number->text = &pfile->token_list.namebuf[orig_used];
-  number->len = pfile->token_list.name_used - orig_used;
+  /* Null-terminate the number.  */
+  *dest = '\0';
+
+  number->text = POOL_FRONT (pool);
+  number->len = dest - number->text;
+  POOL_COMMIT (pool, number->len + 1);
 }
 
 /* Subroutine of parse_string.  Emits error for unterminated strings.  */
 static void
-unterminated (pfile, line, term)
+unterminated (pfile, term)
      cpp_reader *pfile;
-     unsigned int line;
      int term;
 {
   cpp_error (pfile, "missing terminating %c character", term);
 
-  if (term == '\"' && pfile->mls_line && pfile->mls_line != line)
+  if (term == '\"' && pfile->mlstring_pos.line
+      && pfile->mlstring_pos.line != pfile->lexer_pos.line)
     {
-      cpp_error_with_line (pfile, pfile->mls_line, pfile->mls_column,
+      cpp_error_with_line (pfile, pfile->mlstring_pos.line,
+                          pfile->mlstring_pos.col,
                           "possible start of unterminated string literal");
-      pfile->mls_line = 0;
+      pfile->mlstring_pos.line = 0;
     }
 }
 
+/* Subroutine of parse_string.  */
+static int
+unescaped_terminator_p (pfile, dest)
+     cpp_reader *pfile;
+     const unsigned char *dest;
+{
+  const unsigned char *start, *temp;
+
+  /* In #include-style directives, terminators are not escapeable.  */
+  if (pfile->state.angled_headers)
+    return 1;
+
+  start = POOL_FRONT (pfile->string_pool);
+
+  /* An odd number of consecutive backslashes represents an escaped
+     terminator.  */
+  for (temp = dest; temp > start && temp[-1] == '\\'; temp--)
+    ;
+
+  return ((dest - temp) & 1) == 0;
+}
+
 /* Parses a string, character constant, or angle-bracketed header file
    name.  Handles embedded trigraphs and escaped newlines.
 
@@ -843,16 +630,20 @@ parse_string (pfile, token, terminator)
      cppchar_t terminator;
 {
   cpp_buffer *buffer = pfile->buffer;
-  unsigned int orig_used = pfile->token_list.name_used;
+  cpp_pool *pool = pfile->string_pool;
+  unsigned char *dest, *limit;
   cppchar_t c;
   unsigned int nulls = 0;
 
+  dest = POOL_FRONT (pool);
+  limit = POOL_LIMIT (pool);
+
   for (;;)
     {
       if (buffer->cur == buffer->rlimit)
        {
          c = EOF;
-         unterminated (pfile, token->line, terminator);
+         unterminated (pfile, terminator);
          break;
        }
       c = *buffer->cur++;
@@ -862,20 +653,10 @@ parse_string (pfile, token, terminator)
       if (c == '?' || c == '\\')
        c = skip_escaped_newlines (buffer, c);
 
-      if (c == terminator)
+      if (c == terminator && unescaped_terminator_p (pfile, dest))
        {
-         unsigned int u = pfile->token_list.name_used;
-
-         /* An odd number of consecutive backslashes represents an
-            escaped terminator.  */
-         while (u > orig_used && pfile->token_list.namebuf[u - 1] == '\\')
-           u--;
-
-         if ((pfile->token_list.name_used - u) % 2 == 0)
-           {
-             c = EOF;
-             break;
-           }
+         c = EOF;
+         break;
        }
       else if (is_vspace (c))
        {
@@ -888,18 +669,16 @@ parse_string (pfile, token, terminator)
          /* Character constants and header names may not extend over
             multiple lines.  In Standard C, neither may strings.
             Unfortunately, we accept multiline strings as an
-            extension.  (Deprecatedly even in directives - otherwise,
-            glibc's longlong.h breaks.)  */
+            extension.  */
          if (terminator != '"')
            {
-             unterminated (pfile, token->line, terminator);
+             unterminated (pfile, terminator);
              break;
            }
 
-         if (pfile->mls_line == 0)
+         if (pfile->mlstring_pos.line == 0)
            {
-             pfile->mls_line = token->line;
-             pfile->mls_column = token->col;
+             pfile->mlstring_pos = pfile->lexer_pos;
              if (CPP_PEDANTIC (pfile))
                cpp_pedwarn (pfile, "multi-line string constant");
            }
@@ -913,11 +692,11 @@ parse_string (pfile, token, terminator)
            cpp_warning (pfile, "null character(s) preserved in literal");
        }
 
-      if (pfile->token_list.name_used == pfile->token_list.name_cap)
-       _cpp_expand_name_space (&pfile->token_list,
-                               pfile->token_list.name_used + 256);
+      /* No terminating null for strings - they could contain nulls.  */
+      if (dest >= limit)
+       limit = _cpp_next_chunk (pool, 0, &dest);
+      *dest++ = c;
 
-      pfile->token_list.namebuf[pfile->token_list.name_used++] = c;
       /* If we had a new line, the next character is in read_ahead.  */
       if (c != '\n')
        continue;
@@ -926,14 +705,15 @@ parse_string (pfile, token, terminator)
        goto have_char;
     }
 
+  /* Remember the next character.  */
   buffer->read_ahead = c;
 
-  token->val.str.text = &pfile->token_list.namebuf[orig_used];
-  token->val.str.len = pfile->token_list.name_used - orig_used;
+  token->val.str.text = POOL_FRONT (pool);
+  token->val.str.len = dest - token->val.str.text;
+  POOL_COMMIT (pool, token->val.str.len);
 }
 
-/* For output routine simplicity, the stored comment includes the
-   comment start and any terminator.  */
+/* The stored comment includes the comment start and any terminator.  */
 static void
 save_comment (pfile, token, from)
      cpp_reader *pfile;
@@ -942,12 +722,9 @@ save_comment (pfile, token, from)
 {
   unsigned char *buffer;
   unsigned int len;
-  cpp_toklist *list = &pfile->token_list;
   
   len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'.  */
-  _cpp_reserve_name_space (list, len);
-  buffer = list->namebuf + list->name_used;
-  list->name_used += len;
+  buffer = _cpp_pool_alloc (pfile->string_pool, len);
   
   token->type = CPP_COMMENT;
   token->val.str.len = len;
@@ -1029,9 +806,7 @@ lex_dot (pfile, result)
   if (c >= '0' && c <= '9')
     {
       result->type = CPP_NUMBER;
-      buffer->pfile->state.seen_dot = 1;
-      parse_number (pfile, &result->val.str, c);
-      buffer->pfile->state.seen_dot = 0;
+      parse_number (pfile, &result->val.str, c, 1);
     }
   else
     {
@@ -1053,26 +828,29 @@ lex_dot (pfile, result)
     }
 }
 
-static void
-lex_token (pfile, result)
+void
+_cpp_lex_token (pfile, result)
      cpp_reader *pfile;
      cpp_token *result;
 {
   cppchar_t c;
   cpp_buffer *buffer = pfile->buffer;
   const unsigned char *comment_start;
+  unsigned char was_skip_newlines = pfile->state.skip_newlines;
+  unsigned char newline_in_args = 0;
 
+  pfile->state.skip_newlines = 0;
   result->flags = 0;
  next_char:
-  result->line = CPP_BUF_LINE (buffer);
+  pfile->lexer_pos.line = buffer->lineno;
  next_char2:
-  result->col = CPP_BUF_COLUMN (buffer, buffer->cur);
+  pfile->lexer_pos.col = CPP_BUF_COLUMN (buffer, buffer->cur);
 
   c = buffer->read_ahead;
   if (c == EOF && buffer->cur < buffer->rlimit)
     {
       c = *buffer->cur++;
-      result->col++;
+      pfile->lexer_pos.col++;
     }
 
  do_switch:
@@ -1080,12 +858,11 @@ lex_token (pfile, result)
   switch (c)
     {
     case EOF:
-      /* Non-empty files should end in a newline.  Testing
-         skip_newlines ensures we only emit the warning once.  */
-      if (buffer->cur != buffer->line_base && buffer->cur != buffer->buf
-         && pfile->state.skip_newlines)
-       cpp_pedwarn_with_line (pfile, buffer->lineno, CPP_BUF_COL (buffer),
-                              "no newline at end of file");
+      /* Non-empty files should end in a newline.  Ignore for command
+        line - we get e.g. -A options with no trailing \n.  */
+      if (pfile->lexer_pos.col != 0 && pfile->done_initializing)
+       cpp_pedwarn (pfile, "no newline at end of file");
+      pfile->state.skip_newlines = 1;
       result->type = CPP_EOF;
       break;
 
@@ -1095,15 +872,35 @@ lex_token (pfile, result)
       goto next_char2;
 
     case '\n': case '\r':
-      result->type = CPP_EOF;
-      handle_newline (buffer, c);
-      /* Handling here will change significantly when moving to
-        token-at-a-time.  */
-      if (pfile->state.skip_newlines)
+      /* Don't let directives spill over to the next line.  */
+      if (pfile->state.in_directive)
+       buffer->read_ahead = c;
+      else
        {
-         result->flags &= ~PREV_WHITE; /* Clear any whitespace flag.   */
-         goto next_char;
+         handle_newline (buffer, c);
+
+         pfile->lexer_pos.output_line = buffer->lineno;
+
+         /* Skip newlines in macro arguments (except in directives).  */
+         if (pfile->state.parsing_args)
+           {
+             /* Set the whitespace flag.   */
+             newline_in_args = 1;
+             result->flags |= PREV_WHITE;
+             goto next_char;
+           }
+
+         if (was_skip_newlines)
+           {
+             /* Clear any whitespace flag.   */
+             result->flags &= ~PREV_WHITE;
+             goto next_char;
+           }
        }
+
+      /* Next we're at BOL, so skip new lines.  */
+      pfile->state.skip_newlines = 1;
+      result->type = CPP_EOF;
       break;
 
     case '?':
@@ -1133,7 +930,7 @@ lex_token (pfile, result)
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
       result->type = CPP_NUMBER;
-      parse_number (pfile, &result->val.str, c);
+      parse_number (pfile, &result->val.str, c, 0);
       break;
 
     case '$':
@@ -1156,7 +953,7 @@ lex_token (pfile, result)
       result->val.node = parse_identifier (pfile, c);
 
       /* 'L' may introduce wide characters or strings.  */
-      if (result->val.node == pfile->spec_nodes->n_L)
+      if (result->val.node == pfile->spec_nodes.n_L)
        {
          c = buffer->read_ahead; /* For make_string.  */
          if (c == '\'' || c == '"')
@@ -1166,10 +963,10 @@ lex_token (pfile, result)
            }
        }
       /* Convert named operators to their proper types.  */
-      else if (result->val.node->type == T_OPERATOR)
+      else if (result->val.node->flags & NODE_OPERATOR)
        {
          result->flags |= NAMED_OP;
-         result->type = result->val.node->value.code;
+         result->type = result->val.node->value.operator;
        }
       break;
 
@@ -1193,7 +990,8 @@ lex_token (pfile, result)
       if (c == '*')
        {
          if (skip_block_comment (pfile))
-           cpp_error_with_line (pfile, result->line, result->col,
+           cpp_error_with_line (pfile, pfile->lexer_pos.line,
+                                pfile->lexer_pos.col,
                                 "unterminated comment");
        }
       else
@@ -1218,7 +1016,8 @@ lex_token (pfile, result)
 
          /* Skip_line_comment updates buffer->read_ahead.  */
          if (skip_line_comment (pfile))
-           cpp_warning_with_line (pfile, result->line, result->col,
+           cpp_warning_with_line (pfile, pfile->lexer_pos.line,
+                                  pfile->lexer_pos.col,
                                   "multi-line comment");
        }
 
@@ -1290,6 +1089,8 @@ lex_token (pfile, result)
 
     case '%':
       lex_percent (buffer, result);
+      if (result->type == CPP_HASH)
+       goto do_hash;
       break;
 
     case '.':
@@ -1349,9 +1150,21 @@ lex_token (pfile, result)
       break;
          
     case '#':
-      result->type = CPP_HASH;
       if (get_effective_char (buffer) == '#')
        ACCEPT_CHAR (CPP_PASTE);
+      else
+       {
+         result->type = CPP_HASH;
+       do_hash:
+         /* CPP_DHASH is the hash introducing a directive.  */
+         if (was_skip_newlines || newline_in_args)
+           {
+             result->type = CPP_DHASH;
+             /* Get whitespace right - newline_in_args sets it.  */
+             if (pfile->lexer_pos.col == 1)
+               result->flags &= ~PREV_WHITE;
+           }
+       }
       break;
 
     case '|':
@@ -1423,117 +1236,30 @@ lex_token (pfile, result)
     }
 }
 
-/*
- *  The tokenizer's main loop.  Returns a token list, representing a
- *  logical line in the input file.  On EOF after some tokens have
- *  been processed, we return immediately.  Then in next call, or if
- *  EOF occurred at the beginning of a logical line, a single CPP_EOF
- *  token is placed in the list.
- */
-
-static void
-lex_line (pfile, list)
-     cpp_reader *pfile;
-     cpp_toklist *list;
+/* An upper bound on the number of bytes needed to spell a token,
+   including preceding whitespace.  */
+unsigned int
+cpp_token_len (token)
+     const cpp_token *token;
 {
-  unsigned int first_token;
-  cpp_token *cur_token, *first;
-  cpp_buffer *buffer = pfile->buffer;
-
-  pfile->state.in_lex_line = 1;
-  if (pfile->buffer->cur == pfile->buffer->buf)
-    list->flags |= BEG_OF_FILE;
-
- retry:
-  pfile->state.in_directive = 0;
-  pfile->state.angled_headers = 0;
-  pfile->state.skip_newlines = 1;
-  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
-  first_token = list->tokens_used;
-  list->file = buffer->nominal_fname;
-
-  do
-    {
-      if (list->tokens_used >= list->tokens_cap)
-       _cpp_expand_token_space (list, 256);
-
-      cur_token = list->tokens + list->tokens_used;
-      lex_token (pfile, cur_token);
-
-      if (pfile->state.skip_newlines)
-       {
-         pfile->state.skip_newlines = 0;
-         list->line = buffer->lineno;
-         if (cur_token->type == CPP_HASH)
-           {
-             pfile->state.in_directive = 1;
-             pfile->state.save_comments = 0;
-             pfile->state.indented = cur_token->flags & PREV_WHITE;
-           }
-         /* 6.10.3.10: Within the sequence of preprocessing tokens
-            making up the invocation of a function-like macro, new
-            line is considered a normal white-space character.  */
-         else if (first_token != 0)
-           cur_token->flags |= PREV_WHITE;
-       }
-      else if (IN_DIRECTIVE (pfile) && list->tokens_used == first_token + 1)
-       {
-         if (cur_token->type == CPP_NUMBER)
-           list->directive = _cpp_check_linemarker (pfile, cur_token);
-         else
-           list->directive = _cpp_check_directive (pfile, cur_token);
-       }
+  unsigned int len;
 
-      /* _cpp_get_line assumes list->tokens_used refers to the current
-        token being lexed.  So do this after _cpp_check_directive to
-        get the warnings therein correct.  */
-      list->tokens_used++;
-    }
-  while (cur_token->type != CPP_EOF);
-
-  /* All tokens are allocated, so the memory location is fixed.  */
-  first = &list->tokens[first_token];
-  first->flags |= BOL;
-  pfile->first_directive_token = first;
-
-  /* Don't complain about the null directive, nor directives 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 (IN_DIRECTIVE (pfile) && !KNOWN_DIRECTIVE (list) && !pfile->skipping
-      && !CPP_OPTION (pfile, lang_asm))
+  switch (TOKEN_SPELL (token))
     {
-      if (cur_token > first + 1)
-       {
-         if (first[1].type == CPP_NAME)
-           cpp_error_with_line (pfile, first->line, first->col,
-                                "invalid preprocessing directive #%s",
-                                first[1].val.node->name);
-         else
-           cpp_error_with_line (pfile, first->line, first->col,
-                                "invalid preprocessing directive");
-       }
-
-      /* Discard this line to prevent further errors from cc1.  */
-      _cpp_clear_toklist (list);
-      goto retry;
+    default:           len = 0;                        break;
+    case SPELL_STRING: len = token->val.str.len;       break;
+    case SPELL_IDENT:  len = token->val.node->length;  break;
     }
-
-  /* Drop the EOF unless really at EOF or in a directive.  */
-  if (cur_token != first && !KNOWN_DIRECTIVE (list)
-      && pfile->done_initializing)
-    list->tokens_used--;
-
-  pfile->state.in_lex_line = 0;
+  /* 1 for whitespace, 4 for comment delimeters.  */
+  return len + 5;
 }
 
 /* Write the spelling of a token TOKEN to BUFFER.  The buffer must
    already contain the enough space to hold the token's spelling.
    Returns a pointer to the character after the last character
    written.  */
-
-static unsigned char *
-spell_token (pfile, token, buffer)
+unsigned char *
+cpp_spell_token (pfile, token, buffer)
      cpp_reader *pfile;                /* Would be nice to be rid of this...  */
      const cpp_token *token;
      unsigned char *buffer;
@@ -1546,7 +1272,7 @@ spell_token (pfile, token, buffer)
        unsigned char c;
 
        if (token->flags & DIGRAPH)
-         spelling = _cpp_digraph_spellings[token->type - CPP_FIRST_DIGRAPH];
+         spelling = digraph_spellings[token->type - CPP_FIRST_DIGRAPH];
        else if (token->flags & NAMED_OP)
          goto spell_ident;
        else
@@ -1596,581 +1322,145 @@ spell_token (pfile, token, buffer)
   return buffer;
 }
 
-/* Macro expansion algorithm.
-
-Macro expansion is implemented by a single-pass algorithm; there are
-no rescan passes involved.  cpp_get_token expands just enough to be
-able to return a token to the caller, a consequence is that when it
-returns the preprocessor can be in a state of mid-expansion.  The
-algorithm does not work by fully expanding a macro invocation into
-some kind of token list, and then returning them one by one.
-
-Our expansion state is recorded in a context stack.  We start out with
-a single context on the stack, let's call it base context.  This
-consists of the token list returned by lex_line that forms the next
-logical line in the source file.
-
-The current level in the context stack is stored in the cur_context
-member of the cpp_reader structure.  The context it references keeps,
-amongst other things, a count of how many tokens form that context and
-our position within those tokens.
-
-Fundamentally, calling cpp_get_token will return the next token from
-the current context.  If we're at the end of the current context, that
-context is popped from the stack first, unless it is the base context,
-in which case the next logical line is lexed from the source file.
-
-However, before returning the token, if it is a CPP_NAME token
-_cpp_get_token checks to see if it is a macro and if it is enabled.
-Each time it encounters a macro name, it calls push_macro_context.
-This function checks that the macro should be expanded (with
-is_macro_enabled), and if so pushes a new macro context on the stack
-which becomes the current context.  It then loops back to read the
-first token of the macro context.
-
-A macro context basically consists of the token list representing the
-macro's replacement list, which was saved in the hash table by
-save_macro_expansion when its #define statement was parsed.  If the
-macro is function-like, it also contains the tokens that form the
-arguments to the macro.  I say more about macro arguments below, but
-for now just saying that each argument is a set of pointers to tokens
-is enough.
-
-When taking tokens from a macro context, we may get a CPP_MACRO_ARG
-token.  This represents an argument passed to the macro, with the
-argument number stored in the token's AUX field.  The argument should
-be substituted, this is achieved by pushing an "argument context".  An
-argument context is just refers to the tokens forming the argument,
-which are obtained directly from the macro context.  The STRINGIFY
-flag on a CPP_MACRO_ARG token indicates that the argument should be
-stringified.
-
-Here's a few simple rules the context stack obeys:-
-
-  1) The lex_line token list is always context zero.
-
-  2) Context 1, if it exists, must be a macro context.
-
-  3) An argument context can only appear above a macro context.
-
-  4) A macro context can appear above the base context, another macro
-  context, or an argument context.
-
-  5) These imply that the minimal level of an argument context is 2.
-
-The only tricky thing left is ensuring that macros are enabled and
-disabled correctly.  The algorithm controls macro expansion by the
-level of the context a token is taken from in the context stack.  If a
-token is taken from a level equal to no_expand_level (a member of
-struct cpp_reader), no expansion is performed.
-
-When popping a context off the stack, if no_expand_level equals the
-level of the popped context, it is reduced by one to match the new
-context level, so that expansion is still disabled.  It does not
-increase if a context is pushed, though.  It starts out life as
-UINT_MAX, which has the effect that initially macro expansion is
-enabled.  I explain how this mechanism works below.
-
-The standard requires:-
-
-  1) Arguments to be fully expanded before substitution.
-
-  2) Stringified arguments to not be expanded, nor the tokens
-  immediately surrounding a ## operator.
-
-  3) Continual rescanning until there are no more macros left to
-  replace.
-
-  4) Once a macro has been expanded in stage 1) or 3), it cannot be
-  expanded again during later rescans.  This prevents infinite
-  recursion.
-
-The first thing to observe is that stage 3) is mostly redundant.
-Since a macro is disabled once it has been expanded, how can a rescan
-find an unexpanded macro name?  There are only two cases where this is
-possible:-
-
-  a) If the macro name results from a token paste operation.
-
-  b) If the macro in question is a function-like macro that hasn't
-  already been expanded because previously there was not the required
-  '(' token immediately following it.  This is only possible when an
-  argument is substituted, and after substitution the last token of
-  the argument can bind with a parenthesis appearing in the tokens
-  following the substitution.  Note that if the '(' appears within the
-  argument, the ')' must too, as expanding macro arguments cannot
-  "suck in" tokens outside the argument.
-
-So we tackle this as follows.  When parsing the macro invocation for
-arguments, we record the tokens forming each argument as a list of
-pointers to those tokens.  We do not expand any tokens that are "raw",
-i.e. directly from the macro invocation, but other tokens that come
-from (nested) argument substitution are fully expanded.
-
-This is achieved by setting the no_expand_level to that of the macro
-invocation.  A CPP_MACRO_ARG token never appears in the list of tokens
-forming an argument, because parse_args (indirectly) calls
-get_raw_token which automatically pushes argument contexts and traces
-into them.  Since these contexts are at a higher level than the
-no_expand_level, they get fully macro expanded.
-
-"Raw" and non-raw tokens are separated in arguments by null pointers,
-with the policy that the initial state of an argument is raw.  If the
-first token is not raw, it should be preceded by a null pointer.  When
-tracing through the tokens of an argument context, each time
-get_raw_token encounters a null pointer, it toggles the flag
-CONTEXT_RAW.
-
-This flag, when set, indicates to is_macro_disabled that we are
-reading raw tokens which should be macro-expanded.  Similarly, if
-clear, is_macro_disabled suppresses re-expansion.
-
-It's probably time for an example.
-
-#define hash #
-#define str(x) #x
-#define xstr(y) str(y hash)
-str(hash)                      // "hash"
-xstr(hash)                     // "# hash"
-
-In the invocation of str, parse_args turns off macro expansion and so
-parses the argument as <hash>.  This is the only token (pointer)
-passed as the argument to str.  Since <hash> is raw there is no need
-for an initial null pointer.  stringify_arg is called from
-get_raw_token when tracing through the expansion of str, since the
-argument has the STRINGIFY flag set.  stringify_arg turns off
-macro_expansion by setting the no_expand_level to that of the argument
-context.  Thus it gets the token <hash> and stringifies it to "hash"
-correctly.
-
-Similary xstr is passed <hash>.  However, when parse_args is parsing
-the invocation of str() in xstr's expansion, get_raw_token encounters
-a CPP_MACRO_ARG token for y.  Transparently to parse_args, it pushes
-an argument context, and enters the tokens of the argument,
-i.e. <hash>.  This is at a higher context level than parse_args
-disabled, and so is_macro_disabled permits expansion of it and a macro
-context is pushed on top of the argument context.  This contains the
-<#> token, and the end result is that <hash> is macro expanded.
-However, after popping off the argument context, the <hash> of xstr's
-expansion does not get macro expanded because we're back at the
-no_expand_level.  The end result is that the argument passed to str is
-<NULL> <#> <NULL> <hash>.  Note the nulls - policy is we start off
-raw, <#> is not raw, but then <hash> is.
-
-*/
-
-
-/* Free the storage allocated for macro arguments.  */
-static void
-free_macro_args (args)
-     macro_args *args;
-{
-  if (args->tokens)
-    free ((PTR) args->tokens);
-  free (args->ends);
-  free (args);
-}
-
-/* Determines if a macro has been already used (and is therefore
-   disabled).  */
-static int
-is_macro_disabled (pfile, expansion, token)
+/* Returns a token as a null-terminated string.  The string is
+   temporary, and automatically freed later.  Useful for diagnostics.  */
+unsigned char *
+cpp_token_as_text (pfile, token)
      cpp_reader *pfile;
-     const cpp_toklist *expansion;
      const cpp_token *token;
 {
-  cpp_context *context = CURRENT_CONTEXT (pfile);
-
-  /* Arguments on either side of ## are inserted in place without
-     macro expansion (6.10.3.3.2).  Conceptually, any macro expansion
-     occurs during a later rescan pass.  The effect is that we expand
-     iff we would as part of the macro's expansion list, so we should
-     drop to the macro's context.  */
-  if (IS_ARG_CONTEXT (context))
-    {
-      if (token->flags & PASTED)
-       context--;
-      else if (!(context->flags & CONTEXT_RAW))
-       return 1;
-      else if (context->flags & (CONTEXT_PASTEL | CONTEXT_PASTER))
-       context--;
-    }
+  unsigned int len = cpp_token_len (token);
+  unsigned char *start = _cpp_pool_alloc (&pfile->temp_string_pool, len), *end;
 
-  /* Have we already used this macro?  */
-  while (context->level > 0)
-    {
-      if (!IS_ARG_CONTEXT (context) && context->u.list == expansion)
-       return 1;
-      /* Raw argument tokens are judged based on the token list they
-         came from.  */
-      if (context->flags & CONTEXT_RAW)
-       context = pfile->contexts + context->level;
-      else
-       context--;
-    }
+  end = cpp_spell_token (pfile, token, start);
+  end[0] = '\0';
 
-  /* Function-like macros may be disabled if the '(' is not in the
-     current context.  We check this without disrupting the context
-     stack.  */
-  if (expansion->paramc >= 0)
-    {
-      const cpp_token *next;
-      unsigned int prev_nme;
+  return start;
+}
 
-      context = CURRENT_CONTEXT (pfile);
-      /* Drop down any contexts we're at the end of: the '(' may
-         appear in lower macro expansions, or in the rest of the file.  */
-      while (context->posn == context->count && context > pfile->contexts)
-       {
-         context--;
-         /* If we matched, we are disabled, as we appear in the
-            expansion of each macro we meet.  */
-         if (!IS_ARG_CONTEXT (context) && context->u.list == expansion)
-           return 1;
-       }
+/* Used by C front ends.  Should really move to using cpp_token_as_text.  */
+const char *
+cpp_type2name (type)
+     enum cpp_ttype type;
+{
+  return (const char *) token_spellings[type].name;
+}
 
-      prev_nme = pfile->no_expand_level;
-      pfile->no_expand_level = context - pfile->contexts;
-      next = _cpp_get_token (pfile);
-      restore_macro_expansion (pfile, prev_nme);
+/* Writes the spelling of token to FP.  Separate from cpp_spell_token
+   for efficiency - to avoid double-buffering.  Also, outputs a space
+   if PREV_WHITE is flagged.  */
+void
+cpp_output_token (token, fp)
+     const cpp_token *token;
+     FILE *fp;
+{
+  if (token->flags & PREV_WHITE)
+    putc (' ', fp);
 
-      if (next->type != CPP_OPEN_PAREN)
-       {
-         _cpp_push_token (pfile, next);
-         if (CPP_WTRADITIONAL (pfile))
-           cpp_warning (pfile,
-        "function macro %s must be used with arguments in traditional C",
-                        token->val.node->name);
-         return 1;
-       }
-    }
-
-  return 0;
-}
-
-/* Add a token to the set of tokens forming the arguments to the macro
-   being parsed in parse_args.  */
-static void
-save_token (args, token)
-     macro_args *args;
-     const cpp_token *token;
-{
-  if (args->used == args->capacity)
-    {
-      args->capacity += args->capacity + 100;
-      args->tokens = (const cpp_token **)
-       xrealloc ((PTR) args->tokens,
-                 args->capacity * sizeof (const cpp_token *));
-    }
-  args->tokens[args->used++] = token;
-}
-
-/* Take and save raw tokens until we finish one argument.  Empty
-   arguments are saved as a single CPP_PLACEMARKER token.  */
-static const cpp_token *
-parse_arg (pfile, var_args, paren_context, args, pcount)
-     cpp_reader *pfile;
-     int var_args;
-     unsigned int paren_context;
-     macro_args *args;
-     unsigned int *pcount;
-{
-  const cpp_token *token;
-  unsigned int paren = 0, count = 0;
-  int raw, was_raw = 1;
-  
-  for (count = 0;; count++)
+  switch (TOKEN_SPELL (token))
     {
-      token = _cpp_get_token (pfile);
-
-      switch (token->type)
-       {
-       default:
-         break;
+    case SPELL_OPERATOR:
+      {
+       const unsigned char *spelling;
 
-       case CPP_OPEN_PAREN:
-         paren++;
-         break;
+       if (token->flags & DIGRAPH)
+         spelling = digraph_spellings[token->type - CPP_FIRST_DIGRAPH];
+       else if (token->flags & NAMED_OP)
+         goto spell_ident;
+       else
+         spelling = TOKEN_NAME (token);
 
-       case CPP_CLOSE_PAREN:
-         if (paren-- != 0)
-           break;
-         goto out;
+       ufputs (spelling, fp);
+      }
+      break;
 
-       case CPP_COMMA:
-         /* Commas are not terminators within parantheses or var_args.  */
-         if (paren || var_args)
-           break;
-         goto out;
+    spell_ident:
+    case SPELL_IDENT:
+      ufputs (token->val.node->name, fp);
+    break;
 
-       case CPP_EOF:           /* Error reported by caller.  */
-         goto out;
-       }
+    case SPELL_STRING:
+      {
+       int left, right, tag;
+       switch (token->type)
+         {
+         case CPP_STRING:      left = '"';  right = '"';  tag = '\0'; break;
+         case CPP_WSTRING:     left = '"';  right = '"';  tag = 'L';  break;
+         case CPP_OSTRING:     left = '"';  right = '"';  tag = '@';  break;
+         case CPP_CHAR:        left = '\''; right = '\''; tag = '\0'; break;
+         case CPP_WCHAR:       left = '\''; right = '\''; tag = 'L';  break;
+         case CPP_HEADER_NAME: left = '<';  right = '>';  tag = '\0'; break;
+         default:              left = '\0'; right = '\0'; tag = '\0'; break;
+         }
+       if (tag) putc (tag, fp);
+       if (left) putc (left, fp);
+       fwrite (token->val.str.text, 1, token->val.str.len, fp);
+       if (right) putc (right, fp);
+      }
+      break;
 
-      raw = pfile->cur_context <= paren_context;
-      if (raw != was_raw)
-       {
-         was_raw = raw;
-         save_token (args, 0);
-         count++;
-       }
-      save_token (args, token);
-    }
+    case SPELL_CHAR:
+      putc (token->val.aux, fp);
+      break;
 
- out:
-  if (count == 0)
-    {
-      /* Duplicate the placemarker.  Then we can set its flags and
-        position and safely be using more than one.  */
-      save_token (args, duplicate_token (pfile, &placemarker_token));
-      count++;
+    case SPELL_NONE:
+      /* An error, most probably.  */
+      break;
     }
-
-  *pcount = count;
-  return token;
 }
 
-/* This macro returns true if the argument starting at offset O of arglist
-   A is empty - that is, it's either a single PLACEMARKER token, or a null
-   pointer followed by a PLACEMARKER.  */
-
-#define empty_argument(A, O) \
- ((A)->tokens[O] ? (A)->tokens[O]->type == CPP_PLACEMARKER \
-                : (A)->tokens[(O)+1]->type == CPP_PLACEMARKER)
-   
-/* Parse the arguments making up a macro invocation.  Nested arguments
-   are automatically macro expanded, but immediate macros are not
-   expanded; this enables e.g. operator # to work correctly.  Returns
-   non-zero on error.  */
-static int
-parse_args (pfile, hp, args)
-     cpp_reader *pfile;
-     cpp_hashnode *hp;
-     macro_args *args;
+/* Compare two tokens.  */
+int
+_cpp_equiv_tokens (a, b)
+     const cpp_token *a, *b;
 {
-  const cpp_token *token;
-  const cpp_toklist *macro;
-  unsigned int total = 0;
-  unsigned int paren_context = pfile->cur_context;
-  int argc = 0;
-
-  macro = hp->value.expansion;
-  do
-    {
-      unsigned int count;
-
-      token = parse_arg (pfile, (argc + 1 == macro->paramc
-                                && (macro->flags & VAR_ARGS)),
-                        paren_context, args, &count);
-      if (argc < macro->paramc)
-       {
-         total += count;
-         args->ends[argc] = total;
-       }
-      argc++;
-    }
-  while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF);
-
-  if (token->type == CPP_EOF)
-    {
-      cpp_error(pfile, "unterminated argument list for macro \"%s\"", hp->name);
-      return 1;
-    }
-  else if (argc < macro->paramc)
-    {
-      /* A rest argument is allowed to not appear in the invocation at all.
-        e.g. #define debug(format, args...) ...
-        debug("string");
-        This is exactly the same as if the rest argument had received no
-        tokens - debug("string",);  This extension is deprecated.  */
-
-      if (argc + 1 == macro->paramc && (macro->flags & VAR_ARGS))
-       {
-         /* Duplicate the placemarker.  Then we can set its flags and
-             position and safely be using more than one.  */
-         save_token (args, duplicate_token (pfile, &placemarker_token));
-         args->ends[argc] = total + 1;
-
-         if (CPP_OPTION (pfile, c99) && CPP_PEDANTIC (pfile))
-           cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used");
-
-         return 0;
-       }
-      else
-       {
-         cpp_error (pfile, "%u arguments is not enough for macro \"%s\"",
-                    argc, hp->name);
-         return 1;
-       }
-    }
-  /* An empty argument to an empty function-like macro is fine.  */
-  else if (argc > macro->paramc
-          && !(macro->paramc == 0 && argc == 1 && empty_argument (args, 0)))
-    {
-      cpp_error (pfile, "%u arguments is too many for macro \"%s\"",
-                argc, hp->name);
-      return 1;
-    }
+  if (a->type == b->type && a->flags == b->flags)
+    switch (TOKEN_SPELL (a))
+      {
+      default:                 /* Keep compiler happy.  */
+      case SPELL_OPERATOR:
+       return 1;
+      case SPELL_CHAR:
+       return a->val.aux == b->val.aux; /* Character.  */
+      case SPELL_NONE:
+       return (a->type != CPP_MACRO_ARG || a->val.aux == b->val.aux);
+      case SPELL_IDENT:
+       return a->val.node == b->val.node;
+      case SPELL_STRING:
+       return (a->val.str.len == b->val.str.len
+               && !memcmp (a->val.str.text, b->val.str.text,
+                           a->val.str.len));
+      }
 
   return 0;
 }
 
-/* Adds backslashes before all backslashes and double quotes appearing
-   in strings.  Non-printable characters are converted to octal.  */
-static U_CHAR *
-quote_string (dest, src, len)
-     U_CHAR *dest;
-     const U_CHAR *src;
-     unsigned int len;
-{
-  while (len--)
-    {
-      U_CHAR c = *src++;
-
-      if (c == '\\' || c == '"')
-       {
-         *dest++ = '\\';
-         *dest++ = c;
-       }
-      else
-       {
-         if (ISPRINT (c))
-           *dest++ = c;
-         else
-           {
-             sprintf ((char *) dest, "\\%03o", c);
-             dest += 4;
-           }
-       }
-    }
-
-  return dest;
-}
-
-/* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a
-   CPP_STRING token containing TEXT in quoted form.  */
-static cpp_token *
-make_string_token (token, text, len)
-     cpp_token *token;
-     const U_CHAR *text;
-     unsigned int len;
-{
-  U_CHAR *buf;
-  buf = (U_CHAR *) xmalloc (len * 4);
-  token->type = CPP_STRING;
-  token->flags = 0;
-  token->val.str.text = buf;
-  token->val.str.len = quote_string (buf, text, len) - buf;
-  return token;
-}
-
-/* Allocates and converts a temporary token to a CPP_NUMBER token,
-   evaluating to NUMBER.  */
-static cpp_token *
-alloc_number_token (pfile, number)
-     cpp_reader *pfile;
-     int number;
-{
-  cpp_token *result;
-  char *buf;
-
-  result = get_temp_token (pfile);
-  buf = xmalloc (20);
-  sprintf (buf, "%d", number);
-
-  result->type = CPP_NUMBER;
-  result->flags = 0;
-  result->val.str.text = (U_CHAR *) buf;
-  result->val.str.len = strlen (buf);
-  return result;
-}
-
-/* Returns a temporary token from the temporary token store of PFILE.  */
-static cpp_token *
-get_temp_token (pfile)
-     cpp_reader *pfile;
-{
-  if (pfile->temp_used == pfile->temp_alloced)
-    {
-      if (pfile->temp_used == pfile->temp_cap)
-       {
-         pfile->temp_cap += pfile->temp_cap + 20;
-         pfile->temp_tokens = (cpp_token **) xrealloc
-           (pfile->temp_tokens, pfile->temp_cap * sizeof (cpp_token *));
-       }
-      pfile->temp_tokens[pfile->temp_alloced++] = (cpp_token *) xmalloc
-       (sizeof (cpp_token));
-    }
-
-  return pfile->temp_tokens[pfile->temp_used++];
-}
-
-/* Release (not free) for re-use the temporary tokens of PFILE.  */
-static void
-release_temp_tokens (pfile)
-     cpp_reader *pfile;
+#if 0
+/* Compare two token lists.  */
+int
+_cpp_equiv_toklists (a, b)
+     const struct toklist *a, *b;
 {
-  while (pfile->temp_used)
-    {
-      cpp_token *token = pfile->temp_tokens[--pfile->temp_used];
+  unsigned int i, count;
 
-      if (TOKEN_SPELL (token) == SPELL_STRING)
-       {
-         free ((char *) token->val.str.text);
-         token->val.str.text = 0;
-       }
-    }
-}
-
-/* Free all of PFILE's dynamically-allocated temporary tokens.  */
-void
-_cpp_free_temp_tokens (pfile)
-     cpp_reader *pfile;
-{
-  if (pfile->temp_tokens)
-    {
-      /* It is possible, though unlikely (looking for '(' of a funlike
-        macro into EOF), that we haven't released the tokens yet.  */
-      release_temp_tokens (pfile);
-      while (pfile->temp_alloced)
-       free (pfile->temp_tokens[--pfile->temp_alloced]);
-      free (pfile->temp_tokens);
-    }
-
-  if (pfile->date)
-    {
-      free ((char *) pfile->date->val.str.text);
-      free (pfile->date);
-      free ((char *) pfile->time->val.str.text);
-      free (pfile->time);
-    }
-}
+  count = a->limit - a->first;
+  if (count != (b->limit - b->first))
+    return 0;
 
-/* Copy TOKEN into a temporary token from PFILE's store.  */
-static cpp_token *
-duplicate_token (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
-{
-  cpp_token *result = get_temp_token (pfile);
+  for (i = 0; i < count; i++)
+    if (! _cpp_equiv_tokens (&a->first[i], &b->first[i]))
+      return 0;
 
-  *result = *token;
-  if (TOKEN_SPELL (token) == SPELL_STRING)
-    {
-      U_CHAR *buff = (U_CHAR *) xmalloc (token->val.str.len);
-      memcpy (buff, token->val.str.text, token->val.str.len);
-      result->val.str.text = buff;
-    }
-  return result;
+  return 1;
 }
+#endif
 
 /* Determine whether two tokens can be pasted together, and if so,
    what the resulting token is.  Returns CPP_EOF if the tokens cannot
    be pasted, or the appropriate type for the merged token if they
    can.  */
 enum cpp_ttype
-_cpp_can_paste (pfile, token1, token2, digraph)
+cpp_can_paste (pfile, token1, token2, digraph)
      cpp_reader * pfile;
      const cpp_token *token1, *token2;
      int* digraph;
@@ -2247,11 +1537,11 @@ _cpp_can_paste (pfile, token1, token2, digraph)
     case CPP_NAME:
       if (b == CPP_NAME)       return CPP_NAME;
       if (b == CPP_NUMBER
-         && is_numstart(token2->val.str.text[0]))       return CPP_NAME;
+         && name_p (pfile, &token2->val.str)) return CPP_NAME;
       if (b == CPP_CHAR
-         && token1->val.node == pfile->spec_nodes->n_L) return CPP_WCHAR;
+         && token1->val.node == pfile->spec_nodes.n_L) return CPP_WCHAR;
       if (b == CPP_STRING
-         && token1->val.node == pfile->spec_nodes->n_L) return CPP_WSTRING;
+         && token1->val.node == pfile->spec_nodes.n_L) return CPP_WSTRING;
       break;
 
     case CPP_NUMBER:
@@ -2278,882 +1568,230 @@ _cpp_can_paste (pfile, token1, token2, digraph)
   return CPP_EOF;
 }
 
-/* Check if TOKEN is to be ##-pasted with the token after it.  */
-static const cpp_token *
-maybe_paste_with_next (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
-{
-  cpp_token *pasted;
-  const cpp_token *second;
-  cpp_context *context = CURRENT_CONTEXT (pfile);
-
-  /* Is this token on the LHS of ## ? */
-
-  while ((token->flags & PASTE_LEFT)
-        || ((context->flags & CONTEXT_PASTEL)
-            && context->posn == context->count))
-    {
-      /* Suppress macro expansion for next token, but don't conflict
-        with the other method of suppression.  If it is an argument,
-        macro expansion within the argument will still occur.  */
-      pfile->paste_level = pfile->cur_context;
-      second = _cpp_get_token (pfile);
-      pfile->paste_level = 0;
-      context = CURRENT_CONTEXT (pfile);
-
-      /* Ignore placemarker argument tokens (cannot be from an empty
-        macro since macros are not expanded).  */
-      if (token->type == CPP_PLACEMARKER)
-       pasted = duplicate_token (pfile, second);
-      else if (second->type == CPP_PLACEMARKER)
-       {
-         /* GCC has special extended semantics for , ## b where b is
-            a varargs parameter: the comma disappears if b was given
-            no actual arguments (not merely if b is an empty
-            argument).  */
-         if (token->type == CPP_COMMA && (context->flags & CONTEXT_VARARGS))
-           pasted = duplicate_token (pfile, second);
-         else
-           pasted = duplicate_token (pfile, token);
-       }
-      else
-       {
-         int digraph = 0;
-         enum cpp_ttype type = _cpp_can_paste (pfile, token, second, &digraph);
-
-         if (type == CPP_EOF)
-           {
-             if (CPP_OPTION (pfile, warn_paste))
-               {
-                 /* Do not complain about , ## <whatever> if
-                    <whatever> came from a variable argument, because
-                    the author probably intended the ## to trigger
-                    the special extended semantics (see above).  */
-                 if (token->type == CPP_COMMA
-                     && (context->flags & CONTEXT_VARARGS))
-                   /* no warning */;
-                 else
-                   cpp_warning (pfile,
-                       "pasting would not give a valid preprocessing token");
-               }
-             _cpp_push_token (pfile, second);
-             /* A short term hack to safely clear the PASTE_LEFT flag.  */
-             pasted = duplicate_token (pfile, token);
-             pasted->flags &= ~PASTE_LEFT;
-             return pasted;
-           }
-
-         if (type == CPP_NAME || type == CPP_NUMBER)
-           {
-             /* Join spellings.  */
-             U_CHAR *buf, *end;
-
-             pasted = get_temp_token (pfile);
-             buf = (U_CHAR *) alloca (TOKEN_LEN (token) + TOKEN_LEN (second));
-             end = spell_token (pfile, token, buf);
-             end = spell_token (pfile, second, end);
-             *end = '\0';
-
-             if (type == CPP_NAME)
-               pasted->val.node = cpp_lookup (pfile, buf, end - buf);
-             else
-               {
-                 pasted->val.str.text = uxstrdup (buf);
-                 pasted->val.str.len = end - buf;
-               }
-           }
-         else if (type == CPP_WCHAR || type == CPP_WSTRING
-                  || type == CPP_OSTRING)
-           pasted = duplicate_token (pfile, second);
-         else
-           {
-             pasted = get_temp_token (pfile);
-             pasted->val.integer = 0;
-           }
-
-         pasted->type = type;
-         pasted->flags = digraph ? DIGRAPH : 0;
-
-         if (type == CPP_NAME && pasted->val.node->type == T_OPERATOR)
-           {
-             pasted->type = pasted->val.node->value.code;
-             pasted->flags |= NAMED_OP;
-           }
-       }
+/* Returns nonzero if a space should be inserted to avoid an
+   accidental token paste for output.  For simplicity, it is
+   conservative, and occasionally advises a space where one is not
+   needed, e.g. "." and ".2".  */
 
-      /* The pasted token gets the whitespace flags and position of the
-        first token, the PASTE_LEFT flag of the second token, plus the
-        PASTED flag to indicate it is the result of a paste.  However, we
-        want to preserve the DIGRAPH flag.  */
-      pasted->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT);
-      pasted->flags |= ((token->flags & (PREV_WHITE | BOL))
-                       | (second->flags & PASTE_LEFT) | PASTED);
-      pasted->col = token->col;
-      pasted->line = token->line;
-
-      /* See if there is another token to be pasted onto the one we just
-        constructed.  */
-      token = pasted;
-      /* and loop */
-    }
-  return token;
-}
-
-/* Convert a token sequence to a single string token according to the
-   rules of the ISO C #-operator.  */
-#define INIT_SIZE 200
-static cpp_token *
-stringify_arg (pfile, token)
+int
+cpp_avoid_paste (pfile, token1, token2)
      cpp_reader *pfile;
-     const cpp_token *token;
+     const cpp_token *token1, *token2;
 {
-  cpp_token *result;
-  unsigned char *main_buf;
-  unsigned int prev_value, backslash_count = 0;
-  unsigned int buf_used = 0, whitespace = 0, buf_cap = INIT_SIZE;
-
-  push_arg_context (pfile, token);
-  prev_value  = prevent_macro_expansion (pfile);
-  main_buf = (unsigned char *) xmalloc (buf_cap);
-
-  result = get_temp_token (pfile);
-  ASSIGN_FLAGS_AND_POS (result, token);
-
-  for (; (token = _cpp_get_token (pfile))->type != CPP_EOF; )
-    {
-      int escape;
-      unsigned char *buf;
-      unsigned int len = TOKEN_LEN (token);
-
-      if (token->type == CPP_PLACEMARKER)
-       continue;
-
-      escape = (token->type == CPP_STRING || token->type == CPP_WSTRING
-               || token->type == CPP_CHAR || token->type == CPP_WCHAR);
-      if (escape)
-       len *= 4 + 1;
-
-      if (buf_used + len > buf_cap)
-       {
-         buf_cap = buf_used + len + INIT_SIZE;
-         main_buf = xrealloc (main_buf, buf_cap);
-       }
-
-      if (whitespace && (token->flags & PREV_WHITE))
-       main_buf[buf_used++] = ' ';
-
-      if (escape)
-       buf = (unsigned char *) xmalloc (len);
-      else
-       buf = main_buf + buf_used;
-      
-      len = spell_token (pfile, token, buf) - buf;
-      if (escape)
-       {
-         buf_used = quote_string (&main_buf[buf_used], buf, len) - main_buf;
-         free (buf);
-       }
-      else
-       buf_used += len;
-
-      whitespace = 1;
-      if (token->type == CPP_BACKSLASH)
-       backslash_count++;
-      else
-       backslash_count = 0;
-    }
+  enum cpp_ttype a = token1->type, b = token2->type;
+  cppchar_t c;
 
-  /* Ignore the final \ of invalid string literals.  */
-  if (backslash_count & 1)
-    {
-      cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
-      buf_used--;
-    }
+  if (token1->flags & NAMED_OP)
+    a = CPP_NAME;
+  if (token2->flags & NAMED_OP)
+    b = CPP_NAME;
 
-  result->type = CPP_STRING;
-  result->val.str.text = main_buf;
-  result->val.str.len = buf_used;
-  restore_macro_expansion (pfile, prev_value);
-  return result;
-}
+  c = EOF;
+  if (token2->flags & DIGRAPH)
+    c = digraph_spellings[b - CPP_FIRST_DIGRAPH][0];
+  else if (token_spellings[b].category == SPELL_OPERATOR)
+    c = token_spellings[b].name[0];
 
-/* Allocate more room on the context stack of PFILE.  */
-static void
-expand_context_stack (pfile)
-     cpp_reader *pfile;
-{
-  pfile->context_cap += pfile->context_cap + 20;
-  pfile->contexts = (cpp_context *)
-    xrealloc (pfile->contexts, pfile->context_cap * sizeof (cpp_context));
-}
+  /* Quickly get everything that can paste with an '='.  */
+  if (a <= CPP_LAST_EQ && c == '=')
+    return 1;
 
-/* Push the context of macro NODE onto the context stack.  TOKEN is
-   the CPP_NAME token invoking the macro.  */
-static int
-push_macro_context (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
-{
-  unsigned char orig_flags;
-  macro_args *args;
-  cpp_context *context;
-  cpp_hashnode *node = token->val.node;
-
-  /* Token's flags may change when parsing args containing a nested
-     invocation of this macro.  */
-  orig_flags = token->flags & (PREV_WHITE | BOL);
-  args = 0;
-  if (node->value.expansion->paramc >= 0)
+  switch (a)
     {
-      unsigned int error, prev_nme;
-
-      /* Allocate room for the argument contexts, and parse them.  */
-      args  = (macro_args *) xmalloc (sizeof (macro_args));
-      args->ends = (unsigned int *)
-       xmalloc (node->value.expansion->paramc * sizeof (unsigned int));
-      args->tokens = 0;
-      args->capacity = 0;
-      args->used = 0;
-
-      prev_nme = prevent_macro_expansion (pfile);
-      pfile->args = args;
-      error = parse_args (pfile, node, args);
-      pfile->args = 0;
-      restore_macro_expansion (pfile, prev_nme);
-      if (error)
-       {
-         free_macro_args (args);
-         return 1;
-       }
-      /* Set the level after the call to parse_args.  */
-      args->level = pfile->cur_context;
+    case CPP_GREATER:  return c == '>' || c == '?';
+    case CPP_LESS:     return c == '<' || c == '?' || c == '%' || c == ':';
+    case CPP_PLUS:     return c == '+';
+    case CPP_MINUS:    return c == '-' || c == '>';
+    case CPP_DIV:      return c == '/' || c == '*'; /* Comments.  */
+    case CPP_MOD:      return c == ':' || c == '>';
+    case CPP_AND:      return c == '&';
+    case CPP_OR:       return c == '|';
+    case CPP_COLON:    return c == ':' || c == '>';
+    case CPP_DEREF:    return c == '*';
+    case CPP_DOT:      return c == '.' || c == '%';
+    case CPP_HASH:     return c == '#' || c == '%'; /* Digraph form.  */
+    case CPP_NAME:     return ((b == CPP_NUMBER
+                                && name_p (pfile, &token2->val.str))
+                               || b == CPP_NAME
+                               || b == CPP_CHAR || b == CPP_STRING); /* L */
+    case CPP_NUMBER:   return (b == CPP_NUMBER || b == CPP_NAME
+                               || c == '.' || c == '+' || c == '-');
+    case CPP_OTHER:    return (CPP_OPTION (pfile, objc)
+                               && token1->val.aux == '@'
+                               && (b == CPP_NAME || b == CPP_STRING));
+    default:           break;
     }
 
-  /* Now push its context.  */
-  pfile->cur_context++;
-  if (pfile->cur_context == pfile->context_cap)
-    expand_context_stack (pfile);
-
-  context = CURRENT_CONTEXT (pfile);
-  context->u.list = node->value.expansion;
-  context->args = args;
-  context->posn = 0;
-  context->count = context->u.list->tokens_used;
-  context->level = pfile->cur_context;
-  context->flags = 0;
-  context->pushed_token = 0;
-
-  /* Set the flags of the first token.  We know there must
-     be one, empty macros are a single placemarker token.  */
-  MODIFY_FLAGS_AND_POS (&context->u.list->tokens[0], token, orig_flags);
-
   return 0;
 }
 
-/* Push an argument to the current macro onto the context stack.
-   TOKEN is the MACRO_ARG token representing the argument expansion.  */
-static void
-push_arg_context (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
-{
-  cpp_context *context;
-  macro_args *args;
-
-  pfile->cur_context++;
-  if (pfile->cur_context == pfile->context_cap)
-      expand_context_stack (pfile);
-
-  context = CURRENT_CONTEXT (pfile);
-  args = context[-1].args;
-
-  context->count = token->val.aux ? args->ends[token->val.aux - 1]: 0;
-  context->u.arg = args->tokens + context->count;
-  context->count = args->ends[token->val.aux] - context->count;
-  context->args = 0;
-  context->posn = 0;
-  context->level = args->level;
-  context->flags = CONTEXT_ARG | CONTEXT_RAW;
-  if ((context[-1].u.list->flags & VAR_ARGS)
-      && token->val.aux + 1 == (unsigned) context[-1].u.list->paramc)
-    context->flags |= CONTEXT_VARARGS;
-  context->pushed_token = 0;
-
-  /* Set the flags of the first token.  There is one.  */
-  {
-    const cpp_token *first = context->u.arg[0];
-    if (!first)
-      first = context->u.arg[1];
-
-    MODIFY_FLAGS_AND_POS ((cpp_token *) first, token,
-                         token->flags & (PREV_WHITE | BOL));
-  }
-
-  if (token->flags & PASTE_LEFT)
-    context->flags |= CONTEXT_PASTEL;
-  if (pfile->paste_level)
-    context->flags |= CONTEXT_PASTER;
-}
-
-/* "Unget" a token.  It is effectively inserted in the token queue and
-   will be returned by the next call to get_raw_token.  */
+/* Output all the remaining tokens on the current line, and a newline
+   character, to FP.  Leading whitespace is removed.  */
 void
-_cpp_push_token (pfile, token)
+cpp_output_line (pfile, fp)
      cpp_reader *pfile;
-     const cpp_token *token;
+     FILE *fp;
 {
-  cpp_context *context = CURRENT_CONTEXT (pfile);
+  cpp_token token;
 
-  if (context->posn > 0)
+  _cpp_get_token (pfile, &token);
+  token.flags &= ~PREV_WHITE;
+  while (token.type != CPP_EOF)
     {
-      const cpp_token *prev;
-      if (IS_ARG_CONTEXT (context))
-       prev = context->u.arg[context->posn - 1];
-      else
-       prev = &context->u.list->tokens[context->posn - 1];
-
-      if (prev == token)
-       {
-         context->posn--;
-         return;
-       }
+      cpp_output_token (&token, fp);
+      _cpp_get_token (pfile, &token);
     }
 
-  if (context->pushed_token)
-    cpp_ice (pfile, "two tokens pushed in a row");
-  if (token->type != CPP_EOF)
-    context->pushed_token = token;
-  /* Don't push back a directive's CPP_EOF, step back instead.  */
-  else if (pfile->cur_context == 0)
-    pfile->contexts[0].posn--;
+  putc ('\n', fp);
 }
 
-/* Handle a preprocessing directive.  TOKEN is the CPP_HASH token
-   introducing the directive.  */
-void
-_cpp_process_directive (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
-{
-  const struct directive *d = pfile->token_list.directive;
-  int prev_nme = 0;
-
-  /* Skip over the directive name.  */
-  if (token[1].type == CPP_NAME)
-    _cpp_get_raw_token (pfile);
-  else if (token[1].type != CPP_NUMBER)
-    cpp_ice (pfile, "directive begins with %s?!", TOKEN_NAME (token));
-
-  if (! (d->flags & EXPAND))
-    prev_nme = prevent_macro_expansion (pfile);
-  (void) (*d->handler) (pfile);
-  if (! (d->flags & EXPAND))
-    restore_macro_expansion (pfile, prev_nme);
-  _cpp_skip_rest_of_line (pfile);
-}
-
-/* The external interface to return the next token.  All macro
-   expansion and directive processing is handled internally, the
-   caller only ever sees the output after preprocessing.  */
-const cpp_token *
-cpp_get_token (pfile)
-     cpp_reader *pfile;
-{
-  const cpp_token *token;
-  /* Loop till we hit a non-directive, non-placemarker token.  */
-  for (;;)
-    {
-      token = _cpp_get_token (pfile);
-
-      if (token->type == CPP_PLACEMARKER)
-       continue;
+/* Memory pools.  */
 
-      if (token->type == CPP_HASH && token->flags & BOL
-         && pfile->token_list.directive)
-       {
-         _cpp_process_directive (pfile, token);
-         continue;
-       }
-
-      return token;
-    }
-}
-
-/* The internal interface to return the next token.  There are two
-   differences between the internal and external interfaces: the
-   internal interface may return a PLACEMARKER token, and it does not
-   process directives.  */
-const cpp_token *
-_cpp_get_token (pfile)
-     cpp_reader *pfile;
+struct dummy
 {
-  const cpp_token *token, *old_token;
-  cpp_hashnode *node;
-
-  /* Loop until we hit a non-macro token.  */
-  for (;;)
-    {
-      token = get_raw_token (pfile);
-
-      /* Short circuit EOF. */
-      if (token->type == CPP_EOF)
-       return token;
+  char c;
+  union
+  {
+    double d;
+    int *p;
+  } u;
+};
 
-      /* If we are skipping... */
-      if (pfile->skipping)
-       {
-         /* we still have to process directives,  */
-         if (pfile->token_list.directive)
-           return token;
+#define DEFAULT_ALIGNMENT (offsetof (struct dummy, u))
 
-         /* but everything else is ignored.  */
-         _cpp_skip_rest_of_line (pfile);
-         continue;
-       }
-
-      /* If there's a potential control macro and we get here, then that
-        #ifndef didn't cover the entire file and its argument shouldn't
-        be taken as a control macro.  */
-      pfile->potential_control_macro = 0;
-
-      /* If we are rescanning preprocessed input, no macro expansion or
-        token pasting may occur.  */
-      if (CPP_OPTION (pfile, preprocessed))
-       return token;
-
-      old_token = token;
-
-      /* See if there's a token to paste with this one.  */
-      if (!pfile->paste_level)
-       token = maybe_paste_with_next (pfile, token);
-
-      /* If it isn't a macro, return it now.  */
-      if (token->type != CPP_NAME || token->val.node->type == T_VOID)
-       return token;
-
-      /* Is macro expansion disabled in general, or are we in the
-        middle of a token paste, or was this token just pasted?
-        (Note we don't check token->flags & PASTED, because that
-        counts tokens that were pasted at some point in the past,
-        we're only interested in tokens that were pasted by this call
-        to maybe_paste_with_next.)  */
-      if (pfile->no_expand_level == pfile->cur_context
-         || pfile->paste_level
-         || (token != old_token
-             && pfile->no_expand_level + 1 == pfile->cur_context))
-       return token;
-
-      node = token->val.node;
-      if (node->type != T_MACRO)
-       return special_symbol (pfile, node, token);
-
-      if (is_macro_disabled (pfile, node->value.expansion, token))
-       return token;
-
-      if (push_macro_context (pfile, token))
-       return token;
-      /* else loop */
-    }
+static int
+chunk_suitable (pool, chunk, size)
+     cpp_pool *pool;
+     cpp_chunk *chunk;
+     unsigned int size;
+{
+  /* Being at least twice SIZE means we can use memcpy in
+     _cpp_next_chunk rather than memmove.  Besides, it's a good idea
+     anyway.  */
+  return (chunk && pool->locked != chunk
+         && (unsigned int) (chunk->limit - chunk->base) >= size * 2);
 }
 
-/* Returns the next raw token, i.e. without performing macro
-   expansion.  Argument contexts are automatically entered.  */
-static const cpp_token *
-get_raw_token (pfile)
-     cpp_reader *pfile;
+/* Returns the end of the new pool.  PTR points to a char in the old
+   pool, and is updated to point to the same char in the new pool.  */
+unsigned char *
+_cpp_next_chunk (pool, len, ptr)
+     cpp_pool *pool;
+     unsigned int len;
+     unsigned char **ptr;
 {
-  const cpp_token *result;
-  cpp_context *context;
+  cpp_chunk *chunk = pool->cur->next;
 
-  for (;;)
+  /* LEN is the minimum size we want in the new pool.  */
+  len += POOL_ROOM (pool);
+  if (! chunk_suitable (pool, chunk, len))
     {
-      context = CURRENT_CONTEXT (pfile);
-      if (context->pushed_token)
-       {
-         result = context->pushed_token;
-         context->pushed_token = 0;
-         return result;        /* Cannot be a CPP_MACRO_ARG */
-       }
-      else if (context->posn == context->count)
-       {
-         if (pop_context (pfile))
-           return &eof_token;
-         continue;
-       }
-      else if (IS_ARG_CONTEXT (context))
-       {
-         result = context->u.arg[context->posn++];
-         if (result == 0)
-           {
-             context->flags ^= CONTEXT_RAW;
-             result = context->u.arg[context->posn++];
-           }
-         return result;        /* Cannot be a CPP_MACRO_ARG */
-       }
-
-      result = &context->u.list->tokens[context->posn++];
-
-      if (result->type != CPP_MACRO_ARG)
-       return result;
-
-      if (result->flags & STRINGIFY_ARG)
-       return stringify_arg (pfile, result);
-
-      push_arg_context (pfile, result);
-    }
-}
-
-/* Internal interface to get the token without macro expanding.  */
-const cpp_token *
-_cpp_get_raw_token (pfile)
-     cpp_reader *pfile;
-{
-  int prev_nme = prevent_macro_expansion (pfile);
-  const cpp_token *result = _cpp_get_token (pfile);
-  restore_macro_expansion (pfile, prev_nme);
-  return result;
-}
-
-/* A thin wrapper to lex_line.  CLEAR is non-zero if the current token
-   list should be overwritten, or zero if we need to append
-   (typically, if we are within the arguments to a macro, or looking
-   for the '(' to start a function-like macro invocation).  */
-static int
-lex_next (pfile, clear)
-     cpp_reader *pfile;
-     int clear;
-{
-  cpp_toklist *list = &pfile->token_list;
-  const cpp_token *old_list = list->tokens;
-  unsigned int old_used = list->tokens_used;
+      chunk = new_chunk (POOL_SIZE (pool) * 2 + len);
 
-  if (clear)
-    {
-      /* Release all temporary tokens.  */
-      _cpp_clear_toklist (list);
-      pfile->contexts[0].posn = 0;
-      if (pfile->temp_used)
-       release_temp_tokens (pfile);
+      chunk->next = pool->cur->next;
+      pool->cur->next = chunk;
     }
-  lex_line (pfile, list);
-  pfile->contexts[0].count = list->tokens_used;
 
-  if (!clear && pfile->args)
-    {
-      /* Fix up argument token pointers.  */
-      if (old_list != list->tokens)
-       {
-         unsigned int i;
+  /* Update the pointer before changing chunk's front.  */
+  if (ptr)
+    *ptr += chunk->base - POOL_FRONT (pool);
 
-         for (i = 0; i < pfile->args->used; i++)
-           {
-             const cpp_token *token = pfile->args->tokens[i];
-             if (token >= old_list && token < old_list + old_used)
-               pfile->args->tokens[i] = (const cpp_token *)
-               ((char *) token + ((char *) list->tokens - (char *) old_list));
-           }
-       }
-
-      /* 6.10.3 paragraph 11: If there are sequences of preprocessing
-        tokens within the list of arguments that would otherwise act as
-        preprocessing directives, the behavior is undefined.
-
-        This implementation will report a hard error and treat the
-        'sequence of preprocessing tokens' as part of the macro argument,
-        not a directive.  
+  memcpy (chunk->base, POOL_FRONT (pool), POOL_ROOM (pool));
+  chunk->front = chunk->base;
 
-         Note if pfile->args == 0, we're OK since we're only inside a
-         macro argument after a '('.  */
-      if (list->directive)
-       {
-         cpp_error_with_line (pfile, list->tokens[old_used].line,
-                              list->tokens[old_used].col,
-                              "#%s may not be used inside a macro argument",
-                              list->directive->name);
-         return 1;
-       }
-    }
-
-  return 0;
+  pool->cur = chunk;
+  return POOL_LIMIT (pool);
 }
 
-/* Pops a context off the context stack.  If we're at the bottom, lexes
-   the next logical line.  Returns EOF if we're at the end of the
-   argument list to the # operator, or we should not "overflow"
-   into the rest of the file (e.g. 6.10.3.1.1).  */
-static int
-pop_context (pfile)
-     cpp_reader *pfile;
+static cpp_chunk *
+new_chunk (size)
+     unsigned int size;
 {
-  cpp_context *context;
+  unsigned char *base;
+  cpp_chunk *result;
 
-  if (pfile->cur_context == 0)
-    {
-      /* If we are currently processing a directive, do not advance.  6.10
-        paragraph 2: A new-line character ends the directive even if it
-        occurs within what would otherwise be an invocation of a
-        function-like macro.  */
-      if (pfile->token_list.directive)
-       return 1;
+  size = ALIGN (size, DEFAULT_ALIGNMENT);
+  base = (unsigned char *) xmalloc (size + sizeof (cpp_chunk));
+  /* Put the chunk descriptor at the end.  Then chunk overruns will
+     cause obvious chaos.  */
+  result = (cpp_chunk *) (base + size);
+  result->base = base;
+  result->front = base;
+  result->limit = base + size;
+  result->next = 0;
 
-      return lex_next (pfile, pfile->no_expand_level == UINT_MAX);
-    }
-
-  /* Argument contexts, when parsing args or handling # operator
-     return CPP_EOF at the end.  */
-  context = CURRENT_CONTEXT (pfile);
-  if (IS_ARG_CONTEXT (context) && pfile->cur_context == pfile->no_expand_level)
-    return 1;
-
-  /* Free resources when leaving macro contexts.  */
-  if (context->args)
-    free_macro_args (context->args);
-
-  if (pfile->cur_context == pfile->no_expand_level)
-    pfile->no_expand_level--;
-  pfile->cur_context--;
-
-  return 0;
+  return result;
 }
 
-/* Turn off macro expansion at the current context level.  */
-static unsigned int
-prevent_macro_expansion (pfile)
-     cpp_reader *pfile;
-{
-  unsigned int prev_value = pfile->no_expand_level;
-  pfile->no_expand_level = pfile->cur_context;
-  return prev_value;
+void
+_cpp_init_pool (pool, size, align, temp)
+     cpp_pool *pool;
+     unsigned int size, align, temp;
+{
+  if (align == 0)
+    align = DEFAULT_ALIGNMENT;
+  if (align & (align - 1))
+    abort ();
+  pool->align = align;
+  pool->cur = new_chunk (size);
+  pool->locked = 0;
+  pool->locks = 0;
+  if (temp)
+    pool->cur->next = pool->cur;
 }
 
-/* Restore macro expansion to its previous state.  */
-static void
-restore_macro_expansion (pfile, prev_value)
-     cpp_reader *pfile;
-     unsigned int prev_value;
+void
+_cpp_lock_pool (pool)
+     cpp_pool *pool;
 {
-  pfile->no_expand_level = prev_value;
+  if (pool->locks++ == 0)
+    pool->locked = pool->cur;
 }
 
-/* Used by cpperror.c to obtain the correct line and column to report
-   in a diagnostic.  */
-unsigned int
-_cpp_get_line (pfile, pcol)
-     cpp_reader *pfile;
-     unsigned int *pcol;
+void
+_cpp_unlock_pool (pool)
+     cpp_pool *pool;
 {
-  unsigned int index;
-  const cpp_token *cur_token;
-
-  if (pfile->state.in_lex_line)
-    index = pfile->token_list.tokens_used;
-  else
-    {
-      index = pfile->contexts[0].posn;
-
-      if (index == 0)
-       {
-         if (pcol)
-           *pcol = 0;
-         return 0;
-       }
-      index--;
-    }
-
-  cur_token = &pfile->token_list.tokens[index];
-  if (pcol)
-    *pcol = cur_token->col;
-  return cur_token->line;
+  if (--pool->locks == 0)
+    pool->locked = 0;
 }
 
-#define DSC(str) (const U_CHAR *)str, sizeof str - 1
-static const char * const monthnames[] =
-{
-  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-};
-
-/* Handle builtin macros like __FILE__.  */
-static const cpp_token *
-special_symbol (pfile, node, token)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
-     const cpp_token *token;
+void
+_cpp_free_pool (pool)
+     cpp_pool *pool;
 {
-  cpp_token *result;
-  cpp_buffer *ip;
+  cpp_chunk *chunk = pool->cur, *next;
 
-  switch (node->type)
+  do
     {
-    case T_FILE:
-    case T_BASE_FILE:
-      {
-       const char *file;
-
-       ip = CPP_BUFFER (pfile);
-       if (ip == 0)
-         file = "";
-       else
-         {
-           if (node->type == T_BASE_FILE)
-             while (CPP_PREV_BUFFER (ip) != NULL)
-               ip = CPP_PREV_BUFFER (ip);
-
-           file = ip->nominal_fname;
-         }
-       result = make_string_token (get_temp_token (pfile), (U_CHAR *) file,
-                                   strlen (file));
-      }
-      break;
-       
-    case T_INCLUDE_LEVEL:
-      /* pfile->include_depth counts the primary source as level 1,
-        but historically __INCLUDE_DEPTH__ has called the primary
-        source level 0.  */
-      result = alloc_number_token (pfile, pfile->include_depth - 1);
-      break;
-
-    case T_SPECLINE:
-      /* If __LINE__ is embedded in a macro, it must expand to the
-        line of the macro's invocation, not its definition.
-        Otherwise things like assert() will not work properly.  */
-      result = alloc_number_token (pfile, _cpp_get_line (pfile, NULL));
-      break;
-
-    case T_STDC:
-      {
-       int stdc = 1;
-
-#ifdef STDC_0_IN_SYSTEM_HEADERS
-       if (CPP_IN_SYSTEM_HEADER (pfile)
-           && pfile->spec_nodes->n__STRICT_ANSI__->type == T_VOID)
-         stdc = 0;
-#endif
-       result = alloc_number_token (pfile, stdc);
-      }
-      break;
-
-    case T_DATE:
-    case T_TIME:
-      if (pfile->date == 0)
-       {
-         /* Allocate __DATE__ and __TIME__ from permanent storage,
-            and save them in pfile so we don't have to do this again.
-            We don't generate these strings at init time because
-            time() and localtime() are very slow on some systems.  */
-         time_t tt = time (NULL);
-         struct tm *tb = localtime (&tt);
-
-         pfile->date = make_string_token
-           ((cpp_token *) xmalloc (sizeof (cpp_token)), DSC("Oct 11 1347"));
-         pfile->time = make_string_token
-           ((cpp_token *) xmalloc (sizeof (cpp_token)), DSC("12:34:56"));
-
-         sprintf ((char *) pfile->date->val.str.text, "%s %2d %4d",
-                  monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
-         sprintf ((char *) pfile->time->val.str.text, "%02d:%02d:%02d",
-                  tb->tm_hour, tb->tm_min, tb->tm_sec);
-       }
-      result = node->type == T_DATE ? pfile->date: pfile->time;
-      break;
-
-    case T_POISON:
-      cpp_error (pfile, "attempt to use poisoned \"%s\"", node->name);
-      return token;
-
-    default:
-      cpp_ice (pfile, "invalid special hash type");
-      return token;
+      next = chunk->next;
+      free (chunk->base);
+      chunk = next;
     }
-
-  ASSIGN_FLAGS_AND_POS (result, token);
-  return result;
+  while (chunk && chunk != pool->cur);
 }
-#undef DSC
 
-/* Allocate pfile->input_buffer, and initialize _cpp_trigraph_map[]
-   if it hasn't happened already.  */
-
-void
-_cpp_init_input_buffer (pfile)
-     cpp_reader *pfile;
+/* Reserve LEN bytes from a memory pool.  */
+unsigned char *
+_cpp_pool_reserve (pool, len)
+     cpp_pool *pool;
+     unsigned int len;
 {
-  cpp_context *base;
-
-  _cpp_init_toklist (&pfile->token_list, 0);
-  pfile->no_expand_level = UINT_MAX;
-  pfile->context_cap = 20;
-  pfile->cur_context = 0;
-
-  pfile->contexts = (cpp_context *)
-    xmalloc (pfile->context_cap * sizeof (cpp_context));
-
-  /* Clear the base context.  */
-  base = &pfile->contexts[0];
-  base->u.list = &pfile->token_list;
-  base->posn = 0;
-  base->count = 0;
-  base->args = 0;
-  base->level = 0;
-  base->flags = 0;
-  base->pushed_token = 0;
-}
+  len = ALIGN (len, pool->align);
+  if (len > (unsigned int) POOL_ROOM (pool))
+    _cpp_next_chunk (pool, len, 0);
 
-/* Moves to the end of the directive line, popping contexts as
-   necessary.  */
-void
-_cpp_skip_rest_of_line (pfile)
-     cpp_reader *pfile;
-{
-  /* Discard all stacked contexts.  */
-  int i;
-  for (i = pfile->cur_context; i > 0; i--)
-    if (pfile->contexts[i].args)
-      free_macro_args (pfile->contexts[i].args);
-
-  if (pfile->no_expand_level <= pfile->cur_context)
-    pfile->no_expand_level = 0;
-  pfile->cur_context = 0;
-
-  /* Clear the base context, and clear the directive pointer so that
-     get_raw_token will advance to the next line.  */
-  pfile->contexts[0].count = 0;
-  pfile->contexts[0].posn = 0;
-  pfile->token_list.directive = 0;
+  return POOL_FRONT (pool);
 }
 
-/* Directive handler wrapper used by the command line option
-   processor.  */
-void
-_cpp_run_directive (pfile, dir, buf, count, name)
-     cpp_reader *pfile;
-     const struct directive *dir;
-     const char *buf;
-     size_t count;
-     const char *name;
+/* Allocate LEN bytes from a memory pool.  */
+unsigned char *
+_cpp_pool_alloc (pool, len)
+     cpp_pool *pool;
+     unsigned int len;
 {
-  if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL)
-    {
-      unsigned int prev_lvl = 0;
+  unsigned char *result = _cpp_pool_reserve (pool, len);
 
-      if (name)
-       CPP_BUFFER (pfile)->nominal_fname = name;
-      else
-       CPP_BUFFER (pfile)->nominal_fname = _("<command line>");
-      CPP_BUFFER (pfile)->lineno = (unsigned int)-1;
-
-      /* Scan the line now, else prevent_macro_expansion won't work.  */
-      lex_next (pfile, 1);
-      if (! (dir->flags & EXPAND))
-       prev_lvl = prevent_macro_expansion (pfile);
-
-      (void) (*dir->handler) (pfile);
-
-      if (! (dir->flags & EXPAND))
-       restore_macro_expansion (pfile, prev_lvl);
-      
-      _cpp_skip_rest_of_line (pfile);
-      cpp_pop_buffer (pfile);
-    }
+  POOL_COMMIT (pool, len);
+  return result;
 }
index 37dbe02..5f54e60 100644 (file)
@@ -28,48 +28,112 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "obstack.h"
 #include "symcat.h"
 
+/* 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).  */
 
 struct if_stack
 {
   struct if_stack *next;
-  unsigned int lineno;         /* line number where condition started */
-  unsigned int colno;          /* and column */
+  cpp_lexer_pos pos;           /* line and column where condition started */
+  const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
   int was_skipping;            /* value of pfile->skipping before this if */
-  const cpp_hashnode *cmacro;  /* macro name for #ifndef around entire file */
   int type;                    /* type of last directive seen in this group */
 };
 
+/* 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 run_directive      PARAMS ((cpp_reader *, int,
+                                        const char *, unsigned int,
+                                        const char *));
+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 int  read_line_number   PARAMS ((cpp_reader *, int *));
 static int  strtoul_for_line   PARAMS ((const U_CHAR *, unsigned int,
                                         unsigned long *));
 static void do_diagnostic      PARAMS ((cpp_reader *, enum error_type));
-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 *));
+       lex_macro_node          PARAMS ((cpp_reader *));
 static void unwind_if_stack    PARAMS ((cpp_reader *, cpp_buffer *));
+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 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 *));
 
 /* 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
@@ -78,27 +142,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 | IN_I)/* 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,     IN_I)           /*   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,    IN_I)           /*    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, IN_I)           /*     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.  */
 
@@ -114,6 +157,7 @@ DIRECTIVE_TABLE
 #define D(n, tag, o, f) tag,
 enum
 {
+  T_BAD_DIRECTIVE,
   DIRECTIVE_TABLE
   N_DIRECTIVES
 };
@@ -123,241 +167,387 @@ 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)
+/* Skip any remaining tokens in a directive.  */
+static void
+skip_rest_of_line (pfile)
      cpp_reader *pfile;
-     const cpp_token *token;
 {
-  unsigned int i;
+  cpp_token token;
+
+  /* Discard all stacked contexts.  */
+  while (pfile->context != &pfile->base_context)
+    _cpp_pop_context (pfile);
+
+  /* Sweep up all tokens remaining on the line.  We need to read
+     tokens from lookahead, but cannot just drop the lookahead buffers
+     because they may be saving tokens prior to this directive for an
+     external client.  So we use cpp_get_token, with macros disabled.  */
+  pfile->state.prevent_expansion++;
+  while (!pfile->state.skip_newlines)
+    _cpp_lex_token (pfile, &token);
+  pfile->state.prevent_expansion--;
+}
 
-  if (token->type != CPP_NAME)
+/* Ensure there are no stray tokens at the end of a directive.  */
+static void
+check_eol (pfile)
+     cpp_reader *pfile;
+{
+  if (!pfile->state.skip_newlines)
     {
-      if (token->type == CPP_EOF && CPP_WTRADITIONAL (pfile)
-         && pfile->state.indented)
-       cpp_warning (pfile, "traditional C ignores #\\n with the # indented");
+      cpp_token token;
 
-      return 0;
+      _cpp_lex_token (pfile, &token);
+      if (token.type != CPP_EOF)
+       cpp_pedwarn (pfile, "extra tokens at end of #%s directive",
+                    pfile->directive->name);
     }
+}
+
+/* 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;
+{
+  const directive *dir = 0;
+  cpp_token dname;
+  int not_asm = 1;
 
-  for (i = 0; i < N_DIRECTIVES; i++)
-    if (pfile->spec_nodes->dirs[i] == token->val.node)
-      break;
+  /* Some handlers need the position of the # for diagnostics.  */
+  pfile->directive_pos = pfile->lexer_pos;
 
-  if (i == N_DIRECTIVES)
-    return 0;
+  /* We're now in a directive.  This ensures we get pedantic warnings
+     about /v and /f in whitespace.  */
+  pfile->state.in_directive = 1;
+  pfile->state.save_comments = 0;
 
-  /* We should lex headers correctly, regardless of whether we're
-     skipping or not.  */
-  pfile->state.angled_headers = dtable[i].flags & INCL;
+  /* Lex the directive name directly.  */
+  _cpp_lex_token (pfile, &dname);
 
-  /* 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))
+  if (dname.type == CPP_NAME)
     {
-      if (!dtable[i].flags & IN_I)
-       return 0;
+      unsigned int index = dname.val.node->directive_index;
+      if (index)
+       dir = &dtable[index - 1];
     }
-  else
+  else if (dname.type == CPP_NUMBER)
     {
-      /* 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))
+      /* # 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))
        {
-         if (pfile->state.indented && dtable[i].origin == KANDR)
-           cpp_warning (pfile, 
-                        "traditional C ignores #%s with the # indented",
-                        dtable[i].name);
-
-         else if (!pfile->state.indented && dtable[i].origin != KANDR)
-           cpp_warning (pfile,
-                "suggest hiding #%s from traditional C with an indented #",
-                        dtable[i].name);
+         dir = &dtable[T_LINE];
+         _cpp_push_token (pfile, &dname, &pfile->directive_pos);
+         if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc
+             && ! CPP_OPTION (pfile, preprocessed))
+           cpp_pedwarn (pfile, "# followed by integer");
        }
+    }
 
-      /* If we are skipping a failed conditional group, all non-conditional
-        directives are ignored.  */
-      if (pfile->skipping && !(dtable[i].flags & COND))
-       return 0;
+  pfile->directive = dir;
+  if (dir)
+    {
+      /* Make sure we lex headers correctly, whether skipping or not.  */
+      pfile->state.angled_headers = dir->flags & INCL;
 
-      /* 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);
+      /* 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 (!pfile->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)
+    {
+      /* The null directive.  */
+      if (indented && CPP_WTRADITIONAL (pfile))
+       cpp_warning (pfile, "traditional C ignores #\\n with the # indented");
+    }
+  else
+    {
+      /* 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_asm))
+       {
+         /* Output the # and lookahead token for the assembler.  */
+         not_asm = 0;
+         _cpp_push_token (pfile, &dname, &pfile->directive_pos);
+       }
+      else if (!pfile->skipping)
+       cpp_error (pfile, "invalid preprocessing directive #%s",
+                  cpp_token_as_text (pfile, &dname));
     }
 
-  /* Only flag to save comments if we process the directive.  */
-  pfile->state.save_comments = (! CPP_OPTION (pfile, discard_comments)
-                               && (dtable[i].flags & COMMENTS));
+  /* Save the lookahead token for assembler.  */
+  if (not_asm)
+    skip_rest_of_line (pfile);
+  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
+  pfile->state.in_directive = 0;
+  pfile->state.angled_headers = 0;
+  pfile->directive = 0;
 
-  return &dtable[i];
+  return not_asm;
 }
 
-const struct directive *
-_cpp_check_linemarker (pfile, token)
+/* Directive handler wrapper used by the command line option
+   processor.  */
+static void
+run_directive (pfile, dir_no, buf, count, name)
      cpp_reader *pfile;
-     const cpp_token *token ATTRIBUTE_UNUSED;
+     int dir_no;
+     const char *buf;
+     size_t count;
+     const char *name;
 {
-  /* # 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 (pfile->state.indented && CPP_WTRADITIONAL (pfile))
-    cpp_warning (pfile, "traditional C ignores #%s with the # indented",
-                dtable[T_LINE].name);
-
-  return &dtable[T_LINE];
-}  
+  if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL)
+    {
+      const struct directive *dir = &dtable[dir_no];
+
+      if (name)
+       CPP_BUFFER (pfile)->nominal_fname = name;
+      else
+       CPP_BUFFER (pfile)->nominal_fname = _("<command line>");
+      CPP_BUFFER (pfile)->lineno = (unsigned int)-1;
+
+      pfile->state.in_directive = 1;
+      pfile->directive = dir;
+      (void) (*dir->handler) (pfile);
+      pfile->directive = 0;
+      pfile->state.in_directive = 0;
 
+      skip_rest_of_line (pfile);
+      cpp_pop_buffer (pfile);
+    }
+}
+
+/* Checks for validity the macro name in #define, #undef, #ifdef and
+   #ifndef directives.  */
 static cpp_hashnode *
-get_define_node (pfile)
+lex_macro_node (pfile)
      cpp_reader *pfile;
 {
-  const cpp_token *token;
+  cpp_token token;
 
-  /* Skip any -C comments.  */
-  while ((token = _cpp_get_token (pfile))->type == CPP_COMMENT)
-    ;
+  /* 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_NAME)
     {
-      if (token->type == CPP_DEFINED)
-       cpp_error_with_line (pfile, token->line, token->col,
-                            "\"defined\" cannot be used as a macro name");
-      else if (token->flags & NAMED_OP)
-       cpp_error_with_line (pfile, token->line, token->col,
-                            "\"%s\" cannot be used as a macro name in C++",
-                            token->val.node->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_with_line (pfile, token->line, token->col,
-                          "macro names must be identifiers");
-      return 0;
-    }
-
-  /* In Objective C, some keywords begin with '@', but general identifiers
-     do not, and you're not allowed to #define them.  */
-  if (token->val.node->name[0] == '@')
-    {
-      cpp_error_with_line (pfile, token->line, token->col,
-                          "\"%s\" cannot be used as a macro name",
-                          token->val.node->name);
-      return 0;
+       cpp_error (pfile, "macro names must be identifiers");
     }
-
-  /* Check for poisoned identifiers now.  */
-  if (token->val.node->type == T_POISON)
+  else
     {
-      cpp_error_with_line (pfile, token->line, token->col,
-                          "attempt to use poisoned \"%s\"",
-                          token->val.node->name);
-      return 0;
+      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;
     }
 
-  return token->val.node;
+  return 0;
 }
 
-/* Process a #define command.  */
+/* Process a #define directive.  Most work is done in cppmacro.c.  */
 static void
 do_define (pfile)
      cpp_reader *pfile;
 {
-  cpp_hashnode *node;
+  cpp_hashnode *node = lex_macro_node (pfile);
 
-  if ((node = get_define_node (pfile)))
-    if (_cpp_create_definition (pfile, node))
-      if (pfile->cb.define)
-       (*pfile->cb.define) (pfile, node);
+  if (node)
+    {
+      /* Use the permanent pool for storage.  */
+      pfile->string_pool = &pfile->ident_pool;
+
+      if (_cpp_create_definition (pfile, node))
+       if (pfile->cb.define)
+         (*pfile->cb.define) (pfile, node);
+
+      /* Revert to the temporary pool.  */
+      pfile->string_pool = &pfile->temp_string_pool;
+    }
 }
 
-/* Remove the definition of a symbol from the symbol table.  */
+/* Handle #undef.  Marks the identifier NT_VOID in the hash table.  */
 static void
 do_undef (pfile)
      cpp_reader *pfile;
 {
-  cpp_hashnode *node = get_define_node (pfile);  
-
-  if (_cpp_get_token (pfile)->type != CPP_EOF)
-    cpp_pedwarn (pfile, "junk on line after #undef");
+  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 (pfile->cb.undef)
        (*pfile->cb.undef) (pfile, node);
 
-      if (node->type != T_MACRO)
+      if (node->flags & NODE_BUILTIN)
        cpp_warning (pfile, "undefining \"%s\"", node->name);
 
       _cpp_free_definition (node);
     }
+  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 *) realloc (buffer, capacity);
+       }
+
+      if (token.flags & PREV_WHITE)
+       buffer[total_len++] = ' ';
+
+      total_len = cpp_spell_token (pfile, &token, &buffer[total_len]) - buffer;
+    }
+
+  if (token.type == CPP_EOF)
+    cpp_error (pfile, "missing terminating > character");
+  else
+    {
+      token_mem = _cpp_pool_alloc (pfile->string_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;
+    }
 
-/* Handle #include and #import.  */
+  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 (name->type != CPP_STRING && name->type != CPP_HEADER_NAME)
+  if (is_pragma)
+    dir = U"pragma dependency";
+  else
+    dir = pfile->directive->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.str.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);
-
-  *lenp = name->val.str.len;
-  *strp = name->val.str.text;
-  *abp = (name->type == CPP_HEADER_NAME);
+  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);
+    }
 
-  if (pfile->cb.include)
-    (*pfile->cb.include) (pfile, dir, *strp, *lenp, *abp);
   return 0;
 }
 
@@ -365,23 +555,17 @@ 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;
+  cpp_token header;
 
-  _cpp_execute_include (pfile, str, len, 0, 0, ab);
+  if (!parse_include (pfile, &header))
+    _cpp_execute_include (pfile, &header, 0, 0);
 }
 
 static void
 do_import (pfile)
      cpp_reader *pfile;
 {
-  unsigned int len;
-  const U_CHAR *str;
-  int ab;
+  cpp_token header;
 
   if (!pfile->import_warning && CPP_OPTION (pfile, warn_import))
     {
@@ -390,22 +574,18 @@ do_import (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;
-
-  _cpp_execute_include (pfile, str, len, 1, 0, ab);
+  if (!parse_include (pfile, &header))
+    _cpp_execute_include (pfile, &header, 1, 0);
 }
 
 static void
 do_include_next (pfile)
      cpp_reader *pfile;
 {
-  unsigned int len;
-  const U_CHAR *str;
+  cpp_token header;
   struct file_name_list *search_start = 0;
-  int ab;
 
-  if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab))
+  if (parse_include (pfile, &header))
     return;
 
   /* For #include_next, skip in the search path past the dir in which
@@ -426,7 +606,7 @@ do_include_next (pfile)
   else
     cpp_warning (pfile, "#include_next in primary source file");
 
-  _cpp_execute_include (pfile, str, len, 0, search_start, ab);
+  _cpp_execute_include (pfile, &header, 0, search_start);
 }
 
 /* Subroutine of do_line.  Read next token from PFILE without adding it to
@@ -439,22 +619,23 @@ read_line_number (pfile, num)
      cpp_reader *pfile;
      int *num;
 {
-  const cpp_token *tok = _cpp_get_token (pfile);
-  enum cpp_ttype type = tok->type;
-  const U_CHAR *p = tok->val.str.text;
-  unsigned int len = tok->val.str.len;
+  cpp_token token;
+  unsigned int val;
 
-  if (type == CPP_NUMBER && len == 1 && p[0] >= '1' && p[0] <= '4')
+  _cpp_lex_token (pfile, &token);
+  if (token.type == CPP_NUMBER && token.val.str.len == 1)
     {
-      *num = p[0] - '0';
-      return 1;
-    }
-  else
-    {
-      if (type != CPP_EOF)
-       cpp_error (pfile, "invalid format #line");
-      return 0;
+      val = token.val.str.text[0] - '1';
+      if (val <= 3)
+       {
+         *num = val + 1;
+         return 1;
+       }
     }
+
+  if (token.type != CPP_EOF)
+    cpp_error (pfile, "invalid format #line");
+  return 0;
 }
 
 /* Another subroutine of do_line.  Convert a number in STR, of length
@@ -489,90 +670,88 @@ do_line (pfile)
      cpp_reader *pfile;
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
-  unsigned long new_lineno, old_lineno;
+  unsigned long new_lineno;
   /* C99 raised the minimum limit on #line numbers.  */
   unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
-  int action_number = 0;
   int enter = 0, leave = 0, rename = 0;
-  enum cpp_ttype type;
-  const U_CHAR *str;
-  char *fname;
-  unsigned int len;
-  const cpp_token *tok;
-
-  tok = _cpp_get_token (pfile);
-  type = tok->type;
-  str = tok->val.str.text;
-  len = tok->val.str.len;
-
-  if (type != CPP_NUMBER || strtoul_for_line (str, len, &new_lineno))
+  cpp_token token;
+
+  /* #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");
+      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.str.text;
-  len = tok->val.str.len;
+  _cpp_get_token (pfile, &token);
 
-  if (type == CPP_EOF)
-    goto done;
-  else if (type != CPP_STRING)
+  if (token.type != CPP_EOF)
     {
-      cpp_error (pfile, "second token after #line is not a string");
-      ip->lineno = old_lineno;  /* malformed #line should have no effect */
-      return;
-    }
+      char *fname;
+      unsigned int len;
+      int action_number = 0;
 
-  fname = alloca (len + 1);
-  memcpy (fname, str, len);
-  fname[len] = '\0';
-    
-  if (strcmp (fname, ip->nominal_fname))
-    {
-      rename = 1;
-      if (!strcmp (fname, ip->inc->name))
-       ip->nominal_fname = ip->inc->name;
-      else
-       ip->nominal_fname = _cpp_fake_include (pfile, fname);
-    }
+      if (token.type != CPP_STRING)
+       {
+         cpp_error (pfile, "\"%s\" is not a valid filename",
+                    cpp_token_as_text (pfile, &token));
+         return;
+       }
 
-  if (read_line_number (pfile, &action_number) == 0)
-    goto done;
+      len = token.val.str.len;
+      fname = alloca (len + 1);
+      memcpy (fname, token.val.str.text, len);
+      fname[len] = '\0';
+    
+      if (strcmp (fname, ip->nominal_fname))
+       {
+         rename = 1;
+         if (!strcmp (fname, ip->inc->name))
+           ip->nominal_fname = ip->inc->name;
+         else
+           ip->nominal_fname = _cpp_fake_include (pfile, fname);
+       }
 
-  if (CPP_PEDANTIC (pfile))
-    cpp_pedwarn (pfile, "garbage at end of #line");
+      if (read_line_number (pfile, &action_number) != 0)
+       {
+         if (CPP_PEDANTIC (pfile))
+           cpp_pedwarn (pfile,  "extra tokens at end of #line directive");
 
-  if (action_number == 1)
-    {
-      enter = 1;
-      cpp_make_system_header (pfile, ip, 0);
-      read_line_number (pfile, &action_number);
-    }
-  else if (action_number == 2)
-    {
-      leave = 1;
-      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 (action_number == 4)
-    {
-      cpp_make_system_header (pfile, ip, 2);
-      read_line_number (pfile, &action_number);
+         if (action_number == 1)
+           {
+             enter = 1;
+             cpp_make_system_header (pfile, ip, 0);
+             read_line_number (pfile, &action_number);
+           }
+         else if (action_number == 2)
+           {
+             leave = 1;
+             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 (action_number == 4)
+           {
+             cpp_make_system_header (pfile, ip, 2);
+             read_line_number (pfile, &action_number);
+           }
+       }
+      check_eol (pfile);
     }
 
- done:
+  /* Our line number is incremented after the directive is processed.  */
+  ip->lineno = new_lineno - 1;
+  pfile->lexer_pos.output_line = ip->lineno;
   if (enter && pfile->cb.enter_file)
     (*pfile->cb.enter_file) (pfile);
   if (leave && pfile->cb.leave_file)
@@ -591,11 +770,12 @@ do_diagnostic (pfile, code)
      cpp_reader *pfile;
      enum error_type code;
 {
-  if (_cpp_begin_message (pfile, code, NULL, 0, 0))
+  if (_cpp_begin_message (pfile, code, NULL, 0))
     {
-      cpp_output_list (pfile, stderr, &pfile->token_list,
-                      pfile->first_directive_token);
-      putc ('\n', stderr);
+      fprintf (stderr, "#%s ", pfile->directive->name);
+      pfile->state.prevent_expansion++;
+      cpp_output_line (pfile, stderr);
+      pfile->state.prevent_expansion--;
     }
 }
 
@@ -619,16 +799,15 @@ static void
 do_ident (pfile)
      cpp_reader *pfile;
 {
-  const cpp_token *str = _cpp_get_token (pfile);
+  cpp_token str;
 
-  if (str->type == CPP_STRING && _cpp_get_token (pfile)->type == CPP_EOF)
-    {
-      if (pfile->cb.ident)
-       (*pfile->cb.ident) (pfile, str->val.str.text, str->val.str.len);
-      return;
-    }
+  _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);
 
-  cpp_error (pfile, "invalid #ident");
+  check_eol (pfile);
 }
 
 /* Pragmata handling.  We handle some of these, and pass the rest on
@@ -723,11 +902,6 @@ cpp_register_pragma_space (pfile, space)
   pfile->pragmas = new;
 }
   
-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 *));
-
 void
 _cpp_init_internal_pragmas (pfile)
      cpp_reader *pfile;
@@ -749,46 +923,47 @@ do_pragma (pfile)
      cpp_reader *pfile;
 {
   const struct pragma_entry *p;
-  const cpp_token *tok;
+  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:
-  tok = _cpp_get_token (pfile);
-  if (tok->type == CPP_EOF)
-    return;
-
-  if (tok->type != CPP_NAME)
+  cpp_get_token (pfile, &tok);
+  if (tok.type == CPP_NAME)
     {
-      cpp_error (pfile, "malformed #pragma directive");
-      return;
-    }
-
-  node = tok->val.node;
-  name = node->name;
-  len = node->length;
-  while (p)
-    {
-      if (strlen (p->name) == len && !memcmp (p->name, name, len))
+      node = tok.val.node;
+      name = node->name;
+      len = node->length;
+      while (p)
        {
-         if (p->isnspace)
+         if (strlen (p->name) == len && !memcmp (p->name, name, len))
            {
-             p = p->u.space;
-             goto new_space;
-           }
-         else
-           {
-             (*p->u.handler) (pfile);
-             return;
+             if (p->isnspace)
+               {
+                 p = p->u.space;
+                 goto new_space;
+               }
+             else
+               {
+                 (*p->u.handler) (pfile);
+                 drop = 1;
+                 break;
+               }
            }
+         p = p->next;
        }
-      p = p->next;
     }
 
-  if (pfile->cb.def_pragma)
+  cpp_stop_lookahead (pfile, drop);
+  pfile->state.prevent_expansion--;
+
+  if (!drop && pfile->cb.def_pragma)
     (*pfile->cb.def_pragma) (pfile);
 }
 
@@ -798,14 +973,14 @@ do_pragma_once (pfile)
 {
   cpp_buffer *ip = CPP_BUFFER (pfile);
 
-  /* Allow #pragma once in system headers, since that's not the user's
-     fault.  */
   cpp_warning (pfile, "#pragma once is obsolete");
  
   if (CPP_PREV_BUFFER (ip) == NULL)
-    cpp_warning (pfile, "#pragma once outside include file");
+    cpp_warning (pfile, "#pragma once in main file");
   else
     ip->inc->cmacro = NEVER_REREAD;
+
+  check_eol (pfile);
 }
 
 static void
@@ -814,34 +989,36 @@ do_pragma_poison (pfile)
 {
   /* Poison these symbols so that all subsequent usage produces an
      error message.  */
-  const cpp_token *tok;
+  cpp_token tok;
   cpp_hashnode *hp;
 
+  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;
+         cpp_error (pfile, "invalid #pragma GCC poison directive");
+         break;
        }
 
-      hp = tok->val.node;
-      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;
     }
+  pfile->state.poisoned_ok = 0;
 
-  if (pfile->cb.poison)
+#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
@@ -859,6 +1036,8 @@ do_pragma_system_header (pfile)
     cpp_warning (pfile, "#pragma system_header outside include file");
   else
     cpp_make_system_header (pfile, ip, 1);
+
+  check_eol (pfile);
 }
 
 /* Check the modified date of the current include file against a specified
@@ -868,32 +1047,25 @@ 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))
+  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, (int)len, name, right);
-      if (msg->type != CPP_EOF
-         && _cpp_begin_message (pfile, WARNING, NULL, msg->line, msg->col))
-       {
-         cpp_output_list (pfile, stderr, &pfile->token_list, msg);
-         putc ('\n', stderr);
-       }
+      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 && _cpp_begin_message (pfile, WARNING, NULL, 0))
+       cpp_output_line (pfile, stderr);
     }
 }
 
@@ -906,137 +1078,61 @@ do_sccs (pfile)
 }
 #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)
-     cpp_reader *pfile;
-{
-  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;
-
-  token++;
-  if (token->type != CPP_DEFINED)
-    return 0;
-
-  token++;
-  if (token->type == CPP_OPEN_PAREN)
-    token++;
-
-  if (token->type != CPP_NAME)
-    return 0;
-
-  cmacro = token->val.node;
-
-  if (token[-1].type == CPP_OPEN_PAREN)
-    {
-      token++;
-      if (token->type != CPP_CLOSE_PAREN)
-       return 0;
-    }
-
-  token++;
-  if (token->type != CPP_EOF)
-    return 0;
-
-  return cmacro;
-}
-
-/* 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)
-     cpp_reader *pfile;
-     const U_CHAR *name;
-{
-  enum cpp_ttype type;
-  const cpp_hashnode *node = 0;
-
-  const cpp_token *token = _cpp_get_token (pfile);
-  type = token->type;
-
-  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);
-
-  if (type == CPP_NAME)
-    node = token->val.node;
-  if (node && node->type == T_POISON)
-    {
-      cpp_error (pfile, "attempt to use poisoned identifier \"%s\"",
-                node->name);
-      node = 0;
-    }
-
-  return node;
-}
-
-/* #ifdef is dead simple.  */
-
 static void
 do_ifdef (pfile)
      cpp_reader *pfile;
 {
-  const cpp_hashnode *node = 0;
+  int skip = 1;
 
   if (! pfile->skipping)
-    node = parse_ifdef (pfile, dtable[T_IFDEF].name);
+    {
+      const cpp_hashnode *node = lex_macro_node (pfile);
 
-  push_conditional (pfile, !(node && node->type != T_VOID), T_IFDEF, 0);
-}
+      if (node)
+       skip = node->type != NT_MACRO;
+    }
 
-/* #ifndef is a tad more complex, because we need to check for a
-   no-reinclusion wrapper.  */
+  push_conditional (pfile, skip, T_IFDEF, 0);
+}
 
 static void
 do_ifndef (pfile)
      cpp_reader *pfile;
 {
-  int start_of_file = 0;
+  int skip = 1;
   const cpp_hashnode *node = 0;
 
   if (! pfile->skipping)
     {
-      start_of_file = (pfile->token_list.flags & BEG_OF_FILE);
-      node = parse_ifdef (pfile, dtable[T_IFNDEF].name);
+      node = lex_macro_node (pfile);
+      if (node)
+       skip = node->type == NT_MACRO;
     }
 
-  push_conditional (pfile, node && node->type != T_VOID,
-                   T_IFNDEF, start_of_file ? node : 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 void
 do_if (pfile)
      cpp_reader *pfile;
 {
+  int skip = 1;
   const cpp_hashnode *cmacro = 0;
-  int value = 0;
 
-  if (! pfile->skipping)
+  if (!pfile->skipping)
     {
-      if (pfile->token_list.flags & BEG_OF_FILE)
-       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);
+
+  push_conditional (pfile, skip, T_IF, cmacro);
 }
 
 /* #else flips pfile->skipping and continues without changing
@@ -1048,37 +1144,36 @@ do_else (pfile)
      cpp_reader *pfile;
 {
   struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
-  validate_else (pfile, dtable[T_ELSE].name);
 
   if (ifs == NULL)
+    cpp_error (pfile, "#else without #if");
+  else
     {
-      cpp_error (pfile, "#else without #if");
-      return;
-    }
-  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");
+       }
 
-  /* #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;
+      /* Invalidate any controlling macro.  */
+      ifs->mi_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 skip the else block.  */
+         if (pfile->skipping < 2)
+           pfile->skipping = ! pfile->skipping;
+       }
     }
+
+  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 void
 do_elif (pfile)
@@ -1091,13 +1186,17 @@ do_elif (pfile)
       cpp_error (pfile, "#elif without #if");
       return;
     }
+
   if (ifs->type == T_ELSE)
     {
       cpp_error (pfile, "#elif after #else");
-      cpp_error_with_line (pfile, ifs->lineno, ifs->colno,
+      cpp_error_with_line (pfile, ifs->pos.line, ifs->pos.col,
                           "the conditional began here");
     }
 
+  /* Invalidate any controlling macro.  */
+  ifs->mi_cmacro = 0;
+
   ifs->type = T_ELIF;
   if (ifs->was_skipping)
     return;  /* Don't evaluate a nested #if */
@@ -1119,19 +1218,24 @@ do_endif (pfile)
 {
   struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
 
-  validate_else (pfile, dtable[T_ENDIF].name);
-
   if (ifs == NULL)
     cpp_error (pfile, "#endif without #if");
   else
     {
+      /* 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;
+       }
+
       CPP_BUFFER (pfile)->if_stack = ifs->next;
       pfile->skipping = ifs->was_skipping;
-      pfile->potential_control_macro = ifs->cmacro;
       obstack_free (pfile->buffer_ob, ifs);
     }
-}
 
+  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,
@@ -1147,11 +1251,14 @@ push_conditional (pfile, skip, type, cmacro)
   struct if_stack *ifs;
 
   ifs = xobnew (pfile->buffer_ob, struct if_stack);
-  ifs->lineno = _cpp_get_line (pfile, &ifs->colno);
+  ifs->pos = pfile->directive_pos;
   ifs->next = CPP_BUFFER (pfile)->if_stack;
-  ifs->cmacro = cmacro;
   ifs->was_skipping = pfile->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;
@@ -1159,18 +1266,6 @@ push_conditional (pfile, skip, type, cmacro)
   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);
-}
-
 /* 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.  */
@@ -1179,147 +1274,187 @@ unwind_if_stack (pfile, pbuf)
      cpp_reader *pfile;
      cpp_buffer *pbuf;
 {
-  struct if_stack *ifs, *nifs;
+  struct if_stack *ifs;
+
+  /* No need to free stack - they'll all go away with the buffer.  */
+  for (ifs = pbuf->if_stack; ifs; ifs = ifs->next)
+    cpp_error_with_line (pfile, ifs->pos.line, ifs->pos.col,
+                        "unterminated #%s", dtable[ifs->type].name);
 
-  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;
 }
 
-/* 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)
+/* 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.  */
+
+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, 1); /* Empty.  */
-
   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_SPELL (token) == SPELL_STRING)
+      if (token->type == CPP_EOF)
        {
-         _cpp_expand_name_space (list, token->val.str.len);
-         dest->val.str.text = list->namebuf + list->name_used;
-         memcpy (list->namebuf + list->name_used,
-                 token->val.str.text, token->val.str.len);
-         list->name_used += token->val.str.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.node->length;
-  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.  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.  */
+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++;
+
+  /* Use the permanent pool for storage (for the answers).  */
+  pfile->string_pool = &pfile->ident_pool;
+
+  *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.node->name, len);
-  return cpp_lookup (pfile, sym, len + 1);
+      /* 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->string_pool = &pfile->temp_string_pool;
+  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;
 }
 
+/* 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;
@@ -1327,26 +1462,27 @@ do_assert (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.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;
-
- err:
-  cpp_warning (pfile, "\"%s\" re-asserted", node->name + 1);
-  FREE_ANSWER (new_answer);
 }
 
 static void
@@ -1354,34 +1490,30 @@ do_unassert (pfile)
      cpp_reader *pfile;
 {
   cpp_hashnode *node;
-  struct answer *answer, *temp;
+  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
-           _cpp_free_definition (node);
-       }
+         /* 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);
     }
+
+  /* We don't commit the memory for the answer - it's temporary only.  */
 }
 
 /* These are for -D, -U, -A.  */
@@ -1421,7 +1553,7 @@ cpp_define (pfile, str)
       strcpy (&buf[count-4], " 1\n");
     }
 
-  _cpp_run_directive (pfile, &dtable[T_DEFINE], buf, count - 1, 0);
+  run_directive (pfile, T_DEFINE, buf, count - 1, 0);
 }
 
 /* Slight variant of the above for use by initialize_builtins, which (a)
@@ -1432,9 +1564,7 @@ _cpp_define_builtin (pfile, str)
      cpp_reader *pfile;
      const char *str;
 {
-  _cpp_run_directive (pfile, &dtable[T_DEFINE],
-                     str, strlen (str),
-                     _("<builtin>"));
+  run_directive (pfile, T_DEFINE, str, strlen (str), _("<builtin>"));
 }
 
 /* Process MACRO as if it appeared as the body of an #undef.  */
@@ -1443,7 +1573,7 @@ cpp_undef (pfile, macro)
      cpp_reader *pfile;
      const char *macro;
 {
-  _cpp_run_directive (pfile, &dtable[T_UNDEF], macro, strlen (macro), 0);
+  run_directive (pfile, T_UNDEF, macro, strlen (macro), 0);
 }
 
 /* Process the string STR as if it appeared as the body of a #assert. */
@@ -1452,7 +1582,7 @@ cpp_assert (pfile, str)
      cpp_reader *pfile;
      const char *str;
 {
-  _cpp_run_directive (pfile, &dtable[T_ASSERT], str, strlen (str), 0);
+  run_directive (pfile, T_ASSERT, str, strlen (str), 0);
 }
 
 /* Process STR as if it appeared as the body of an #unassert. */
@@ -1461,7 +1591,7 @@ cpp_unassert (pfile, str)
      cpp_reader *pfile;
      const char *str;
 {
-  _cpp_run_directive (pfile, &dtable[T_UNASSERT], str, strlen (str), 0);
+  run_directive (pfile, T_UNASSERT, str, strlen (str), 0);
 }  
 
 /* Determine whether the identifier ID, of length LEN, is a defined macro.  */
@@ -1472,18 +1602,15 @@ cpp_defined (pfile, id, len)
      int len;
 {
   cpp_hashnode *hp = cpp_lookup (pfile, id, len);
-  if (hp->type == T_POISON)
-    {
-      cpp_error (pfile, "attempt to use poisoned \"%s\"", hp->name);
-      return 0;
-    }
-  return (hp->type != T_VOID);
+
+  /* If it's of type NT_MACRO, it cannot be poisoned.  */
+  return hp->type == NT_MACRO;
 }
 
-/* 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.  */
+/* 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.  */
 
 cpp_buffer *
 cpp_push_buffer (pfile, buffer, length)
@@ -1498,15 +1625,18 @@ cpp_push_buffer (pfile, buffer, length)
       cpp_fatal (pfile, "#include nested too deeply");
       return NULL;
     }
-  if (pfile->cur_context > 0)
+
+  if (pfile->context->prev)
     {
       cpp_ice (pfile, "buffer pushed with contexts stacked");
-      _cpp_skip_rest_of_line (pfile);
+      skip_rest_of_line (pfile);
     }
 
   new = xobnew (pfile->buffer_ob, cpp_buffer);
+  /* Clears, amongst other things, if_stack and mi_cmacro.  */
   memset (new, 0, sizeof (cpp_buffer));
 
+  pfile->lexer_pos.output_line = 1;
   new->line_base = new->buf = new->cur = buffer;
   new->rlimit = buffer + length;
   new->prev = buf;
@@ -1514,6 +1644,7 @@ cpp_push_buffer (pfile, buffer, length)
   /* No read ahead or extra char initially.  */
   new->read_ahead = EOF;
   new->extra_char = EOF;
+  pfile->state.skip_newlines = 1;
 
   CPP_BUFFER (pfile) = new;
   return new;
@@ -1535,7 +1666,7 @@ cpp_pop_buffer (pfile)
   obstack_free (pfile->buffer_ob, buf);
   pfile->buffer_stack_depth--;
 
-  if (wfb && pfile->cb.leave_file && CPP_BUFFER (pfile))
+  if (CPP_BUFFER (pfile) && wfb && pfile->cb.leave_file)
     (*pfile->cb.leave_file) (pfile);
   
   return CPP_BUFFER (pfile);
@@ -1543,25 +1674,22 @@ cpp_pop_buffer (pfile)
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
-#define DSC(x) U x, sizeof x - 1
 void
 _cpp_init_stacks (pfile)
      cpp_reader *pfile;
 {
   int i;
-  struct spec_nodes *s;
+  cpp_hashnode *node;
 
   pfile->buffer_ob = xnew (struct obstack);
   obstack_init (pfile->buffer_ob);
 
-  /* Perhaps not the ideal place to put this.  */
-  pfile->spec_nodes = s = xnew (struct spec_nodes);
-  s->n_L                = cpp_lookup (pfile, DSC("L"));
-  s->n__STRICT_ANSI__   = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
-  s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
-  s->n__VA_ARGS__       = cpp_lookup (pfile, DSC("__VA_ARGS__"));
-  for (i = 0; i < N_DIRECTIVES; i++)
-    s->dirs[i] = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
+  /* 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
index 0f52352..eecd867 100644 (file)
@@ -34,11 +34,21 @@ typedef struct cpp_reader cpp_reader;
 #endif
 typedef struct cpp_buffer cpp_buffer;
 typedef struct cpp_options cpp_options;
-typedef struct cpp_printer cpp_printer;
 typedef struct cpp_token cpp_token;
-typedef struct cpp_toklist cpp_toklist;
 typedef struct cpp_string cpp_string;
 typedef struct cpp_hashnode cpp_hashnode;
+typedef struct cpp_pool cpp_pool;
+typedef struct cpp_macro cpp_macro;
+typedef struct cpp_lexer_pos cpp_lexer_pos;
+typedef struct cpp_lookahead cpp_lookahead;
+
+struct directive;              /* These are deliberately incomplete.  */
+struct answer;
+struct cpp_macro;
+struct macro_args;
+struct cpp_chunk;
+struct file_name_map_list;
+struct htab;
 
 /* The first two groups, apart from '=', can appear in preprocessor
    expressions.  This allows a lookup table to be implemented in
@@ -114,7 +124,6 @@ typedef struct cpp_hashnode cpp_hashnode;
   OP(CPP_SCOPE,                "::")                   \
   OP(CPP_DEREF_STAR,   "->*")                  \
   OP(CPP_DOT_STAR,     ".*")                   \
-  OP(CPP_DEFINED,      "defined") /* #if */    \
 \
   TK(CPP_NAME,         SPELL_IDENT)    /* word */                      \
   TK(CPP_INT,          SPELL_STRING)   /* 23 */                        \
@@ -131,9 +140,10 @@ typedef struct cpp_hashnode cpp_hashnode;
   TK(CPP_HEADER_NAME,  SPELL_STRING)   /* <stdio.h> in #include */     \
 \
   TK(CPP_COMMENT,      SPELL_STRING)   /* Only if output comments.  */ \
+  TK(CPP_DHASH,                SPELL_NONE)     /* The # of a directive.  */    \
   TK(CPP_MACRO_ARG,    SPELL_NONE)     /* Macro argument.  */          \
   TK(CPP_PLACEMARKER,  SPELL_NONE)     /* Placemarker token.  */       \
-  TK(CPP_EOF,          SPELL_NONE)     /* End of file.  */
+  OP(CPP_EOF,          "EOL")          /* End of line or file.  */
 
 #define OP(e, s) e,
 #define TK(e, s) e,
@@ -145,6 +155,10 @@ enum cpp_ttype
 #undef OP
 #undef TK
 
+/* Multiple-include optimisation.  */
+enum mi_state {MI_FAILED = 0, MI_OUTSIDE};
+enum mi_ind {MI_IND_NONE = 0, MI_IND_NOT};
+
 /* Payload of a NUMBER, FLOAT, STRING, or COMMENT token.  */
 struct cpp_string
 {
@@ -154,19 +168,17 @@ struct cpp_string
 
 /* Flags for the cpp_token structure.  */
 #define PREV_WHITE     (1 << 0) /* If whitespace before this token.  */
-#define BOL            (1 << 1) /* Beginning of logical line.  */
-#define DIGRAPH                (1 << 2) /* If it was a digraph.  */
-#define STRINGIFY_ARG  (1 << 3) /* If macro argument to be stringified.  */
-#define PASTE_LEFT     (1 << 4) /* If on LHS of a ## operator.  */
-#define PASTED         (1 << 5) /* The result of a ## operator.  */
-#define NAMED_OP       (1 << 6) /* C++ named operators, also "defined".  */
+#define DIGRAPH                (1 << 1) /* If it was a digraph.  */
+#define STRINGIFY_ARG  (1 << 2) /* If macro argument to be stringified.  */
+#define PASTE_LEFT     (1 << 3) /* If on LHS of a ## operator.  */
+#define NAMED_OP       (1 << 4) /* C++ named operators, also "defined".  */
+#define NO_EXPAND      (1 << 5) /* Do not macro-expand this token.  */
+#define VARARGS_FIRST   STRINGIFY_ARG /* First token of varargs expansion.  */
 
 /* A preprocessing token.  This has been carefully packed and should
-   occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts.  */
+   occupy 12 bytes on 32-bit hosts and 16 bytes on 64-bit hosts.  */
 struct cpp_token
 {
-  unsigned int line;           /* starting line number of this token */
-  unsigned short col;          /* starting column of this token */
   ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT;  /* token type */
   unsigned char flags;         /* flags - see above */
 
@@ -180,37 +192,58 @@ struct cpp_token
   } val;
 };
 
-/* cpp_toklist flags.  */
-#define VAR_ARGS       (1 << 0)
-#define BEG_OF_FILE    (1 << 1)
-
-struct directive;              /* These are deliberately incomplete.  */
-struct answer;
-struct macro_args;
-struct cpp_context;
+/* The position of a token in the current file.  */
+struct cpp_lexer_pos
+{
+  unsigned int line;
+  unsigned int output_line;
+  unsigned short col;
+};
 
-struct cpp_toklist
+typedef struct cpp_token_with_pos cpp_token_with_pos;
+struct cpp_token_with_pos
 {
-  cpp_token *tokens;           /* actual tokens as an array */
-  unsigned int tokens_used;    /* tokens used */
-  unsigned int tokens_cap;     /* tokens allocated */
+  cpp_token token;
+  cpp_lexer_pos pos;
+};
 
-  unsigned char *namebuf;      /* names buffer */
-  unsigned int name_used;      /* _bytes_ used */
-  unsigned int name_cap;       /* _bytes_ allocated */
+/* Token lookahead.  */
+struct cpp_lookahead
+{
+  struct cpp_lookahead *next;
+  cpp_token_with_pos *tokens;
+  cpp_lexer_pos pos;
+  unsigned int cur, count, cap;
+};
 
-  /* If the list represents a directive, this points to it.  */
-  const struct directive *directive;
+/* Memory pools.  */
+struct cpp_pool
+{
+  struct cpp_chunk *cur, *locked;
+  unsigned char *pos;          /* Current position.  */
+  unsigned int align;
+  unsigned int locks;
+};
 
-  const char *file;            /* in file name */
-  unsigned int line;           /* starting line number */
+typedef struct toklist toklist;
+struct toklist
+{
+  cpp_token *first;
+  cpp_token *limit;
+};
 
-  unsigned short params_len;   /* length of macro parameter names.  */
+typedef struct cpp_context cpp_context;
+struct cpp_context
+{
+  /* Doubly-linked list.  */
+  cpp_context *next, *prev;
 
-  short int paramc;            /* no. of macro params (-1 = obj-like).  */
+  /* Contexts other than the base context are contiguous tokens.
+     e.g. macro expansions, expanded argument tokens.  */
+  struct toklist list;
 
-  /* Per-list flags, see above */
-  unsigned short flags;
+  /* For a macro context, these are the macro and its arguments.  */
+  cpp_macro *macro;
 };
 
 /* A standalone character.  We may want to make it unsigned for the
@@ -257,9 +290,6 @@ struct cpp_buffer
   char warned_cplusplus_comments;
 };
 
-struct file_name_map_list;
-struct htab;
-
 /* Maximum nesting of cpp_buffers.  We use a static limit, partly for
    efficiency, and partly to limit runaway recursion.  */
 #define CPP_STACK_MAX 200
@@ -448,10 +478,6 @@ struct lexer_state
   /* Nonzero if first token on line is CPP_HASH.  */
   unsigned char in_directive;
 
-  /* Nonzero if the directive's # was not in the first column.  Used
-     by -Wtraditional.  */
-  unsigned char indented;
-
   /* Nonzero if in a directive that takes angle-bracketed headers.  */
   unsigned char angled_headers;
 
@@ -459,24 +485,38 @@ struct lexer_state
      all directives apart from #define.  */
   unsigned char save_comments;
 
-  /* Nonzero to force the lexer to skip newlines.  */
+  /* If nonzero the lexer skips newlines.  Internal to the lexer.  */
   unsigned char skip_newlines;
 
-  /* Nonzero if we're in the subroutine lex_line.  */
-  unsigned char in_lex_line;
-
   /* Nonzero if we're mid-comment.  */
   unsigned char lexing_comment;
 
-  /* Tells parse_number we saw a leading period.  */
-  unsigned char seen_dot;
+  /* Nonzero if lexing __VA_ARGS__ is valid.  */
+  unsigned char va_args_ok;
+
+  /* Nonzero if lexing poisoned identifiers is valid.  */
+  unsigned char poisoned_ok;
+
+  /* Nonzero to prevent macro expansion.  */
+  unsigned char prevent_expansion;  
+
+  /* Nonzero when parsing arguments to a function-like macro.  */
+  unsigned char parsing_args;
 };
-#define IN_DIRECTIVE(pfile) (pfile->state.in_directive)
-#define KNOWN_DIRECTIVE(list) (list->directive != 0)
 
-/* A cpp_reader encapsulates the "state" of a pre-processor run.
+/* Special nodes - identifiers with predefined significance.  */
+struct spec_nodes
+{
+  cpp_hashnode *n_L;                   /* L"str" */
+  cpp_hashnode *n_defined;             /* defined operator */
+  cpp_hashnode *n__STRICT_ANSI__;      /* STDC_0_IN_SYSTEM_HEADERS */
+  cpp_hashnode *n__CHAR_UNSIGNED__;    /* plain char is unsigned */
+  cpp_hashnode *n__VA_ARGS__;          /* C99 vararg macros */
+};
+
+/* a cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
-   tokens.  Usually, there is only one cpp_reader object active. */
+   tokens.  Usually, there is only one cpp_reader object active.  */
 
 struct cpp_reader
 {
@@ -486,70 +526,76 @@ struct cpp_reader
   /* Lexer state.  */
   struct lexer_state state;
 
-  /* Error counter for exit code */
+  /* The position of the last lexed token, last lexed directive, and
+     last macro invocation.  */
+  cpp_lexer_pos lexer_pos;
+  cpp_lexer_pos macro_pos;
+  cpp_lexer_pos directive_pos;
+
+  /* Memory pools.  */
+  cpp_pool ident_pool;         /* For all identifiers, and permanent
+                                  numbers and strings.  */
+  cpp_pool temp_string_pool;   /* For temporary numbers and strings.   */
+  cpp_pool macro_pool;         /* For macro definitions.  Permanent.  */
+  cpp_pool argument_pool;      /* For macro arguments.  Temporary.   */
+  cpp_pool* string_pool;       /* Either temp_string_pool or ident_pool.   */
+
+  /* Context stack.  */
+  struct cpp_context base_context;
+  struct cpp_context *context;
+
+  /* If in_directive, the directive if known.  */
+  const struct directive *directive;
+
+  /* Multiple inlcude optimisation.  */
+  enum mi_state mi_state;
+  enum mi_ind mi_if_not_defined;
+  unsigned int mi_lexed;
+  const cpp_hashnode *mi_cmacro;
+  const cpp_hashnode *mi_ind_cmacro;
+
+  /* Token lookahead.  */
+  struct cpp_lookahead *la_read;       /* Read from this lookahead.  */
+  struct cpp_lookahead *la_write;      /* Write to this lookahead.  */
+  struct cpp_lookahead *la_unused;     /* Free store.  */
+
+  /* Error counter for exit code.  */
   unsigned int errors;
 
   /* Line and column where a newline was first seen in a string
      constant (multi-line strings).  */
-  unsigned int mls_line;
-  unsigned int mls_column;
+  cpp_lexer_pos mlstring_pos;
+
+  /* Buffer to hold macro definition string.  */
+  unsigned char *macro_buffer;
+  unsigned int macro_buffer_len;
 
   /* Current depth in #include directives that use <...>.  */
   unsigned int system_include_depth;
 
-  /* Current depth of buffer stack. */
+  /* Current depth of buffer stack.  */
   unsigned int buffer_stack_depth;
 
   /* Current depth in #include directives.  */
   unsigned int include_depth;
 
-  /* Hash table of macros and assertions.  See cpphash.c */
+  /* Hash table of macros and assertions.  See cpphash.c */
   struct htab *hashtab;
 
-  /* Tree of other included files.  See cppfiles.c */
+  /* Tree of other included files.  See cppfiles.c */
   struct splay_tree_s *all_include_files;
 
-  /* Chain of `actual directory' file_name_list entries,
-     for "" inclusion. */
+  /* Chain of `actual directory' file_name_list entries, for ""
+     inclusion.  */
   struct file_name_list *actual_dirs;
 
   /* Current maximum length of directory names in the search path
      for include files.  (Altered as we get more of them.)  */
   unsigned int max_include_len;
 
-  /* Potential controlling macro for the current buffer.  This is only
-     live between the #endif and the end of file, and there can only
-     be one at a time, so it is per-reader not per-buffer.  */
-  const cpp_hashnode *potential_control_macro;
-
-  /* Token list used to store logical lines with new lexer.  */
-  cpp_toklist token_list;
-
-  /* Temporary token store.  */
-  cpp_token **temp_tokens;
-  unsigned int temp_cap;
-  unsigned int temp_alloced;
-  unsigned int temp_used;
-
   /* Date and time tokens.  Calculated together if either is requested.  */
-  cpp_token *date;
-  cpp_token *time;
-
-  /* The # of a the current directive. It may not be first in line if
-     we append, and finding it is tedious.  */
-  const cpp_token *first_directive_token;
-
-  /* Context stack.  Used for macro expansion and for determining
-     which macros are disabled.  */
-  unsigned int context_cap;
-  unsigned int cur_context;
-  unsigned int no_expand_level;
-  unsigned int paste_level;
-  struct cpp_context *contexts;
-
-  /* Current arguments when scanning arguments. Used for pointer
-     fix-up.  */
-  struct macro_args *args;
+  cpp_token date;
+  cpp_token time;
 
   /* Buffer of -M output.  */
   struct deps *deps;
@@ -572,17 +618,21 @@ struct cpp_reader
     void (*leave_file) PARAMS ((cpp_reader *));
     void (*rename_file) PARAMS ((cpp_reader *));
     void (*include) PARAMS ((cpp_reader *, const unsigned char *,
-                            const unsigned char *, unsigned int, int));
+                            const cpp_token *));
     void (*define) PARAMS ((cpp_reader *, cpp_hashnode *));
     void (*undef) PARAMS ((cpp_reader *, cpp_hashnode *));
     void (*poison) PARAMS ((cpp_reader *));
-    void (*ident) PARAMS ((cpp_reader *, const unsigned char *, unsigned int));
+    void (*ident) PARAMS ((cpp_reader *, const cpp_string *));
     void (*def_pragma) PARAMS ((cpp_reader *));
   } cb;
 
   /* User visible options.  */
   struct cpp_options opts;
 
+  /* Special nodes - identifiers with predefined significance to the
+     preprocessor.  */
+  struct spec_nodes spec_nodes;
+
   /* Nonzero means we have printed (while error reporting) a list of
      containing files that matches the current status.  */
   unsigned char input_stack_listing_current;
@@ -596,28 +646,6 @@ struct cpp_reader
 
   /* True if we are skipping a failed conditional group.  */
   unsigned char skipping;
-
-  /* True if we need to save parameter spellings - only if -pedantic,
-     or we might need to write out definitions.  */
-  unsigned char save_parameter_spellings;
-
-  /* True if output_line_command needs to output a newline.  */
-  unsigned char need_newline;
-
-  /* Special nodes - identifiers with predefined significance to the
-     preprocessor.  */
-  struct spec_nodes *spec_nodes;
-};
-
-/* struct cpp_printer encapsulates state used to convert the stream of
-   tokens coming from cpp_get_token back into a text file.  Not
-   everyone wants to do that, hence we separate the function.  */
-
-struct cpp_printer
-{
-  FILE *outf;                  /* stream to write to */
-  const char *last_fname;      /* previous file name */
-  unsigned int lineno;         /* line currently being written */
 };
 
 #define CPP_FATAL_LIMIT 1000
@@ -633,28 +661,41 @@ struct cpp_printer
 /* Name under which this program was invoked.  */
 extern const char *progname;
 
-/* The structure of a node in the hash table.  The hash table
-   has entries for all tokens defined by #define commands (type T_MACRO),
-   plus some special tokens like __LINE__ (these each have their own
-   type, and the appropriate code is run when that type of node is seen.
-   It does not contain control words like "#define", which are recognized
-   by a separate piece of code. */
-
-/* different flavors of hash nodes */
+/* The structure of a node in the hash table.  The hash table has
+   entries for all identifiers: either macros defined by #define
+   commands (type NT_MACRO), assertions created with #assert
+   (NT_ASSERTION), or neither of the above (NT_VOID).  Builtin macros
+   like __LINE__ are flagged NODE_BUILTIN.  Poisioned identifiers are
+   flagged NODE_POISONED.  NODE_OPERATOR (C++ only) indicates an
+   identifier that behaves like an operator such as "xor".
+   NODE_DIAGNOSTIC is for speed in lex_token: it indicates a
+   diagnostic may be required for this node.  Currently this only
+   applies to __VA_ARGS__ and poisoned identifiers.  */
+
+/* Hash node flags.  */
+#define NODE_OPERATOR  (1 << 0)        /* C++ named operator.  */
+#define NODE_POISONED  (1 << 1)        /* Poisoned identifier.  */
+#define NODE_BUILTIN   (1 << 2)        /* Builtin macro.  */
+#define NODE_DIAGNOSTIC (1 << 3)       /* Possible diagnostic when lexed.  */
+
+/* Different flavors of hash node.  */
 enum node_type
 {
-  T_VOID = 0,     /* no definition yet */
-  T_SPECLINE,     /* `__LINE__' */
-  T_DATE,         /* `__DATE__' */
-  T_FILE,         /* `__FILE__' */
-  T_BASE_FILE,    /* `__BASE_FILE__' */
-  T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
-  T_TIME,         /* `__TIME__' */
-  T_STDC,         /* `__STDC__' */
-  T_OPERATOR,     /* operator with a name; val.code is token type */
-  T_POISON,       /* poisoned identifier */
-  T_MACRO,        /* a macro, either object-like or function-like */
-  T_ASSERTION     /* predicate for #assert */
+  NT_VOID = 0,    /* No definition yet.  */
+  NT_MACRO,       /* A macro of some form.  */
+  NT_ASSERTION    /* Predicate for #assert.  */
+};
+
+/* Different flavors of builtin macro.  */
+enum builtin_type
+{
+  BT_SPECLINE = 0,             /* `__LINE__' */
+  BT_DATE,                     /* `__DATE__' */
+  BT_FILE,                     /* `__FILE__' */
+  BT_BASE_FILE,                        /* `__BASE_FILE__' */
+  BT_INCLUDE_LEVEL,            /* `__INCLUDE_LEVEL__' */
+  BT_TIME,                     /* `__TIME__' */
+  BT_STDC                      /* `__STDC__' */
 };
 
 /* There is a slot in the hashnode for use by front ends when integrated
@@ -665,47 +706,56 @@ union tree_node;
 
 struct cpp_hashnode
 {
+  const unsigned char *name;           /* null-terminated name */
   unsigned int hash;                   /* cached hash value */
-  unsigned short length;               /* length of name */
-  ENUM_BITFIELD(node_type) type : 8;   /* node type */
+  unsigned short length;               /* length of name excluding null */
+  unsigned short arg_index;            /* macro argument index */
+  unsigned char directive_index;       /* index into directive table.  */
+  ENUM_BITFIELD(node_type) type : 8;   /* node type.  */
+  unsigned char flags;                 /* node flags.  */
 
   union
   {
-    const cpp_toklist *expansion;      /* a macro's replacement list.  */
+    cpp_macro *macro;                  /* a macro.  */
     struct answer *answers;            /* answers to an assertion.  */
-    enum cpp_ttype code;               /* code for a named operator.  */
+    enum cpp_ttype operator;           /* code for a named operator.  */
+    enum builtin_type builtin;         /* code for a builtin macro.  */
   } value;
 
   union tree_node *fe_value;           /* front end value */
-
-  const unsigned char name[1];         /* name[length] */
 };
 
+extern unsigned int cpp_token_len PARAMS ((const cpp_token *));
+extern unsigned char *cpp_token_as_text PARAMS ((cpp_reader *, const cpp_token *));
+extern unsigned char *cpp_spell_token PARAMS ((cpp_reader *, const cpp_token *,
+                                              unsigned char *));
 extern void cpp_init PARAMS ((void));
 extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
 extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **));
 extern void cpp_reader_init PARAMS ((cpp_reader *));
-extern cpp_printer *cpp_printer_init PARAMS ((cpp_reader *, cpp_printer *));
 
 extern void cpp_register_pragma PARAMS ((cpp_reader *,
                                         const char *, const char *,
                                         void (*) PARAMS ((cpp_reader *))));
 extern void cpp_register_pragma_space PARAMS ((cpp_reader *, const char *));
 
-extern int cpp_start_read PARAMS ((cpp_reader *, cpp_printer *, const char *));
-extern void cpp_output_tokens PARAMS ((cpp_reader *, cpp_printer *,
-                                      unsigned int));
-extern void cpp_finish PARAMS ((cpp_reader *, cpp_printer *));
+extern int cpp_start_read PARAMS ((cpp_reader *, const char *));
+extern void cpp_finish PARAMS ((cpp_reader *));
 extern void cpp_cleanup PARAMS ((cpp_reader *));
-
-extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *));
+extern int cpp_avoid_paste PARAMS ((cpp_reader *, const cpp_token *,
+                                   const cpp_token *));
+extern enum cpp_ttype cpp_can_paste PARAMS ((cpp_reader *, const cpp_token *,
+                                            const cpp_token *, int *));
+extern void cpp_get_token PARAMS ((cpp_reader *, cpp_token *));
+extern const cpp_lexer_pos *cpp_get_line PARAMS ((cpp_reader *));
+extern const unsigned char *cpp_macro_definition PARAMS ((cpp_reader *,
+                                                 const cpp_hashnode *));
 
 extern void cpp_define PARAMS ((cpp_reader *, const char *));
 extern void cpp_assert PARAMS ((cpp_reader *, const char *));
 extern void cpp_undef  PARAMS ((cpp_reader *, const char *));
 extern void cpp_unassert PARAMS ((cpp_reader *, const char *));
 
-extern void cpp_free_token_list PARAMS ((cpp_toklist *));
 extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
                                            const unsigned char *, long));
 extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *));
@@ -740,32 +790,23 @@ extern void cpp_pedwarn_with_file_and_line PARAMS ((cpp_reader *, const char *,
 extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *));
 extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *));
 
-extern const char *cpp_type2name PARAMS ((enum cpp_ttype));
-
 /* In cpplex.c */
-extern cpp_buffer *cpp_push_buffer     PARAMS ((cpp_reader *,
-                                                const unsigned char *, long));
-extern cpp_buffer *cpp_pop_buffer      PARAMS ((cpp_reader *));
-extern void cpp_scan_buffer            PARAMS ((cpp_reader *, cpp_printer *));
-extern void cpp_scan_buffer_nooutput   PARAMS ((cpp_reader *));
 extern int cpp_ideq                    PARAMS ((const cpp_token *,
                                                 const char *));
-extern void cpp_printf                 PARAMS ((cpp_reader *, cpp_printer *,
-                                                const char *, ...));
-
-extern void cpp_output_list            PARAMS ((cpp_reader *, FILE *,
-                                                const cpp_toklist *,
-                                                const cpp_token *));
+extern void cpp_output_line            PARAMS ((cpp_reader *, FILE *));
+extern void cpp_output_token           PARAMS ((const cpp_token *, FILE *));
+extern const char *cpp_type2name       PARAMS ((enum cpp_ttype));
 
 /* In cpphash.c */
-extern cpp_hashnode *cpp_lookup        PARAMS ((cpp_reader *,
-                                        const unsigned char *, size_t));
-extern void cpp_forall_identifiers PARAMS ((cpp_reader *,
-                                           int (*) PARAMS ((cpp_reader *,
-                                                            cpp_hashnode *))));
+extern cpp_hashnode *cpp_lookup                PARAMS ((cpp_reader *,
+                                                const unsigned char *, size_t));
+extern void cpp_forall_identifiers     PARAMS ((cpp_reader *,
+                                                int (*) PARAMS ((cpp_reader *,
+                                                                 cpp_hashnode *))));
 /* In cppmacro.c */
-extern void cpp_dump_definition PARAMS ((cpp_reader *, FILE *,
-                                        const cpp_hashnode *));
+extern void cpp_scan_buffer_nooutput   PARAMS ((cpp_reader *));
+extern void cpp_start_lookahead                PARAMS ((cpp_reader *));
+extern void cpp_stop_lookahead         PARAMS ((cpp_reader *, int));
 
 /* In cppfiles.c */
 extern int cpp_included        PARAMS ((cpp_reader *, const char *));
@@ -773,6 +814,64 @@ extern int cpp_read_file PARAMS ((cpp_reader *, const char *));
 extern void cpp_make_system_header PARAMS ((cpp_reader *, cpp_buffer *, int));
 extern const char *cpp_syshdr_flags PARAMS ((cpp_reader *, cpp_buffer *));
 
+/* These are inline functions instead of macros so we can get type
+   checking.  */
+typedef unsigned char U_CHAR;
+#define U (const U_CHAR *)  /* Intended use: U"string" */
+
+static inline int ustrcmp      PARAMS ((const U_CHAR *, const U_CHAR *));
+static inline int ustrncmp     PARAMS ((const U_CHAR *, const U_CHAR *,
+                                        size_t));
+static inline size_t ustrlen   PARAMS ((const U_CHAR *));
+static inline U_CHAR *uxstrdup PARAMS ((const U_CHAR *));
+static inline U_CHAR *ustrchr  PARAMS ((const U_CHAR *, int));
+static inline int ufputs       PARAMS ((const U_CHAR *, FILE *));
+
+static inline int
+ustrcmp (s1, s2)
+     const U_CHAR *s1, *s2;
+{
+  return strcmp ((const char *)s1, (const char *)s2);
+}
+
+static inline int
+ustrncmp (s1, s2, n)
+     const U_CHAR *s1, *s2;
+     size_t n;
+{
+  return strncmp ((const char *)s1, (const char *)s2, n);
+}
+
+static inline size_t
+ustrlen (s1)
+     const U_CHAR *s1;
+{
+  return strlen ((const char *)s1);
+}
+
+static inline U_CHAR *
+uxstrdup (s1)
+     const U_CHAR *s1;
+{
+  return (U_CHAR *) xstrdup ((const char *)s1);
+}
+
+static inline U_CHAR *
+ustrchr (s1, c)
+     const U_CHAR *s1;
+     int c;
+{
+  return (U_CHAR *) strchr ((const char *)s1, c);
+}
+
+static inline int
+ufputs (s, f)
+     const U_CHAR *s;
+     FILE *f;
+{
+  return fputs ((const char *)s, f);
+}
+
 #ifdef __cplusplus
 }
 #endif
index 321b318..58d3020 100644 (file)
@@ -1,4 +1,4 @@
-/* Part of CPP library.  (Macro handling.)
+/* Part of CPP library.  (Macro and #define handling.)
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
    1999, 2000 Free Software Foundation, Inc.
    Written by Per Bothner, 1994.
@@ -25,573 +25,1521 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 #include "config.h"
 #include "system.h"
+#include "intl.h"              /* for _("<command line>") below.  */
 #include "cpplib.h"
 #include "cpphash.h"
 
-/* Stores basic information about a macro, before it is allocated.  */
-struct macro_info
+struct cpp_macro
 {
-  const cpp_token *first_param;        /* First parameter token.  */
-  const cpp_token *first;      /* First expansion token.  */
-  unsigned int paramlen;       /* Length of parameter names. */
-  unsigned int len;            /* Length of token strings.  */
-  unsigned int ntokens;                /* Number of tokens in expansion.  */
-  short paramc;                        /* Number of parameters.  */
-  unsigned char flags;
+  cpp_hashnode **params;       /* Parameters, if any.  */
+  cpp_token *expansion;                /* First token of replacement list.   */
+  const char *file;            /* Defined in file name.  */
+  unsigned int line;           /* Starting line number.  */
+  unsigned int count;          /* Number of tokens in expansion.  */
+  unsigned short paramc;       /* Number of parameters.  */
+  unsigned int fun_like : 1;   /* If a function-like macro.  */
+  unsigned int var_args : 1;   /* If a variable-args macro.  */
+  unsigned int disabled : 1;   /* If macro is disabled.  */
+};
+
+typedef struct macro_arg macro_arg;
+struct macro_arg
+{
+  cpp_token *first;            /* First token in unexpanded argument.  */
+  cpp_token *expanded;         /* Macro-expanded argument.   */
+  cpp_token *stringified;      /* Stringified argument.  */
+  unsigned int count;          /* # of tokens in argument.  */
+  unsigned int expanded_count; /* # of tokens in expanded argument.  */
 };
 
-static void count_params PARAMS ((cpp_reader *, struct macro_info *));
-static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
-
-static int parse_define PARAMS((cpp_reader *, struct macro_info *));
-static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
-                                           const cpp_toklist *));
-static const cpp_toklist * save_expansion PARAMS((cpp_reader *,
-                                                 struct macro_info *));
-static unsigned int find_param PARAMS ((const cpp_token *,
-                                       const cpp_token *));
-static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *));
+/* Macro expansion.  */
+
+static void lock_pools PARAMS ((cpp_reader *));
+static void unlock_pools PARAMS ((cpp_reader *));
+static int enter_macro_context PARAMS ((cpp_reader *, cpp_token *));
+static void builtin_macro PARAMS ((cpp_reader *, cpp_token *));
+static cpp_context *push_arg_context PARAMS ((cpp_reader *, macro_arg *));
+static enum cpp_ttype parse_arg PARAMS ((cpp_reader *, macro_arg *, int));
+static macro_arg *parse_args PARAMS ((cpp_reader *, const cpp_hashnode *));
+static cpp_context *next_context PARAMS ((cpp_reader *));
+static void expand_arg PARAMS ((cpp_reader *, macro_arg *));
+static unsigned char *quote_string PARAMS ((unsigned char *,
+                                           const unsigned char *,
+                                           unsigned int));
+static void make_string_token PARAMS ((cpp_pool *, cpp_token *,
+                                      const U_CHAR *, unsigned int));
+static void make_number_token PARAMS ((cpp_reader *, cpp_token *, int));
+static void stringify_arg PARAMS ((cpp_reader *, macro_arg *));
+static void paste_all_tokens PARAMS ((cpp_reader *, cpp_token *));
+static void paste_payloads PARAMS ((cpp_reader *, cpp_token *,
+                                   const cpp_token *));
+static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *,
+                                         struct toklist *));
+static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *,
+                                 struct toklist *));
+
+/* Lookaheads.  */
+
+static void save_lookahead_token PARAMS ((cpp_reader *, const cpp_token *));
+static void take_lookahead_token PARAMS ((cpp_reader *, cpp_token *));
+static void release_lookahead PARAMS ((cpp_reader *));
+static cpp_lookahead *alloc_lookahead PARAMS ((cpp_reader *));
+static void free_lookahead PARAMS ((cpp_lookahead *));
+
+/* #define directive parsing and handling.  */
+
+static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
+static int check_macro_redefinition PARAMS ((cpp_reader *,
+                                            const cpp_hashnode *,
+                                            const cpp_macro *));
+static int save_parameter PARAMS ((cpp_reader *, cpp_macro *, cpp_hashnode *));
+static int parse_params PARAMS ((cpp_reader *, cpp_macro *));
 static void check_trad_stringification PARAMS ((cpp_reader *,
-                                               const struct macro_info *,
+                                               const cpp_macro *,
                                                const cpp_string *));
 
-/* These are all the tokens that can have something pasted after them.
-   Comma is included in the list only to support the GNU varargs extension
-   (where you write a ## b and a disappears if b is an empty rest argument).
-   CPP_OTHER is included because of Objective C's use of '@'.  */
-#define CAN_PASTE_AFTER(type) \
-((type) <= CPP_LAST_EQ || (type) == CPP_COLON || (type) == CPP_HASH \
- || (type) == CPP_DEREF || (type) == CPP_DOT || (type) == CPP_NAME \
- || (type) == CPP_INT || (type) == CPP_FLOAT || (type) == CPP_NUMBER \
- || (type) == CPP_MACRO_ARG || (type) == CPP_PLACEMARKER \
- || (type) == CPP_COMMA || (type) == CPP_OTHER)
-
-/* Scans for a given token, returning the parameter number if found,
-   or 0 if not found.  Scans from FIRST to TOKEN - 1 or the first
-   CPP_CLOSE_PAREN for TOKEN.  */
-static unsigned int
-find_param (first, token)
-     const cpp_token *first, *token;
-{
-  unsigned int param = 0;
-
-  for (; first < token && first->type != CPP_CLOSE_PAREN; first++)
-    if (first->type == CPP_NAME || first->type == CPP_DEFINED)
+/* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a
+   CPP_STRING token containing TEXT in quoted form.  */
+static void
+make_string_token (pool, token, text, len)
+     cpp_pool *pool;
+     cpp_token *token;
+     const U_CHAR *text;
+     unsigned int len;
+{
+  U_CHAR *buf = _cpp_pool_alloc (pool, len * 4);
+
+  token->type = CPP_STRING;
+  token->val.str.text = buf;
+  token->val.str.len = quote_string (buf, text, len) - buf;
+  token->flags = 0;
+}
+
+/* Allocates and converts a temporary token to a CPP_NUMBER token,
+   evaluating to NUMBER.  */
+static void
+make_number_token (pfile, token, number)
+     cpp_reader *pfile;
+     cpp_token *token;
+     int number;
+{
+  unsigned char *buf = _cpp_pool_alloc (pfile->string_pool, 20);
+
+  sprintf ((char *) buf, "%d", number);
+  token->type = CPP_NUMBER;
+  token->val.str.text = buf;
+  token->val.str.len = ustrlen (buf);
+  token->flags = 0;
+}
+
+static const char * const monthnames[] =
+{
+  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/* Handle builtin macros like __FILE__.  */
+static void
+builtin_macro (pfile, token)
+     cpp_reader *pfile;
+     cpp_token *token;
+{
+  unsigned char flags = token->flags & PREV_WHITE;
+  cpp_hashnode *node = token->val.node;
+  cpp_buffer *ip;
+
+  switch (node->value.builtin)
+    {
+    case BT_FILE:
+    case BT_BASE_FILE:
       {
-       param++;
-       if (first->val.node == token->val.node)
-         return param;
+       const char *file;
+
+       ip = CPP_BUFFER (pfile);
+       if (ip == 0)
+         file = "";
+       else
+         {
+           if (node->value.builtin == BT_BASE_FILE)
+             while (CPP_PREV_BUFFER (ip) != NULL)
+               ip = CPP_PREV_BUFFER (ip);
+
+           file = ip->nominal_fname;
+         }
+       make_string_token (pfile->string_pool, token,
+                          (U_CHAR *) file, strlen (file));
       }
+      break;
+       
+    case BT_INCLUDE_LEVEL:
+      /* pfile->include_depth counts the primary source as level 1,
+        but historically __INCLUDE_DEPTH__ has called the primary
+        source level 0.  */
+      make_number_token (pfile, token, pfile->include_depth - 1);
+      break;
+
+    case BT_SPECLINE:
+      /* If __LINE__ is embedded in a macro, it must expand to the
+        line of the macro's invocation, not its definition.
+        Otherwise things like assert() will not work properly.  */
+      make_number_token (pfile, token, cpp_get_line (pfile)->line);
+      break;
+
+    case BT_STDC:
+      {
+       int stdc = 1;
+
+#ifdef STDC_0_IN_SYSTEM_HEADERS
+       if (CPP_IN_SYSTEM_HEADER (pfile)
+           && pfile->spec_nodes.n__STRICT_ANSI__->type == T_VOID)
+         stdc = 0;
+#endif
+       make_number_token (pfile, token, stdc);
+      }
+      break;
 
-  return 0;
+    case BT_DATE:
+    case BT_TIME:
+      if (pfile->date.type == CPP_EOF)
+       {
+         /* Allocate __DATE__ and __TIME__ from permanent storage,
+            and save them in pfile so we don't have to do this again.
+            We don't generate these strings at init time because
+            time() and localtime() are very slow on some systems.  */
+         time_t tt = time (NULL);
+         struct tm *tb = localtime (&tt);
+
+         make_string_token (&pfile->ident_pool, &pfile->date,
+                            DSC("Oct 11 1347"));
+         make_string_token (&pfile->ident_pool, &pfile->time,
+                            DSC("12:34:56"));
+
+         sprintf ((char *) pfile->date.val.str.text, "%s %2d %4d",
+                  monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
+         sprintf ((char *) pfile->time.val.str.text, "%02d:%02d:%02d",
+                  tb->tm_hour, tb->tm_min, tb->tm_sec);
+       }
+      *token = node->value.builtin == BT_DATE ? pfile->date: pfile->time;
+      break;
+
+    default:
+      cpp_ice (pfile, "invalid builtin macro \"%s\"", node->name);
+      break;
+    }
+
+  token->flags = flags;
 }
 
-/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
-   replacement list of a variable-arguments macro.  TOKEN is assumed
-   to be of type CPP_NAME.  */
-static int
-is__va_args__ (pfile, token)
+/* Used by cpperror.c to obtain the correct line and column to report
+   in a diagnostic.  */
+const cpp_lexer_pos *
+cpp_get_line (pfile)
      cpp_reader *pfile;
-     const cpp_token *token;
 {
-  if (!CPP_PEDANTIC (pfile)
-      || token->val.node != pfile->spec_nodes->n__VA_ARGS__)
-    return 0;
+  /* Within a macro expansion, return the position of the outermost
+     invocation.  */
+  if (pfile->context->prev)
+    return &pfile->macro_pos;
+  return &pfile->lexer_pos;
+}
 
-  cpp_pedwarn_with_line (pfile, token->line, token->col,
-       "\"%s\" is only valid in the replacement list of a function-like macro",
-                      token->val.node->name);
-  return 1;
+static void
+lock_pools (pfile)
+     cpp_reader *pfile;
+{
+  _cpp_lock_pool (&pfile->temp_string_pool);
+  _cpp_lock_pool (&pfile->argument_pool);
 }
 
-/* Counts the parameters to a function-like macro, the length of their
-   null-terminated names, and whether the macro is a variable-argument
-   one.  FIRST is the token immediately after the open parenthesis,
-   INFO stores the data.
+static void
+unlock_pools (pfile)
+     cpp_reader *pfile;
+{
+  _cpp_unlock_pool (&pfile->temp_string_pool);
+  _cpp_unlock_pool (&pfile->argument_pool);
+}
 
-   On success, info->first is updated to the token after the closing
-   parenthesis, i.e. the first token of the expansion.  Otherwise
-   there was an error, which has been reported.  */
 static void
-count_params (pfile, info)
+paste_payloads (pfile, lhs, rhs)
      cpp_reader *pfile;
-     struct macro_info *info;
+     cpp_token *lhs;
+     const cpp_token *rhs;
 {
-  unsigned int prev_ident = 0;
-  const cpp_token *token;
+  unsigned int total_len = cpp_token_len (lhs) + cpp_token_len (rhs);
+  unsigned char *result, *end;
+  cpp_pool *pool;
+
+  pool = lhs->type == CPP_NAME ? &pfile->ident_pool: pfile->string_pool;
+  result = _cpp_pool_alloc (pool, total_len + 1);
 
-  info->paramc = 0;
-  info->paramlen = 0;
-  info->flags = 0;
-  info->first = info->first_param; /* Not a ')' indicating success.  */
+  /* Paste the spellings and null terminate.  */
+  end = cpp_spell_token (pfile, rhs, cpp_spell_token (pfile, lhs, result));
+  *end = '\0';
+  total_len = end - result;
 
-  for (token = info->first_param;; token++)
+  if (lhs->type == CPP_NAME)
     {
-      switch (token->type)
+      lhs->val.node = cpp_lookup (pfile, result, total_len);
+      if (lhs->val.node->flags & NODE_OPERATOR)
        {
-       default:
-         cpp_error_with_line (pfile, token->line, token->col,
-                              "token may not appear in macro parameter list");
-         return;
-
-       case CPP_EOF:
-       missing_paren:
-         cpp_error_with_line (pfile, token->line, token->col,
-                              "missing ')' in macro parameter list");
-         return;
+         lhs->flags |= NAMED_OP;
+         lhs->type = lhs->val.node->value.operator;
+       }
+    }
+  else
+    {
+      lhs->val.str.text = result;
+      lhs->val.str.len = total_len;
+    }
+}
 
-       case CPP_COMMENT:
-         continue;             /* Ignore -C comments.  */
+/* Adds backslashes before all backslashes and double quotes appearing
+   in strings.  Non-printable characters are converted to octal.  */
+static U_CHAR *
+quote_string (dest, src, len)
+     U_CHAR *dest;
+     const U_CHAR *src;
+     unsigned int len;
+{
+  while (len--)
+    {
+      U_CHAR c = *src++;
 
-       case CPP_DEFINED:       /* 'defined' may be used as a macro
-                                  parameter name.  */
-       case CPP_NAME:
-         if (prev_ident)
+      if (c == '\\' || c == '"')
+       {
+         *dest++ = '\\';
+         *dest++ = c;
+       }
+      else
+       {
+         if (ISPRINT (c))
+           *dest++ = c;
+         else
            {
-             cpp_error_with_line (pfile, token->line, token->col,
-                          "macro parameters must be comma-separated");
-             return;
+             sprintf ((char *) dest, "\\%03o", c);
+             dest += 4;
            }
+       }
+    }
 
-         /* Constraint 6.10.3.5  */
-         if (is__va_args__ (pfile, token))
-           return;
+  return dest;
+}
 
-         /* Constraint 6.10.3.6 - duplicate parameter names.  */
-         if (find_param (info->first, token))
-           {
-             cpp_error_with_line (pfile, token->line, token->col,
-                                  "duplicate macro parameter \"%s\"",
-                                  token->val.node->name);
-             return;
-           }
+/* Convert a token sequence to a single string token according to the
+   rules of the ISO C #-operator.  */
+static void
+stringify_arg (pfile, arg)
+     cpp_reader *pfile;
+     macro_arg *arg;
+{
+  cpp_pool *pool = pfile->string_pool;
+  unsigned char *start = POOL_FRONT (pool);
+  unsigned int i, escape_it, total_len = 0, backslash_count = 0;
+  unsigned int prev_white = 0;
 
-         prev_ident = 1;
-         info->paramc++;
-         info->paramlen += token->val.node->length + 1;
-         continue;
+  /* Loop, reading in the argument's tokens.  */
+  for (i = 0; i < arg->count; i++)
+    {
+      unsigned char *dest;
+      const cpp_token *token = &arg->first[i];
+      unsigned int len = cpp_token_len (token);
 
-       case CPP_CLOSE_PAREN:
-         if (prev_ident || info->paramc == 0)
-           break;
+      escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
+                  || token->type == CPP_CHAR || token->type == CPP_WCHAR
+                  || token->type == CPP_OSTRING);
 
-         /* Fall through to pick up the error.  */
-       case CPP_COMMA:
-         if (!prev_ident)
-           {
-             cpp_error_with_line (pfile, token->line, token->col,
-                                  "parameter name expected");
-             return;
-           }
-         prev_ident = 0;
-         continue;
+      if (escape_it)
+       /* Worst case is each char is octal.  */
+       len *= 4;
+      len++;                   /* Room for initial space.  */
 
-       case CPP_ELLIPSIS:
-         /* Convert ISO-style var_args to named varargs by changing
-            the ellipsis into an identifier with name __VA_ARGS__.
-            This simplifies other handling. */
-         if (!prev_ident)
-           {
-             cpp_token *tok = (cpp_token *) token;
+      dest = &start[total_len];
+      if (dest + len > POOL_LIMIT (pool))
+       {
+         _cpp_next_chunk (pool, len, (unsigned char **) &start);
+         dest = &start[total_len];
+       }
 
-             tok->type = CPP_NAME;
-             tok->val.node = pfile->spec_nodes->n__VA_ARGS__;
+      prev_white |= token->flags & PREV_WHITE;
+      if (token->type == CPP_PLACEMARKER)
+       continue;
 
-             info->paramc++;
-             info->paramlen += tok->val.node->length + 1;
+      /* No leading white space.  */
+      if (prev_white)
+       {
+         prev_white = 0;
+         if (total_len > 0)
+           *dest++ = ' ';
+       }
 
-             if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
-               cpp_pedwarn (pfile,
-                            "C89 does not permit anon varargs macros");
-           }
-         else
+      if (escape_it)
+       {
+         unsigned char *buf = (unsigned char *) xmalloc (len);
+
+         len = cpp_spell_token (pfile, token, buf) - buf;
+         dest = quote_string (dest, buf, len);
+         free (buf);
+       }
+      else
+       dest = cpp_spell_token (pfile, token, dest);
+      total_len = dest - start;
+
+      if (token->type == CPP_BACKSLASH)
+       backslash_count++;
+      else
+       backslash_count = 0;
+    }
+
+  /* Ignore the final \ of invalid string literals.  */
+  if (backslash_count & 1)
+    {
+      cpp_warning (pfile, "invalid string literal, ignoring final '\\'");
+      total_len--;
+    }
+
+  POOL_COMMIT (pool, total_len);
+
+  arg->stringified = xnew (cpp_token);
+  arg->stringified->flags = 0;
+  arg->stringified->type = CPP_STRING;
+  arg->stringified->val.str.text = start;
+  arg->stringified->val.str.len = total_len;
+}
+
+/* Handles an arbitrarily long sequence of ## operators.  This
+   implementation is left-associative, non-recursive, and finishes a
+   paste before handling succeeding ones.  If the paste fails, the
+   right hand side of the ## operator is placed in the then-current
+   context's lookahead buffer, with the effect that it appears in the
+   output stream normally.  */
+static void
+paste_all_tokens (pfile, lhs)
+     cpp_reader *pfile;
+     cpp_token *lhs;
+{
+  unsigned char orig_flags = lhs->flags;
+  cpp_token *rhs;
+
+  do
+    {
+      /* Take the token directly from the current context.  We can do
+        this, because we are in the replacement list of either an
+        object-like macro, or a function-like macro with arguments
+        inserted.  In either case, the constraints to #define
+        guarantee we have at least one more token (empty arguments
+        become placemarkers).  */
+      rhs = pfile->context->list.first++;
+
+      if (rhs->type == CPP_PLACEMARKER)
+       {
+         /* GCC has special extended semantics for , ## b where b is
+            a varargs parameter: the comma disappears if b was given
+            no actual arguments (not merely if b is an empty
+            argument).  */
+         if (lhs->type == CPP_COMMA && (rhs->flags & VARARGS_FIRST))
+           lhs->type = CPP_PLACEMARKER;
+       }
+      else if (lhs->type == CPP_PLACEMARKER)
+       *lhs = *rhs;
+      else
+       {
+         int digraph = 0;
+         enum cpp_ttype type = cpp_can_paste (pfile, lhs, rhs, &digraph);
+
+         if (type == CPP_EOF)
            {
-             if (CPP_PEDANTIC (pfile))
-               cpp_pedwarn (pfile,
-                            "ISO C does not permit named varargs parameters");
+             /* Do nothing special about , ## <whatever> if
+                <whatever> came from a variable argument, because the
+                author probably intended the ## to trigger the
+                special extended semantics (see above).  */
+             if (lhs->type == CPP_COMMA && (rhs->flags & VARARGS_FIRST))
+               /* nothing */;
+             else
+               {
+                 if (CPP_OPTION (pfile, warn_paste))
+                   cpp_warning (pfile,
+                "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
+                                cpp_token_as_text (pfile, lhs),
+                                cpp_token_as_text (pfile, rhs));
+
+                 /* The standard states that behaviour is undefined.
+                    By the principle of least surpise, we step back
+                    before the RHS, and mark it to prevent macro
+                    expansion.  Tests in the testsuite rely on
+                    clearing PREV_WHITE here, though you could argue
+                    we should actually set it.  */
+                 rhs->flags &= ~PREV_WHITE;
+                 rhs->flags |= NO_EXPAND;
+               }
+
+             /* Step back so we read the RHS in next.  */
+             pfile->context->list.first--;
+             break;
            }
 
-         info->flags |= VAR_ARGS;
-         token++;
-         if (token->type == CPP_CLOSE_PAREN)
-           break;
-         goto missing_paren;
+         lhs->type = type;
+         lhs->flags &= ~DIGRAPH;
+         if (digraph)
+           lhs->flags |= DIGRAPH;
+
+         if (type == CPP_NAME || type == CPP_NUMBER)
+           paste_payloads (pfile, lhs, rhs);
+         else if (type == CPP_WCHAR || type == CPP_WSTRING)
+           lhs->val.str = rhs->val.str;
+       }
+    }
+  while (rhs->flags & PASTE_LEFT);
+
+  /* The pasted token has the PREV_WHITE flag of the LHS, is no longer
+     PASTE_LEFT, and is subject to macro expansion.  */
+  lhs->flags &= ~(PREV_WHITE | PASTE_LEFT | NO_EXPAND);
+  lhs->flags |= orig_flags & PREV_WHITE;
+}
+
+/* Reads the unexpanded tokens of a macro argument into ARG.  Empty
+   arguments are saved as a single CPP_PLACEMARKER token.  VAR_ARGS is
+   non-zero if this is a variable argument.  Returns the type of the
+   token that caused reading to finish.  */
+static enum cpp_ttype
+parse_arg (pfile, arg, var_args)
+     cpp_reader *pfile;
+     struct macro_arg *arg;
+     int var_args;
+{
+  enum cpp_ttype result;
+  unsigned int paren = 0;
+
+  arg->first = (cpp_token *) POOL_FRONT (&pfile->argument_pool);
+  for (;; arg->count++)
+    {
+      cpp_token *token = &arg->first[arg->count];
+      if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->argument_pool))
+       {
+         _cpp_next_chunk (&pfile->argument_pool, sizeof (cpp_token),
+                          (unsigned char **) &arg->first);
+         token = &arg->first[arg->count];
+       }
+
+      _cpp_get_token (pfile, token);
+      result = token->type;
+
+      if (result == CPP_OPEN_PAREN)
+       paren++;
+      else if (result == CPP_CLOSE_PAREN && paren-- == 0)
+       break;
+      /* Commas are not terminators within parantheses or var_args.  */
+      else if (result == CPP_COMMA && paren == 0 && !var_args)
+       break;
+      else if (result == CPP_EOF)
+       break;          /* Error reported by caller.  */
+      else if (result == CPP_DHASH)
+       {
+         /* 6.10.3 paragraph 11: If there are sequences of
+            preprocessing tokens within the list of arguments that
+            would otherwise act as preprocessing directives, the
+            behavior is undefined.
+
+            This implementation will report a hard error, terminate
+            the macro invocation, and proceed to process the
+            directive.  */
+         cpp_error (pfile, "directives may not be used inside a macro argument");
+         _cpp_push_token (pfile, token, &pfile->lexer_pos);
+         result = CPP_EOF;
+         break;
        }
+    }
 
-      /* Success.  */
-      info->first = token + 1;
-      if (!pfile->save_parameter_spellings)
-       info->paramlen = 0;
-      return;
+  /* Empty arguments become a single placemarker token.  */
+  if (arg->count == 0)
+    {
+      arg->first->type = CPP_PLACEMARKER;
+      arg->count = 1;
     }
+
+  /* Commit the memory used to store the arguments.  */
+  POOL_COMMIT (&pfile->argument_pool, arg->count * sizeof (cpp_token));
+
+  return result;
 }
 
-/* Parses a #define directive.  On success, returns zero, and INFO is
-   filled in appropriately.  */
+/* Parse the arguments making up a macro invocation.  */
+static macro_arg *
+parse_args (pfile, node)
+     cpp_reader *pfile;
+     const cpp_hashnode *node;
+{
+  cpp_macro *macro = node->value.macro;
+  macro_arg *args, *cur;
+  enum cpp_ttype type;
+  int argc, error = 0;
+
+  /* Allocate room for at least one argument, and zero it out.  */
+  argc = macro->paramc ? macro->paramc: 1;
+  args = xcnewvec (macro_arg, argc);
+
+  for (cur = args, argc = 0; ;)
+    {
+      argc++;
+
+      type = parse_arg (pfile, cur, argc == macro->paramc && macro->var_args);
+      if (type == CPP_CLOSE_PAREN || type == CPP_EOF)
+       break;
+
+      /* Re-use the last argument for excess arguments.  */
+      if (argc < macro->paramc)
+       cur++;
+    }
+
+  if (type == CPP_EOF)
+    {
+      cpp_error (pfile, "unterminated argument list invoking macro \"%s\"",
+                node->name);
+      error = 1;
+    }
+  else if (argc < macro->paramc)
+    {
+      /* As an extension, a rest argument is allowed to not appear in
+        the invocation at all.
+        e.g. #define debug(format, args...) something
+        debug("string");
+        
+        This is exactly the same as if there had been an empty rest
+        argument - debug("string", ).  */
+
+      if (argc + 1 == macro->paramc && macro->var_args)
+       {
+         /* parse_arg ensured there was space for the closing
+            parenthesis.  Use this space to store a placemarker.  */
+         args[argc].first = (cpp_token *) POOL_FRONT (&pfile->argument_pool);
+         args[argc].first->type = CPP_PLACEMARKER;
+         args[argc].count = 1;
+         POOL_COMMIT (&pfile->argument_pool, sizeof (cpp_token));
+
+         if (CPP_OPTION (pfile, c99) && CPP_PEDANTIC (pfile))
+           cpp_pedwarn (pfile, "ISO C99 requires rest arguments to be used");
+       }
+      else
+       {
+         cpp_error (pfile,
+                    "macro \"%s\" requires %u arguments, but only %u given",
+                    node->name, macro->paramc, argc);
+         error = 1;
+       }
+    }
+  else if (argc > macro->paramc)
+    {
+      /* An empty argument to an empty function-like macro is fine.  */
+      if (argc != 1 || args[0].first->type != CPP_PLACEMARKER)
+       {
+         cpp_error (pfile,
+                    "macro \"%s\" passed %u arguments, but takes just %u",
+                    node->name, argc, macro->paramc);
+         error = 1;
+       }
+    }
+
+  if (error)
+    {
+      free (args);
+      args = 0;
+    }
+
+  return args;
+}
+
+static int
+funlike_invocation_p (pfile, node, list)
+     cpp_reader *pfile;
+     const cpp_hashnode *node;
+     struct toklist *list;
+{
+  cpp_context *orig_context;
+  cpp_token maybe_paren;
+  macro_arg *args = 0;
+
+  pfile->state.parsing_args = 1;
+  pfile->state.prevent_expansion++;
+  orig_context = pfile->context;
+
+  cpp_start_lookahead (pfile);
+  cpp_get_token (pfile, &maybe_paren);
+  cpp_stop_lookahead (pfile, maybe_paren.type == CPP_OPEN_PAREN);
+
+  if (maybe_paren.type == CPP_OPEN_PAREN)
+    args = parse_args (pfile, node);
+  else if (CPP_WTRADITIONAL (pfile))
+    cpp_warning (pfile,
+        "function-like macro \"%s\" must be used with arguments in traditional C",
+                node->name);
+
+  /* Restore original context.  */
+  pfile->context = orig_context;
+  pfile->state.prevent_expansion--;
+  pfile->state.parsing_args = 0;
+
+  if (args)
+    {
+      if (node->value.macro->paramc > 0)
+       replace_args (pfile, node->value.macro, args, list);
+      free (args);
+    }
+
+  return args != 0;
+}
+
+/* Push the context of a macro onto the context stack.  TOKEN is the
+   macro name.  If we can successfully start expanding the macro,
+   TOKEN is replaced with the first token of the expansion.  */
 static int
-parse_define (pfile, info)
+enter_macro_context (pfile, token)
      cpp_reader *pfile;
-     struct macro_info *info;
+     cpp_token *token;
 {
-  const cpp_token *token;
-  int prev_white = 0;
+  cpp_context *context;
+  cpp_macro *macro;
+  unsigned char flags;
+  struct toklist list;
 
-  /* The first token after the macro's name.  */
-  token = _cpp_get_token (pfile);
+  macro = token->val.node->value.macro;
+  if (macro->disabled)
+    {
+      token->flags |= NO_EXPAND;
+      return 1;
+    }
 
-  /* Constraint 6.10.3.5  */
-  if (is__va_args__ (pfile, token - 1))
-    return 1;
+  /* Save the position of the outermost macro invocation.  */
+  if (!pfile->context->prev)
+    {
+      pfile->macro_pos = pfile->lexer_pos;
+      lock_pools (pfile);
+    }
 
-  while (token->type == CPP_COMMENT)
-    token++, prev_white = 1;
-  prev_white |= token->flags & PREV_WHITE;
+  if (macro->fun_like && !funlike_invocation_p (pfile, token->val.node, &list))
+    {
+      if (!pfile->context->prev)
+       unlock_pools (pfile);
+      return 1;
+    }
 
-  if (token->type == CPP_OPEN_PAREN && !prev_white)
+  /* Now push its context.  */
+  context = next_context (pfile);
+  if (macro->paramc == 0)
     {
-      /* A function-like macro.  */
-      info->first_param = token + 1;
-      count_params (pfile, info);
-      if (info->first[-1].type != CPP_CLOSE_PAREN)
-       return 1;
+      context->list.first = macro->expansion;
+      context->list.limit = macro->expansion + macro->count;
     }
   else
+    context->list = list;
+  context->macro = macro;
+
+  /* The first expansion token inherits the PREV_WHITE of TOKEN.  */
+  flags = token->flags & PREV_WHITE;
+  *token = *context->list.first++;
+  token->flags |= flags;
+
+  /* Disable the macro within its expansion.  */
+  macro->disabled = 1;
+
+  return 0;
+}
+
+/* Move to the next context.  Create one if there is none.  */
+static cpp_context *
+next_context (pfile)
+     cpp_reader *pfile;
+{
+  cpp_context *prev = pfile->context;
+  cpp_context *result = prev->next;
+
+  if (result == 0)
     {
-      /* An object-like macro.  */
-      info->paramc = -1;
-      info->paramlen = 0;
-      info->flags = 0;
-      info->first = token;
-      if (!prev_white && token->type != CPP_EOF)
-       cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
+      result = xnew (cpp_context);
+      prev->next = result;
+      result->prev = prev;
+      result->next = 0;
     }
 
-  /* Count tokens in expansion.  We drop paste tokens, and stringize
-     tokens, so don't count them.  */
-  info->ntokens = info->len = 0;
-  for (token = info->first; token->type != CPP_EOF; token++)
+  pfile->context = result;
+  return result;
+}
+
+static void
+replace_args (pfile, macro, args, list)
+     cpp_reader *pfile;
+     cpp_macro *macro;
+     macro_arg *args;
+     struct toklist *list;
+{
+  unsigned int i, total;
+  const cpp_token *src, *limit;
+  cpp_token *dest;
+  macro_arg *arg;
+
+  src = macro->expansion;
+  limit = src + macro->count;
+
+  /* First, fully macro-expand arguments, calculating the number of
+     tokens in the final expansion as we go.  This ensures that the
+     possible recursive use of argument_pool is fine.  */
+  total = limit - src;
+  for (; src < limit; src++)
+    if (src->type == CPP_MACRO_ARG)
+      {
+       /* We have an argument.  If it is not being stringified or
+          pasted it is macro-replaced before insertion.  */
+       arg = &args[src->val.aux - 1];
+       if (src->flags & STRINGIFY_ARG)
+         {
+           if (!arg->stringified)
+             stringify_arg (pfile, arg);
+         }
+       else if ((src->flags & PASTE_LEFT)
+                || (src > macro->expansion && (src[-1].flags & PASTE_LEFT)))
+         total += arg->count - 1;
+       else
+         {
+           if (!arg->expanded)
+             expand_arg (pfile, arg);
+           total += arg->expanded_count - 1;
+         }
+      }
+
+  dest = (cpp_token *) _cpp_pool_alloc (&pfile->argument_pool,
+                                       total * sizeof (cpp_token));
+  list->first = dest;
+  list->limit = list->first + total;
+
+  for (src = macro->expansion; src < limit; src++)
+    if (src->type == CPP_MACRO_ARG)
+      {
+       unsigned int count;
+       const cpp_token *from;
+
+       arg = &args[src->val.aux - 1];
+       if (src->flags & STRINGIFY_ARG)
+         from = arg->stringified, count = 1;
+       else if ((src->flags & PASTE_LEFT)
+                || (src > macro->expansion && (src[-1].flags & PASTE_LEFT)))
+         count = arg->count, from = arg->first;
+       else
+         count = arg->expanded_count, from = arg->expanded;
+       memcpy (dest, from, count * sizeof (cpp_token));
+
+       /* The first token gets PREV_WHITE of the CPP_MACRO_ARG.  If
+           it is a variable argument, it is also flagged.  */
+       dest->flags &= ~PREV_WHITE;
+       dest->flags |= src->flags & PREV_WHITE;
+       if (macro->var_args && src->val.aux == macro->paramc)
+         dest->flags |= VARARGS_FIRST;
+
+       /* The last token gets the PASTE_LEFT of the CPP_MACRO_ARG.  */
+       dest[count - 1].flags |= src->flags & PASTE_LEFT;
+
+       dest += count;
+      }
+    else
+      *dest++ = *src;
+
+  /* Free the expanded arguments.  */
+  for (i = 0; i < macro->paramc; i++)
     {
-      if (token->type == CPP_PASTE)
+      if (args[i].expanded)
+       free (args[i].expanded);
+      if (args[i].stringified)
+       free (args[i].stringified);
+    }
+}
+
+/* Subroutine of expand_arg to put the unexpanded tokens on the
+   context stack.  */
+static cpp_context *
+push_arg_context (pfile, arg)
+     cpp_reader *pfile;
+     macro_arg *arg;
+{
+  cpp_context *context = next_context (pfile);
+  context->macro = 0;
+  context->list.first = arg->first;
+  context->list.limit = arg->first + arg->count;
+
+  return context;
+}
+
+static void
+expand_arg (pfile, arg)
+     cpp_reader *pfile;
+     macro_arg *arg;
+{
+  cpp_token *token;
+  unsigned int capacity = 256;
+
+  /* Loop, reading in the arguments.  */
+  arg->expanded = (cpp_token *) xmalloc (capacity * sizeof (cpp_token));
+  arg->expanded_count = 0;
+
+  push_arg_context (pfile, arg);
+  do
+    {
+      if (arg->expanded_count >= capacity)
        {
-         /* Token-paste ##, can appear in both object-like and
-            function-like macros, but not at the ends.  Constraint
-            6.10.3.3.1 */
-         if (token == info->first || token[1].type == CPP_EOF)
+         capacity *= 2;
+         arg->expanded = (cpp_token *)
+           xrealloc (arg->expanded, capacity * sizeof (cpp_token));
+       }
+      token = &arg->expanded[arg->expanded_count++];
+      _cpp_get_token (pfile, token);
+    }
+  while (token->type != CPP_EOF);
+
+  arg->expanded_count--;
+
+  /* Pop the context we pushed.  */ 
+  pfile->context = pfile->context->prev;
+}
+
+void
+_cpp_pop_context (pfile)
+     cpp_reader *pfile;
+{
+  cpp_context *context = pfile->context;
+
+  pfile->context = context->prev;
+  /* Re-enable a macro and free resources when leaving its expansion.  */
+  if (!pfile->state.parsing_args)
+    {
+      if (!pfile->context->prev)
+       unlock_pools (pfile);
+      context->macro->disabled = 0;
+    }
+}
+
+/* Internal routine to return a token, either from an in-progress
+   macro expansion, or from the source file as appropriate.  Handles
+   macros, so tokens returned are post-expansion.  Does not filter
+   CPP_PLACEMARKER tokens.  Returns CPP_EOF at EOL and EOF.  */
+void
+_cpp_get_token (pfile, token)
+     cpp_reader *pfile;
+     cpp_token *token;
+{
+  for (;;)
+    {
+      cpp_context *context = pfile->context;
+
+      if (pfile->la_read)
+       take_lookahead_token (pfile, token);
+      /* Context->prev == 0 <=> base context.  */
+      else if (!context->prev)
+       _cpp_lex_token (pfile, token);
+      else if (context->list.first != context->list.limit)
+       *token = *context->list.first++;
+      else
+       {
+         if (context->macro)
            {
-             cpp_error_with_line (pfile, token->line, token->col,
-               "'##' cannot appear at either end of a macro expansion");
-             return 1;
+             _cpp_pop_context (pfile);
+             continue;
            }
+         token->type = CPP_EOF;
+         token->flags = 0;
+       }
+      break;
+    }
+
+  /* Only perform macro expansion (and therefore pasting) when not
+     skipping, or when skipping but in a directive.  The only
+     directive where this could be true is #elif.  A possible later
+     optimisation: get do_elif to clear skipping so we don't need the
+     directive test here.  */
+  if (pfile->skipping && !pfile->state.in_directive)
+    return;
+
+  for (;;)
+    {
+      if (token->flags & PASTE_LEFT)
+       paste_all_tokens (pfile, token);
+
+      if (token->type != CPP_NAME
+         || token->val.node->type != NT_MACRO
+         || pfile->state.prevent_expansion
+         || token->flags & NO_EXPAND)
+       break;
+
+      /* Macros, built-in or not, invalidate controlling macros.  */
+      pfile->mi_state = MI_FAILED;
+
+      if (token->val.node->flags & NODE_BUILTIN)
+       {
+         builtin_macro (pfile, token);
+         break;
+       }
+      else if (enter_macro_context (pfile, token))
+       break;
+    }
+}
+
+/* External interface to get a token.  Tokens are returned after macro
+   expansion and directives have been handled, as a continuous stream.
+   Transparently enters included files.  CPP_EOF indicates end of
+   original source file.  Filters out CPP_PLACEMARKER tokens.
+
+   For the benefit of #pragma callbacks which may want to get the
+   pragma's tokens, returns CPP_EOF to indicate end-of-directive in
+   this case.  */
+void
+cpp_get_token (pfile, token)
+     cpp_reader *pfile;
+     cpp_token *token;
+{
+  for (;;)
+    {
+      _cpp_get_token (pfile, token);
+
+      if (token->type == CPP_EOF)
+       {
+         /* In directives we should pass through EOLs for the callbacks.  */
+         if (pfile->buffer->cur == pfile->buffer->rlimit
+             || pfile->state.in_directive || pfile->state.parsing_args)
+           break;
          continue;
        }
-      else if (token->type == CPP_HASH)
+      else if (token->type == CPP_DHASH)
        {
-         /* Stringifying #, but a normal character in object-like
-             macros.  Must come before a parameter name.  Constraint
-             6.10.3.2.1.  */
-         if (info->paramc >= 0)
-           {
-             if (token[1].type == CPP_NAME
-                 && find_param (info->first_param, token + 1))
-               continue;
-             if (! CPP_OPTION (pfile, lang_asm))
-               {
-                 cpp_error_with_line (pfile, token->line, token->col,
-                              "'#' is not followed by a macro parameter");
-                 return 1;
-               }
-           }
+         /* Handle directives.  */
+         if (_cpp_handle_directive (pfile, token->flags & PREV_WHITE))
+           continue;
+         /* This is in fact an assembler #.  */
+         if (pfile->skipping)
+           continue;
+         token->type = CPP_HASH;
        }
-      else if (token->type == CPP_NAME)
+      /* We are not merging the PREV_WHITE of CPP_PLACEMARKERS.  I
+         don't think it really matters.  */
+      else if (pfile->skipping || token->type == CPP_PLACEMARKER)
+       continue;
+
+      /* Non-comment tokens invalidate any controlling macros.  */
+      if (token->type != CPP_COMMENT)
+       pfile->mi_state = MI_FAILED;
+
+      break;
+    }
+
+  if (pfile->la_write)
+    save_lookahead_token (pfile, token);
+}
+
+/* Read each token in, until EOF.  Directives are transparently
+   processed.  */
+void
+cpp_scan_buffer_nooutput (pfile)
+     cpp_reader *pfile;
+{
+  cpp_token token;
+
+  do
+    do
+      cpp_get_token (pfile, &token);
+    while (token.type != CPP_EOF);
+  while (cpp_pop_buffer (pfile) != 0);
+}
+
+/* Lookahead handling.  */
+
+static void
+save_lookahead_token (pfile, token)
+     cpp_reader *pfile;
+     const cpp_token *token;
+{
+  if (token->type != CPP_EOF)
+    {
+      cpp_lookahead *la = pfile->la_write;
+      cpp_token_with_pos *twp;
+
+      if (la->count == la->cap)
        {
-         /* Constraint 6.10.3.5  */
-         if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token))
-           return 1;
+         la->cap += la->cap + 8;
+         la->tokens = (cpp_token_with_pos *)
+           xrealloc (la->tokens, la->cap * sizeof (cpp_token_with_pos));
        }
-      info->ntokens++;
-      if (TOKEN_SPELL (token) == SPELL_STRING)
-       info->len += token->val.str.len;
+
+      twp = &la->tokens[la->count++];
+      twp->token = *token;
+      twp->pos = *cpp_get_line (pfile);
     }
-  
-  return 0;
 }
 
-/* Returns non-zero if a macro redefinition is trivial.  */
-static int
-check_macro_redefinition (pfile, hp, list2)
+static void
+take_lookahead_token (pfile, token)
      cpp_reader *pfile;
-     cpp_hashnode *hp;
-     const cpp_toklist *list2;
+     cpp_token *token;
 {
-  const cpp_toklist *list1;
+  cpp_lookahead *la = pfile->la_read;
+  cpp_token_with_pos *twp = &la->tokens[la->cur];
 
-  if (hp->type != T_MACRO)
-    return ! pfile->done_initializing;
+  *token = twp->token;
+  pfile->lexer_pos = twp->pos;
 
-  /* Clear the whitespace and BOL flags of the first tokens.  They get
-     altered during macro expansion, but is not significant here.  */
-  list1  = hp->value.expansion;
-  list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
-  list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
+  if (++la->cur == la->count)
+    release_lookahead (pfile);
+}
 
-  if (!_cpp_equiv_toklists (list1, list2))
-    return 0;
+/* Moves the lookahead at the front of the read list to the free store.  */
+static void
+release_lookahead (pfile)
+     cpp_reader *pfile;
+{
+  cpp_lookahead *la = pfile->la_read;
 
-  if (CPP_OPTION (pfile, pedantic)
-      && list1->paramc > 0
-      && (list1->params_len != list2->params_len
-         || memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
-    return 0;
+  pfile->la_read = la->next;
+  la->next = pfile->la_unused;
+  pfile->la_unused = la;
+  unlock_pools (pfile);
+}
 
-  return 1;
+/* Take a new lookahead from the free store, or allocate one if none.  */
+static cpp_lookahead *
+alloc_lookahead (pfile)
+     cpp_reader *pfile;
+{
+  cpp_lookahead *la = pfile->la_unused;
+
+  if (la)
+    pfile->la_unused = la->next;
+  else
+    {
+      la = xnew (cpp_lookahead);
+      la->tokens = 0;
+      la->cap = 0;
+    }
+
+  la->cur = la->count = 0;
+  return la;
 }
 
-/* This is a dummy structure whose only purpose is getting alignment
-   correct.  */
-struct toklist_dummy
+/* Free memory associated with a lookahead list.  */
+static void
+free_lookahead (la)
+     cpp_lookahead *la;
 {
-  cpp_toklist list;
-  cpp_token first_token;
-};
+  if (la->tokens)
+    free ((PTR) la->tokens);
+  free ((PTR) la);
+}
 
-/* Allocate space to hold the token list, its tokens, their text, and
-   the parameter names if needed.  Empty expansions are stored as a
-   single placemarker token.
+/* Free all the lookaheads of a cpp_reader.  */
+void
+_cpp_free_lookaheads (pfile)
+     cpp_reader *pfile;
+{
+  cpp_lookahead *la, *lan;
+
+  if (pfile->la_read)
+    free_lookahead (pfile->la_read);
+  if (pfile->la_write)
+    free_lookahead (pfile->la_write);
+
+  for (la = pfile->la_unused; la; la = lan)
+    {
+      lan = la->next;
+      free_lookahead (la);
+    }
+}
 
-   These are all allocated in a block together for performance
-   reasons.  Therefore, this token list cannot be expanded like a
-   normal token list.  Try to do so, and you lose.  */
-static cpp_toklist *
-alloc_macro (pfile, info)
+/* Allocate a lookahead and move it to the front of the write list.  */
+void
+cpp_start_lookahead (pfile)
      cpp_reader *pfile;
-     struct macro_info *info;
 {
-  unsigned int size;
-  struct toklist_dummy *dummy;
-  cpp_toklist *list;
+  cpp_lookahead *la = alloc_lookahead (pfile);
 
-  /* Empty macros become a single placemarker token.  */
-  if (info->ntokens == 0)
-    info->ntokens = 1;
+  la->next = pfile->la_write;
+  pfile->la_write = la;
 
-  size = sizeof (struct toklist_dummy);
-  size += (info->ntokens - 1) * sizeof(cpp_token);
-  size += info->len + info->paramlen;
+  la->pos = *cpp_get_line (pfile);
 
-  dummy = (struct toklist_dummy *) xmalloc (size);
-  list = (cpp_toklist *) dummy;
-  
-  /* Initialize the monster.  */
-  list->tokens = &dummy->first_token;
-  list->tokens_used = list->tokens_cap = info->ntokens;
+  /* Don't allow memory pools to be re-used whilst we're reading ahead.  */
+  lock_pools (pfile);
+}
 
-  list->namebuf = (unsigned char *) &list->tokens[info->ntokens];
-  list->name_used = list->name_cap = info->len + info->paramlen;
+/* Stop reading ahead - either step back, or drop the read ahead.  */
+void
+cpp_stop_lookahead (pfile, drop)
+     cpp_reader *pfile;
+     int drop;
+{
+  cpp_lookahead *la = pfile->la_write;
 
-  list->directive = 0;
-  list->line = pfile->token_list.line;
-  list->file = pfile->token_list.file;
-  list->params_len = info->paramlen;
-  list->paramc = info->paramc;
-  list->flags = info->flags;
+  pfile->la_write = la->next;
+  la->next = pfile->la_read;
+  pfile->la_read = la;
 
-  return list;
+  if (drop || la->count == 0)
+    release_lookahead (pfile);
+  else
+    pfile->lexer_pos = la->pos;
 }
 
-/* Free the definition of macro H.  */
+/* Push a single token back to the front of the queue.  Only to be
+   used by cpplib, and only then when necessary.  POS is the position
+   to report for the preceding token.  */
+void
+_cpp_push_token (pfile, token, pos)
+     cpp_reader *pfile;
+     const cpp_token *token;
+     const cpp_lexer_pos *pos;
+{
+  cpp_start_lookahead (pfile);
+  save_lookahead_token (pfile, token);
+  cpp_stop_lookahead (pfile, 0);
+  pfile->lexer_pos = *pos;
+}
+
+/* #define directive parsing and handling.  */
+
+/* Returns non-zero if a macro redefinition is trivial.  */
+static int
+check_macro_redefinition (pfile, node, macro2)
+     cpp_reader *pfile;
+     const cpp_hashnode *node;
+     const cpp_macro *macro2;
+{
+  const cpp_macro *macro1;
+  unsigned int i;
+
+  if (node->type != NT_MACRO || node->flags & NODE_BUILTIN)
+    return ! pfile->done_initializing;
+
+  macro1 = node->value.macro;
+
+  /* The quick failures.  */
+  if (macro1->count != macro2->count
+      || macro1->paramc != macro2->paramc
+      || macro1->fun_like != macro2->fun_like
+      || macro1->var_args != macro2->var_args)
+    return 0;
+
+  /* Check each token.  */
+  for (i = 0; i < macro1->count; i++)
+    if (! _cpp_equiv_tokens (&macro1->expansion[i], &macro2->expansion[i]))
+      return 0;
+
+  /* Check parameter spellings.  */
+  for (i = 0; i < macro1->paramc; i++)
+    if (macro1->params[i] != macro2->params[i])
+      return 0;
+
+  return 1;
+}
+
+/* Free the definition of hashnode H.  */
 
 void
 _cpp_free_definition (h)
      cpp_hashnode *h;
 {
-  if (h->type == T_MACRO)
-    free ((PTR) h->value.expansion);
-  else if (h->type == T_ASSERTION)
+  /* Macros and assertions no longer have anything to free.  */
+  h->type = NT_VOID;
+  /* Clear builtin flag in case of redefinition.  */
+  h->flags &= ~NODE_BUILTIN;
+}
+
+static int
+save_parameter (pfile, macro, node)
+     cpp_reader *pfile;
+     cpp_macro *macro;
+     cpp_hashnode *node;
+{
+  cpp_hashnode **dest;
+
+  /* Constraint 6.10.3.6 - duplicate parameter names.  */
+  if (node->arg_index)
     {
-      struct answer *temp, *next;
+      cpp_error (pfile, "duplicate macro parameter \"%s\"", node->name);
+      return 1;
+    }
 
-      for (temp = h->value.answers; temp; temp = next)
-       {
-         next = temp->next;
-         FREE_ANSWER (temp);
-       }
+  dest = &macro->params[macro->paramc];
+
+  /* Check we have room for the parameters.  */
+  if ((unsigned char *) (dest + 1) >= POOL_LIMIT (&pfile->macro_pool))
+    {
+      _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_hashnode *),
+                      (unsigned char **) &macro->params);
+      dest = &macro->params[macro->paramc];
     }
 
-  h->type = T_VOID;
-  h->value.expansion = NULL;
+  *dest = node;
+  node->arg_index = ++macro->paramc;
+  return 0;
 }
 
-/* Copy the tokens of the expansion, beginning with info->first until
-   CPP_EOF.  INFO contains information about the macro.
-
-   Change the type of macro arguments in the expansion from CPP_NAME
-   to CPP_MACRO_ARG.  Remove #'s that represent stringification,
-   flagging the CPP_MACRO_ARG it operates on STRINGIFY.  Remove ##'s,
-   flagging the token on its immediate left PASTE_LEFT.  Returns the
-   token list for the macro expansion.  */
-static const cpp_toklist *
-save_expansion (pfile, info)
+static int
+parse_params (pfile, macro)
      cpp_reader *pfile;
-     struct macro_info *info;
+     cpp_macro *macro;
 {
-  const cpp_token *token;
-  cpp_toklist *list;
-  cpp_token *dest;
-  unsigned char *buf;
-      
-  list = alloc_macro (pfile, info);
-  buf = list->namebuf;
-
-  /* Store the null-terminated parameter spellings of a macro, to
-     provide pedantic warnings to satisfy 6.10.3.2, or for use when
-     dumping macro definitions.  They must go first.  */
-  if (list->params_len)
-    for (token = info->first_param; token < info->first; token++)
-      if (token->type == CPP_NAME || token->type == CPP_DEFINED)
-       {
-         /* Copy null too.  */
-         memcpy (buf, token->val.node->name, token->val.node->length + 1);
-         buf += token->val.node->length + 1;
-       }
+  cpp_token token;
+  unsigned int prev_ident = 0;
 
-  dest = list->tokens;
-  for (token = info->first; token->type != CPP_EOF; token++)
+  macro->params = (cpp_hashnode **) POOL_FRONT (&pfile->macro_pool);
+  for (;;)
     {
-      unsigned int param_no;
+      _cpp_lex_token (pfile, &token);
 
-      switch (token->type)
+      switch (token.type)
        {
-       case CPP_DEFINED:
+       default:
+         cpp_error (pfile, "\"%s\" may not appear in macro parameter list",
+                    cpp_token_as_text (pfile, &token));
+         return 0;
+
        case CPP_NAME:
-         if (list->paramc == -1)
-           break;
+         if (prev_ident)
+           {
+             cpp_error (pfile, "macro parameters must be comma-separated");
+             return 0;
+           }
+         prev_ident = 1;
+
+         if (save_parameter (pfile, macro, token.val.node))
+           return 0;
+         continue;
 
-         /* Check if the name is a macro parameter.  */
-         param_no = find_param (info->first_param, token);
-         if (param_no == 0)
+       case CPP_CLOSE_PAREN:
+         if (prev_ident || macro->paramc == 0)
            break;
-         dest->val.aux = param_no - 1;
 
-         dest->type = CPP_MACRO_ARG;
-         if (token[-1].type == CPP_HASH)
-           dest->flags = token[-1].flags | STRINGIFY_ARG;
-         else
-           dest->flags = token->flags;  /* Particularly PREV_WHITE.  */
-         /* Turn off PREV_WHITE if we immediately follow a paste.
-            That way, even if the paste turns out to be invalid, there
-            will be no space between the two tokens in the output.  */
-         if (token[-1].type == CPP_PASTE)
-           dest->flags &= ~PREV_WHITE;
-         dest++;
+         /* Fall through to pick up the error.  */
+       case CPP_COMMA:
+         if (!prev_ident)
+           {
+             cpp_error (pfile, "parameter name missing");
+             return 0;
+           }
+         prev_ident = 0;
          continue;
 
-       case CPP_PASTE:
-         /* Set the paste flag on the token to our left, unless there
-            is no possible token to which it might be pasted.  That
-            is critical for correct operation under some circumstances;
-            see gcc.dg/cpp/paste6.c. */
-         if (CAN_PASTE_AFTER (dest[-1].type) || (dest[-1].flags & NAMED_OP))
-           dest[-1].flags |= PASTE_LEFT;
-         else if (CPP_OPTION (pfile, warn_paste))
-           cpp_warning_with_line (pfile, dest[-1].line, dest[-1].col,
-                                  "nothing can be pasted after this token");
-         continue;
+       case CPP_ELLIPSIS:
+         macro->var_args = 1;
+         if (!prev_ident)
+           {
+             save_parameter (pfile, macro, pfile->spec_nodes.n__VA_ARGS__);
+             pfile->state.va_args_ok = 1;
+             if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic))
+               cpp_pedwarn (pfile,
+                    "C89 does not permit anonymous variable arguments");
+           }
+         else if (CPP_OPTION (pfile, pedantic))
+           cpp_pedwarn (pfile,
+                        "ISO C does not permit named variable arguments");
 
-       case CPP_HASH:
-         /* Stringifying #.  Constraint 6.10.3.2.1  */
-         if (list->paramc >= 0 && token[1].type == CPP_NAME
-             && find_param (info->first_param, token + 1))
-           continue;
-         break;
+         /* We're at the end, and just expect a closing parenthesis.  */
+         _cpp_lex_token (pfile, &token);
+         if (token.type == CPP_CLOSE_PAREN)
+           break;
+         /* Fall through.  */
 
-       case CPP_STRING:
-       case CPP_CHAR:
-         if (CPP_WTRADITIONAL (pfile) && list->paramc > 0)
-           check_trad_stringification (pfile, info, &token->val.str);
-         break;
-         
-       default:
-         break;
+       case CPP_EOF:
+         cpp_error (pfile, "missing ')' in macro parameter list");
+         return 0;
        }
 
-      /* Copy the token.  */
-      *dest = *token;
-      if (TOKEN_SPELL (token) == SPELL_STRING)
-       {
-         memcpy (buf, token->val.str.text, token->val.str.len);
-         dest->val.str.text = buf;
-         buf += dest->val.str.len;
-       }
-      if (token[-1].type == CPP_PASTE)
-       dest->flags &= ~PREV_WHITE;
-      dest++;
+      /* Success.  Commit the parameter array.  */
+      POOL_COMMIT (&pfile->macro_pool,
+                  macro->paramc * sizeof (cpp_hashnode *));
+      return 1;
     }
+}
+
+/* Lex a token from a macro's replacement list.  Translate it to a
+   CPP_MACRO_ARG if appropriate.  */
+static cpp_token *
+lex_expansion_token (pfile, macro)
+     cpp_reader *pfile;
+     cpp_macro *macro;
+{
+  cpp_token *token = &macro->expansion[macro->count];
 
-  /* Empty macros become a single placemarker token.  */
-  if (dest == list->tokens)
+  /* Check we have room for the token.  */
+  if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
     {
-      dest->type = CPP_PLACEMARKER;
-      dest->flags = 0;
-      dest->val.aux = 0;
+      _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_token),
+                      (unsigned char **) &macro->expansion);
+      token = &macro->expansion[macro->count];
     }
 
-  return list;
+  macro->count++;
+  _cpp_lex_token (pfile, token);
+
+  /* Is this an argument?  */
+  if (token->type == CPP_NAME && token->val.node->arg_index)
+    {
+      token->type = CPP_MACRO_ARG;
+      token->val.aux = token->val.node->arg_index;
+    }
+  else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0
+          && (token->type == CPP_STRING || token->type == CPP_CHAR))
+    check_trad_stringification (pfile, macro, &token->val.str);
+
+  return token;
 }
 
 /* Parse a macro and save its expansion.  Returns non-zero on success.  */
 int
-_cpp_create_definition (pfile, hp)
+_cpp_create_definition (pfile, node)
      cpp_reader *pfile;
-     cpp_hashnode *hp;
+     cpp_hashnode *node;
 {
-  struct macro_info info;
-  const cpp_toklist *list;
+  cpp_macro *macro;
+  cpp_token *token;
+  unsigned int i, ok = 1;
+
+  macro = (cpp_macro *) _cpp_pool_alloc (&pfile->macro_pool,
+                                        sizeof (cpp_macro));
+  macro->file = pfile->buffer->nominal_fname;
+  macro->line = pfile->directive_pos.line;
+  macro->params = 0;
+  macro->paramc = 0;
+  macro->fun_like = 0;
+  macro->var_args = 0;
+  macro->disabled = 0;
+  macro->count = 0;
+  macro->expansion = (cpp_token *) POOL_FRONT (&pfile->macro_pool);
+
+  /* Get the first token of the expansion (or the '(' of a
+     function-like macro).  */
+  token = lex_expansion_token (pfile, macro);
+  if (token->type == CPP_OPEN_PAREN && !(token->flags & PREV_WHITE))
+    {
+      if (!(ok = parse_params (pfile, macro)))
+       goto cleanup;
+      macro->count = 0;
+      macro->fun_like = 1;
+      /* Some of the pool may have been used for the parameter store.  */
+      macro->expansion = (cpp_token *) POOL_FRONT (&pfile->macro_pool);
+      token = lex_expansion_token (pfile, macro);
+    }
+  else if (token->type != CPP_EOF && !(token->flags & PREV_WHITE))
+    cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
 
-  if (parse_define (pfile, &info))
-    return 0;
-  list = save_expansion (pfile, &info);
+  /* Setting it here means we don't catch leading comments.  */
+  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
 
-  /* Check for a redefinition.  Redefinition of a macro is allowed if
-     and only if the old and new definitions are the same.
-     (6.10.3 paragraph 2). */
+  for (;;)
+    {
+      /* Check the stringifying # constraint 6.10.3.2.1 of
+        function-like macros when lexing the subsequent token.  */
+      if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like)
+       {
+         if (token->type == CPP_MACRO_ARG)
+           {
+             token->flags &= ~PREV_WHITE;
+             token->flags |= STRINGIFY_ARG;
+             token->flags |= token[-1].flags & PREV_WHITE;
+             token[-1] = token[0];
+             macro->count--;
+           }
+         /* Let assembler get away with murder.  */
+         else if (!CPP_OPTION (pfile, lang_asm))
+           {
+             ok = 0;
+             cpp_error (pfile, "'#' is not followed by a macro parameter");
+             goto cleanup;
+           }
+       }
+
+      if (token->type == CPP_EOF)
+       break;
+
+      /* Paste operator constraint 6.10.3.3.1.  */
+      if (token->type == CPP_PASTE)
+       {
+         /* Token-paste ##, can appear in both object-like and
+            function-like macros, but not at the ends.  */
+         if (--macro->count > 0)
+           token = lex_expansion_token (pfile, macro);
+
+         if (macro->count == 0 || token->type == CPP_EOF)
+           {
+             ok = 0;
+             cpp_error (pfile,
+                        "'##' cannot appear at either end of a macro expansion");
+             goto cleanup;
+           }
 
-  if (hp->type != T_VOID)
+         token[-1].flags |= PASTE_LEFT;
+         /* Give it a PREV_WHITE for -dM etc.  */
+         token->flags |= PREV_WHITE;
+       }
+
+      token = lex_expansion_token (pfile, macro);
+    }
+
+  /* Don't count the CPP_EOF.  Empty macros become a place marker.  */
+  if (macro->count > 1)
+    macro->count--;
+  else
+    macro->expansion[0].type = CPP_PLACEMARKER;
+
+  /* Clear the whitespace flag from the leading token.  */
+  macro->expansion[0].flags &= ~PREV_WHITE;
+
+  /* Commit the memory.  */
+  POOL_COMMIT (&pfile->macro_pool, macro->count * sizeof (cpp_token));
+
+  /* Redefinition of a macro is allowed if and only if the old and new
+     definitions are the same.  (6.10.3 paragraph 2). */
+  if (node->type != NT_VOID)
     {
-      if (!check_macro_redefinition (pfile, hp, list))
+      if (CPP_PEDANTIC (pfile)
+         && !check_macro_redefinition (pfile, node, macro))
        {
-         cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
-         if (pfile->done_initializing && hp->type == T_MACRO)
+         cpp_pedwarn_with_line (pfile, pfile->directive_pos.line,
+                                pfile->directive_pos.col,
+                                "\"%s\" redefined", node->name);
+
+         if (pfile->done_initializing && node->type == NT_MACRO
+             && !(node->flags & NODE_BUILTIN))
            cpp_pedwarn_with_file_and_line (pfile,
-                                           hp->value.expansion->file,
-                                           hp->value.expansion->line, 1,
+                                           node->value.macro->file,
+                                           node->value.macro->line, 1,
                            "this is the location of the previous definition");
        }
-      _cpp_free_definition (hp);
+      _cpp_free_definition (node);
     }
 
   /* Enter definition in hash table.  */
-  hp->type = T_MACRO;
-  hp->value.expansion = list;
+  node->type = NT_MACRO;
+  node->value.macro = macro;
 
-  return 1;
+ cleanup:
+
+  /* Stop the lexer accepting __VA_ARGS__.  */
+  pfile->state.va_args_ok = 0;
+
+  /* Clear the fast argument lookup indices.  */
+  for (i = macro->paramc; i-- > 0; )
+    macro->params[i]->arg_index = 0;
+
+  return ok;
 }
 
 /* Warn if a token in `string' matches one of the function macro
    arguments in `info'.  This function assumes that the macro is a
    function macro and not an object macro.  */
 static void
-check_trad_stringification (pfile, info, string)
+check_trad_stringification (pfile, macro, string)
      cpp_reader *pfile;
-     const struct macro_info *info;
+     const cpp_macro *macro;
      const cpp_string *string;
 {
+  unsigned int i, len;
   const U_CHAR *p, *q, *limit = string->text + string->len;
   
   /* Loop over the string.  */
   for (p = string->text; p < limit; p = q)
     {
-      const cpp_token *token;
-
       /* Find the start of an identifier.  */
       while (p < limit && !is_idstart (*p))
        p++;
@@ -600,23 +1548,130 @@ check_trad_stringification (pfile, info, string)
       q = p;
       while (q < limit && is_idchar (*q))
        q++;
-     
+
+      len = q - p;
+
       /* Loop over the function macro arguments to see if the
         identifier inside the string matches one of them.  */
-      for (token = info->first_param; token < info->first; token++)
-        {
-         /* Skip the commas in between the arguments.  */
-         if (token->type != CPP_NAME)
-           continue;
+      for (i = 0; i < macro->paramc; i++)
+       {
+         const cpp_hashnode *node = macro->params[i];
 
-         if (token->val.node->length == (q - p)
-             && !memcmp (p, token->val.node->name, (q - p)))
+         if (node->length == len && !memcmp (p, node->name, len))
            {
              cpp_warning (pfile,
-                          "macro arg \"%.*s\" would be stringified with -traditional.",
-                          (int) (q - p), p);
+          "macro argument \"%s\" would be stringified with -traditional.",
+                          node->name);
              break;
            }
        }
     }
 }
+
+/* Returns the expansion of a macro, in a format suitable to be read
+   back in again, and therefore also for DWARF 2 debugging info.
+   Caller is expected to generate the "#define NAME" bit.  The
+   returned text is temporary, and automatically freed later.  */
+
+const unsigned char *
+cpp_macro_definition (pfile, node)
+     cpp_reader *pfile;
+     const cpp_hashnode *node;
+{
+  unsigned int i, len;
+  const cpp_macro *macro = node->value.macro;
+  unsigned char *buffer;
+
+  if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
+    {
+      cpp_ice (pfile, "invalid hash type %d in dump_definition", node->type);
+      return 0;
+    }
+
+  /* Calculate length.  */
+  len = 1;                     /* ' ' */
+  if (macro->fun_like)
+    {
+      len += 3;                /* "()" plus possible final "." of ellipsis.  */
+      for (i = 0; i < macro->paramc; i++)
+       len += macro->params[i]->length + 2; /* ", " */
+    }
+
+  if (macro->count > 1 || macro->expansion[0].type != CPP_PLACEMARKER)
+    {
+      for (i = 0; i < macro->count; i++)
+       {
+         cpp_token *token = &macro->expansion[i];
+
+         if (token->type == CPP_MACRO_ARG)
+           len += macro->params[token->val.aux - 1]->length;
+         else
+           len += cpp_token_len (token); /* Includes room for ' '.  */
+         if (token->flags & STRINGIFY_ARG)
+           len++;                      /* "#" */
+         if (token->flags & PASTE_LEFT)
+           len += 3;           /* " ##" */
+       }
+    }
+
+  if (len > pfile->macro_buffer_len)
+    pfile->macro_buffer = (U_CHAR *) xrealloc (pfile->macro_buffer, len);
+  buffer = pfile->macro_buffer;
+
+  /* Parameter names.  */
+  if (macro->fun_like)
+    {
+      *buffer++ = '(';
+      for (i = 0; i < macro->paramc; i++)
+       {
+         cpp_hashnode *param = macro->params[i];
+
+         if (param != pfile->spec_nodes.n__VA_ARGS__)
+           {
+             memcpy (buffer, param->name, param->length);
+             buffer += param->length;
+           }
+
+         if (i + 1 < macro->paramc)
+           *buffer++ = ',', *buffer++ = ' ';
+         else if (macro->var_args)
+           *buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
+       }
+      *buffer++ = ')';
+    }
+
+  /* Expansion tokens.  */
+  if (macro->count > 1 || macro->expansion[0].type != CPP_PLACEMARKER)
+    {
+      *buffer++ = ' ';
+      for (i = 0; i < macro->count; i++)
+       {
+         cpp_token *token = &macro->expansion[i];
+
+         if (token->flags & PREV_WHITE)
+           *buffer++ = ' ';
+         if (token->flags & STRINGIFY_ARG)
+           *buffer++ = '#';
+
+         if (token->type == CPP_MACRO_ARG)
+           {
+             len = macro->params[token->val.aux - 1]->length;
+             memcpy (buffer, macro->params[token->val.aux - 1]->name, len);
+             buffer += len;
+           }
+         else
+           buffer = cpp_spell_token (pfile, token, buffer);
+
+         if (token->flags & PASTE_LEFT)
+           {
+             *buffer++ = ' ';
+             *buffer++ = '#';
+             *buffer++ = '#';
+             /* Next has PREV_WHITE; see _cpp_create_definition.  */
+           }
+       }
+    }
+
+  *buffer = '\0';
+  return pfile->macro_buffer;
+}
index 5c88e95..fc58f6a 100644 (file)
@@ -25,29 +25,45 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #include "cpplib.h"
 #include "intl.h"
 
-const char *progname;
-
-cpp_reader parse_in;
-cpp_printer parse_out;
+/* Encapsulates state used to convert the stream of tokens coming from
+   cpp_get_token back into a text file.  */
+struct printer
+{
+  FILE *outf;                  /* stream to write to.  */
+  const char *last_fname;      /* previous file name.  */
+  const char *syshdr_flags;    /* system header flags, if any.  */
+  unsigned int lineno;         /* line currently being written.  */
+  unsigned char printed;       /* nonzero if something output at lineno.  */
+  unsigned char no_line_dirs;  /* nonzero to output no line directives.  */
+};
 
 int main               PARAMS ((int, char **));
 
+/* General output routines.  */
+static void scan_buffer        PARAMS ((cpp_reader *));
+static int printer_init PARAMS ((cpp_reader *));
+static int dump_macro PARAMS ((cpp_reader *, cpp_hashnode *));
+
+static void print_line PARAMS ((const char *));
+static void maybe_print_line PARAMS ((unsigned int));
+static void move_printer PARAMS ((cpp_reader *, unsigned int, const char *));
+
 /* Callback routines for the parser.   Most of these are active only
    in specific modes.  */
 static void cb_define  PARAMS ((cpp_reader *, cpp_hashnode *));
 static void cb_undef   PARAMS ((cpp_reader *, cpp_hashnode *));
 static void cb_include PARAMS ((cpp_reader *, const unsigned char *,
-                                const unsigned char *, unsigned int, int));
-
-static void cb_ident     PARAMS ((cpp_reader *, const unsigned char *,
-                                  unsigned int));
+                                const cpp_token *));
+static void cb_ident     PARAMS ((cpp_reader *, const cpp_string *));
 static void cb_enter_file PARAMS ((cpp_reader *));
 static void cb_leave_file PARAMS ((cpp_reader *));
 static void cb_rename_file PARAMS ((cpp_reader *));
 static void cb_def_pragma PARAMS ((cpp_reader *));
-
 static void do_pragma_implementation PARAMS ((cpp_reader *));
-static int dump_macros_helper PARAMS ((cpp_reader *, cpp_hashnode *));
+
+const char *progname;
+cpp_reader parse_in;
+struct printer print;
 
 int
 main (argc, argv)
@@ -56,7 +72,6 @@ main (argc, argv)
 {
   char *p;
   cpp_reader *pfile = &parse_in;
-  cpp_printer *print;
   int argi = 1;  /* Next argument to handle.  */
 
   p = argv[0] + strlen (argv[0]);
@@ -83,8 +98,7 @@ main (argc, argv)
   /* Open the output now.  We must do so even if no_output is on,
      because there may be other output than from the actual
      preprocessing (e.g. from -dM).  */
-  print = cpp_printer_init (pfile, &parse_out);
-  if (! print)
+  if (printer_init (pfile))
     return (FATAL_EXIT_CODE);
 
   /* Set callbacks.  */
@@ -116,134 +130,260 @@ main (argc, argv)
   cpp_register_pragma(pfile, 0, "implementation", do_pragma_implementation);
   cpp_register_pragma(pfile, "GCC", "implementation", do_pragma_implementation);
 
-  if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname)))
+  if (! cpp_start_read (pfile, CPP_OPTION (pfile, in_fname)))
     return (FATAL_EXIT_CODE);
 
-  if (CPP_OPTION (pfile, no_output))
-    while (CPP_BUFFER (pfile) != NULL)
-      cpp_scan_buffer_nooutput (pfile);
-  else
-    while (CPP_BUFFER (pfile) != NULL)
-      cpp_scan_buffer (pfile, print);
+  if (CPP_BUFFER (pfile))
+    {
+      if (CPP_OPTION (pfile, no_output))
+       cpp_scan_buffer_nooutput (pfile);
+      else
+       scan_buffer (pfile);
+    }
 
+  /* -dM command line option.  */
   if (CPP_OPTION (pfile, dump_macros) == dump_only)
-    cpp_forall_identifiers (pfile, dump_macros_helper);
-  
-  cpp_finish (pfile, print);
+    cpp_forall_identifiers (pfile, dump_macro);
+
+  cpp_finish (pfile);
   cpp_cleanup (pfile);
 
+  /* Flush any pending output.  */
+  if (print.printed)
+    putc ('\n', print.outf);
+  if (ferror (print.outf) || fclose (print.outf))
+    cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname));
+
   if (parse_in.errors)
     return (FATAL_EXIT_CODE);
   return (SUCCESS_EXIT_CODE);
 }
 
-/* Callbacks */
+/* Writes out the preprocessed file.  Alternates between two tokens,
+   so that we can avoid accidental token pasting.  */
+static void
+scan_buffer (pfile)
+     cpp_reader *pfile;
+{
+  unsigned int index, line;
+  cpp_token tokens[2], *token;
 
+  do
+    {
+      for (index = 0;; index = 1 - index)
+       {
+         token = &tokens[index];
+         cpp_get_token (pfile, token);
+
+         if (token->type == CPP_EOF)
+           break;
+
+         line = cpp_get_line (pfile)->output_line;
+         if (print.lineno != line)
+           {
+             unsigned int col = cpp_get_line (pfile)->col;
+
+             /* Supply enough whitespace to put this token in its original
+                column.  Don't bother trying to reconstruct tabs; we can't
+                get it right in general, and nothing ought to care.  (Yes,
+                some things do care; the fault lies with them.)  */
+             maybe_print_line (line);
+             if (col > 1)
+               {
+                 if (token->flags & PREV_WHITE)
+                   col--;
+                 while (--col)
+                   putc (' ', print.outf);
+               }
+           }
+         else if (print.printed && ! (token->flags & PREV_WHITE)
+                  && cpp_avoid_paste (pfile, &tokens[1 - index], token))
+           token->flags |= PREV_WHITE;
+
+         cpp_output_token (token, print.outf);
+         print.printed = 1;
+       }
+    }
+  while (cpp_pop_buffer (pfile) != 0);
+}
+
+/* Initialize a cpp_printer structure.  As a side effect, open the
+   output file.  */
+static int
+printer_init (pfile)
+     cpp_reader *pfile;
+{
+  print.last_fname = 0;
+  print.lineno = 0;
+  print.printed = 0;
+  print.no_line_dirs = CPP_OPTION (pfile, no_line_commands);
+
+  if (CPP_OPTION (pfile, out_fname) == NULL)
+    CPP_OPTION (pfile, out_fname) = "";
+  
+  if (CPP_OPTION (pfile, out_fname)[0] == '\0')
+    print.outf = stdout;
+  else
+    {
+      print.outf = fopen (CPP_OPTION (pfile, out_fname), "w");
+      if (! print.outf)
+       {
+         cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname));
+         return 1;
+       }
+    }
+  return 0;
+}
+
+/* Newline-terminate any output line currently in progress.  If
+   appropriate, write the current line number to the output, or pad
+   with newlines so the output line matches the current line.  */
 static void
-cb_ident (pfile, str, len)
+maybe_print_line (line)
+     unsigned int line;
+{
+  /* End the previous line of text (probably only needed until we get
+     multi-line tokens fixed).  */
+  if (print.printed)
+    {
+      putc ('\n', print.outf);
+      print.lineno++;
+      print.printed = 0;
+    }
+
+  if (print.no_line_dirs)
+    return;
+
+  if (line >= print.lineno && line < print.lineno + 8)
+    {
+      while (line > print.lineno)
+       {
+         putc ('\n', print.outf);
+         print.lineno++;
+       }
+    }
+  else
+    {
+      print.lineno = line;
+      print_line ("");
+    }
+}
+
+static void
+print_line (special_flags)
+  const char *special_flags;
+{
+  /* End any previous line of text.  */
+  if (print.printed)
+    putc ('\n', print.outf);
+  print.printed = 0;
+
+  fprintf (print.outf, "# %u \"%s\"%s%s\n",
+          print.lineno, print.last_fname, special_flags, print.syshdr_flags);
+}
+
+static void
+move_printer (pfile, line, special_flags)
      cpp_reader *pfile;
-     const unsigned char *str;
-     unsigned int len;
+     unsigned int line;
+     const char *special_flags;
+{
+  print.lineno = line;
+  print.last_fname = pfile->buffer->nominal_fname;
+  print.syshdr_flags = cpp_syshdr_flags (pfile, pfile->buffer);
+  print_line (special_flags);
+}
+
+/* Callbacks */
+
+static void
+cb_ident (pfile, str)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     const cpp_string * str;
 {
-  cpp_printf (pfile, &parse_out, "#ident \"%.*s\"\n", (int) len, str);
-  parse_out.lineno++;
+  maybe_print_line (cpp_get_line (pfile)->output_line);
+  fprintf (print.outf, "#ident \"%.*s\"\n", (int) str->len, str->text);
+  print.lineno++;
 }
 
 static void
-cb_define (pfile, hash)
+cb_define (pfile, node)
      cpp_reader *pfile;
-     cpp_hashnode *hash;
+     cpp_hashnode *node;
 {
   if (pfile->done_initializing)
     {
-      cpp_printf (pfile, &parse_out, "#define %s", hash->name);
+      maybe_print_line (cpp_get_line (pfile)->output_line);
+      fprintf (print.outf, "#define %s", node->name);
+
+      /* -dD or -g3 command line options.  */
       if (CPP_OPTION (pfile, debug_output)
          || CPP_OPTION (pfile, dump_macros) == dump_definitions)
-       cpp_dump_definition (pfile, parse_out.outf, hash);
-      putc ('\n', parse_out.outf);
-      parse_out.lineno++;
+       fputs ((const char *) cpp_macro_definition (pfile, node), print.outf);
+
+      putc ('\n', print.outf);
+      print.lineno++;
     }
 }
 
 static void
-cb_undef (pfile, hash)
+cb_undef (pfile, node)
      cpp_reader *pfile;
-     cpp_hashnode *hash;
+     cpp_hashnode *node;
 {
   if (pfile->done_initializing)
     {
-      cpp_printf (pfile, &parse_out, "#undef %s\n", hash->name);
-      parse_out.lineno++;
+      maybe_print_line (cpp_get_line (pfile)->output_line);
+      fprintf (print.outf, "#undef %s\n", node->name);
+      print.lineno++;
     }
 }
 
 static void
-cb_include (pfile, dir, str, len, ab)
-     cpp_reader *pfile;
+cb_include (pfile, dir, header)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
      const unsigned char *dir;
-     const unsigned char *str;
-     unsigned int len;
-     int ab;
+     const cpp_token *header;
 {
-  int l, r;
-  if (ab)
-    l = '<', r = '>';
-  else
-    l = '"', r = '"';
-
-  cpp_printf (pfile, &parse_out, "#%s %c%.*s%c\n", dir, l, (int) len, str, r);
-  parse_out.lineno++;
+  maybe_print_line (cpp_get_line (pfile)->output_line);
+  fprintf (print.outf, "#%s %s\n", dir, cpp_token_as_text (pfile, header));
+  print.lineno++;
 }
 
 static void
 cb_enter_file (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
+  /* Bring current file to correct line (except main file).  FIXME: we
+     may be using the same buffer via a # NUMBER "file" 1 directive.  */
+  if (pfile->done_initializing && pfile->buffer->prev)
+    maybe_print_line (pfile->buffer->prev->lineno);
 
-  cpp_printf (pfile, &parse_out, "# 1 \"%s\"%s%s\n", ip->nominal_fname,
-             pfile->done_initializing ? " 1" : "",
-             cpp_syshdr_flags (pfile, ip));
-
-  parse_out.lineno = 1;
-  parse_out.last_fname = ip->nominal_fname;
+  move_printer (pfile, 1, pfile->done_initializing ? " 1": "");
 }
 
 static void
 cb_leave_file (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-
-  cpp_printf (pfile, &parse_out, "# %u \"%s\" 2%s\n", ip->lineno,
-             ip->nominal_fname, cpp_syshdr_flags (pfile, ip));
-
-  parse_out.lineno = ip->lineno;
-  parse_out.last_fname = ip->nominal_fname;
+  move_printer (pfile, pfile->buffer->lineno + 1, " 2");
 }
 
 static void
 cb_rename_file (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-
-  cpp_printf (pfile, &parse_out, "# %u \"%s\"%s\n", ip->lineno,
-             ip->nominal_fname, cpp_syshdr_flags (pfile, ip));
-
-  parse_out.lineno = ip->lineno;
-  parse_out.last_fname = ip->nominal_fname;
+  move_printer (pfile, pfile->buffer->lineno + 1, "");
 }
 
 static void
 cb_def_pragma (pfile)
      cpp_reader *pfile;
 {
-  cpp_printf (pfile, &parse_out, "#pragma ");
-  cpp_output_list (pfile, parse_out.outf, &pfile->token_list,
-                  pfile->first_directive_token + 2);
-  putc ('\n', parse_out.outf);
-  parse_out.lineno++;
+  maybe_print_line (cpp_get_line (pfile)->output_line);
+  fputs ("#pragma ", print.outf);
+  cpp_output_line (pfile, print.outf);
+  print.lineno++;
 }
 
 static void
@@ -252,47 +392,54 @@ do_pragma_implementation (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;
+  cpp_token token;
 
-  if (tok->type != CPP_EOF)
-    {
-      if (tok->type != CPP_STRING || cpp_get_token (pfile)->type != CPP_EOF)
-       {
-         cpp_error (pfile, "malformed #pragma implementation");
-         return;
-       }
+  cpp_start_lookahead (pfile);
+  cpp_get_token (pfile, &token);
+  cpp_stop_lookahead (pfile, 0);
 
-      /* Make a NUL-terminated copy of the string.  */
-      copy = alloca (tok->val.str.len + 1);
-      memcpy (copy, tok->val.str.text, tok->val.str.len);
-      copy[tok->val.str.len] = '\0';
-  
-      if (cpp_included (pfile, copy))
+  /* If it's not a string, pass it through and let the front end complain.  */
+  if (token.type == CPP_STRING)
+    {
+     /* Make a NUL-terminated copy of the string.  */
+      char *filename = alloca (token.val.str.len + 1);
+      memcpy (filename, token.val.str.text, token.val.str.len);
+      filename[token.val.str.len] = '\0';
+      if (cpp_included (pfile, filename))
        cpp_warning (pfile,
-               "#pragma implementation for %s appears after file is included",
-                    copy);
+            "#pragma GCC implementation for \"%s\" appears after file is included",
+                    filename);
+    }
+  else if (token.type != CPP_EOF)
+    {
+      cpp_error (pfile, "malformed #pragma GCC implementation");
+      return;
     }
 
-  /* forward to default-pragma handler.  */
+  /* Output?  This is nasty, but we don't have [GCC] implementation in
+     the buffer.  */
   if (pfile->cb.def_pragma)
-    (*pfile->cb.def_pragma) (pfile);
+    {
+      maybe_print_line (cpp_get_line (pfile)->output_line);
+      fputs ("#pragma GCC implementation ", print.outf);
+      cpp_output_line (pfile, print.outf);
+      print.lineno++;
+    }
 }
 
 /* Dump out the hash table.  */
 static int
-dump_macros_helper (pfile, hp)
+dump_macro (pfile, node)
      cpp_reader *pfile;
-     cpp_hashnode *hp;
+     cpp_hashnode *node;
 {
-  if (hp->type == T_MACRO)
+  if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
     {
-      cpp_printf (pfile, &parse_out, "#define %s", hp->name);
-      cpp_dump_definition (pfile, parse_out.outf, hp);
-      putc ('\n', parse_out.outf);
-      parse_out.lineno++;
+      fprintf (print.outf, "#define %s", node->name);
+      fputs ((const char *) cpp_macro_definition (pfile, node), print.outf);
+      putc ('\n', print.outf);
+      print.lineno++;
     }
 
   return 1;
 }
-
diff --git a/gcc/cppoutput.c b/gcc/cppoutput.c
deleted file mode 100644 (file)
index 53433ce..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/* CPP Library - non-diagnostic output.
-   Copyright (C) 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
-   Broken out to separate file, Sep 2000
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-#include "config.h"
-#include "system.h"
-#include "intl.h"
-#include "cpplib.h"
-#include "cpphash.h"
-
-static void output_line_command PARAMS ((cpp_reader *, cpp_printer *,
-                                        unsigned int));
-static void output_token PARAMS ((cpp_reader *, FILE *, const cpp_token *,
-                                 const cpp_token *, int));
-static void dump_macro_args PARAMS ((FILE *, const cpp_toklist *));
-static void dump_param_spelling PARAMS ((FILE *, const cpp_toklist *,
-                                        unsigned int));
-
-/* Scan until CPP_BUFFER (PFILE) is exhausted, discarding output.  Used
-   for handling -imacros, -dM, -M and -MM.  */
-void
-cpp_scan_buffer_nooutput (pfile)
-     cpp_reader *pfile;
-{
-  cpp_buffer *stop = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
-  const cpp_token *token;
-
-  /* In no-output mode, we can ignore everything but directives.  */
-  for (;;)
-    {
-      token = _cpp_get_token (pfile);
-
-      if (token->type == CPP_EOF)
-       {
-         cpp_pop_buffer (pfile);
-         if (CPP_BUFFER (pfile) == stop)
-           break;
-       }
-
-      if (token->type == CPP_HASH && token->flags & BOL
-         && pfile->token_list.directive)
-       {
-         _cpp_process_directive (pfile, token);
-         continue;
-       }
-
-      _cpp_skip_rest_of_line (pfile);
-    }
-}
-
-/* Scan until CPP_BUFFER (pfile) is exhausted, writing output to PRINT.  */
-void
-cpp_scan_buffer (pfile, print)
-     cpp_reader *pfile;
-     cpp_printer *print;
-{
-  cpp_buffer *stop = CPP_PREV_BUFFER (CPP_BUFFER (pfile));
-  const cpp_token *token, *prev = 0;
-
-  for (;;)
-    {
-      token = _cpp_get_token (pfile);
-      if (token->type == CPP_EOF)
-       {
-         cpp_pop_buffer (pfile);
-
-         if (CPP_BUFFER (pfile) == stop)
-           return;
-
-         prev = 0;
-         continue;
-       }
-
-      if (token->flags & BOL)
-       {
-         output_line_command (pfile, print, token->line);
-         prev = 0;
-
-         if (token->type == CPP_HASH && pfile->token_list.directive)
-           {
-             _cpp_process_directive (pfile, token);
-             continue;
-           }
-       }
-
-      if (token->type != CPP_PLACEMARKER)
-       {
-         output_token (pfile, print->outf, token, prev, 1);
-         pfile->need_newline = 1;
-       }
-
-      prev = token;
-    }
-}
-
-/* Notify the compiler proper that the current line number has jumped,
-   or the current file name has changed.  */
-static void
-output_line_command (pfile, print, line)
-     cpp_reader *pfile;
-     cpp_printer *print;
-     unsigned int line;
-{
-  cpp_buffer *ip = CPP_BUFFER (pfile);
-
-  if (line == 0)
-    return;
-
-  /* End the previous line of text.  */
-  if (pfile->need_newline)
-    {
-      putc ('\n', print->outf);
-      print->lineno++;
-    }
-  pfile->need_newline = 0;
-
-  if (CPP_OPTION (pfile, no_line_commands))
-    return;
-
-  /* If the current file has not changed, we can output a few newlines
-     instead if we want to increase the line number by a small amount.
-     We cannot do this if print->lineno is zero, because that means we
-     haven't output any line commands yet.  (The very first line
-     command output is a `same_file' command.)
-
-     'nominal_fname' values are unique, so they can be compared by
-     comparing pointers.  */
-  if (ip->nominal_fname == print->last_fname && print->lineno > 0
-      && line >= print->lineno && line < print->lineno + 8)
-    {
-      while (line > print->lineno)
-       {
-         putc ('\n', print->outf);
-         print->lineno++;
-       }
-      return;
-    }
-
-  fprintf (print->outf, "# %u \"%s\"%s\n", line, ip->nominal_fname,
-          cpp_syshdr_flags (pfile, ip));
-
-  print->last_fname = ip->nominal_fname;
-  print->lineno = line;
-}
-
-/* Output all the tokens of LIST, starting at TOKEN, to FP.  */
-void
-cpp_output_list (pfile, fp, list, token)
-     cpp_reader *pfile;
-     FILE *fp;
-     const cpp_toklist *list;
-     const cpp_token *token;
-{
-  const cpp_token *limit = list->tokens + list->tokens_used;
-  const cpp_token *prev = 0;
-  int white = 0;
-
-  while (token < limit)
-    {
-      /* XXX Find some way we can write macro args from inside
-        output_token/spell_token.  */
-      if (token->type == CPP_MACRO_ARG)
-       {
-         if (white && token->flags & PREV_WHITE)
-           putc (' ', fp);
-         if (token->flags & STRINGIFY_ARG)
-           putc ('#', fp);
-         dump_param_spelling (fp, list, token->val.aux);
-       }
-      else
-       output_token (pfile, fp, token, prev, white);
-      if (token->flags & PASTE_LEFT)
-       fputs (" ##", fp);
-      prev = token;
-      token++;
-      white = 1;
-    }
-}
-
-/* Write the spelling of a token TOKEN, with any appropriate
-   whitespace before it, to FP.  PREV is the previous token, which
-   is used to determine if we need to shove in an extra space in order
-   to avoid accidental token paste.  If WHITE is 0, do not insert any
-   leading whitespace.  */
-static void
-output_token (pfile, fp, token, prev, white)
-     cpp_reader *pfile;
-     FILE *fp;
-     const cpp_token *token, *prev;
-     int white;
-{
-  if (white)
-    {
-      int dummy;
-
-      if (token->col && (token->flags & BOL))
-       {
-         /* Supply enough whitespace to put this token in its original
-            column.  Don't bother trying to reconstruct tabs; we can't
-            get it right in general, and nothing ought to care.  (Yes,
-            some things do care; the fault lies with them.)  */
-         unsigned int spaces = token->col - 1;
-      
-         while (spaces--)
-           putc (' ', fp);
-       }
-      else if (token->flags & PREV_WHITE)
-       putc (' ', fp);
-      else
-      /* Check for and prevent accidental token pasting.
-        In addition to the cases handled by _cpp_can_paste, consider
-
-        a + ++b - if there is not a space between the + and ++, it
-        will be misparsed as a++ + b.  But + ## ++ doesn't produce
-        a valid token.  */
-       if (prev
-           && (_cpp_can_paste (pfile, prev, token, &dummy) != CPP_EOF
-               || (prev->type == CPP_PLUS && token->type == CPP_PLUS_PLUS)
-               || (prev->type == CPP_MINUS && token->type == CPP_MINUS_MINUS)))
-       putc (' ', fp);
-    }
-
-  switch (TOKEN_SPELL (token))
-    {
-    case SPELL_OPERATOR:
-      {
-       const unsigned char *spelling;
-
-       if (token->flags & DIGRAPH)
-         spelling = _cpp_digraph_spellings[token->type - CPP_FIRST_DIGRAPH];
-       else if (token->flags & NAMED_OP)
-         goto spell_ident;
-       else
-         spelling = TOKEN_NAME (token);
-
-       ufputs (spelling, fp);
-      }
-      break;
-
-    case SPELL_IDENT:
-      spell_ident:
-      ufputs (token->val.node->name, fp);
-      break;
-
-    case SPELL_STRING:
-      {
-       int left, right, tag;
-       switch (token->type)
-         {
-         case CPP_STRING:      left = '"';  right = '"';  tag = '\0'; break;
-         case CPP_WSTRING:     left = '"';  right = '"';  tag = 'L';  break;
-         case CPP_OSTRING:     left = '"';  right = '"';  tag = '@';  break;
-         case CPP_CHAR:        left = '\''; right = '\''; tag = '\0'; break;
-         case CPP_WCHAR:       left = '\''; right = '\''; tag = 'L';  break;
-         case CPP_HEADER_NAME: left = '<';  right = '>';  tag = '\0'; break;
-         default:              left = '\0'; right = '\0'; tag = '\0'; break;
-         }
-       if (tag) putc (tag, fp);
-       if (left) putc (left, fp);
-       fwrite (token->val.str.text, 1, token->val.str.len, fp);
-       if (right) putc (right, fp);
-      }
-      break;
-
-    case SPELL_CHAR:
-      putc (token->val.aux, fp);
-      break;
-
-    case SPELL_NONE:
-      /* Placemarker or EOF - no output.  (Macro args are handled
-         elsewhere.  */
-      break;
-    }
-}
-
-/* Dump the original user's spelling of argument index ARG_NO to the
-   macro whose expansion is LIST.  */
-static void
-dump_param_spelling (fp, list, arg_no)
-     FILE *fp;
-     const cpp_toklist *list;
-     unsigned int arg_no;
-{
-  const U_CHAR *param = list->namebuf;
-
-  while (arg_no--)
-    param += ustrlen (param) + 1;
-  ufputs (param, fp);
-}
-
-/* Dump the definition of macro MACRO on FP.  The format is suitable
-   to be read back in again.  Caller is expected to generate the
-   "#define NAME" bit.  */
-
-void
-cpp_dump_definition (pfile, fp, hp)
-     cpp_reader *pfile;
-     FILE *fp;
-     const cpp_hashnode *hp;
-{
-  const cpp_toklist *list = hp->value.expansion;
-
-  if (hp->type != T_MACRO)
-    {
-      cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
-      return;
-    }
-
-  if (list->paramc >= 0)
-    dump_macro_args (fp, list);
-
-  putc (' ', fp);
-  cpp_output_list (pfile, fp, list, list->tokens);
-}
-
-static void
-dump_macro_args (fp, list)
-     FILE *fp;
-     const cpp_toklist *list;
-{
-  int i;
-  const U_CHAR *param = list->namebuf;
-
-  putc ('(', fp);
-  for (i = 0; i++ < list->paramc;)
-    {
-      unsigned int len;
-
-      len = ustrlen (param);
-      if (!(list->flags & VAR_ARGS) || ustrcmp (param, U"__VA_ARGS__"))
-       ufputs (param, fp);
-      if (i < list->paramc)
-       fputs (", ", fp);
-      else if (list->flags & VAR_ARGS)
-       fputs ("...", fp);
-
-      param += len + 1;
-    }
-  putc (')', fp);
-}
-
-/* Like fprintf, but writes to a printer object.  You should be sure
-   always to generate a complete line when you use this function.  */
-void
-cpp_printf VPARAMS ((cpp_reader *pfile, cpp_printer *print,
-                    const char *fmt, ...))
-{
-  va_list ap;
-#ifndef ANSI_PROTOTYPES
-  cpp_reader *pfile;
-  cpp_printer *print;
-  const char *fmt;
-#endif
-
-  VA_START (ap, fmt);
-
-#ifndef ANSI_PROTOTYPES
-  pfile = va_arg (ap, cpp_reader *);
-  print = va_arg (ap, cpp_printer *);
-  fmt = va_arg (ap, const char *);
-#endif
-
-  /* End the previous line of text.  */
-  if (pfile->need_newline)
-    {
-      putc ('\n', print->outf);
-      print->lineno++;
-    }
-  pfile->need_newline = 0;
-
-  vfprintf (print->outf, fmt, ap);
-  va_end (ap);
-}
index 25c75bb..3741a13 100644 (file)
@@ -517,8 +517,9 @@ recognized_extern (name)
    'f' for other function declarations.  */
 
 void
-recognized_function (fname, kind, have_arg_list, file_seen)
+recognized_function (fname, line, kind, have_arg_list, file_seen)
      const cpp_token *fname;
+     unsigned int line;
      int kind; /* One of 'f' 'F' or 'I' */
      int have_arg_list;
      const char *file_seen;
@@ -566,7 +567,7 @@ recognized_function (fname, kind, have_arg_list, file_seen)
   partial_count++;
   partial = (struct partial_proto *)
     obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
-  partial->line_seen = fname->line;
+  partial->line_seen = line;
   partial->fn = fn;
   fn->partial = partial;
   partial->next = partial_proto_list;
@@ -622,7 +623,7 @@ read_scan_file (in_fname, argc, argv)
   if (CPP_FATAL_ERRORS (&scan_in))
     exit (FATAL_EXIT_CODE);
 
-  if (! cpp_start_read (&scan_in, 0, in_fname))
+  if (! cpp_start_read (&scan_in, in_fname))
     exit (FATAL_EXIT_CODE);
 
   /* We are scanning a system header, so mark it as such.  */
@@ -647,15 +648,16 @@ read_scan_file (in_fname, argc, argv)
       /* Scan the macro expansion of "getchar();".  */
       for (;;)
        {
-         const cpp_token *t = cpp_get_token (&scan_in);
+         cpp_token t;
 
-         if (t->type == CPP_EOF)
+         cpp_get_token (&scan_in, &t);
+         if (t.type == CPP_EOF)
            {
              cpp_pop_buffer (&scan_in);
              if (CPP_BUFFER (&scan_in) == buf)
                break;
            }
-         else if (cpp_ideq (t, "_filbuf"))
+         else if (cpp_ideq (&t, "_filbuf"))
            seen_filbuf++;
        }
       if (seen_filbuf)
index 215ebef..223d684 100644 (file)
@@ -582,7 +582,6 @@ cpplex.c
 cpplib.c
 cpplib.h
 cppmain.c
-cppoutput.c
 cppspec.c
 #crtstuff.c is part of the GCC library
 cse.c
index b8451b9..6adcbcb 100644 (file)
@@ -45,7 +45,11 @@ skip_to_closing_brace (pfile)
   int nesting = 1;
   for (;;)
     {
-      enum cpp_ttype token = cpp_get_token (pfile)->type;
+      cpp_token tok;
+      enum cpp_ttype token;
+
+      cpp_get_token (pfile, &tok);
+      token = tok.type;
       if (token == CPP_EOF)
        break;
       if (token == CPP_OPEN_BRACE)
@@ -84,17 +88,16 @@ scan_decls (pfile, argc, argv)
      char **argv ATTRIBUTE_UNUSED;
 {
   int saw_extern, saw_inline;
-  const cpp_token *prev_id;
-  const cpp_token *token;
+  cpp_token token, prev_id;
 
  new_statement:
-  token = cpp_get_token (pfile);
+  cpp_get_token (pfile, &token);
 
  handle_statement:
   current_extern_C = 0;
   saw_extern = 0;
   saw_inline = 0;
-  if (token->type == CPP_OPEN_BRACE)
+  if (token.type == CPP_OPEN_BRACE)
     {
       /* Pop an 'extern "C"' nesting level, if appropriate.  */
       if (extern_C_braces_length
@@ -103,12 +106,12 @@ scan_decls (pfile, argc, argv)
       brace_nesting--;
       goto new_statement;
     }
-  if (token->type == CPP_OPEN_BRACE)
+  if (token.type == CPP_OPEN_BRACE)
     {
       brace_nesting++;
       goto new_statement;
     }
-  if (token->type == CPP_EOF)
+  if (token.type == CPP_EOF)
     {
       cpp_pop_buffer (pfile);
       if (CPP_BUFFER (pfile) == NULL)
@@ -116,15 +119,15 @@ scan_decls (pfile, argc, argv)
 
       goto new_statement;
     }
-  if (token->type == CPP_SEMICOLON)
+  if (token.type == CPP_SEMICOLON)
     goto new_statement;
-  if (token->type != CPP_NAME)
+  if (token.type != CPP_NAME)
     goto new_statement;
 
-  prev_id = 0;
+  prev_id.type = CPP_EOF;
   for (;;)
     {
-      switch (token->type)
+      switch (token.type)
        {
        default:
          goto handle_statement;
@@ -136,11 +139,11 @@ scan_decls (pfile, argc, argv)
 
        case CPP_COMMA:
        case CPP_SEMICOLON:
-         if (prev_id && saw_extern)
+         if (prev_id.type != CPP_EOF && saw_extern)
            {
-             recognized_extern (prev_id);
+             recognized_extern (&prev_id);
            }
-         if (token->type == CPP_COMMA)
+         if (token.type == CPP_COMMA)
            break;
          /* ... fall through ...  */
        case CPP_OPEN_BRACE:  case CPP_CLOSE_BRACE:
@@ -154,60 +157,61 @@ scan_decls (pfile, argc, argv)
 
        case CPP_OPEN_PAREN:
          /* Looks like this is the start of a formal parameter list.  */
-         if (prev_id)
+         if (prev_id.type != CPP_EOF)
            {
              int nesting = 1;
              int have_arg_list = 0;
              for (;;)
                {
-                 token = cpp_get_token (pfile);
-                 if (token->type == CPP_OPEN_PAREN)
+                 cpp_get_token (pfile, &token);
+                 if (token.type == CPP_OPEN_PAREN)
                    nesting++;
-                 else if (token->type == CPP_CLOSE_PAREN)
+                 else if (token.type == CPP_CLOSE_PAREN)
                    {
                      nesting--;
                      if (nesting == 0)
                        break;
                    }
-                 else if (token->type == CPP_EOF)
+                 else if (token.type == CPP_EOF)
                    break;
-                 else if (token->type == CPP_NAME
-                          || token->type == CPP_ELLIPSIS)
+                 else if (token.type == CPP_NAME
+                          || token.type == CPP_ELLIPSIS)
                    have_arg_list = 1;
                }
-             recognized_function (prev_id, 
+             recognized_function (&prev_id, 
+                                  cpp_get_line (pfile)->line,
                                   (saw_inline ? 'I'
                                    : in_extern_C_brace || current_extern_C
                                    ? 'F' : 'f'), have_arg_list,
                                   CPP_BUFFER (pfile)->nominal_fname);
-             token = cpp_get_token (pfile);
-             if (token->type == CPP_OPEN_BRACE)
+             cpp_get_token (pfile, &token);
+             if (token.type == CPP_OPEN_BRACE)
                {
                  /* skip body of (normally) inline function */
                  skip_to_closing_brace (pfile);
                  goto new_statement;
                }
-             if (token->type == CPP_SEMICOLON)
+             if (token.type == CPP_SEMICOLON)
                goto new_statement;
            }
          break;
        case CPP_NAME:
          /* "inline" and "extern" are recognized but skipped */
-         if (cpp_ideq (token, "inline"))
+         if (cpp_ideq (&token, "inline"))
            {
              saw_inline = 1;
            }
-         else if (cpp_ideq (token, "extern"))
+         else if (cpp_ideq (&token, "extern"))
            {
              saw_extern = 1;
-             token = cpp_get_token (pfile);
-             if (token->type == CPP_STRING
-                 && token->val.str.len == 1
-                 && token->val.str.text[0] == 'C')
+             cpp_get_token (pfile, &token);
+             if (token.type == CPP_STRING
+                 && token.val.str.len == 1
+                 && token.val.str.text[0] == 'C')
                {
                  current_extern_C = 1;
-                 token = cpp_get_token (pfile);
-                 if (token->type == CPP_OPEN_BRACE)
+                 cpp_get_token (pfile, &token);
+                 if (token.type == CPP_OPEN_BRACE)
                    {
                      brace_nesting++;
                      extern_C_braces[extern_C_braces_length++]
@@ -223,6 +227,6 @@ scan_decls (pfile, argc, argv)
          prev_id = token;
          break;
        }
-      token = cpp_get_token (pfile);
+      cpp_get_token (pfile, &token);
     }
 }
index e861096..d0ae23c 100644 (file)
@@ -60,7 +60,8 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int));
 extern int scan_string _PARAMS((FILE *, sstring *, int));
 extern int read_upto _PARAMS((FILE *, sstring *, int));
 extern unsigned long hash _PARAMS((const char *));
-extern void recognized_function _PARAMS((const struct cpp_token *, int, int,
+extern void recognized_function _PARAMS((const struct cpp_token *,
+                                        unsigned int, int, int,
                                         const char *));
 extern void recognized_extern _PARAMS((const struct cpp_token *));
 extern unsigned int hashstr _PARAMS((const char *, unsigned int));