diff options
author | Neil Booth <neilb@earthling.net> | 2000-10-28 17:59:06 +0000 |
---|---|---|
committer | Neil Booth <neil@gcc.gnu.org> | 2000-10-28 17:59:06 +0000 |
commit | 93c80368d9a16c073f2b930bef4232661971765f (patch) | |
tree | b1f50a88de9fbdd6a784d0c03fa8cd31e4ac5916 | |
parent | de48b52da8468f94c0bdffc11fa7e8fe49b4ba66 (diff) | |
download | gcc-93c80368d9a16c073f2b930bef4232661971765f.zip gcc-93c80368d9a16c073f2b930bef4232661971765f.tar.gz gcc-93c80368d9a16c073f2b930bef4232661971765f.tar.bz2 |
New macro expander.
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.
From-SVN: r37098
-rw-r--r-- | gcc/ChangeLog | 158 | ||||
-rw-r--r-- | gcc/Makefile.in | 3 | ||||
-rw-r--r-- | gcc/cpperror.c | 58 | ||||
-rw-r--r-- | gcc/cppexp.c | 181 | ||||
-rw-r--r-- | gcc/cppfiles.c | 66 | ||||
-rw-r--r-- | gcc/cpphash.c | 84 | ||||
-rw-r--r-- | gcc/cpphash.h | 239 | ||||
-rw-r--r-- | gcc/cppinit.c | 224 | ||||
-rw-r--r-- | gcc/cpplex.c | 2400 | ||||
-rw-r--r-- | gcc/cpplib.c | 1460 | ||||
-rw-r--r-- | gcc/cpplib.h | 441 | ||||
-rw-r--r-- | gcc/cppmacro.c | 1891 | ||||
-rw-r--r-- | gcc/cppmain.c | 357 | ||||
-rw-r--r-- | gcc/cppoutput.c | 390 | ||||
-rw-r--r-- | gcc/fix-header.c | 14 | ||||
-rw-r--r-- | gcc/po/POTFILES.in | 1 | ||||
-rw-r--r-- | gcc/scan-decls.c | 72 | ||||
-rw-r--r-- | gcc/scan.h | 3 |
18 files changed, 3911 insertions, 4131 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cebbe87..cd5df85 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2ea2ef9..27561cd 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/cpperror.c b/gcc/cpperror.c index fa44708..d598fbd 100644 --- a/gcc/cpperror.c +++ b/gcc/cpperror.c @@ -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; -} - diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 5403dce..566eb15 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -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); +} diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index 3110f00..f54fe8a 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -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)) diff --git a/gcc/cpphash.c b/gcc/cpphash.c index dee77a9..1c7366d 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -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); diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 8787a6c..bba1ba9 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -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 diff --git a/gcc/cppinit.c b/gcc/cppinit.c index 3fbf77e..20dfc63 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -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); diff --git a/gcc/cpplex.c b/gcc/cpplex.c index 426e82d..fa737a9 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -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; - - 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; +static int name_p PARAMS ((cpp_reader *, const cpp_string *)); - 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--; - } - - /* 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--; - } - - /* 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; + unsigned int len = cpp_token_len (token); + unsigned char *start = _cpp_pool_alloc (&pfile->temp_string_pool, len), *end; - 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; - } + end = cpp_spell_token (pfile, token, start); + end[0] = '\0'; - prev_nme = pfile->no_expand_level; - pfile->no_expand_level = context - pfile->contexts; - next = _cpp_get_token (pfile); - restore_macro_expansion (pfile, prev_nme); - - 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; + return start; } -/* 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; +/* Used by C front ends. Should really move to using cpp_token_as_text. */ +const char * +cpp_type2name (type) + enum cpp_ttype type; { - 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++) - { - token = _cpp_get_token (pfile); - - switch (token->type) - { - default: - break; - - case CPP_OPEN_PAREN: - paren++; - break; - - case CPP_CLOSE_PAREN: - if (paren-- != 0) - break; - goto out; - - case CPP_COMMA: - /* Commas are not terminators within parantheses or var_args. */ - if (paren || var_args) - break; - goto out; - - case CPP_EOF: /* Error reported by caller. */ - goto out; - } - - raw = pfile->cur_context <= paren_context; - if (raw != was_raw) - { - was_raw = raw; - save_token (args, 0); - count++; - } - save_token (args, token); - } - - 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++; - } - - *pcount = count; - return token; + return (const char *) token_spellings[type].name; } -/* 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; +/* 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; { - 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; + if (token->flags & PREV_WHITE) + putc (' ', fp); - 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; - } - - 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--) + switch (TOKEN_SPELL (token)) { - U_CHAR c = *src++; - - if (c == '\\' || c == '"') - { - *dest++ = '\\'; - *dest++ = c; - } - else - { - if (ISPRINT (c)) - *dest++ = c; - else - { - sprintf ((char *) dest, "\\%03o", c); - dest += 4; - } - } - } + case SPELL_OPERATOR: + { + const unsigned char *spelling; - return dest; -} + 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); -/* 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; -} + ufputs (spelling, fp); + } + break; -/* 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; + spell_ident: + case SPELL_IDENT: + ufputs (token->val.node->name, fp); + break; - result = get_temp_token (pfile); - buf = xmalloc (20); - sprintf (buf, "%d", number); + 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; - result->type = CPP_NUMBER; - result->flags = 0; - result->val.str.text = (U_CHAR *) buf; - result->val.str.len = strlen (buf); - return result; -} + case SPELL_CHAR: + putc (token->val.aux, fp); + break; -/* 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)); + case SPELL_NONE: + /* An error, most probably. */ + break; } - - 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; +/* Compare two tokens. */ +int +_cpp_equiv_tokens (a, b) + const cpp_token *a, *b; { - while (pfile->temp_used) - { - cpp_token *token = pfile->temp_tokens[--pfile->temp_used]; + 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)); + } - if (TOKEN_SPELL (token) == SPELL_STRING) - { - free ((char *) token->val.str.text); - token->val.str.text = 0; - } - } + return 0; } -/* Free all of PFILE's dynamically-allocated temporary tokens. */ -void -_cpp_free_temp_tokens (pfile) - cpp_reader *pfile; +#if 0 +/* Compare two token lists. */ +int +_cpp_equiv_toklists (a, b) + const struct toklist *a, *b; { - 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); - } + unsigned int i, count; - 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'; +/* 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". */ - 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; - } - } - - /* 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); -} +/* Memory pools. */ -/* 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; +struct dummy { - 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; + char c; + union + { + double d; + int *p; + } u; +}; - if (token->type == CPP_HASH && token->flags & BOL - && pfile->token_list.directive) - { - _cpp_process_directive (pfile, token); - continue; - } +#define DEFAULT_ALIGNMENT (offsetof (struct dummy, u)) - return token; - } +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); } -/* 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; +/* 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 *token, *old_token; - cpp_hashnode *node; + cpp_chunk *chunk = pool->cur->next; - /* Loop until we hit a non-macro token. */ - for (;;) + /* LEN is the minimum size we want in the new pool. */ + len += POOL_ROOM (pool); + if (! chunk_suitable (pool, chunk, len)) { - token = get_raw_token (pfile); - - /* Short circuit EOF. */ - if (token->type == CPP_EOF) - return token; - - /* If we are skipping... */ - if (pfile->skipping) - { - /* we still have to process directives, */ - if (pfile->token_list.directive) - return token; - - /* but everything else is ignored. */ - _cpp_skip_rest_of_line (pfile); - continue; - } + chunk = new_chunk (POOL_SIZE (pool) * 2 + len); - /* 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 */ + chunk->next = pool->cur->next; + pool->cur->next = chunk; } -} - -/* 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; -{ - const cpp_token *result; - cpp_context *context; - for (;;) - { - 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; + /* Update the pointer before changing chunk's front. */ + if (ptr) + *ptr += chunk->base - POOL_FRONT (pool); - if (result->flags & STRINGIFY_ARG) - return stringify_arg (pfile, result); - - push_arg_context (pfile, result); - } -} + memcpy (chunk->base, POOL_FRONT (pool), POOL_ROOM (pool)); + chunk->front = chunk->base; -/* 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; + pool->cur = chunk; + return POOL_LIMIT (pool); } -/* 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; +static cpp_chunk * +new_chunk (size) + unsigned int size; { - cpp_toklist *list = &pfile->token_list; - const cpp_token *old_list = list->tokens; - unsigned int old_used = list->tokens_used; - - if (clear) - { - /* Release all temporary tokens. */ - _cpp_clear_toklist (list); - pfile->contexts[0].posn = 0; - if (pfile->temp_used) - release_temp_tokens (pfile); - } - 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; - - 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)); - } - } + unsigned char *base; + cpp_chunk *result; - /* 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. + 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; - This implementation will report a hard error and treat the - 'sequence of preprocessing tokens' as part of the macro argument, - not a directive. - - 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; -} - -/* 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; -{ - cpp_context *context; - - 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; - - 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; - - if (name) - CPP_BUFFER (pfile)->nominal_fname = name; - else - CPP_BUFFER (pfile)->nominal_fname = _("<command line>"); - CPP_BUFFER (pfile)->lineno = (unsigned int)-1; + unsigned char *result = _cpp_pool_reserve (pool, len); - /* 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; } diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 37dbe02..5f54e60 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -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 diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 0f52352..eecd867 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -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 diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c index 321b318..58d3020 100644 --- a/gcc/cppmacro.c +++ b/gcc/cppmacro.c @@ -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 (¯o1->expansion[i], ¯o2->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 = ¯o->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 **) ¯o->params); + dest = ¯o->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 = ¯o->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 **) ¯o->expansion); + token = ¯o->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 = ¯o->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 = ¯o->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; +} diff --git a/gcc/cppmain.c b/gcc/cppmain.c index 5c88e95..fc58f6a 100644 --- a/gcc/cppmain.c +++ b/gcc/cppmain.c @@ -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 index 53433ce..0000000 --- a/gcc/cppoutput.c +++ /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); -} diff --git a/gcc/fix-header.c b/gcc/fix-header.c index 25c75bb..3741a13 100644 --- a/gcc/fix-header.c +++ b/gcc/fix-header.c @@ -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) diff --git a/gcc/po/POTFILES.in b/gcc/po/POTFILES.in index 215ebef..223d684 100644 --- a/gcc/po/POTFILES.in +++ b/gcc/po/POTFILES.in @@ -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 diff --git a/gcc/scan-decls.c b/gcc/scan-decls.c index b8451b9..6adcbcb 100644 --- a/gcc/scan-decls.c +++ b/gcc/scan-decls.c @@ -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); } } @@ -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)); |