Commit 93c80368 by Neil Booth Committed by Neil Booth

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
parent de48b52d
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> 2000-10-27 Mark Mitchell <mark@codesourcery.com>
* c-typeck.c (check_init_type_bitfields): Remove. * c-typeck.c (check_init_type_bitfields): Remove.
......
...@@ -1841,7 +1841,7 @@ PREPROCESSOR_DEFINES = \ ...@@ -1841,7 +1841,7 @@ PREPROCESSOR_DEFINES = \
-DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \ 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 mkdeps.o prefix.o version.o mbchar.o
LIBCPP_DEPS = cpplib.h cpphash.h intl.h system.h LIBCPP_DEPS = cpplib.h cpphash.h intl.h system.h
...@@ -1863,7 +1863,6 @@ cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS) ...@@ -1863,7 +1863,6 @@ cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS) defaults.h cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS) defaults.h
cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS) cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS)
cppmacro.o: cppmacro.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) cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
cpphash.o: cpphash.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 cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
......
...@@ -57,11 +57,10 @@ print_containing_files (pfile, ip) ...@@ -57,11 +57,10 @@ print_containing_files (pfile, ip)
if (first) if (first)
{ {
first = 0; first = 0;
/* N.B. The current line in each outer source file is one /* The current line in each outer source file is now the
greater than the line of the #include, so we must same as the line of the #include. */
subtract one to correct for that. */
fprintf (stderr, _("In file included from %s:%u"), fprintf (stderr, _("In file included from %s:%u"),
ip->nominal_fname, CPP_BUF_LINE (ip) - 1); ip->nominal_fname, CPP_BUF_LINE (ip));
} }
else else
/* Translators note: this message is used in conjunction /* Translators note: this message is used in conjunction
...@@ -107,12 +106,11 @@ print_file_and_line (filename, line, column) ...@@ -107,12 +106,11 @@ print_file_and_line (filename, line, column)
If it returns 0, this error has been suppressed. */ If it returns 0, this error has been suppressed. */
int int
_cpp_begin_message (pfile, code, file, line, col) _cpp_begin_message (pfile, code, file, pos)
cpp_reader *pfile; cpp_reader *pfile;
enum error_type code; enum error_type code;
const char *file; const char *file;
unsigned int line; const cpp_lexer_pos *pos;
unsigned int col;
{ {
cpp_buffer *ip = CPP_BUFFER (pfile); cpp_buffer *ip = CPP_BUFFER (pfile);
int is_warning = 0; int is_warning = 0;
...@@ -177,11 +175,11 @@ _cpp_begin_message (pfile, code, file, line, col) ...@@ -177,11 +175,11 @@ _cpp_begin_message (pfile, code, file, line, col)
{ {
if (file == NULL) if (file == NULL)
file = ip->nominal_fname; file = ip->nominal_fname;
if (line == 0) if (pos == 0)
line = _cpp_get_line (pfile, &col); pos = cpp_get_line (pfile);
print_containing_files (pfile, ip); print_containing_files (pfile, ip);
print_file_and_line (file, line, print_file_and_line (file, pos->line,
CPP_OPTION (pfile, show_column) ? col : 0); CPP_OPTION (pfile, show_column) ? pos->col : 0);
} }
else else
fprintf (stderr, "%s: ", progname); fprintf (stderr, "%s: ", progname);
...@@ -213,7 +211,7 @@ cpp_ice VPARAMS ((cpp_reader *pfile, const char *msgid, ...)) ...@@ -213,7 +211,7 @@ cpp_ice VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #endif
if (_cpp_begin_message (pfile, ICE, NULL, 0, 0)) if (_cpp_begin_message (pfile, ICE, NULL, 0))
v_message (msgid, ap); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -240,7 +238,7 @@ cpp_fatal VPARAMS ((cpp_reader *pfile, const char *msgid, ...)) ...@@ -240,7 +238,7 @@ cpp_fatal VPARAMS ((cpp_reader *pfile, const char *msgid, ...))
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #endif
if (_cpp_begin_message (pfile, FATAL, NULL, 0, 0)) if (_cpp_begin_message (pfile, FATAL, NULL, 0))
v_message (msgid, ap); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -261,7 +259,7 @@ cpp_error VPARAMS ((cpp_reader * pfile, const char *msgid, ...)) ...@@ -261,7 +259,7 @@ cpp_error VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #endif
if (_cpp_begin_message (pfile, ERROR, NULL, 0, 0)) if (_cpp_begin_message (pfile, ERROR, NULL, 0))
v_message (msgid, ap); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -277,6 +275,7 @@ cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column, ...@@ -277,6 +275,7 @@ cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column,
const char *msgid; const char *msgid;
#endif #endif
va_list ap; va_list ap;
cpp_lexer_pos pos;
VA_START (ap, msgid); VA_START (ap, msgid);
...@@ -287,7 +286,9 @@ cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column, ...@@ -287,7 +286,9 @@ cpp_error_with_line VPARAMS ((cpp_reader *pfile, int line, int column,
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #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); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -317,7 +318,7 @@ cpp_warning VPARAMS ((cpp_reader * pfile, const char *msgid, ...)) ...@@ -317,7 +318,7 @@ cpp_warning VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #endif
if (_cpp_begin_message (pfile, WARNING, NULL, 0, 0)) if (_cpp_begin_message (pfile, WARNING, NULL, 0))
v_message (msgid, ap); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -333,6 +334,7 @@ cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column, ...@@ -333,6 +334,7 @@ cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
const char *msgid; const char *msgid;
#endif #endif
va_list ap; va_list ap;
cpp_lexer_pos pos;
VA_START (ap, msgid); VA_START (ap, msgid);
...@@ -343,7 +345,9 @@ cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column, ...@@ -343,7 +345,9 @@ cpp_warning_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #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); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -364,7 +368,7 @@ cpp_pedwarn VPARAMS ((cpp_reader * pfile, const char *msgid, ...)) ...@@ -364,7 +368,7 @@ cpp_pedwarn VPARAMS ((cpp_reader * pfile, const char *msgid, ...))
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #endif
if (_cpp_begin_message (pfile, PEDWARN, NULL, 0, 0)) if (_cpp_begin_message (pfile, PEDWARN, NULL, 0))
v_message (msgid, ap); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -380,6 +384,7 @@ cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column, ...@@ -380,6 +384,7 @@ cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
const char *msgid; const char *msgid;
#endif #endif
va_list ap; va_list ap;
cpp_lexer_pos pos;
VA_START (ap, msgid); VA_START (ap, msgid);
...@@ -390,7 +395,9 @@ cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column, ...@@ -390,7 +395,9 @@ cpp_pedwarn_with_line VPARAMS ((cpp_reader * pfile, int line, int column,
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #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); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -411,6 +418,7 @@ cpp_pedwarn_with_file_and_line VPARAMS ((cpp_reader *pfile, ...@@ -411,6 +418,7 @@ cpp_pedwarn_with_file_and_line VPARAMS ((cpp_reader *pfile,
const char *msgid; const char *msgid;
#endif #endif
va_list ap; va_list ap;
cpp_lexer_pos pos;
VA_START (ap, msgid); VA_START (ap, msgid);
...@@ -422,7 +430,9 @@ cpp_pedwarn_with_file_and_line VPARAMS ((cpp_reader *pfile, ...@@ -422,7 +430,9 @@ cpp_pedwarn_with_file_and_line VPARAMS ((cpp_reader *pfile,
msgid = va_arg (ap, const char *); msgid = va_arg (ap, const char *);
#endif #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); v_message (msgid, ap);
va_end(ap); va_end(ap);
} }
...@@ -462,11 +472,3 @@ cpp_notice_from_errno (pfile, name) ...@@ -462,11 +472,3 @@ cpp_notice_from_errno (pfile, name)
name = "stdout"; name = "stdout";
cpp_notice (pfile, "%s: %s", name, xstrerror (errno)); 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;
}
...@@ -63,10 +63,10 @@ static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, ...@@ -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_number PARAMS ((cpp_reader *, const cpp_token *));
static struct op parse_charconst 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_defined PARAMS ((cpp_reader *));
static struct op parse_assertion PARAMS ((cpp_reader *));
static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **, static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **,
const U_CHAR *, HOST_WIDEST_INT)); 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 struct op
{ {
...@@ -291,7 +291,7 @@ parse_charconst (pfile, tok) ...@@ -291,7 +291,7 @@ parse_charconst (pfile, tok)
/* If char type is signed, sign-extend the constant. */ /* If char type is signed, sign-extend the constant. */
num_bits = num_chars * width; 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) || ((result >> (num_bits - 1)) & 1) == 0)
op.value = result & ((unsigned HOST_WIDEST_INT) ~0 op.value = result & ((unsigned HOST_WIDEST_INT) ~0
>> (HOST_BITS_PER_WIDEST_INT - num_bits)); >> (HOST_BITS_PER_WIDEST_INT - num_bits));
...@@ -313,85 +313,85 @@ static struct op ...@@ -313,85 +313,85 @@ static struct op
parse_defined (pfile) parse_defined (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int paren; int paren = 0;
const cpp_token *tok; cpp_hashnode *node = 0;
cpp_token token;
struct op op; struct op op;
paren = 0; /* Don't expand macros. */
tok = _cpp_get_raw_token (pfile); pfile->state.prevent_expansion++;
if (tok->type == CPP_OPEN_PAREN)
_cpp_get_token (pfile, &token);
if (token.type == CPP_OPEN_PAREN)
{ {
paren = 1; paren = 1;
tok = _cpp_get_raw_token (pfile); _cpp_get_token (pfile, &token);
} }
if (tok->type != CPP_NAME) if (token.type == CPP_NAME)
SYNTAX_ERROR ("\"defined\" without an identifier"); {
node = token.val.node;
if (paren && _cpp_get_raw_token (pfile)->type != CPP_CLOSE_PAREN) if (paren)
SYNTAX_ERROR ("missing close paren after \"defined\""); {
_cpp_get_token (pfile, &token);
if (tok->val.node->type == T_POISON) if (token.type != CPP_CLOSE_PAREN)
SYNTAX_ERROR2 ("attempt to use poisoned \"%s\"", tok->val.node->name); {
cpp_error (pfile, "missing ')' after \"defined\"");
op.value = tok->val.node->type != T_VOID; node = 0;
op.unsignedp = 0; }
op.op = CPP_INT; }
return op; }
else
syntax_error: cpp_error (pfile, "\"defined\" without an identifier");
op.op = CPP_ERROR;
return op;
}
static struct op
parse_assertion (pfile)
cpp_reader *pfile;
{
struct op op;
struct answer *answer;
cpp_hashnode *hp;
op.op = CPP_ERROR; if (!node)
hp = _cpp_parse_assertion (pfile, &answer); op.op = CPP_ERROR;
if (hp) else
{ {
/* If we get here, the syntax is valid. */ op.value = node->type == NT_MACRO;
op.op = CPP_INT;
op.unsignedp = 0; op.unsignedp = 0;
op.value = (hp->type == T_ASSERTION && op.op = CPP_INT;
(answer == 0 || *_cpp_find_answer (hp, &answer->list) != 0));
if (answer) /* No macros? At top of file? */
FREE_ANSWER (answer); 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; return op;
} }
/* Read one token. */ /* Read one token. */
static struct op static struct op
lex (pfile, skip_evaluation) lex (pfile, skip_evaluation, token)
cpp_reader *pfile; cpp_reader *pfile;
int skip_evaluation; int skip_evaluation;
cpp_token *token;
{ {
struct op op; struct op op;
const cpp_token *tok;
retry: retry:
tok = _cpp_get_token (pfile); _cpp_get_token (pfile, token);
switch (tok->type) switch (token->type)
{ {
case CPP_PLACEMARKER: case CPP_PLACEMARKER:
goto retry; goto retry;
case CPP_INT: case CPP_INT:
case CPP_NUMBER: case CPP_NUMBER:
return parse_number (pfile, tok); return parse_number (pfile, token);
case CPP_CHAR: case CPP_CHAR:
case CPP_WCHAR: case CPP_WCHAR:
return parse_charconst (pfile, tok); return parse_charconst (pfile, token);
case CPP_STRING: case CPP_STRING:
case CPP_WSTRING: case CPP_WSTRING:
...@@ -401,36 +401,60 @@ lex (pfile, skip_evaluation) ...@@ -401,36 +401,60 @@ lex (pfile, skip_evaluation)
SYNTAX_ERROR ("floating point numbers are not valid in #if"); SYNTAX_ERROR ("floating point numbers are not valid in #if");
case CPP_OTHER: case CPP_OTHER:
if (ISGRAPH (tok->val.aux)) if (ISGRAPH (token->val.aux))
SYNTAX_ERROR2 ("invalid character '%c' in #if", tok->val.aux); SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.aux);
else else
SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", tok->val.aux); SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.aux);
case CPP_DEFINED:
return parse_defined (pfile);
case CPP_NAME: 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.op = CPP_INT;
op.unsignedp = 0; op.unsignedp = 0;
op.value = 0; op.value = 0;
if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation) 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; return op;
case CPP_HASH: 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: default:
if ((tok->type > CPP_EQ && tok->type < CPP_PLUS_EQ) if ((token->type > CPP_EQ && token->type < CPP_PLUS_EQ)
|| tok->type == CPP_EOF) || token->type == CPP_EOF)
{ {
op.op = tok->type; op.op = token->type;
return op; 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: syntax_error:
op.op = CPP_ERROR; op.op = CPP_ERROR;
...@@ -709,8 +733,6 @@ op_to_prio[] = ...@@ -709,8 +733,6 @@ op_to_prio[] =
/* Parse and evaluate a C expression, reading from PFILE. /* Parse and evaluate a C expression, reading from PFILE.
Returns the truth value of the expression. */ Returns the truth value of the expression. */
#define TYPE_NAME(t) _cpp_token_spellings[t].name
int int
_cpp_parse_expr (pfile) _cpp_parse_expr (pfile)
cpp_reader *pfile; cpp_reader *pfile;
...@@ -729,6 +751,7 @@ _cpp_parse_expr (pfile) ...@@ -729,6 +751,7 @@ _cpp_parse_expr (pfile)
struct op init_stack[INIT_STACK_SIZE]; struct op init_stack[INIT_STACK_SIZE];
struct op *stack = init_stack; struct op *stack = init_stack;
struct op *limit = stack + INIT_STACK_SIZE; struct op *limit = stack + INIT_STACK_SIZE;
cpp_token token;
register struct op *top = stack + 1; register struct op *top = stack + 1;
int skip_evaluation = 0; int skip_evaluation = 0;
int result; int result;
...@@ -737,6 +760,10 @@ _cpp_parse_expr (pfile) ...@@ -737,6 +760,10 @@ _cpp_parse_expr (pfile)
int save_skipping = pfile->skipping; int save_skipping = pfile->skipping;
pfile->skipping = 0; 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. */ /* We've finished when we try to reduce this. */
top->op = CPP_EOF; top->op = CPP_EOF;
/* Nifty way to catch missing '('. */ /* Nifty way to catch missing '('. */
...@@ -751,7 +778,8 @@ _cpp_parse_expr (pfile) ...@@ -751,7 +778,8 @@ _cpp_parse_expr (pfile)
struct op op; struct op op;
/* Read a token */ /* 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 /* If the token is an operand, push its value and get next
token. If it is an operator, get its priority and flags, and token. If it is an operator, get its priority and flags, and
...@@ -797,7 +825,7 @@ _cpp_parse_expr (pfile) ...@@ -797,7 +825,7 @@ _cpp_parse_expr (pfile)
SYNTAX_ERROR ("void expression between '(' and ')'"); SYNTAX_ERROR ("void expression between '(' and ')'");
else else
SYNTAX_ERROR2 ("operator '%s' has no right operand", SYNTAX_ERROR2 ("operator '%s' has no right operand",
TYPE_NAME (top->op)); op_as_text (pfile, top->op));
} }
unsigned2 = top->unsignedp, v2 = top->value; unsigned2 = top->unsignedp, v2 = top->value;
...@@ -808,7 +836,8 @@ _cpp_parse_expr (pfile) ...@@ -808,7 +836,8 @@ _cpp_parse_expr (pfile)
switch (top[1].op) switch (top[1].op)
{ {
default: 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; goto syntax_error;
case CPP_NOT: UNARY(!); break; case CPP_NOT: UNARY(!); break;
...@@ -967,13 +996,13 @@ _cpp_parse_expr (pfile) ...@@ -967,13 +996,13 @@ _cpp_parse_expr (pfile)
{ {
if (top->flags & HAVE_VALUE) if (top->flags & HAVE_VALUE)
SYNTAX_ERROR2 ("missing binary operator before '%s'", SYNTAX_ERROR2 ("missing binary operator before '%s'",
TYPE_NAME (op.op)); op_as_text (pfile, top->op));
} }
else else
{ {
if (!(top->flags & HAVE_VALUE)) if (!(top->flags & HAVE_VALUE))
SYNTAX_ERROR2 ("operator '%s' has no left operand", SYNTAX_ERROR2 ("operator '%s' has no left operand",
TYPE_NAME (op.op)); op_as_text (pfile, top->op));
} }
/* Check for and handle stack overflow. */ /* Check for and handle stack overflow. */
...@@ -1017,3 +1046,15 @@ _cpp_parse_expr (pfile) ...@@ -1017,3 +1046,15 @@ _cpp_parse_expr (pfile)
pfile->skipping = save_skipping; pfile->skipping = save_skipping;
return result; 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);
}
...@@ -217,6 +217,10 @@ stack_include_file (pfile, inc) ...@@ -217,6 +217,10 @@ stack_include_file (pfile, inc)
if (fp == 0) if (fp == 0)
return 0; return 0;
/* Initialise controlling macro state. */
pfile->mi_state = MI_OUTSIDE;
pfile->mi_cmacro = 0;
fp->inc = inc; fp->inc = inc;
fp->nominal_fname = inc->name; fp->nominal_fname = inc->name;
fp->buf = inc->buffer; fp->buf = inc->buffer;
...@@ -233,8 +237,10 @@ stack_include_file (pfile, inc) ...@@ -233,8 +237,10 @@ stack_include_file (pfile, inc)
fp->inc->refcnt++; fp->inc->refcnt++;
pfile->include_depth++; pfile->include_depth++;
pfile->input_stack_listing_current = 0; pfile->input_stack_listing_current = 0;
if (pfile->cb.enter_file) if (pfile->cb.enter_file)
(*pfile->cb.enter_file) (pfile); (*pfile->cb.enter_file) (pfile);
return 1; return 1;
} }
...@@ -562,17 +568,21 @@ report_missing_guard (n, b) ...@@ -562,17 +568,21 @@ report_missing_guard (n, b)
#define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth)) #define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
void 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; cpp_reader *pfile;
const U_CHAR *f; const cpp_token *header;
unsigned int len;
int no_reinclude; int no_reinclude;
struct file_name_list *search_start; 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; struct include_file *inc;
char *fname; char *fname;
fname = alloca (len + 1);
memcpy (fname, header->val.str.text, len);
fname[len] = '\0';
if (!search_start) if (!search_start)
{ {
if (angle_brackets) if (angle_brackets)
...@@ -581,18 +591,14 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start, 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); search_start = CPP_OPTION (pfile, quote_include);
else else
search_start = CPP_BUFFER (pfile)->actual_dir; search_start = CPP_BUFFER (pfile)->actual_dir;
}
if (!search_start) if (!search_start)
{ {
cpp_error (pfile, "No include path in which to find %s", f); cpp_error (pfile, "No include path in which to find %s", fname);
return; return;
}
} }
fname = alloca (len + 1);
memcpy (fname, f, len);
fname[len] = '\0';
inc = find_include_file (pfile, fname, search_start); inc = find_include_file (pfile, fname, search_start);
if (inc) if (inc)
...@@ -666,20 +672,17 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets) ...@@ -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, /* 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. */ if F cannot be located or dated, 1, if it is newer and 0 if older. */
int int
_cpp_compare_file_date (pfile, f, len, angle_brackets) _cpp_compare_file_date (pfile, f)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *f; const cpp_token *f;
unsigned int len;
int angle_brackets;
{ {
unsigned int len = f->val.str.len;
char *fname; char *fname;
struct file_name_list *search_start; struct file_name_list *search_start;
struct include_file *inc; 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); search_start = CPP_OPTION (pfile, bracket_include);
else if (CPP_OPTION (pfile, ignore_srcdir)) else if (CPP_OPTION (pfile, ignore_srcdir))
search_start = CPP_OPTION (pfile, quote_include); search_start = CPP_OPTION (pfile, quote_include);
...@@ -687,7 +690,7 @@ _cpp_compare_file_date (pfile, f, len, angle_brackets) ...@@ -687,7 +690,7 @@ _cpp_compare_file_date (pfile, f, len, angle_brackets)
search_start = CPP_BUFFER (pfile)->actual_dir; search_start = CPP_BUFFER (pfile)->actual_dir;
fname = alloca (len + 1); fname = alloca (len + 1);
memcpy (fname, f, len); memcpy (fname, f->val.str.text, len);
fname[len] = '\0'; fname[len] = '\0';
inc = find_include_file (pfile, fname, search_start); inc = find_include_file (pfile, fname, search_start);
...@@ -699,7 +702,7 @@ _cpp_compare_file_date (pfile, f, len, angle_brackets) ...@@ -699,7 +702,7 @@ _cpp_compare_file_date (pfile, f, len, angle_brackets)
inc->fd = -1; 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) ...@@ -723,6 +726,10 @@ cpp_read_file (pfile, fname)
return 0; return 0;
} }
/* Return success for zero-length files. */
if (DO_NOT_REREAD (f))
return 1;
return stack_include_file (pfile, f); return stack_include_file (pfile, f);
} }
...@@ -739,13 +746,18 @@ _cpp_pop_file_buffer (pfile, buf) ...@@ -739,13 +746,18 @@ _cpp_pop_file_buffer (pfile, buf)
pfile->system_include_depth--; pfile->system_include_depth--;
if (pfile->include_depth) if (pfile->include_depth)
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) /* This could be NULL meaning no controlling macro. */
inc->cmacro = pfile->potential_control_macro; inc->cmacro = pfile->mi_cmacro;
pfile->potential_control_macro = 0; inc->defined = 1;
} }
pfile->input_stack_listing_current = 0;
/* Invalidate control macros in the #including file. */
pfile->mi_state = MI_FAILED;
inc->refcnt--; inc->refcnt--;
if (inc->refcnt == 0 && DO_NOT_REREAD (inc)) if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
......
...@@ -49,7 +49,7 @@ static unsigned long higher_prime_number PARAMS ((unsigned long)); ...@@ -49,7 +49,7 @@ static unsigned long higher_prime_number PARAMS ((unsigned long));
/* Set up and tear down internal structures for macro expansion. */ /* Set up and tear down internal structures for macro expansion. */
void void
_cpp_init_macros (pfile) _cpp_init_hashtable (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
pfile->hash_ob = xnew (struct obstack); pfile->hash_ob = xnew (struct obstack);
...@@ -63,7 +63,7 @@ _cpp_init_macros (pfile) ...@@ -63,7 +63,7 @@ _cpp_init_macros (pfile)
} }
void void
_cpp_cleanup_macros (pfile) _cpp_cleanup_hashtable (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_hashnode **p, **limit; cpp_hashnode **p, **limit;
...@@ -101,29 +101,32 @@ cpp_lookup (pfile, name, len) ...@@ -101,29 +101,32 @@ cpp_lookup (pfile, name, len)
size_t n = len; size_t n = len;
unsigned int r = 0; unsigned int r = 0;
const U_CHAR *str = name; const U_CHAR *str = name;
U_CHAR *dest = _cpp_pool_reserve (&pfile->ident_pool, len + 1);
do do
{ {
r = HASHSTEP (r, *str); r = HASHSTEP (r, *str);
str++; *dest++ = *str++;
} }
while (--n); 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_hashnode *
_cpp_lookup_with_hash (pfile, name, len, hash) _cpp_lookup_with_hash (pfile, len, hash)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *name;
size_t len; size_t len;
unsigned int hash; unsigned int hash;
{ {
unsigned int index; unsigned int index;
unsigned int hash2;
size_t size; size_t size;
cpp_hashnode *entry; cpp_hashnode *entry;
cpp_hashnode **entries; cpp_hashnode **entries;
unsigned char *name = POOL_FRONT (&pfile->ident_pool);
entries = pfile->hashtab->entries; entries = pfile->hashtab->entries;
size = pfile->hashtab->size; size = pfile->hashtab->size;
...@@ -132,48 +135,49 @@ _cpp_lookup_with_hash (pfile, name, len, hash) ...@@ -132,48 +135,49 @@ _cpp_lookup_with_hash (pfile, name, len, hash)
index = hash % size; index = hash % size;
entry = entries[index]; entry = entries[index];
if (entry == NULL) if (entry)
goto insert;
if (entry->hash == hash && entry->length == len
&& !memcmp (entry->name, name, len))
return entry;
hash2 = 1 + hash % (size - 2);
for (;;)
{ {
index += hash2; unsigned int hash2;
if (index >= size)
index -= size;
entry = entries[index];
if (entry == NULL)
goto insert;
if (entry->hash == hash && entry->length == len if (entry->hash == hash && entry->length == len
&& !memcmp (entry->name, name, len)) && !memcmp (entry->name, name, len))
return entry; 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: /* Commit the memory for the identifier. */
pfile->hashtab->nelts++; POOL_COMMIT (&pfile->ident_pool, len + 1);
/* Create a new hash node. */ /* Create a new hash node and insert it in the table. */
{ entries[index] = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode));
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;
}
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) if (size * 3 <= pfile->hashtab->nelts * 4)
expand_hash (pfile->hashtab); expand_hash (pfile->hashtab);
......
...@@ -22,68 +22,30 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ...@@ -22,68 +22,30 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef __GCC_CPPHASH__ #ifndef __GCC_CPPHASH__
#define __GCC_CPPHASH__ #define __GCC_CPPHASH__
typedef unsigned char U_CHAR; /* Test if a sign is valid within a preprocessing number. */
#define U (const U_CHAR *) /* Intended use: U"string" */ #define VALID_SIGN(c, prevc) \
(((c) == '+' || (c) == '-') && \
/* Tokens with SPELL_STRING store their spelling in the token list, ((prevc) == 'e' || (prevc) == 'E' \
and it's length in the token->val.name.len. */ || (((prevc) == 'p' || (prevc) == 'P') && !CPP_OPTION (pfile, c89))))
enum spell_type
/* 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, cpp_chunk *next;
SPELL_CHAR, unsigned char *front;
SPELL_IDENT, unsigned char *limit;
SPELL_STRING, unsigned char *base;
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. */
}; };
/* List of directories to look for include files in. */ /* List of directories to look for include files in. */
...@@ -122,28 +84,18 @@ struct include_file ...@@ -122,28 +84,18 @@ struct include_file
unsigned short refcnt; /* number of stacked buffers using this file */ unsigned short refcnt; /* number of stacked buffers using this file */
unsigned char sysp; /* file is a system header */ unsigned char sysp; /* file is a system header */
unsigned char mapped; /* file buffer is mmapped */ 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 /* 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. If it's NEVER_REREAD, the file is never to be
included again. Otherwise it is a macro hashnode, and the file is 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 NEVER_REREAD ((const cpp_hashnode *)-1)
#define DO_NOT_REREAD(inc) \ #define DO_NOT_REREAD(inc) \
((inc)->cmacro && \ ((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \
((inc)->cmacro == NEVER_REREAD || (inc)->cmacro->type != T_VOID)) || ((inc)->cmacro->type == NT_MACRO) == (inc)->defined))
/* 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 */
};
/* Character classes. /* Character classes.
If the definition of `numchar' looks odd to you, please look up the 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]; ...@@ -200,27 +152,30 @@ extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
/* In cpperror.c */ /* In cpperror.c */
enum error_type { WARNING = 0, PEDWARN, ERROR, FATAL, ICE }; enum error_type { WARNING = 0, PEDWARN, ERROR, FATAL, ICE };
extern int _cpp_begin_message PARAMS ((cpp_reader *, enum error_type, extern int _cpp_begin_message PARAMS ((cpp_reader *, enum error_type,
const char *, unsigned int, const char *, const cpp_lexer_pos *));
unsigned int));
/* In cppmacro.c */ /* In cppmacro.c */
extern void _cpp_free_definition PARAMS ((cpp_hashnode *)); extern void _cpp_free_definition PARAMS ((cpp_hashnode *));
extern int _cpp_create_definition PARAMS ((cpp_reader *, 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 */ /* In cpphash.c */
extern void _cpp_init_macros PARAMS ((cpp_reader *)); extern void _cpp_init_hashtable PARAMS ((cpp_reader *));
extern void _cpp_cleanup_macros PARAMS ((cpp_reader *)); extern void _cpp_cleanup_hashtable PARAMS ((cpp_reader *));
extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, const U_CHAR *, extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, size_t,
size_t, unsigned int)); unsigned int));
/* In cppfiles.c */ /* In cppfiles.c */
extern void _cpp_simplify_pathname PARAMS ((char *)); extern void _cpp_simplify_pathname PARAMS ((char *));
extern void _cpp_execute_include PARAMS ((cpp_reader *, const U_CHAR *, extern void _cpp_execute_include PARAMS ((cpp_reader *,
unsigned int, int, const cpp_token *, int,
struct file_name_list *, struct file_name_list *));
int)); extern int _cpp_compare_file_date PARAMS ((cpp_reader *,
extern int _cpp_compare_file_date PARAMS ((cpp_reader *, const U_CHAR *, const cpp_token *));
unsigned int, int));
extern void _cpp_report_missing_guards PARAMS ((cpp_reader *)); extern void _cpp_report_missing_guards PARAMS ((cpp_reader *));
extern void _cpp_init_includes PARAMS ((cpp_reader *)); extern void _cpp_init_includes PARAMS ((cpp_reader *));
extern void _cpp_cleanup_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 *)); ...@@ -231,113 +186,33 @@ extern void _cpp_pop_file_buffer PARAMS ((cpp_reader *, cpp_buffer *));
extern int _cpp_parse_expr PARAMS ((cpp_reader *)); extern int _cpp_parse_expr PARAMS ((cpp_reader *));
/* In cpplex.c */ /* In cpplex.c */
extern const unsigned char *_cpp_digraph_spellings[]; extern void _cpp_lex_token PARAMS ((cpp_reader *, cpp_token *));
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 int _cpp_equiv_tokens PARAMS ((const cpp_token *, extern int _cpp_equiv_tokens PARAMS ((const cpp_token *,
const cpp_token *)); const cpp_token *));
extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *, extern void _cpp_init_pool PARAMS ((cpp_pool *, unsigned int,
const cpp_toklist *)); unsigned int, unsigned int));
extern void _cpp_expand_token_space PARAMS ((cpp_toklist *, unsigned int)); extern void _cpp_free_pool PARAMS ((cpp_pool *));
extern void _cpp_reserve_name_space PARAMS ((cpp_toklist *, unsigned int)); extern unsigned char *_cpp_pool_reserve PARAMS ((cpp_pool *, unsigned int));
extern void _cpp_expand_name_space PARAMS ((cpp_toklist *, unsigned int)); extern unsigned char *_cpp_pool_alloc PARAMS ((cpp_pool *, unsigned int));
extern int _cpp_equiv_tokens PARAMS ((const cpp_token *, extern unsigned char *_cpp_next_chunk PARAMS ((cpp_pool *, unsigned int,
const cpp_token *)); unsigned char **));
extern void _cpp_process_directive PARAMS ((cpp_reader *, const cpp_token *)); extern void _cpp_lock_pool PARAMS ((cpp_pool *));
extern void _cpp_run_directive PARAMS ((cpp_reader *, extern void _cpp_unlock_pool PARAMS ((cpp_pool *));
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 *));
/* In cpplib.c */ /* In cpplib.c */
extern const struct directive *_cpp_check_directive extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *));
PARAMS ((cpp_reader *, const cpp_token *)); extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
extern const struct directive *_cpp_check_linemarker extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *));
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 void _cpp_init_stacks PARAMS ((cpp_reader *)); extern void _cpp_init_stacks PARAMS ((cpp_reader *));
extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *)); extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *));
extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *)); extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));
/* Utility routines and macros. */ /* Utility routines and macros. */
#define DSC(str) (const U_CHAR *)str, sizeof str - 1
#define xnew(T) (T *) xmalloc (sizeof(T)) #define xnew(T) (T *) xmalloc (sizeof(T))
#define xcnew(T) (T *) xcalloc (1, sizeof(T)) #define xcnew(T) (T *) xcalloc (1, sizeof(T))
#define xnewvec(T, N) (T *) xmalloc (sizeof(T) * (N)) #define xnewvec(T, N) (T *) xmalloc (sizeof(T) * (N))
#define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T)) #define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T))
#define xobnew(O, T) (T *) obstack_alloc (O, 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 #endif
...@@ -427,8 +427,19 @@ void ...@@ -427,8 +427,19 @@ void
cpp_reader_init (pfile) cpp_reader_init (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
struct spec_nodes *s;
memset ((char *) pfile, 0, sizeof (cpp_reader)); 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, dollars_in_ident) = 1;
CPP_OPTION (pfile, cplusplus_comments) = 1; CPP_OPTION (pfile, cplusplus_comments) = 1;
CPP_OPTION (pfile, warn_import) = 1; CPP_OPTION (pfile, warn_import) = 1;
...@@ -441,44 +452,45 @@ cpp_reader_init (pfile) ...@@ -441,44 +452,45 @@ cpp_reader_init (pfile)
CPP_OPTION (pfile, pending) = CPP_OPTION (pfile, pending) =
(struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending)); (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
/* If cpp_init hasn't been called, generate a fatal error (by hand) /* Initialize comment saving state. */
and call it here. */ pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
if (!cpp_init_completed)
{ /* Indicate date and time not yet calculated. */
fputs ("cpp_reader_init: internal error: cpp_init not called.\n", stderr); pfile->date.type = CPP_EOF;
pfile->errors = CPP_FATAL_LIMIT;
cpp_init (); /* 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_stacks (pfile);
_cpp_init_includes (pfile); _cpp_init_includes (pfile);
_cpp_init_internal_pragmas (pfile); _cpp_init_internal_pragmas (pfile);
}
/* Initialize a cpp_printer structure. As a side effect, open the /* Initialize the special nodes. */
output file. */ s = &pfile->spec_nodes;
cpp_printer * s->n_L = cpp_lookup (pfile, DSC("L"));
cpp_printer_init (pfile, print) s->n_defined = cpp_lookup (pfile, DSC("defined"));
cpp_reader *pfile; s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
cpp_printer *print; s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
{ s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
memset (print, '\0', sizeof (cpp_printer)); s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
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;
} }
/* Free resources used by PFILE. /* Free resources used by PFILE.
...@@ -487,69 +499,84 @@ void ...@@ -487,69 +499,84 @@ void
cpp_cleanup (pfile) cpp_cleanup (pfile)
cpp_reader *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) while (CPP_BUFFER (pfile) != NULL)
cpp_pop_buffer (pfile); cpp_pop_buffer (pfile);
if (pfile->macro_buffer)
free ((PTR) pfile->macro_buffer);
if (pfile->deps) if (pfile->deps)
deps_free (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_includes (pfile);
_cpp_cleanup_stacks (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->name);
free (dir); 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 /* This structure defines one built-in identifier. A node will be
be entered in the macro hash table under the name NAME, with value entered in the hash table under the name NAME, with value VALUE (if
VALUE (if any). If TYPE is T_OPERATOR, the CODE field is used instead. 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 Two values are not compile time constants, so we tag
them in the FLAGS field instead: them in the FLAGS field instead:
VERS value is the global version_string, quoted VERS value is the global version_string, quoted
ULP value is the global user_label_prefix 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 struct builtin
{ {
const U_CHAR *name; const U_CHAR *name;
const char *value; const char *value;
unsigned char code; unsigned char builtin;
unsigned char type; unsigned char operator;
unsigned short flags; unsigned short flags;
unsigned int len; unsigned short len;
}; };
#define VERS 0x01 #define VERS 0x01
#define ULP 0x02 #define ULP 0x02
#define CPLUS 0x04 #define CPLUS 0x04
#define BUILTIN 0x08
#define B(n, t) { U n, 0, 0, t, 0, sizeof n - 1 } #define OPERATOR 0x10
#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 B(n, t) { U n, 0, t, 0, BUILTIN, sizeof n - 1 }
#define O(n, c, f) { U n, 0, c, T_OPERATOR, f, 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[] = static const struct builtin builtin_array[] =
{ {
B("__TIME__", T_TIME), B("__TIME__", BT_TIME),
B("__DATE__", T_DATE), B("__DATE__", BT_DATE),
B("__FILE__", T_FILE), B("__FILE__", BT_FILE),
B("__BASE_FILE__", T_BASE_FILE), B("__BASE_FILE__", BT_BASE_FILE),
B("__LINE__", T_SPECLINE), B("__LINE__", BT_SPECLINE),
B("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL), B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
B("__STDC__", T_STDC), B("__STDC__", BT_STDC),
X("__VERSION__", VERS), X("__VERSION__", VERS),
X("__USER_LABEL_PREFIX__", ULP), X("__USER_LABEL_PREFIX__", ULP),
...@@ -570,9 +597,8 @@ static const struct builtin builtin_array[] = ...@@ -570,9 +597,8 @@ static const struct builtin builtin_array[] =
/* Named operators known to the preprocessor. These cannot be #defined /* Named operators known to the preprocessor. These cannot be #defined
and always have their stated meaning. They are treated like normal 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). */ are only for C++ (but see iso646.h). */
O("defined", CPP_DEFINED, 0),
O("and", CPP_AND_AND, CPLUS), O("and", CPP_AND_AND, CPLUS),
O("and_eq", CPP_AND_EQ, CPLUS), O("and_eq", CPP_AND_EQ, CPLUS),
O("bitand", CPP_AND, CPLUS), O("bitand", CPP_AND, CPLUS),
...@@ -583,7 +609,7 @@ static const struct builtin builtin_array[] = ...@@ -583,7 +609,7 @@ static const struct builtin builtin_array[] =
O("or", CPP_OR_OR, CPLUS), O("or", CPP_OR_OR, CPLUS),
O("or_eq", CPP_OR_EQ, CPLUS), O("or_eq", CPP_OR_EQ, CPLUS),
O("xor", CPP_XOR, CPLUS), O("xor", CPP_XOR, CPLUS),
O("xor_eq", CPP_XOR_EQ, CPLUS), O("xor_eq", CPP_XOR_EQ, CPLUS)
}; };
#undef B #undef B
#undef C #undef C
...@@ -601,10 +627,25 @@ initialize_builtins (pfile) ...@@ -601,10 +627,25 @@ initialize_builtins (pfile)
for(b = builtin_array; b < builtin_array_end; b++) 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; 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; const char *val;
char *str; char *str;
...@@ -629,17 +670,13 @@ initialize_builtins (pfile) ...@@ -629,17 +670,13 @@ initialize_builtins (pfile)
_cpp_define_builtin (pfile, str); _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 VERS
#undef ULP #undef ULP
#undef CPLUS
#undef builtin_array_end #undef builtin_array_end
/* Another subroutine of cpp_start_read. This one sets up to do /* Another subroutine of cpp_start_read. This one sets up to do
...@@ -799,9 +836,8 @@ initialize_standard_includes (pfile) ...@@ -799,9 +836,8 @@ initialize_standard_includes (pfile)
*/ */
int int
cpp_start_read (pfile, print, fname) cpp_start_read (pfile, fname)
cpp_reader *pfile; cpp_reader *pfile;
cpp_printer *print;
const char *fname; const char *fname;
{ {
struct pending_option *p, *q; struct pending_option *p, *q;
...@@ -829,19 +865,6 @@ cpp_start_read (pfile, print, fname) ...@@ -829,19 +865,6 @@ cpp_start_read (pfile, print, fname)
if (CPP_OPTION (pfile, user_label_prefix) == NULL) if (CPP_OPTION (pfile, user_label_prefix) == NULL)
CPP_OPTION (pfile, user_label_prefix) = USER_LABEL_PREFIX; 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. */ /* Set up the include search path now. */
if (! CPP_OPTION (pfile, no_standard_includes)) if (! CPP_OPTION (pfile, no_standard_includes))
initialize_standard_includes (pfile); initialize_standard_includes (pfile);
...@@ -893,13 +916,6 @@ cpp_start_read (pfile, print, fname) ...@@ -893,13 +916,6 @@ cpp_start_read (pfile, print, fname)
} }
pfile->done_initializing = 1; 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 /* The -imacros files can be scanned now, but the -include files
have to be pushed onto the include stack and processed later, have to be pushed onto the include stack and processed later,
in the main loop calling cpp_get_token. */ in the main loop calling cpp_get_token. */
...@@ -934,9 +950,8 @@ cpp_start_read (pfile, print, fname) ...@@ -934,9 +950,8 @@ cpp_start_read (pfile, print, fname)
clear macro definitions, such that you could call cpp_start_read clear macro definitions, such that you could call cpp_start_read
with a new filename to restart processing. */ with a new filename to restart processing. */
void void
cpp_finish (pfile, print) cpp_finish (pfile)
cpp_reader *pfile; cpp_reader *pfile;
cpp_printer *print;
{ {
if (CPP_BUFFER (pfile)) if (CPP_BUFFER (pfile))
{ {
...@@ -971,15 +986,6 @@ cpp_finish (pfile, print) ...@@ -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. */ /* Report on headers that could use multiple include guards. */
if (CPP_OPTION (pfile, print_include_names)) if (CPP_OPTION (pfile, print_include_names))
_cpp_report_missing_guards (pfile); _cpp_report_missing_guards (pfile);
......
...@@ -20,79 +20,54 @@ You should have received a copy of the GNU General Public License ...@@ -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 along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* /* 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
Cleanups to do:- input stream, to make future changes to support multi-byte
character sets fairly straight-forward.
o Distinguish integers, floats, and 'other' pp-numbers.
o Store ints and char constants as binary values. There is now only one routine where we do step backwards:
o New command-line assertion syntax. skip_escaped_newlines. This routine could probably also be changed
o Comment all functions, and describe macro expansion algorithm. so that it doesn't need to step back. One possibility is to use a
o Move as much out of header files as possible. trick similar to that used in lex_period and lex_percent. Two
o Remove single quote pairs `', and some '', from diagnostics. extra characters might be needed, but skip_escaped_newlines itself
o Correct pastability test for CPP_NAME and CPP_NUMBER. 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 "config.h"
#include "system.h" #include "system.h"
#include "intl.h"
#include "cpplib.h" #include "cpplib.h"
#include "cpphash.h" #include "cpphash.h"
#include "symcat.h" #include "symcat.h"
const unsigned char *_cpp_digraph_spellings [] = {U"%:", U"%:%:", U"<:", /* Tokens with SPELL_STRING store their spelling in the token list,
U":>", U"<%", U"%>"}; and it's length in the token->val.name.len. */
static const cpp_token placemarker_token = {0, 0, CPP_PLACEMARKER, enum spell_type
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
{ {
union SPELL_OPERATOR = 0,
{ SPELL_CHAR,
const cpp_toklist *list; /* Used for macro contexts only. */ SPELL_IDENT,
const cpp_token **arg; /* Used for arg contexts only. */ SPELL_STRING,
} u; SPELL_NONE
/* 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;
}; };
typedef struct macro_args macro_args; struct token_spelling
struct macro_args
{ {
unsigned int *ends; enum spell_type category;
const cpp_token **tokens; const unsigned char *name;
unsigned int capacity;
unsigned int used;
unsigned short level;
}; };
static const cpp_token *get_raw_token PARAMS ((cpp_reader *)); const unsigned char *digraph_spellings [] = {U"%:", U"%:%:", U"<:",
static const cpp_token *parse_arg PARAMS ((cpp_reader *, int, unsigned int, U":>", U"<%", U"%>"};
macro_args *, unsigned int *));
static int parse_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_args *)); #define OP(e, s) { SPELL_OPERATOR, U s },
static void save_token PARAMS ((macro_args *, const cpp_token *)); #define TK(e, s) { s, U STRINGX (e) },
static int pop_context PARAMS ((cpp_reader *)); const struct token_spelling token_spellings [N_TTYPES] = {TTYPE_TABLE };
static int push_macro_context PARAMS ((cpp_reader *, const cpp_token *)); #undef OP
static void push_arg_context PARAMS ((cpp_reader *, const cpp_token *)); #undef TK
static void free_macro_args PARAMS ((macro_args *));
#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 handle_newline PARAMS ((cpp_buffer *, cppchar_t));
static cppchar_t skip_escaped_newlines 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 *)); ...@@ -103,278 +78,18 @@ static int skip_line_comment PARAMS ((cpp_reader *));
static void adjust_column PARAMS ((cpp_reader *)); static void adjust_column PARAMS ((cpp_reader *));
static void skip_whitespace PARAMS ((cpp_reader *, cppchar_t)); static void skip_whitespace PARAMS ((cpp_reader *, cppchar_t));
static cpp_hashnode *parse_identifier 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 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 int trigraph_ok PARAMS ((cpp_reader *, cppchar_t));
static void save_comment PARAMS ((cpp_reader *, cpp_token *, const U_CHAR *)); static void save_comment PARAMS ((cpp_reader *, cpp_token *, const U_CHAR *));
static void lex_percent PARAMS ((cpp_buffer *, cpp_token *)); static void lex_percent PARAMS ((cpp_buffer *, cpp_token *));
static void lex_dot PARAMS ((cpp_reader *, cpp_token *)); static void lex_dot PARAMS ((cpp_reader *, cpp_token *));
static void lex_line PARAMS ((cpp_reader *, cpp_toklist *)); static int name_p PARAMS ((cpp_reader *, const cpp_string *));
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++) static cpp_chunk *new_chunk PARAMS ((unsigned int));
if (TOKEN_SPELL (&list->tokens[i]) == SPELL_STRING) static int chunk_suitable PARAMS ((cpp_pool *, cpp_chunk *, unsigned int));
list->tokens[i].val.str.text += (list->namebuf - old_namebuf);
}
}
/* If there is not enough room for LEN more characters, expand the
list by just enough to have room for LEN characters. */
void
_cpp_reserve_name_space (list, len)
cpp_toklist *list;
unsigned int len;
{
unsigned int room = list->name_cap - list->name_used;
if (room < len)
_cpp_expand_name_space (list, len - room);
}
/* Expand the number of tokens in a list. */
void
_cpp_expand_token_space (list, count)
cpp_toklist *list;
unsigned int count;
{
list->tokens_cap += count;
list->tokens = (cpp_token *)
xrealloc (list->tokens, list->tokens_cap * sizeof (cpp_token));
}
/* Initialize a token list. If EMPTY is false, some token and name
space is provided. */
void
_cpp_init_toklist (list, empty)
cpp_toklist *list;
int empty;
{
if (empty)
{
list->tokens_cap = 0;
list->tokens = 0;
list->name_cap = 0;
list->namebuf = 0;
}
else
{
/* Initialize token space. */
list->tokens_cap = 256; /* 4K's worth. */
list->tokens = (cpp_token *)
xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token));
/* Initialize name space. */
list->name_cap = 1024;
list->namebuf = (unsigned char *) xmalloc (list->name_cap);
}
_cpp_clear_toklist (list);
}
/* Clear a token list. */
void
_cpp_clear_toklist (list)
cpp_toklist *list;
{
list->tokens_used = 0;
list->name_used = 0;
list->directive = 0;
list->paramc = 0;
list->params_len = 0;
list->flags = 0;
}
/* Free a token list. Does not free the list itself, which may be
embedded in a larger structure. */
void
_cpp_free_toklist (list)
const cpp_toklist *list;
{
free (list->tokens);
free (list->namebuf);
}
/* Compare two tokens. */
int
_cpp_equiv_tokens (a, b)
const cpp_token *a, *b;
{
if (a->type == b->type && a->flags == b->flags)
switch (TOKEN_SPELL (a))
{
default: /* Keep compiler happy. */
case SPELL_OPERATOR:
return 1;
case SPELL_CHAR:
case SPELL_NONE:
return a->val.aux == b->val.aux; /* arg_no or character. */
case SPELL_IDENT:
return a->val.node == b->val.node;
case SPELL_STRING:
return (a->val.str.len == b->val.str.len
&& !memcmp (a->val.str.text, b->val.str.text,
a->val.str.len));
}
return 0;
}
/* Compare two token lists. */
int
_cpp_equiv_toklists (a, b)
const cpp_toklist *a, *b;
{
unsigned int i;
if (a->tokens_used != b->tokens_used
|| a->flags != b->flags
|| a->paramc != b->paramc)
return 0;
for (i = 0; i < a->tokens_used; i++)
if (! _cpp_equiv_tokens (&a->tokens[i], &b->tokens[i]))
return 0;
return 1;
}
/* Utility routine: /* Utility routine:
...@@ -389,7 +104,7 @@ cpp_ideq (token, string) ...@@ -389,7 +104,7 @@ cpp_ideq (token, string)
if (token->type != CPP_NAME) if (token->type != CPP_NAME)
return 0; 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 /* Call when meeting a newline. Returns the character after the newline
...@@ -578,7 +293,7 @@ skip_block_comment (pfile) ...@@ -578,7 +293,7 @@ skip_block_comment (pfile)
next_char: next_char:
/* FIXME: For speed, create a new character class of characters /* FIXME: For speed, create a new character class of characters
of no interest inside block comments. */ of interest inside block comments. */
if (c == '?' || c == '\\') if (c == '?' || c == '\\')
c = skip_escaped_newlines (buffer, c); c = skip_escaped_newlines (buffer, c);
...@@ -692,7 +407,7 @@ skip_whitespace (pfile, c) ...@@ -692,7 +407,7 @@ skip_whitespace (pfile, c)
warned = 1; 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_pedwarn_with_line (pfile, CPP_BUF_LINE (buffer),
CPP_BUF_COL (buffer), CPP_BUF_COL (buffer),
"%s in preprocessing directive", "%s in preprocessing directive",
...@@ -710,6 +425,22 @@ skip_whitespace (pfile, c) ...@@ -710,6 +425,22 @@ skip_whitespace (pfile, c)
buffer->read_ahead = 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. /* Parse an identifier, skipping embedded backslash-newlines.
Calculate the hash value of the token while parsing, for improved Calculate the hash value of the token while parsing, for improved
performance. The hashing algorithm *must* match cpp_lookup(). */ performance. The hashing algorithm *must* match cpp_lookup(). */
...@@ -719,18 +450,23 @@ parse_identifier (pfile, c) ...@@ -719,18 +450,23 @@ parse_identifier (pfile, c)
cpp_reader *pfile; cpp_reader *pfile;
cppchar_t c; cppchar_t c;
{ {
cpp_hashnode *result;
cpp_buffer *buffer = pfile->buffer; cpp_buffer *buffer = pfile->buffer;
unsigned char *dest, *limit;
unsigned int r = 0, saw_dollar = 0; 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
{ {
do do
{ {
if (pfile->token_list.name_used == pfile->token_list.name_cap) /* Need room for terminating null. */
_cpp_expand_name_space (&pfile->token_list, if (dest + 1 >= limit)
pfile->token_list.name_used + 256); limit = _cpp_next_chunk (&pfile->ident_pool, 0, &dest);
pfile->token_list.namebuf[pfile->token_list.name_used++] = c;
*dest++ = c;
r = HASHSTEP (r, c); r = HASHSTEP (r, c);
if (c == '$') if (c == '$')
...@@ -751,86 +487,137 @@ parse_identifier (pfile, c) ...@@ -751,86 +487,137 @@ parse_identifier (pfile, c)
} }
while (is_idchar (c)); while (is_idchar (c));
/* Remember the next character. */
buffer->read_ahead = c;
/* $ is not a identifier character in the standard, but is commonly /* $ is not a identifier character in the standard, but is commonly
accepted as an extension. Don't warn about it in skipped accepted as an extension. Don't warn about it in skipped
conditional blocks. */ conditional blocks. */
if (saw_dollar && CPP_PEDANTIC (pfile) && ! pfile->skipping) if (saw_dollar && CPP_PEDANTIC (pfile) && ! pfile->skipping)
cpp_pedwarn (pfile, "'$' character(s) in identifier"); cpp_pedwarn (pfile, "'$' character(s) in identifier");
/* Remember the next character. */ /* Identifiers are null-terminated. */
buffer->read_ahead = c; *dest = '\0';
return _cpp_lookup_with_hash (pfile, &pfile->token_list.namebuf[orig_used],
pfile->token_list.name_used - orig_used, r); /* 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. */ /* Parse a number, skipping embedded backslash-newlines. */
static void static void
parse_number (pfile, number, c) parse_number (pfile, number, c, leading_period)
cpp_reader *pfile; cpp_reader *pfile;
cpp_string *number; cpp_string *number;
cppchar_t c; cppchar_t c;
int leading_period;
{ {
cppchar_t prevc;
cpp_buffer *buffer = pfile->buffer; 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. */ dest = POOL_FRONT (pool);
if (pfile->state.seen_dot) limit = POOL_LIMIT (pool);
pfile->token_list.name_used++;
/* Place a leading period. */
if (leading_period)
{
if (dest >= limit)
limit = _cpp_next_chunk (pool, 0, &dest);
*dest++ = '.';
}
do do
{ {
do do
{ {
if (pfile->token_list.name_used >= pfile->token_list.name_cap) /* Need room for terminating null. */
_cpp_expand_name_space (&pfile->token_list, if (dest + 1 >= limit)
pfile->token_list.name_used + 256); limit = _cpp_next_chunk (pool, 0, &dest);
pfile->token_list.namebuf[pfile->token_list.name_used++] = c; *dest++ = c;
prevc = c;
c = EOF; c = EOF;
if (buffer->cur == buffer->rlimit) if (buffer->cur == buffer->rlimit)
break; break;
c = *buffer->cur++; 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? */ /* Potential escaped newline? */
if (c != '?' && c != '\\') if (c != '?' && c != '\\')
break; break;
c = skip_escaped_newlines (buffer, c); c = skip_escaped_newlines (buffer, c);
} }
while (is_numchar (c) || c == '.' || VALID_SIGN (c, prevc)); while (is_numchar (c) || c == '.' || VALID_SIGN (c, dest[-1]));
/* Put any leading period in place, now we have the room. */
if (pfile->state.seen_dot)
pfile->token_list.namebuf[orig_used] = '.';
/* Remember the next character. */ /* Remember the next character. */
buffer->read_ahead = c; buffer->read_ahead = c;
number->text = &pfile->token_list.namebuf[orig_used]; /* Null-terminate the number. */
number->len = pfile->token_list.name_used - orig_used; *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. */ /* Subroutine of parse_string. Emits error for unterminated strings. */
static void static void
unterminated (pfile, line, term) unterminated (pfile, term)
cpp_reader *pfile; cpp_reader *pfile;
unsigned int line;
int term; int term;
{ {
cpp_error (pfile, "missing terminating %c character", 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"); "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 /* Parses a string, character constant, or angle-bracketed header file
name. Handles embedded trigraphs and escaped newlines. name. Handles embedded trigraphs and escaped newlines.
...@@ -843,16 +630,20 @@ parse_string (pfile, token, terminator) ...@@ -843,16 +630,20 @@ parse_string (pfile, token, terminator)
cppchar_t terminator; cppchar_t terminator;
{ {
cpp_buffer *buffer = pfile->buffer; 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; cppchar_t c;
unsigned int nulls = 0; unsigned int nulls = 0;
dest = POOL_FRONT (pool);
limit = POOL_LIMIT (pool);
for (;;) for (;;)
{ {
if (buffer->cur == buffer->rlimit) if (buffer->cur == buffer->rlimit)
{ {
c = EOF; c = EOF;
unterminated (pfile, token->line, terminator); unterminated (pfile, terminator);
break; break;
} }
c = *buffer->cur++; c = *buffer->cur++;
...@@ -862,20 +653,10 @@ parse_string (pfile, token, terminator) ...@@ -862,20 +653,10 @@ parse_string (pfile, token, terminator)
if (c == '?' || c == '\\') if (c == '?' || c == '\\')
c = skip_escaped_newlines (buffer, 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; c = EOF;
break;
/* 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;
}
} }
else if (is_vspace (c)) else if (is_vspace (c))
{ {
...@@ -888,18 +669,16 @@ parse_string (pfile, token, terminator) ...@@ -888,18 +669,16 @@ parse_string (pfile, token, terminator)
/* Character constants and header names may not extend over /* Character constants and header names may not extend over
multiple lines. In Standard C, neither may strings. multiple lines. In Standard C, neither may strings.
Unfortunately, we accept multiline strings as an Unfortunately, we accept multiline strings as an
extension. (Deprecatedly even in directives - otherwise, extension. */
glibc's longlong.h breaks.) */
if (terminator != '"') if (terminator != '"')
{ {
unterminated (pfile, token->line, terminator); unterminated (pfile, terminator);
break; break;
} }
if (pfile->mls_line == 0) if (pfile->mlstring_pos.line == 0)
{ {
pfile->mls_line = token->line; pfile->mlstring_pos = pfile->lexer_pos;
pfile->mls_column = token->col;
if (CPP_PEDANTIC (pfile)) if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "multi-line string constant"); cpp_pedwarn (pfile, "multi-line string constant");
} }
...@@ -913,11 +692,11 @@ parse_string (pfile, token, terminator) ...@@ -913,11 +692,11 @@ parse_string (pfile, token, terminator)
cpp_warning (pfile, "null character(s) preserved in literal"); cpp_warning (pfile, "null character(s) preserved in literal");
} }
if (pfile->token_list.name_used == pfile->token_list.name_cap) /* No terminating null for strings - they could contain nulls. */
_cpp_expand_name_space (&pfile->token_list, if (dest >= limit)
pfile->token_list.name_used + 256); 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 we had a new line, the next character is in read_ahead. */
if (c != '\n') if (c != '\n')
continue; continue;
...@@ -926,14 +705,15 @@ parse_string (pfile, token, terminator) ...@@ -926,14 +705,15 @@ parse_string (pfile, token, terminator)
goto have_char; goto have_char;
} }
/* Remember the next character. */
buffer->read_ahead = c; buffer->read_ahead = c;
token->val.str.text = &pfile->token_list.namebuf[orig_used]; token->val.str.text = POOL_FRONT (pool);
token->val.str.len = pfile->token_list.name_used - orig_used; 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 /* The stored comment includes the comment start and any terminator. */
comment start and any terminator. */
static void static void
save_comment (pfile, token, from) save_comment (pfile, token, from)
cpp_reader *pfile; cpp_reader *pfile;
...@@ -942,12 +722,9 @@ save_comment (pfile, token, from) ...@@ -942,12 +722,9 @@ save_comment (pfile, token, from)
{ {
unsigned char *buffer; unsigned char *buffer;
unsigned int len; unsigned int len;
cpp_toklist *list = &pfile->token_list;
len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */ len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */
_cpp_reserve_name_space (list, len); buffer = _cpp_pool_alloc (pfile->string_pool, len);
buffer = list->namebuf + list->name_used;
list->name_used += len;
token->type = CPP_COMMENT; token->type = CPP_COMMENT;
token->val.str.len = len; token->val.str.len = len;
...@@ -1029,9 +806,7 @@ lex_dot (pfile, result) ...@@ -1029,9 +806,7 @@ lex_dot (pfile, result)
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
{ {
result->type = CPP_NUMBER; result->type = CPP_NUMBER;
buffer->pfile->state.seen_dot = 1; parse_number (pfile, &result->val.str, c, 1);
parse_number (pfile, &result->val.str, c);
buffer->pfile->state.seen_dot = 0;
} }
else else
{ {
...@@ -1053,26 +828,29 @@ lex_dot (pfile, result) ...@@ -1053,26 +828,29 @@ lex_dot (pfile, result)
} }
} }
static void void
lex_token (pfile, result) _cpp_lex_token (pfile, result)
cpp_reader *pfile; cpp_reader *pfile;
cpp_token *result; cpp_token *result;
{ {
cppchar_t c; cppchar_t c;
cpp_buffer *buffer = pfile->buffer; cpp_buffer *buffer = pfile->buffer;
const unsigned char *comment_start; 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; result->flags = 0;
next_char: next_char:
result->line = CPP_BUF_LINE (buffer); pfile->lexer_pos.line = buffer->lineno;
next_char2: next_char2:
result->col = CPP_BUF_COLUMN (buffer, buffer->cur); pfile->lexer_pos.col = CPP_BUF_COLUMN (buffer, buffer->cur);
c = buffer->read_ahead; c = buffer->read_ahead;
if (c == EOF && buffer->cur < buffer->rlimit) if (c == EOF && buffer->cur < buffer->rlimit)
{ {
c = *buffer->cur++; c = *buffer->cur++;
result->col++; pfile->lexer_pos.col++;
} }
do_switch: do_switch:
...@@ -1080,12 +858,11 @@ lex_token (pfile, result) ...@@ -1080,12 +858,11 @@ lex_token (pfile, result)
switch (c) switch (c)
{ {
case EOF: case EOF:
/* Non-empty files should end in a newline. Testing /* Non-empty files should end in a newline. Ignore for command
skip_newlines ensures we only emit the warning once. */ line - we get e.g. -A options with no trailing \n. */
if (buffer->cur != buffer->line_base && buffer->cur != buffer->buf if (pfile->lexer_pos.col != 0 && pfile->done_initializing)
&& pfile->state.skip_newlines) cpp_pedwarn (pfile, "no newline at end of file");
cpp_pedwarn_with_line (pfile, buffer->lineno, CPP_BUF_COL (buffer), pfile->state.skip_newlines = 1;
"no newline at end of file");
result->type = CPP_EOF; result->type = CPP_EOF;
break; break;
...@@ -1095,15 +872,35 @@ lex_token (pfile, result) ...@@ -1095,15 +872,35 @@ lex_token (pfile, result)
goto next_char2; goto next_char2;
case '\n': case '\r': case '\n': case '\r':
result->type = CPP_EOF; /* Don't let directives spill over to the next line. */
handle_newline (buffer, c); if (pfile->state.in_directive)
/* Handling here will change significantly when moving to buffer->read_ahead = c;
token-at-a-time. */ else
if (pfile->state.skip_newlines)
{ {
result->flags &= ~PREV_WHITE; /* Clear any whitespace flag. */ handle_newline (buffer, c);
goto next_char;
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; break;
case '?': case '?':
...@@ -1133,7 +930,7 @@ lex_token (pfile, result) ...@@ -1133,7 +930,7 @@ lex_token (pfile, result)
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
result->type = CPP_NUMBER; result->type = CPP_NUMBER;
parse_number (pfile, &result->val.str, c); parse_number (pfile, &result->val.str, c, 0);
break; break;
case '$': case '$':
...@@ -1156,7 +953,7 @@ lex_token (pfile, result) ...@@ -1156,7 +953,7 @@ lex_token (pfile, result)
result->val.node = parse_identifier (pfile, c); result->val.node = parse_identifier (pfile, c);
/* 'L' may introduce wide characters or strings. */ /* '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. */ c = buffer->read_ahead; /* For make_string. */
if (c == '\'' || c == '"') if (c == '\'' || c == '"')
...@@ -1166,10 +963,10 @@ lex_token (pfile, result) ...@@ -1166,10 +963,10 @@ lex_token (pfile, result)
} }
} }
/* Convert named operators to their proper types. */ /* 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->flags |= NAMED_OP;
result->type = result->val.node->value.code; result->type = result->val.node->value.operator;
} }
break; break;
...@@ -1193,7 +990,8 @@ lex_token (pfile, result) ...@@ -1193,7 +990,8 @@ lex_token (pfile, result)
if (c == '*') if (c == '*')
{ {
if (skip_block_comment (pfile)) 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"); "unterminated comment");
} }
else else
...@@ -1218,7 +1016,8 @@ lex_token (pfile, result) ...@@ -1218,7 +1016,8 @@ lex_token (pfile, result)
/* Skip_line_comment updates buffer->read_ahead. */ /* Skip_line_comment updates buffer->read_ahead. */
if (skip_line_comment (pfile)) 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"); "multi-line comment");
} }
...@@ -1290,6 +1089,8 @@ lex_token (pfile, result) ...@@ -1290,6 +1089,8 @@ lex_token (pfile, result)
case '%': case '%':
lex_percent (buffer, result); lex_percent (buffer, result);
if (result->type == CPP_HASH)
goto do_hash;
break; break;
case '.': case '.':
...@@ -1349,9 +1150,21 @@ lex_token (pfile, result) ...@@ -1349,9 +1150,21 @@ lex_token (pfile, result)
break; break;
case '#': case '#':
result->type = CPP_HASH;
if (get_effective_char (buffer) == '#') if (get_effective_char (buffer) == '#')
ACCEPT_CHAR (CPP_PASTE); 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; break;
case '|': case '|':
...@@ -1423,117 +1236,30 @@ lex_token (pfile, result) ...@@ -1423,117 +1236,30 @@ lex_token (pfile, result)
} }
} }
/* /* An upper bound on the number of bytes needed to spell a token,
* The tokenizer's main loop. Returns a token list, representing a including preceding whitespace. */
* logical line in the input file. On EOF after some tokens have unsigned int
* been processed, we return immediately. Then in next call, or if cpp_token_len (token)
* EOF occurred at the beginning of a logical line, a single CPP_EOF const cpp_token *token;
* token is placed in the list.
*/
static void
lex_line (pfile, list)
cpp_reader *pfile;
cpp_toklist *list;
{ {
unsigned int first_token; unsigned int len;
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);
}
/* _cpp_get_line assumes list->tokens_used refers to the current switch (TOKEN_SPELL (token))
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))
{ {
if (cur_token > first + 1) default: len = 0; break;
{ case SPELL_STRING: len = token->val.str.len; break;
if (first[1].type == CPP_NAME) case SPELL_IDENT: len = token->val.node->length; break;
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;
} }
/* 1 for whitespace, 4 for comment delimeters. */
/* Drop the EOF unless really at EOF or in a directive. */ return len + 5;
if (cur_token != first && !KNOWN_DIRECTIVE (list)
&& pfile->done_initializing)
list->tokens_used--;
pfile->state.in_lex_line = 0;
} }
/* Write the spelling of a token TOKEN to BUFFER. The buffer must /* Write the spelling of a token TOKEN to BUFFER. The buffer must
already contain the enough space to hold the token's spelling. already contain the enough space to hold the token's spelling.
Returns a pointer to the character after the last character Returns a pointer to the character after the last character
written. */ written. */
unsigned char *
static unsigned char * cpp_spell_token (pfile, token, buffer)
spell_token (pfile, token, buffer)
cpp_reader *pfile; /* Would be nice to be rid of this... */ cpp_reader *pfile; /* Would be nice to be rid of this... */
const cpp_token *token; const cpp_token *token;
unsigned char *buffer; unsigned char *buffer;
...@@ -1546,7 +1272,7 @@ spell_token (pfile, token, buffer) ...@@ -1546,7 +1272,7 @@ spell_token (pfile, token, buffer)
unsigned char c; unsigned char c;
if (token->flags & DIGRAPH) 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) else if (token->flags & NAMED_OP)
goto spell_ident; goto spell_ident;
else else
...@@ -1596,581 +1322,145 @@ spell_token (pfile, token, buffer) ...@@ -1596,581 +1322,145 @@ spell_token (pfile, token, buffer)
return buffer; return buffer;
} }
/* Macro expansion algorithm. /* Returns a token as a null-terminated string. The string is
temporary, and automatically freed later. Useful for diagnostics. */
Macro expansion is implemented by a single-pass algorithm; there are unsigned char *
no rescan passes involved. cpp_get_token expands just enough to be cpp_token_as_text (pfile, token)
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)
cpp_reader *pfile; cpp_reader *pfile;
const cpp_toklist *expansion;
const cpp_token *token; const cpp_token *token;
{ {
cpp_context *context = CURRENT_CONTEXT (pfile); unsigned int len = cpp_token_len (token);
unsigned char *start = _cpp_pool_alloc (&pfile->temp_string_pool, len), *end;
/* 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? */ end = cpp_spell_token (pfile, token, start);
while (context->level > 0) end[0] = '\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 return start;
current context. We check this without disrupting the context }
stack. */
if (expansion->paramc >= 0)
{
const cpp_token *next;
unsigned int prev_nme;
context = CURRENT_CONTEXT (pfile); /* Used by C front ends. Should really move to using cpp_token_as_text. */
/* Drop down any contexts we're at the end of: the '(' may const char *
appear in lower macro expansions, or in the rest of the file. */ cpp_type2name (type)
while (context->posn == context->count && context > pfile->contexts) enum cpp_ttype type;
{ {
context--; return (const char *) token_spellings[type].name;
/* 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;
}
prev_nme = pfile->no_expand_level; /* Writes the spelling of token to FP. Separate from cpp_spell_token
pfile->no_expand_level = context - pfile->contexts; for efficiency - to avoid double-buffering. Also, outputs a space
next = _cpp_get_token (pfile); if PREV_WHITE is flagged. */
restore_macro_expansion (pfile, prev_nme); void
cpp_output_token (token, fp)
const cpp_token *token;
FILE *fp;
{
if (token->flags & PREV_WHITE)
putc (' ', fp);
if (next->type != CPP_OPEN_PAREN) switch (TOKEN_SPELL (token))
{
_cpp_push_token (pfile, next);
if (CPP_WTRADITIONAL (pfile))
cpp_warning (pfile,
"function macro %s must be used with arguments in traditional C",
token->val.node->name);
return 1;
}
}
return 0;
}
/* Add a token to the set of tokens forming the arguments to the macro
being parsed in parse_args. */
static void
save_token (args, token)
macro_args *args;
const cpp_token *token;
{
if (args->used == args->capacity)
{
args->capacity += args->capacity + 100;
args->tokens = (const cpp_token **)
xrealloc ((PTR) args->tokens,
args->capacity * sizeof (const cpp_token *));
}
args->tokens[args->used++] = token;
}
/* Take and save raw tokens until we finish one argument. Empty
arguments are saved as a single CPP_PLACEMARKER token. */
static const cpp_token *
parse_arg (pfile, var_args, paren_context, args, pcount)
cpp_reader *pfile;
int var_args;
unsigned int paren_context;
macro_args *args;
unsigned int *pcount;
{
const cpp_token *token;
unsigned int paren = 0, count = 0;
int raw, was_raw = 1;
for (count = 0;; count++)
{ {
token = _cpp_get_token (pfile); case SPELL_OPERATOR:
{
switch (token->type) const unsigned char *spelling;
{
default:
break;
case CPP_OPEN_PAREN: if (token->flags & DIGRAPH)
paren++; spelling = digraph_spellings[token->type - CPP_FIRST_DIGRAPH];
break; else if (token->flags & NAMED_OP)
goto spell_ident;
else
spelling = TOKEN_NAME (token);
case CPP_CLOSE_PAREN: ufputs (spelling, fp);
if (paren-- != 0) }
break; break;
goto out;
case CPP_COMMA: spell_ident:
/* Commas are not terminators within parantheses or var_args. */ case SPELL_IDENT:
if (paren || var_args) ufputs (token->val.node->name, fp);
break; break;
goto out;
case CPP_EOF: /* Error reported by caller. */ case SPELL_STRING:
goto out; {
} int left, right, tag;
switch (token->type)
{
case CPP_STRING: left = '"'; right = '"'; tag = '\0'; break;
case CPP_WSTRING: left = '"'; right = '"'; tag = 'L'; break;
case CPP_OSTRING: left = '"'; right = '"'; tag = '@'; break;
case CPP_CHAR: left = '\''; right = '\''; tag = '\0'; break;
case CPP_WCHAR: left = '\''; right = '\''; tag = 'L'; break;
case CPP_HEADER_NAME: left = '<'; right = '>'; tag = '\0'; break;
default: left = '\0'; right = '\0'; tag = '\0'; break;
}
if (tag) putc (tag, fp);
if (left) putc (left, fp);
fwrite (token->val.str.text, 1, token->val.str.len, fp);
if (right) putc (right, fp);
}
break;
raw = pfile->cur_context <= paren_context; case SPELL_CHAR:
if (raw != was_raw) putc (token->val.aux, fp);
{ break;
was_raw = raw;
save_token (args, 0);
count++;
}
save_token (args, token);
}
out: case SPELL_NONE:
if (count == 0) /* An error, most probably. */
{ break;
/* 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;
} }
/* This macro returns true if the argument starting at offset O of arglist /* Compare two tokens. */
A is empty - that is, it's either a single PLACEMARKER token, or a null int
pointer followed by a PLACEMARKER. */ _cpp_equiv_tokens (a, b)
const cpp_token *a, *b;
#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;
{ {
const cpp_token *token; if (a->type == b->type && a->flags == b->flags)
const cpp_toklist *macro; switch (TOKEN_SPELL (a))
unsigned int total = 0; {
unsigned int paren_context = pfile->cur_context; default: /* Keep compiler happy. */
int argc = 0; case SPELL_OPERATOR:
return 1;
macro = hp->value.expansion; case SPELL_CHAR:
do return a->val.aux == b->val.aux; /* Character. */
{ case SPELL_NONE:
unsigned int count; return (a->type != CPP_MACRO_ARG || a->val.aux == b->val.aux);
case SPELL_IDENT:
token = parse_arg (pfile, (argc + 1 == macro->paramc return a->val.node == b->val.node;
&& (macro->flags & VAR_ARGS)), case SPELL_STRING:
paren_context, args, &count); return (a->val.str.len == b->val.str.len
if (argc < macro->paramc) && !memcmp (a->val.str.text, b->val.str.text,
{ a->val.str.len));
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; return 0;
} }
/* Adds backslashes before all backslashes and double quotes appearing #if 0
in strings. Non-printable characters are converted to octal. */ /* Compare two token lists. */
static U_CHAR * int
quote_string (dest, src, len) _cpp_equiv_toklists (a, b)
U_CHAR *dest; const struct toklist *a, *b;
const U_CHAR *src;
unsigned int len;
{
while (len--)
{
U_CHAR c = *src++;
if (c == '\\' || c == '"')
{
*dest++ = '\\';
*dest++ = c;
}
else
{
if (ISPRINT (c))
*dest++ = c;
else
{
sprintf ((char *) dest, "\\%03o", c);
dest += 4;
}
}
}
return dest;
}
/* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a
CPP_STRING token containing TEXT in quoted form. */
static cpp_token *
make_string_token (token, text, len)
cpp_token *token;
const U_CHAR *text;
unsigned int len;
{
U_CHAR *buf;
buf = (U_CHAR *) xmalloc (len * 4);
token->type = CPP_STRING;
token->flags = 0;
token->val.str.text = buf;
token->val.str.len = quote_string (buf, text, len) - buf;
return token;
}
/* Allocates and converts a temporary token to a CPP_NUMBER token,
evaluating to NUMBER. */
static cpp_token *
alloc_number_token (pfile, number)
cpp_reader *pfile;
int number;
{
cpp_token *result;
char *buf;
result = get_temp_token (pfile);
buf = xmalloc (20);
sprintf (buf, "%d", number);
result->type = CPP_NUMBER;
result->flags = 0;
result->val.str.text = (U_CHAR *) buf;
result->val.str.len = strlen (buf);
return result;
}
/* Returns a temporary token from the temporary token store of PFILE. */
static cpp_token *
get_temp_token (pfile)
cpp_reader *pfile;
{
if (pfile->temp_used == pfile->temp_alloced)
{
if (pfile->temp_used == pfile->temp_cap)
{
pfile->temp_cap += pfile->temp_cap + 20;
pfile->temp_tokens = (cpp_token **) xrealloc
(pfile->temp_tokens, pfile->temp_cap * sizeof (cpp_token *));
}
pfile->temp_tokens[pfile->temp_alloced++] = (cpp_token *) xmalloc
(sizeof (cpp_token));
}
return pfile->temp_tokens[pfile->temp_used++];
}
/* Release (not free) for re-use the temporary tokens of PFILE. */
static void
release_temp_tokens (pfile)
cpp_reader *pfile;
{ {
while (pfile->temp_used) unsigned int i, count;
{
cpp_token *token = pfile->temp_tokens[--pfile->temp_used];
if (TOKEN_SPELL (token) == SPELL_STRING) count = a->limit - a->first;
{ if (count != (b->limit - b->first))
free ((char *) token->val.str.text); return 0;
token->val.str.text = 0;
}
}
}
/* Free all of PFILE's dynamically-allocated temporary tokens. */
void
_cpp_free_temp_tokens (pfile)
cpp_reader *pfile;
{
if (pfile->temp_tokens)
{
/* It is possible, though unlikely (looking for '(' of a funlike
macro into EOF), that we haven't released the tokens yet. */
release_temp_tokens (pfile);
while (pfile->temp_alloced)
free (pfile->temp_tokens[--pfile->temp_alloced]);
free (pfile->temp_tokens);
}
if (pfile->date)
{
free ((char *) pfile->date->val.str.text);
free (pfile->date);
free ((char *) pfile->time->val.str.text);
free (pfile->time);
}
}
/* Copy TOKEN into a temporary token from PFILE's store. */ for (i = 0; i < count; i++)
static cpp_token * if (! _cpp_equiv_tokens (&a->first[i], &b->first[i]))
duplicate_token (pfile, token) return 0;
cpp_reader *pfile;
const cpp_token *token;
{
cpp_token *result = get_temp_token (pfile);
*result = *token; return 1;
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;
} }
#endif
/* Determine whether two tokens can be pasted together, and if so, /* Determine whether two tokens can be pasted together, and if so,
what the resulting token is. Returns CPP_EOF if the tokens cannot what the resulting token is. Returns CPP_EOF if the tokens cannot
be pasted, or the appropriate type for the merged token if they be pasted, or the appropriate type for the merged token if they
can. */ can. */
enum cpp_ttype enum cpp_ttype
_cpp_can_paste (pfile, token1, token2, digraph) cpp_can_paste (pfile, token1, token2, digraph)
cpp_reader * pfile; cpp_reader * pfile;
const cpp_token *token1, *token2; const cpp_token *token1, *token2;
int* digraph; int* digraph;
...@@ -2247,11 +1537,11 @@ _cpp_can_paste (pfile, token1, token2, digraph) ...@@ -2247,11 +1537,11 @@ _cpp_can_paste (pfile, token1, token2, digraph)
case CPP_NAME: case CPP_NAME:
if (b == CPP_NAME) return CPP_NAME; if (b == CPP_NAME) return CPP_NAME;
if (b == CPP_NUMBER 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 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 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; break;
case CPP_NUMBER: case CPP_NUMBER:
...@@ -2278,882 +1568,230 @@ _cpp_can_paste (pfile, token1, token2, digraph) ...@@ -2278,882 +1568,230 @@ _cpp_can_paste (pfile, token1, token2, digraph)
return CPP_EOF; return CPP_EOF;
} }
/* Check if TOKEN is to be ##-pasted with the token after it. */ /* Returns nonzero if a space should be inserted to avoid an
static const cpp_token * accidental token paste for output. For simplicity, it is
maybe_paste_with_next (pfile, token) conservative, and occasionally advises a space where one is not
cpp_reader *pfile; needed, e.g. "." and ".2". */
const cpp_token *token;
{
cpp_token *pasted;
const cpp_token *second;
cpp_context *context = CURRENT_CONTEXT (pfile);
/* Is this token on the LHS of ## ? */
while ((token->flags & PASTE_LEFT)
|| ((context->flags & CONTEXT_PASTEL)
&& context->posn == context->count))
{
/* Suppress macro expansion for next token, but don't conflict
with the other method of suppression. If it is an argument,
macro expansion within the argument will still occur. */
pfile->paste_level = pfile->cur_context;
second = _cpp_get_token (pfile);
pfile->paste_level = 0;
context = CURRENT_CONTEXT (pfile);
/* Ignore placemarker argument tokens (cannot be from an empty
macro since macros are not expanded). */
if (token->type == CPP_PLACEMARKER)
pasted = duplicate_token (pfile, second);
else if (second->type == CPP_PLACEMARKER)
{
/* GCC has special extended semantics for , ## b where b is
a varargs parameter: the comma disappears if b was given
no actual arguments (not merely if b is an empty
argument). */
if (token->type == CPP_COMMA && (context->flags & CONTEXT_VARARGS))
pasted = duplicate_token (pfile, second);
else
pasted = duplicate_token (pfile, token);
}
else
{
int digraph = 0;
enum cpp_ttype type = _cpp_can_paste (pfile, token, second, &digraph);
if (type == CPP_EOF)
{
if (CPP_OPTION (pfile, warn_paste))
{
/* Do not complain about , ## <whatever> if
<whatever> came from a variable argument, because
the author probably intended the ## to trigger
the special extended semantics (see above). */
if (token->type == CPP_COMMA
&& (context->flags & CONTEXT_VARARGS))
/* no warning */;
else
cpp_warning (pfile,
"pasting would not give a valid preprocessing token");
}
_cpp_push_token (pfile, second);
/* A short term hack to safely clear the PASTE_LEFT flag. */
pasted = duplicate_token (pfile, token);
pasted->flags &= ~PASTE_LEFT;
return pasted;
}
if (type == CPP_NAME || type == CPP_NUMBER)
{
/* Join spellings. */
U_CHAR *buf, *end;
pasted = get_temp_token (pfile);
buf = (U_CHAR *) alloca (TOKEN_LEN (token) + TOKEN_LEN (second));
end = spell_token (pfile, token, buf);
end = spell_token (pfile, second, end);
*end = '\0';
if (type == CPP_NAME)
pasted->val.node = cpp_lookup (pfile, buf, end - buf);
else
{
pasted->val.str.text = uxstrdup (buf);
pasted->val.str.len = end - buf;
}
}
else if (type == CPP_WCHAR || type == CPP_WSTRING
|| type == CPP_OSTRING)
pasted = duplicate_token (pfile, second);
else
{
pasted = get_temp_token (pfile);
pasted->val.integer = 0;
}
pasted->type = type;
pasted->flags = digraph ? DIGRAPH : 0;
if (type == CPP_NAME && pasted->val.node->type == T_OPERATOR)
{
pasted->type = pasted->val.node->value.code;
pasted->flags |= NAMED_OP;
}
}
/* The pasted token gets the whitespace flags and position of the int
first token, the PASTE_LEFT flag of the second token, plus the cpp_avoid_paste (pfile, token1, token2)
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)
cpp_reader *pfile; cpp_reader *pfile;
const cpp_token *token; const cpp_token *token1, *token2;
{ {
cpp_token *result; enum cpp_ttype a = token1->type, b = token2->type;
unsigned char *main_buf; cppchar_t c;
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;
}
/* Ignore the final \ of invalid string literals. */ if (token1->flags & NAMED_OP)
if (backslash_count & 1) a = CPP_NAME;
{ if (token2->flags & NAMED_OP)
cpp_warning (pfile, "invalid string literal, ignoring final '\\'"); b = CPP_NAME;
buf_used--;
}
result->type = CPP_STRING; c = EOF;
result->val.str.text = main_buf; if (token2->flags & DIGRAPH)
result->val.str.len = buf_used; c = digraph_spellings[b - CPP_FIRST_DIGRAPH][0];
restore_macro_expansion (pfile, prev_value); else if (token_spellings[b].category == SPELL_OPERATOR)
return result; c = token_spellings[b].name[0];
}
/* Allocate more room on the context stack of PFILE. */ /* Quickly get everything that can paste with an '='. */
static void if (a <= CPP_LAST_EQ && c == '=')
expand_context_stack (pfile) return 1;
cpp_reader *pfile;
{
pfile->context_cap += pfile->context_cap + 20;
pfile->contexts = (cpp_context *)
xrealloc (pfile->contexts, pfile->context_cap * sizeof (cpp_context));
}
/* Push the context of macro NODE onto the context stack. TOKEN is switch (a)
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)
{ {
unsigned int error, prev_nme; case CPP_GREATER: return c == '>' || c == '?';
case CPP_LESS: return c == '<' || c == '?' || c == '%' || c == ':';
/* Allocate room for the argument contexts, and parse them. */ case CPP_PLUS: return c == '+';
args = (macro_args *) xmalloc (sizeof (macro_args)); case CPP_MINUS: return c == '-' || c == '>';
args->ends = (unsigned int *) case CPP_DIV: return c == '/' || c == '*'; /* Comments. */
xmalloc (node->value.expansion->paramc * sizeof (unsigned int)); case CPP_MOD: return c == ':' || c == '>';
args->tokens = 0; case CPP_AND: return c == '&';
args->capacity = 0; case CPP_OR: return c == '|';
args->used = 0; case CPP_COLON: return c == ':' || c == '>';
case CPP_DEREF: return c == '*';
prev_nme = prevent_macro_expansion (pfile); case CPP_DOT: return c == '.' || c == '%';
pfile->args = args; case CPP_HASH: return c == '#' || c == '%'; /* Digraph form. */
error = parse_args (pfile, node, args); case CPP_NAME: return ((b == CPP_NUMBER
pfile->args = 0; && name_p (pfile, &token2->val.str))
restore_macro_expansion (pfile, prev_nme); || b == CPP_NAME
if (error) || b == CPP_CHAR || b == CPP_STRING); /* L */
{ case CPP_NUMBER: return (b == CPP_NUMBER || b == CPP_NAME
free_macro_args (args); || c == '.' || c == '+' || c == '-');
return 1; case CPP_OTHER: return (CPP_OPTION (pfile, objc)
} && token1->val.aux == '@'
/* Set the level after the call to parse_args. */ && (b == CPP_NAME || b == CPP_STRING));
args->level = pfile->cur_context; 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; return 0;
} }
/* Push an argument to the current macro onto the context stack. /* Output all the remaining tokens on the current line, and a newline
TOKEN is the MACRO_ARG token representing the argument expansion. */ character, to FP. Leading whitespace is removed. */
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. */
void void
_cpp_push_token (pfile, token) cpp_output_line (pfile, fp)
cpp_reader *pfile; 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; cpp_output_token (&token, fp);
if (IS_ARG_CONTEXT (context)) _cpp_get_token (pfile, &token);
prev = context->u.arg[context->posn - 1];
else
prev = &context->u.list->tokens[context->posn - 1];
if (prev == token)
{
context->posn--;
return;
}
} }
if (context->pushed_token) putc ('\n', fp);
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--;
} }
/* Handle a preprocessing directive. TOKEN is the CPP_HASH token /* Memory pools. */
introducing the directive. */
void
_cpp_process_directive (pfile, token)
cpp_reader *pfile;
const cpp_token *token;
{
const struct directive *d = pfile->token_list.directive;
int prev_nme = 0;
/* Skip over the directive name. */
if (token[1].type == CPP_NAME)
_cpp_get_raw_token (pfile);
else if (token[1].type != CPP_NUMBER)
cpp_ice (pfile, "directive begins with %s?!", TOKEN_NAME (token));
if (! (d->flags & EXPAND))
prev_nme = prevent_macro_expansion (pfile);
(void) (*d->handler) (pfile);
if (! (d->flags & EXPAND))
restore_macro_expansion (pfile, prev_nme);
_cpp_skip_rest_of_line (pfile);
}
/* The external interface to return the next token. All macro
expansion and directive processing is handled internally, the
caller only ever sees the output after preprocessing. */
const cpp_token *
cpp_get_token (pfile)
cpp_reader *pfile;
{
const cpp_token *token;
/* Loop till we hit a non-directive, non-placemarker token. */
for (;;)
{
token = _cpp_get_token (pfile);
if (token->type == CPP_PLACEMARKER)
continue;
if (token->type == CPP_HASH && token->flags & BOL struct dummy
&& pfile->token_list.directive)
{
_cpp_process_directive (pfile, token);
continue;
}
return token;
}
}
/* The internal interface to return the next token. There are two
differences between the internal and external interfaces: the
internal interface may return a PLACEMARKER token, and it does not
process directives. */
const cpp_token *
_cpp_get_token (pfile)
cpp_reader *pfile;
{ {
const cpp_token *token, *old_token; char c;
cpp_hashnode *node; union
{
/* Loop until we hit a non-macro token. */ double d;
for (;;) int *p;
{ } u;
token = get_raw_token (pfile); };
/* Short circuit EOF. */
if (token->type == CPP_EOF)
return token;
/* If we are skipping... */ #define DEFAULT_ALIGNMENT (offsetof (struct dummy, u))
if (pfile->skipping)
{
/* we still have to process directives, */
if (pfile->token_list.directive)
return token;
/* but everything else is ignored. */ static int
_cpp_skip_rest_of_line (pfile); chunk_suitable (pool, chunk, size)
continue; cpp_pool *pool;
} cpp_chunk *chunk;
unsigned int size;
/* 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 /* Being at least twice SIZE means we can use memcpy in
be taken as a control macro. */ _cpp_next_chunk rather than memmove. Besides, it's a good idea
pfile->potential_control_macro = 0; anyway. */
return (chunk && pool->locked != chunk
/* If we are rescanning preprocessed input, no macro expansion or && (unsigned int) (chunk->limit - chunk->base) >= size * 2);
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 */
}
} }
/* Returns the next raw token, i.e. without performing macro /* Returns the end of the new pool. PTR points to a char in the old
expansion. Argument contexts are automatically entered. */ pool, and is updated to point to the same char in the new pool. */
static const cpp_token * unsigned char *
get_raw_token (pfile) _cpp_next_chunk (pool, len, ptr)
cpp_reader *pfile; cpp_pool *pool;
unsigned int len;
unsigned char **ptr;
{ {
const cpp_token *result; cpp_chunk *chunk = pool->cur->next;
cpp_context *context;
for (;;) /* LEN is the minimum size we want in the new pool. */
len += POOL_ROOM (pool);
if (! chunk_suitable (pool, chunk, len))
{ {
context = CURRENT_CONTEXT (pfile); chunk = new_chunk (POOL_SIZE (pool) * 2 + len);
if (context->pushed_token)
{
result = context->pushed_token;
context->pushed_token = 0;
return result; /* Cannot be a CPP_MACRO_ARG */
}
else if (context->posn == context->count)
{
if (pop_context (pfile))
return &eof_token;
continue;
}
else if (IS_ARG_CONTEXT (context))
{
result = context->u.arg[context->posn++];
if (result == 0)
{
context->flags ^= CONTEXT_RAW;
result = context->u.arg[context->posn++];
}
return result; /* Cannot be a CPP_MACRO_ARG */
}
result = &context->u.list->tokens[context->posn++];
if (result->type != CPP_MACRO_ARG)
return result;
if (result->flags & STRINGIFY_ARG)
return stringify_arg (pfile, result);
push_arg_context (pfile, result);
}
}
/* Internal interface to get the token without macro expanding. */
const cpp_token *
_cpp_get_raw_token (pfile)
cpp_reader *pfile;
{
int prev_nme = prevent_macro_expansion (pfile);
const cpp_token *result = _cpp_get_token (pfile);
restore_macro_expansion (pfile, prev_nme);
return result;
}
/* A thin wrapper to lex_line. CLEAR is non-zero if the current token
list should be overwritten, or zero if we need to append
(typically, if we are within the arguments to a macro, or looking
for the '(' to start a function-like macro invocation). */
static int
lex_next (pfile, clear)
cpp_reader *pfile;
int clear;
{
cpp_toklist *list = &pfile->token_list;
const cpp_token *old_list = list->tokens;
unsigned int old_used = list->tokens_used;
if (clear) chunk->next = pool->cur->next;
{ pool->cur->next = chunk;
/* 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) /* Update the pointer before changing chunk's front. */
{ if (ptr)
/* Fix up argument token pointers. */ *ptr += chunk->base - POOL_FRONT (pool);
if (old_list != list->tokens)
{
unsigned int i;
for (i = 0; i < pfile->args->used; i++) memcpy (chunk->base, POOL_FRONT (pool), POOL_ROOM (pool));
{ chunk->front = chunk->base;
const cpp_token *token = pfile->args->tokens[i];
if (token >= old_list && token < old_list + old_used)
pfile->args->tokens[i] = (const cpp_token *)
((char *) token + ((char *) list->tokens - (char *) old_list));
}
}
/* 6.10.3 paragraph 11: If there are sequences of preprocessing
tokens within the list of arguments that would otherwise act as
preprocessing directives, the behavior is undefined.
This implementation will report a hard error and treat the
'sequence of preprocessing tokens' as part of the macro argument,
not a directive.
Note if pfile->args == 0, we're OK since we're only inside a pool->cur = chunk;
macro argument after a '('. */ return POOL_LIMIT (pool);
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 static cpp_chunk *
the next logical line. Returns EOF if we're at the end of the new_chunk (size)
argument list to the # operator, or we should not "overflow" unsigned int size;
into the rest of the file (e.g. 6.10.3.1.1). */
static int
pop_context (pfile)
cpp_reader *pfile;
{ {
cpp_context *context; unsigned char *base;
cpp_chunk *result;
if (pfile->cur_context == 0) size = ALIGN (size, DEFAULT_ALIGNMENT);
{ base = (unsigned char *) xmalloc (size + sizeof (cpp_chunk));
/* If we are currently processing a directive, do not advance. 6.10 /* Put the chunk descriptor at the end. Then chunk overruns will
paragraph 2: A new-line character ends the directive even if it cause obvious chaos. */
occurs within what would otherwise be an invocation of a result = (cpp_chunk *) (base + size);
function-like macro. */ result->base = base;
if (pfile->token_list.directive) result->front = base;
return 1; result->limit = base + size;
result->next = 0;
return lex_next (pfile, pfile->no_expand_level == UINT_MAX); return result;
}
/* 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;
} }
/* Turn off macro expansion at the current context level. */ void
static unsigned int _cpp_init_pool (pool, size, align, temp)
prevent_macro_expansion (pfile) cpp_pool *pool;
cpp_reader *pfile; unsigned int size, align, temp;
{ {
unsigned int prev_value = pfile->no_expand_level; if (align == 0)
pfile->no_expand_level = pfile->cur_context; align = DEFAULT_ALIGNMENT;
return prev_value; 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. */ void
static void _cpp_lock_pool (pool)
restore_macro_expansion (pfile, prev_value) cpp_pool *pool;
cpp_reader *pfile;
unsigned int prev_value;
{ {
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 void
in a diagnostic. */ _cpp_unlock_pool (pool)
unsigned int cpp_pool *pool;
_cpp_get_line (pfile, pcol)
cpp_reader *pfile;
unsigned int *pcol;
{ {
unsigned int index; if (--pool->locks == 0)
const cpp_token *cur_token; pool->locked = 0;
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;
} }
#define DSC(str) (const U_CHAR *)str, sizeof str - 1 void
static const char * const monthnames[] = _cpp_free_pool (pool)
{ cpp_pool *pool;
"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;
{ {
cpp_token *result; cpp_chunk *chunk = pool->cur, *next;
cpp_buffer *ip;
switch (node->type) do
{ {
case T_FILE: next = chunk->next;
case T_BASE_FILE: free (chunk->base);
{ chunk = next;
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;
} }
while (chunk && chunk != pool->cur);
ASSIGN_FLAGS_AND_POS (result, token);
return result;
} }
#undef DSC
/* Allocate pfile->input_buffer, and initialize _cpp_trigraph_map[] /* Reserve LEN bytes from a memory pool. */
if it hasn't happened already. */ unsigned char *
_cpp_pool_reserve (pool, len)
void cpp_pool *pool;
_cpp_init_input_buffer (pfile) unsigned int len;
cpp_reader *pfile;
{ {
cpp_context *base; len = ALIGN (len, pool->align);
if (len > (unsigned int) POOL_ROOM (pool))
_cpp_init_toklist (&pfile->token_list, 0); _cpp_next_chunk (pool, len, 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;
}
/* Moves to the end of the directive line, popping contexts as return POOL_FRONT (pool);
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;
} }
/* Directive handler wrapper used by the command line option /* Allocate LEN bytes from a memory pool. */
processor. */ unsigned char *
void _cpp_pool_alloc (pool, len)
_cpp_run_directive (pfile, dir, buf, count, name) cpp_pool *pool;
cpp_reader *pfile; unsigned int len;
const struct directive *dir;
const char *buf;
size_t count;
const char *name;
{ {
if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL) unsigned char *result = _cpp_pool_reserve (pool, len);
{
unsigned int prev_lvl = 0;
if (name) POOL_COMMIT (pool, len);
CPP_BUFFER (pfile)->nominal_fname = name; return result;
else
CPP_BUFFER (pfile)->nominal_fname = _("<command line>");
CPP_BUFFER (pfile)->lineno = (unsigned int)-1;
/* Scan the line now, else prevent_macro_expansion won't work. */
lex_next (pfile, 1);
if (! (dir->flags & EXPAND))
prev_lvl = prevent_macro_expansion (pfile);
(void) (*dir->handler) (pfile);
if (! (dir->flags & EXPAND))
restore_macro_expansion (pfile, prev_lvl);
_cpp_skip_rest_of_line (pfile);
cpp_pop_buffer (pfile);
}
} }
...@@ -28,48 +28,112 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ...@@ -28,48 +28,112 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "obstack.h" #include "obstack.h"
#include "symcat.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 /* Stack of conditionals currently in progress
(including both successful and failing conditionals). */ (including both successful and failing conditionals). */
struct if_stack struct if_stack
{ {
struct if_stack *next; struct if_stack *next;
unsigned int lineno; /* line number where condition started */ cpp_lexer_pos pos; /* line and column where condition started */
unsigned int colno; /* and column */ const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
int was_skipping; /* value of pfile->skipping before this if */ 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 */ 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. */ /* Forward declarations. */
static void validate_else PARAMS ((cpp_reader *, const U_CHAR *)); static void skip_rest_of_line PARAMS ((cpp_reader *));
static int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int, static void check_eol PARAMS ((cpp_reader *));
const U_CHAR **, unsigned int *, static void run_directive PARAMS ((cpp_reader *, int,
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, static void push_conditional PARAMS ((cpp_reader *, int, int,
const cpp_hashnode *)); const cpp_hashnode *));
static int read_line_number PARAMS ((cpp_reader *, int *)); static int read_line_number PARAMS ((cpp_reader *, int *));
static int strtoul_for_line PARAMS ((const U_CHAR *, unsigned int, static int strtoul_for_line PARAMS ((const U_CHAR *, unsigned int,
unsigned long *)); unsigned long *));
static void do_diagnostic PARAMS ((cpp_reader *, enum error_type)); 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 * 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 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 /* This is the table of directive handlers. It is ordered by
frequency of occurrence; the numbers at the end are directive frequency of occurrence; the numbers at the end are directive
counts from all the source code I have lying around (egcs and libc 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 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, #define DIRECTIVE_TABLE \
of which all but #warning and #include_next are deprecated. The name D(define, T_DEFINE = 0, KANDR, IN_I) /* 270554 */ \
is where the extension appears to have come from. */ 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. */ /* #sccs is not always recognized. */
#ifdef SCCS_DIRECTIVE #ifdef SCCS_DIRECTIVE
...@@ -78,27 +142,6 @@ static void unwind_if_stack PARAMS ((cpp_reader *, cpp_buffer *)); ...@@ -78,27 +142,6 @@ static void unwind_if_stack PARAMS ((cpp_reader *, cpp_buffer *));
# define SCCS_ENTRY /* nothing */ # define SCCS_ENTRY /* nothing */
#endif #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 /* Use the table to generate a series of prototypes, an enum for the
directive names, and an array of directive handlers. */ directive names, and an array of directive handlers. */
...@@ -114,6 +157,7 @@ DIRECTIVE_TABLE ...@@ -114,6 +157,7 @@ DIRECTIVE_TABLE
#define D(n, tag, o, f) tag, #define D(n, tag, o, f) tag,
enum enum
{ {
T_BAD_DIRECTIVE,
DIRECTIVE_TABLE DIRECTIVE_TABLE
N_DIRECTIVES N_DIRECTIVES
}; };
...@@ -123,241 +167,387 @@ enum ...@@ -123,241 +167,387 @@ enum
#define D(name, t, origin, flags) \ #define D(name, t, origin, flags) \
{ CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \ { CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \
sizeof STRINGX(name) - 1, origin, flags }, sizeof STRINGX(name) - 1, origin, flags },
static const struct directive dtable[] = static const directive dtable[] =
{ {
DIRECTIVE_TABLE DIRECTIVE_TABLE
}; };
#undef D #undef D
#undef DIRECTIVE_TABLE #undef DIRECTIVE_TABLE
/* Check if a token's name matches that of a known directive. Put in /* Skip any remaining tokens in a directive. */
this file to save exporting dtable and other unneeded information. */ static void
const struct directive * skip_rest_of_line (pfile)
_cpp_check_directive (pfile, token)
cpp_reader *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) cpp_token token;
&& pfile->state.indented)
cpp_warning (pfile, "traditional C ignores #\\n with the # indented");
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++) /* Some handlers need the position of the # for diagnostics. */
if (pfile->spec_nodes->dirs[i] == token->val.node) pfile->directive_pos = pfile->lexer_pos;
break;
if (i == N_DIRECTIVES) /* We're now in a directive. This ensures we get pedantic warnings
return 0; 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 /* Lex the directive name directly. */
skipping or not. */ _cpp_lex_token (pfile, &dname);
pfile->state.angled_headers = dtable[i].flags & INCL;
/* If we are rescanning preprocessed input, only directives tagged if (dname.type == CPP_NAME)
with IN_I are honored, and the warnings below are suppressed. */
if (CPP_OPTION (pfile, preprocessed))
{ {
if (!dtable[i].flags & IN_I) unsigned int index = dname.val.node->directive_index;
return 0; if (index)
dir = &dtable[index - 1];
} }
else else if (dname.type == CPP_NUMBER)
{ {
/* Traditionally, a directive is ignored unless its # is in /* # followed by a number is equivalent to #line. Do not
column 1. Therefore in code intended to work with K+R recognize this form in assembly language source files or
compilers, directives added by C89 must have their # skipped conditional groups. Complain about this form if
indented, and directives present in traditional C must not. we're being pedantic, but not if this is regurgitated input
This is true even of directives in skipped conditional (preprocessed or fed back in by the C++ frontend). */
blocks. */ if (!pfile->skipping && !CPP_OPTION (pfile, lang_asm))
if (CPP_WTRADITIONAL (pfile))
{ {
if (pfile->state.indented && dtable[i].origin == KANDR) dir = &dtable[T_LINE];
cpp_warning (pfile, _cpp_push_token (pfile, &dname, &pfile->directive_pos);
"traditional C ignores #%s with the # indented", if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc
dtable[i].name); && ! CPP_OPTION (pfile, preprocessed))
cpp_pedwarn (pfile, "# followed by integer");
else if (!pfile->state.indented && dtable[i].origin != KANDR)
cpp_warning (pfile,
"suggest hiding #%s from traditional C with an indented #",
dtable[i].name);
} }
}
/* If we are skipping a failed conditional group, all non-conditional pfile->directive = dir;
directives are ignored. */ if (dir)
if (pfile->skipping && !(dtable[i].flags & COND)) {
return 0; /* Make sure we lex headers correctly, whether skipping or not. */
pfile->state.angled_headers = dir->flags & INCL;
/* Issue -pedantic warnings for extended directives. */ /* If we are rescanning preprocessed input, only directives tagged
if (CPP_PEDANTIC (pfile) && dtable[i].origin == EXTENSION) with IN_I are honored, and the warnings below are suppressed. */
cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name); 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. */ /* Save the lookahead token for assembler. */
pfile->state.save_comments = (! CPP_OPTION (pfile, discard_comments) if (not_asm)
&& (dtable[i].flags & COMMENTS)); 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 * /* Directive handler wrapper used by the command line option
_cpp_check_linemarker (pfile, token) processor. */
static void
run_directive (pfile, dir_no, buf, count, name)
cpp_reader *pfile; 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 if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL)
this form in assembly language source files or skipped {
conditional groups. Complain about this form if we're being const struct directive *dir = &dtable[dir_no];
pedantic, but not if this is regurgitated input (preprocessed or
fed back in by the C++ frontend). */ if (name)
if (pfile->skipping || CPP_OPTION (pfile, lang_asm)) CPP_BUFFER (pfile)->nominal_fname = name;
return 0; else
CPP_BUFFER (pfile)->nominal_fname = _("<command line>");
if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc CPP_BUFFER (pfile)->lineno = (unsigned int)-1;
&& ! CPP_OPTION (pfile, preprocessed))
cpp_pedwarn (pfile, "# followed by integer"); pfile->state.in_directive = 1;
pfile->directive = dir;
/* In -traditional mode, a directive is ignored unless its # (void) (*dir->handler) (pfile);
is in column 1. */ pfile->directive = 0;
if (pfile->state.indented && CPP_WTRADITIONAL (pfile)) pfile->state.in_directive = 0;
cpp_warning (pfile, "traditional C ignores #%s with the # indented",
dtable[T_LINE].name);
return &dtable[T_LINE];
}
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 * static cpp_hashnode *
get_define_node (pfile) lex_macro_node (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const cpp_token *token; cpp_token token;
/* Skip any -C comments. */ /* Lex the macro name directly. */
while ((token = _cpp_get_token (pfile))->type == CPP_COMMENT) _cpp_lex_token (pfile, &token);
;
/* The token immediately after #define must be an identifier. That /* The token immediately after #define must be an identifier. That
identifier is not allowed to be "defined". See predefined macro 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 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. */ <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) if (token.type == CPP_EOF)
cpp_error_with_line (pfile, token->line, token->col, cpp_error (pfile, "no macro name given in #%s directive",
"\"defined\" cannot be used as a macro name"); pfile->directive->name);
else if (token->flags & NAMED_OP) else if (token.flags & NAMED_OP)
cpp_error_with_line (pfile, token->line, token->col, cpp_error (pfile,
"\"%s\" cannot be used as a macro name in C++", "\"%s\" cannot be used as a macro name as it is an operator in C++",
token->val.node->name); token.val.node->name);
else else
cpp_error_with_line (pfile, token->line, token->col, cpp_error (pfile, "macro names must be identifiers");
"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;
} }
else
/* Check for poisoned identifiers now. */
if (token->val.node->type == T_POISON)
{ {
cpp_error_with_line (pfile, token->line, token->col, cpp_hashnode *node = token.val.node;
"attempt to use poisoned \"%s\"",
token->val.node->name); /* In Objective C, some keywords begin with '@', but general
return 0; 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 static void
do_define (pfile) do_define (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_hashnode *node; cpp_hashnode *node = lex_macro_node (pfile);
if ((node = get_define_node (pfile))) if (node)
if (_cpp_create_definition (pfile, node)) {
if (pfile->cb.define) /* Use the permanent pool for storage. */
(*pfile->cb.define) (pfile, node); 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 static void
do_undef (pfile) do_undef (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_hashnode *node = get_define_node (pfile); cpp_hashnode *node = lex_macro_node (pfile);
if (_cpp_get_token (pfile)->type != CPP_EOF)
cpp_pedwarn (pfile, "junk on line after #undef");
/* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
is not currently defined as a macro name. */ is not currently defined as a macro name. */
if (node && node->type != T_VOID) if (node && node->type == NT_MACRO)
{ {
if (pfile->cb.undef) if (pfile->cb.undef)
(*pfile->cb.undef) (pfile, node); (*pfile->cb.undef) (pfile, node);
if (node->type != T_MACRO) if (node->flags & NODE_BUILTIN)
cpp_warning (pfile, "undefining \"%s\"", node->name); cpp_warning (pfile, "undefining \"%s\"", node->name);
_cpp_free_definition (node); _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 static int
parse_include (pfile, dir, trail, strp, lenp, abp) parse_include (pfile, header)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *dir; cpp_token *header;
int trail;
const U_CHAR **strp;
unsigned int *lenp;
int *abp;
{ {
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) if (header->type != CPP_LESS)
name = _cpp_glue_header_name (pfile);
else
{ {
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir); cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
return 1; 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); cpp_error (pfile, "empty file name in #%s", dir);
return 1; return 1;
} }
if (!trail && _cpp_get_token (pfile)->type != CPP_EOF) if (!is_pragma)
cpp_error (pfile, "junk at end of #%s", dir); {
check_eol (pfile);
*lenp = name->val.str.len; /* Get out of macro context, if we are. */
*strp = name->val.str.text; skip_rest_of_line (pfile);
*abp = (name->type == CPP_HEADER_NAME); if (pfile->cb.include)
(*pfile->cb.include) (pfile, dir, header);
}
if (pfile->cb.include)
(*pfile->cb.include) (pfile, dir, *strp, *lenp, *abp);
return 0; return 0;
} }
...@@ -365,23 +555,17 @@ static void ...@@ -365,23 +555,17 @@ static void
do_include (pfile) do_include (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
unsigned int len; cpp_token header;
const U_CHAR *str;
int ab;
if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab))
return;
_cpp_execute_include (pfile, str, len, 0, 0, ab); if (!parse_include (pfile, &header))
_cpp_execute_include (pfile, &header, 0, 0);
} }
static void static void
do_import (pfile) do_import (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
unsigned int len; cpp_token header;
const U_CHAR *str;
int ab;
if (!pfile->import_warning && CPP_OPTION (pfile, warn_import)) if (!pfile->import_warning && CPP_OPTION (pfile, warn_import))
{ {
...@@ -390,22 +574,18 @@ do_import (pfile) ...@@ -390,22 +574,18 @@ do_import (pfile)
"#import is obsolete, use an #ifndef wrapper in the header file"); "#import is obsolete, use an #ifndef wrapper in the header file");
} }
if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab)) if (!parse_include (pfile, &header))
return; _cpp_execute_include (pfile, &header, 1, 0);
_cpp_execute_include (pfile, str, len, 1, 0, ab);
} }
static void static void
do_include_next (pfile) do_include_next (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
unsigned int len; cpp_token header;
const U_CHAR *str;
struct file_name_list *search_start = 0; 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; return;
/* For #include_next, skip in the search path past the dir in which /* For #include_next, skip in the search path past the dir in which
...@@ -426,7 +606,7 @@ do_include_next (pfile) ...@@ -426,7 +606,7 @@ do_include_next (pfile)
else else
cpp_warning (pfile, "#include_next in primary source file"); 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 /* Subroutine of do_line. Read next token from PFILE without adding it to
...@@ -439,22 +619,23 @@ read_line_number (pfile, num) ...@@ -439,22 +619,23 @@ read_line_number (pfile, num)
cpp_reader *pfile; cpp_reader *pfile;
int *num; int *num;
{ {
const cpp_token *tok = _cpp_get_token (pfile); cpp_token token;
enum cpp_ttype type = tok->type; unsigned int val;
const U_CHAR *p = tok->val.str.text;
unsigned int len = tok->val.str.len;
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'; val = token.val.str.text[0] - '1';
return 1; if (val <= 3)
} {
else *num = val + 1;
{ return 1;
if (type != CPP_EOF) }
cpp_error (pfile, "invalid format #line");
return 0;
} }
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 /* Another subroutine of do_line. Convert a number in STR, of length
...@@ -489,90 +670,88 @@ do_line (pfile) ...@@ -489,90 +670,88 @@ do_line (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_buffer *ip = CPP_BUFFER (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. */ /* C99 raised the minimum limit on #line numbers. */
unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767; unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
int action_number = 0;
int enter = 0, leave = 0, rename = 0; int enter = 0, leave = 0, rename = 0;
enum cpp_ttype type; cpp_token token;
const U_CHAR *str;
char *fname; /* #line commands expand macros. */
unsigned int len; _cpp_get_token (pfile, &token);
const cpp_token *tok; if (token.type != CPP_NUMBER
|| strtoul_for_line (token.val.str.text, token.val.str.len, &new_lineno))
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_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; return;
} }
if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap)) if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
cpp_pedwarn (pfile, "line number out of range"); cpp_pedwarn (pfile, "line number out of range");
old_lineno = ip->lineno; _cpp_get_token (pfile, &token);
ip->lineno = new_lineno;
tok = _cpp_get_token (pfile);
type = tok->type;
str = tok->val.str.text;
len = tok->val.str.len;
if (type == CPP_EOF) if (token.type != CPP_EOF)
goto done;
else if (type != CPP_STRING)
{ {
cpp_error (pfile, "second token after #line is not a string"); char *fname;
ip->lineno = old_lineno; /* malformed #line should have no effect */ unsigned int len;
return; int action_number = 0;
}
fname = alloca (len + 1); if (token.type != CPP_STRING)
memcpy (fname, str, len); {
fname[len] = '\0'; cpp_error (pfile, "\"%s\" is not a valid filename",
cpp_token_as_text (pfile, &token));
if (strcmp (fname, ip->nominal_fname)) return;
{ }
rename = 1;
if (!strcmp (fname, ip->inc->name))
ip->nominal_fname = ip->inc->name;
else
ip->nominal_fname = _cpp_fake_include (pfile, fname);
}
if (read_line_number (pfile, &action_number) == 0) len = token.val.str.len;
goto done; 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)) if (read_line_number (pfile, &action_number) != 0)
cpp_pedwarn (pfile, "garbage at end of #line"); {
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "extra tokens at end of #line directive");
if (action_number == 1) if (action_number == 1)
{ {
enter = 1; enter = 1;
cpp_make_system_header (pfile, ip, 0); cpp_make_system_header (pfile, ip, 0);
read_line_number (pfile, &action_number); read_line_number (pfile, &action_number);
} }
else if (action_number == 2) else if (action_number == 2)
{ {
leave = 1; leave = 1;
cpp_make_system_header (pfile, ip, 0); cpp_make_system_header (pfile, ip, 0);
read_line_number (pfile, &action_number); read_line_number (pfile, &action_number);
} }
if (action_number == 3) if (action_number == 3)
{ {
cpp_make_system_header (pfile, ip, 1); cpp_make_system_header (pfile, ip, 1);
read_line_number (pfile, &action_number); read_line_number (pfile, &action_number);
} }
if (action_number == 4) if (action_number == 4)
{ {
cpp_make_system_header (pfile, ip, 2); cpp_make_system_header (pfile, ip, 2);
read_line_number (pfile, &action_number); 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) if (enter && pfile->cb.enter_file)
(*pfile->cb.enter_file) (pfile); (*pfile->cb.enter_file) (pfile);
if (leave && pfile->cb.leave_file) if (leave && pfile->cb.leave_file)
...@@ -591,11 +770,12 @@ do_diagnostic (pfile, code) ...@@ -591,11 +770,12 @@ do_diagnostic (pfile, code)
cpp_reader *pfile; cpp_reader *pfile;
enum error_type code; 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, fprintf (stderr, "#%s ", pfile->directive->name);
pfile->first_directive_token); pfile->state.prevent_expansion++;
putc ('\n', stderr); cpp_output_line (pfile, stderr);
pfile->state.prevent_expansion--;
} }
} }
...@@ -619,16 +799,15 @@ static void ...@@ -619,16 +799,15 @@ static void
do_ident (pfile) do_ident (pfile)
cpp_reader *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) _cpp_get_token (pfile, &str);
{ if (str.type != CPP_STRING)
if (pfile->cb.ident) cpp_error (pfile, "invalid #ident");
(*pfile->cb.ident) (pfile, str->val.str.text, str->val.str.len); else if (pfile->cb.ident)
return; (*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 /* Pragmata handling. We handle some of these, and pass the rest on
...@@ -723,11 +902,6 @@ cpp_register_pragma_space (pfile, space) ...@@ -723,11 +902,6 @@ cpp_register_pragma_space (pfile, space)
pfile->pragmas = new; 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 void
_cpp_init_internal_pragmas (pfile) _cpp_init_internal_pragmas (pfile)
cpp_reader *pfile; cpp_reader *pfile;
...@@ -749,46 +923,47 @@ do_pragma (pfile) ...@@ -749,46 +923,47 @@ do_pragma (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const struct pragma_entry *p; const struct pragma_entry *p;
const cpp_token *tok; cpp_token tok;
const cpp_hashnode *node; const cpp_hashnode *node;
const U_CHAR *name; const U_CHAR *name;
size_t len; size_t len;
int drop = 0;
p = pfile->pragmas; p = pfile->pragmas;
pfile->state.prevent_expansion++;
cpp_start_lookahead (pfile);
new_space: new_space:
tok = _cpp_get_token (pfile); cpp_get_token (pfile, &tok);
if (tok->type == CPP_EOF) if (tok.type == CPP_NAME)
return;
if (tok->type != CPP_NAME)
{ {
cpp_error (pfile, "malformed #pragma directive"); node = tok.val.node;
return; name = node->name;
} len = node->length;
while (p)
node = tok->val.node;
name = node->name;
len = node->length;
while (p)
{
if (strlen (p->name) == len && !memcmp (p->name, name, len))
{ {
if (p->isnspace) if (strlen (p->name) == len && !memcmp (p->name, name, len))
{ {
p = p->u.space; if (p->isnspace)
goto new_space; {
} p = p->u.space;
else goto new_space;
{ }
(*p->u.handler) (pfile); else
return; {
(*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); (*pfile->cb.def_pragma) (pfile);
} }
...@@ -798,14 +973,14 @@ do_pragma_once (pfile) ...@@ -798,14 +973,14 @@ do_pragma_once (pfile)
{ {
cpp_buffer *ip = CPP_BUFFER (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"); cpp_warning (pfile, "#pragma once is obsolete");
if (CPP_PREV_BUFFER (ip) == NULL) if (CPP_PREV_BUFFER (ip) == NULL)
cpp_warning (pfile, "#pragma once outside include file"); cpp_warning (pfile, "#pragma once in main file");
else else
ip->inc->cmacro = NEVER_REREAD; ip->inc->cmacro = NEVER_REREAD;
check_eol (pfile);
} }
static void static void
...@@ -814,34 +989,36 @@ do_pragma_poison (pfile) ...@@ -814,34 +989,36 @@ do_pragma_poison (pfile)
{ {
/* Poison these symbols so that all subsequent usage produces an /* Poison these symbols so that all subsequent usage produces an
error message. */ error message. */
const cpp_token *tok; cpp_token tok;
cpp_hashnode *hp; cpp_hashnode *hp;
pfile->state.poisoned_ok = 1;
for (;;) for (;;)
{ {
tok = _cpp_get_token (pfile); _cpp_lex_token (pfile, &tok);
if (tok->type == CPP_EOF) if (tok.type == CPP_EOF)
break; break;
if (tok->type != CPP_NAME) if (tok.type != CPP_NAME)
{ {
cpp_error (pfile, "invalid #pragma poison directive"); cpp_error (pfile, "invalid #pragma GCC poison directive");
return; break;
} }
hp = tok->val.node; hp = tok.val.node;
if (hp->type == T_POISON) if (hp->flags & NODE_POISONED)
; /* It is allowed to poison the same identifier twice. */ continue;
else
{ if (hp->type == NT_MACRO)
if (hp->type != T_VOID) cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name);
cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name); _cpp_free_definition (hp);
_cpp_free_definition (hp); hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
hp->type = T_POISON;
}
} }
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); (*pfile->cb.poison) (pfile);
#endif
} }
/* Mark the current header as a system header. This will suppress /* Mark the current header as a system header. This will suppress
...@@ -859,6 +1036,8 @@ do_pragma_system_header (pfile) ...@@ -859,6 +1036,8 @@ do_pragma_system_header (pfile)
cpp_warning (pfile, "#pragma system_header outside include file"); cpp_warning (pfile, "#pragma system_header outside include file");
else else
cpp_make_system_header (pfile, ip, 1); cpp_make_system_header (pfile, ip, 1);
check_eol (pfile);
} }
/* Check the modified date of the current include file against a specified /* Check the modified date of the current include file against a specified
...@@ -868,32 +1047,25 @@ static void ...@@ -868,32 +1047,25 @@ static void
do_pragma_dependency (pfile) do_pragma_dependency (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const U_CHAR *name; cpp_token header, msg;
unsigned int len; int ordering;
int ordering, ab;
char left, right;
if (parse_include (pfile, U"pragma dependency", 1, &name, &len, &ab)) if (parse_include (pfile, &header))
return; return;
left = ab ? '<' : '"'; ordering = _cpp_compare_file_date (pfile, &header);
right = ab ? '>' : '"';
ordering = _cpp_compare_file_date (pfile, name, len, ab);
if (ordering < 0) 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) else if (ordering > 0)
{ {
const cpp_token *msg = _cpp_get_token (pfile); cpp_warning (pfile, "current file is older than %s",
cpp_token_as_text (pfile, &header));
cpp_warning (pfile, "current file is older than %c%.*s%c", cpp_start_lookahead (pfile);
left, (int)len, name, right); cpp_get_token (pfile, &msg);
if (msg->type != CPP_EOF cpp_stop_lookahead (pfile, msg.type == CPP_EOF);
&& _cpp_begin_message (pfile, WARNING, NULL, msg->line, msg->col)) if (msg.type != CPP_EOF && _cpp_begin_message (pfile, WARNING, NULL, 0))
{ cpp_output_line (pfile, stderr);
cpp_output_list (pfile, stderr, &pfile->token_list, msg);
putc ('\n', stderr);
}
} }
} }
...@@ -906,137 +1078,61 @@ do_sccs (pfile) ...@@ -906,137 +1078,61 @@ do_sccs (pfile)
} }
#endif #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 static void
do_ifdef (pfile) do_ifdef (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const cpp_hashnode *node = 0; int skip = 1;
if (! pfile->skipping) 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 push_conditional (pfile, skip, T_IFDEF, 0);
no-reinclusion wrapper. */ }
static void static void
do_ifndef (pfile) do_ifndef (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int start_of_file = 0; int skip = 1;
const cpp_hashnode *node = 0; const cpp_hashnode *node = 0;
if (! pfile->skipping) if (! pfile->skipping)
{ {
start_of_file = (pfile->token_list.flags & BEG_OF_FILE); node = lex_macro_node (pfile);
node = parse_ifdef (pfile, dtable[T_IFNDEF].name); if (node)
skip = node->type == NT_MACRO;
} }
push_conditional (pfile, node && node->type != T_VOID, push_conditional (pfile, skip, T_IFNDEF, node);
T_IFNDEF, start_of_file ? node : 0);
} }
/* #if is straightforward; just call _cpp_parse_expr, then conditional_skip. /* #if cooperates with parse_defined to handle multiple-include
Also, check for a reinclude preventer of the form #if !defined (MACRO). */ 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 static void
do_if (pfile) do_if (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int skip = 1;
const cpp_hashnode *cmacro = 0; const cpp_hashnode *cmacro = 0;
int value = 0;
if (! pfile->skipping) if (!pfile->skipping)
{ {
if (pfile->token_list.flags & BEG_OF_FILE) /* Controlling macro of #if ! defined () */
cmacro = detect_if_not_defined (pfile); pfile->mi_ind_cmacro = 0;
value = _cpp_parse_expr (pfile); 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 /* #else flips pfile->skipping and continues without changing
...@@ -1048,37 +1144,36 @@ do_else (pfile) ...@@ -1048,37 +1144,36 @@ do_else (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack; struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
validate_else (pfile, dtable[T_ELSE].name);
if (ifs == NULL) if (ifs == NULL)
cpp_error (pfile, "#else without #if");
else
{ {
cpp_error (pfile, "#else without #if"); if (ifs->type == T_ELSE)
return; {
} cpp_error (pfile, "#else after #else");
if (ifs->type == T_ELSE) cpp_error_with_line (pfile, ifs->pos.line, ifs->pos.col,
{ "the conditional began here");
cpp_error (pfile, "#else after #else"); }
cpp_error_with_line (pfile, ifs->lineno, ifs->colno,
"the conditional began here");
}
/* #ifndef can't have its special treatment for containing the whole file /* Invalidate any controlling macro. */
if it has a #else clause. */ ifs->mi_cmacro = 0;
ifs->cmacro = 0;
ifs->type = T_ELSE; ifs->type = T_ELSE;
if (! ifs->was_skipping) if (! ifs->was_skipping)
{ {
/* If pfile->skipping is 2, one of the blocks in an #if/#elif/... chain /* If pfile->skipping is 2, one of the blocks in an #if
succeeded, so we mustn't do the else block. */ #elif ... chain succeeded, so we skip the else block. */
if (pfile->skipping < 2) if (pfile->skipping < 2)
pfile->skipping = ! pfile->skipping; pfile->skipping = ! pfile->skipping;
}
} }
check_eol (pfile);
} }
/* /* handle a #elif directive by not changing if_stack either. see the
* handle a #elif directive by not changing if_stack either. comment above do_else. */
* see the comment above do_else.
*/
static void static void
do_elif (pfile) do_elif (pfile)
...@@ -1091,13 +1186,17 @@ do_elif (pfile) ...@@ -1091,13 +1186,17 @@ do_elif (pfile)
cpp_error (pfile, "#elif without #if"); cpp_error (pfile, "#elif without #if");
return; return;
} }
if (ifs->type == T_ELSE) if (ifs->type == T_ELSE)
{ {
cpp_error (pfile, "#elif after #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"); "the conditional began here");
} }
/* Invalidate any controlling macro. */
ifs->mi_cmacro = 0;
ifs->type = T_ELIF; ifs->type = T_ELIF;
if (ifs->was_skipping) if (ifs->was_skipping)
return; /* Don't evaluate a nested #if */ return; /* Don't evaluate a nested #if */
...@@ -1119,19 +1218,24 @@ do_endif (pfile) ...@@ -1119,19 +1218,24 @@ do_endif (pfile)
{ {
struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack; struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
validate_else (pfile, dtable[T_ENDIF].name);
if (ifs == NULL) if (ifs == NULL)
cpp_error (pfile, "#endif without #if"); cpp_error (pfile, "#endif without #if");
else 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; CPP_BUFFER (pfile)->if_stack = ifs->next;
pfile->skipping = ifs->was_skipping; pfile->skipping = ifs->was_skipping;
pfile->potential_control_macro = ifs->cmacro;
obstack_free (pfile->buffer_ob, ifs); obstack_free (pfile->buffer_ob, ifs);
} }
}
check_eol (pfile);
}
/* Push an if_stack entry and set pfile->skipping accordingly. /* Push an if_stack entry and set pfile->skipping accordingly.
If this is a #ifndef starting at the beginning of a file, If this is a #ifndef starting at the beginning of a file,
...@@ -1147,11 +1251,14 @@ push_conditional (pfile, skip, type, cmacro) ...@@ -1147,11 +1251,14 @@ push_conditional (pfile, skip, type, cmacro)
struct if_stack *ifs; struct if_stack *ifs;
ifs = xobnew (pfile->buffer_ob, struct if_stack); 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->next = CPP_BUFFER (pfile)->if_stack;
ifs->cmacro = cmacro;
ifs->was_skipping = pfile->skipping; ifs->was_skipping = pfile->skipping;
ifs->type = type; 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) if (!pfile->skipping)
pfile->skipping = skip; pfile->skipping = skip;
...@@ -1159,18 +1266,6 @@ push_conditional (pfile, skip, type, cmacro) ...@@ -1159,18 +1266,6 @@ push_conditional (pfile, skip, type, cmacro)
CPP_BUFFER (pfile)->if_stack = ifs; 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 /* 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, conditional stack till we reach its level at entry to this file,
issuing error messages. Then force skipping off. */ issuing error messages. Then force skipping off. */
...@@ -1179,147 +1274,187 @@ unwind_if_stack (pfile, pbuf) ...@@ -1179,147 +1274,187 @@ unwind_if_stack (pfile, pbuf)
cpp_reader *pfile; cpp_reader *pfile;
cpp_buffer *pbuf; 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; pfile->skipping = 0;
} }
/* Parses an assertion, returning a pointer to the hash node of the /* Read the tokens of the answer into the macro pool. Only commit the
predicate, or 0 on error. If an answer was supplied, it is memory if we intend it as permanent storage, i.e. the #assert case.
allocated and placed in ANSWERP, otherwise it is set to 0. We use Returns 0 on success. */
_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 static int
macro expand. */ parse_answer (pfile, answerp, type)
cpp_hashnode *
_cpp_parse_assertion (pfile, answerp)
cpp_reader *pfile; cpp_reader *pfile;
struct answer **answerp; struct answer **answerp;
int type;
{ {
struct answer *answer = 0; cpp_token paren, *token;
cpp_toklist *list; struct answer *answer;
U_CHAR *sym;
const cpp_token *token, *predicate; if (POOL_FRONT (&pfile->macro_pool) + sizeof (struct answer) >
const struct directive *d = pfile->token_list.directive; POOL_LIMIT (&pfile->macro_pool))
unsigned int len = 0; _cpp_next_chunk (&pfile->macro_pool, sizeof (struct answer), 0);
answer = (struct answer *) POOL_FRONT (&pfile->macro_pool);
predicate = _cpp_get_raw_token (pfile); answer->count = 0;
if (predicate->type == CPP_EOF)
/* 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"); /* In a conditional no answer is a test for any answer. It
return 0; could be followed by any token. */
} if (type == T_IF)
else if (predicate->type != CPP_NAME) return 0;
{
cpp_error (pfile, "predicate must be an identifier"); /* #unassert with no answer is valid - it removes all answers. */
return 0; 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"); 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 (;;) for (;;)
{ {
cpp_token *dest; token = &answer->first[answer->count];
/* Check we have room for the token. */
token = _cpp_get_raw_token (pfile); if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
if (token->type == CPP_EOF)
{ {
cpp_error (pfile, "missing ')' to complete answer"); _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_token),
goto error; (unsigned char **) &answer);
token = &answer->first[answer->count];
} }
_cpp_get_token (pfile, token);
if (token->type == CPP_CLOSE_PAREN) if (token->type == CPP_CLOSE_PAREN)
break; break;
/* Copy the token. */ if (token->type == CPP_EOF)
_cpp_expand_token_space (list, 1);
dest = &list->tokens[list->tokens_used++];
*dest = *token;
if (TOKEN_SPELL (token) == SPELL_STRING)
{ {
_cpp_expand_name_space (list, token->val.str.len); cpp_error (pfile, "missing ')' to complete answer");
dest->val.str.text = list->namebuf + list->name_used; return 1;
memcpy (list->namebuf + list->name_used,
token->val.str.text, token->val.str.len);
list->name_used += token->val.str.len;
} }
answer->count++;
} }
if (list->tokens_used == 0) if (answer->count == 0)
{ {
cpp_error (pfile, "predicate's answer is empty"); cpp_error (pfile, "predicate's answer is empty");
goto error; return 1;
} }
/* Drop whitespace at start. */ /* 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]) if (type == T_ASSERT || type == T_UNASSERT)
&& token[1].type != CPP_EOF) check_eol (pfile);
{ return 0;
cpp_error (pfile, "junk at end of assertion"); }
goto error;
}
lookup_node: /* Parses an assertion, returning a pointer to the hash node of the
*answerp = answer; predicate, or 0 on error. If an answer was supplied, it is placed
len = predicate->val.node->length; in ANSWERP, otherwise it is set to 0. We use _cpp_get_raw_token,
sym = alloca (len + 1); 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. */ /* Prefix '#' to get it out of macro namespace. */
sym[0] = '#'; sym[0] = '#';
memcpy (sym + 1, predicate->val.node->name, len); memcpy (sym + 1, predicate.val.node->name, len);
return cpp_lookup (pfile, sym, len + 1); result = cpp_lookup (pfile, sym, len + 1);
}
error: pfile->string_pool = &pfile->temp_string_pool;
FREE_ANSWER (answer); pfile->state.prevent_expansion--;
return 0; return result;
} }
/* Returns a pointer to the pointer to the answer in the answer chain, /* 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. */ or a pointer to NULL if the answer is not in the chain. */
struct answer ** static struct answer **
_cpp_find_answer (node, candidate) find_answer (node, candidate)
cpp_hashnode *node; cpp_hashnode *node;
const cpp_toklist *candidate; const struct answer *candidate;
{ {
unsigned int i;
struct answer **result; struct answer **result;
for (result = &node->value.answers; *result; result = &(*result)->next) 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; 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 static void
do_assert (pfile) do_assert (pfile)
cpp_reader *pfile; cpp_reader *pfile;
...@@ -1327,26 +1462,27 @@ do_assert (pfile) ...@@ -1327,26 +1462,27 @@ do_assert (pfile)
struct answer *new_answer; struct answer *new_answer;
cpp_hashnode *node; cpp_hashnode *node;
node = _cpp_parse_assertion (pfile, &new_answer); node = parse_assertion (pfile, &new_answer, T_ASSERT);
if (node) if (node)
{ {
/* Place the new answer in the answer list. First check there
is not a duplicate. */
new_answer->next = 0; new_answer->next = 0;
new_answer->list.file = pfile->token_list.file; if (node->type == NT_ASSERTION)
if (node->type == T_ASSERTION)
{ {
if (*_cpp_find_answer (node, &new_answer->list)) if (*find_answer (node, new_answer))
goto err; {
cpp_warning (pfile, "\"%s\" re-asserted", node->name + 1);
return;
}
new_answer->next = node->value.answers; new_answer->next = node->value.answers;
} }
node->type = T_ASSERTION; node->type = NT_ASSERTION;
node->value.answers = new_answer; 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 static void
...@@ -1354,34 +1490,30 @@ do_unassert (pfile) ...@@ -1354,34 +1490,30 @@ do_unassert (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_hashnode *node; cpp_hashnode *node;
struct answer *answer, *temp; struct answer *answer;
node = _cpp_parse_assertion (pfile, &answer); node = parse_assertion (pfile, &answer, T_UNASSERT);
if (node) /* 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 (answer)
if (node->type == T_ASSERTION)
{ {
if (answer) struct answer **p = find_answer (node, answer), *temp;
{
struct answer **p = _cpp_find_answer (node, &answer->list);
temp = *p; /* Remove the answer from the list. */
if (temp) temp = *p;
{ if (temp)
*p = temp->next; *p = temp->next;
FREE_ANSWER (temp);
}
if (node->value.answers == 0)
node->type = T_VOID;
}
else
_cpp_free_definition (node);
}
if (answer) /* Did we free the last answer? */
FREE_ANSWER (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. */ /* These are for -D, -U, -A. */
...@@ -1421,7 +1553,7 @@ cpp_define (pfile, str) ...@@ -1421,7 +1553,7 @@ cpp_define (pfile, str)
strcpy (&buf[count-4], " 1\n"); 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) /* Slight variant of the above for use by initialize_builtins, which (a)
...@@ -1432,9 +1564,7 @@ _cpp_define_builtin (pfile, str) ...@@ -1432,9 +1564,7 @@ _cpp_define_builtin (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str; const char *str;
{ {
_cpp_run_directive (pfile, &dtable[T_DEFINE], run_directive (pfile, T_DEFINE, str, strlen (str), _("<builtin>"));
str, strlen (str),
_("<builtin>"));
} }
/* Process MACRO as if it appeared as the body of an #undef. */ /* Process MACRO as if it appeared as the body of an #undef. */
...@@ -1443,7 +1573,7 @@ cpp_undef (pfile, macro) ...@@ -1443,7 +1573,7 @@ cpp_undef (pfile, macro)
cpp_reader *pfile; cpp_reader *pfile;
const char *macro; 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. */ /* Process the string STR as if it appeared as the body of a #assert. */
...@@ -1452,7 +1582,7 @@ cpp_assert (pfile, str) ...@@ -1452,7 +1582,7 @@ cpp_assert (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str; 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. */ /* Process STR as if it appeared as the body of an #unassert. */
...@@ -1461,7 +1591,7 @@ cpp_unassert (pfile, str) ...@@ -1461,7 +1591,7 @@ cpp_unassert (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str; 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. */ /* Determine whether the identifier ID, of length LEN, is a defined macro. */
...@@ -1472,18 +1602,15 @@ cpp_defined (pfile, id, len) ...@@ -1472,18 +1602,15 @@ cpp_defined (pfile, id, len)
int len; int len;
{ {
cpp_hashnode *hp = cpp_lookup (pfile, id, len); cpp_hashnode *hp = cpp_lookup (pfile, id, len);
if (hp->type == T_POISON)
{ /* If it's of type NT_MACRO, it cannot be poisoned. */
cpp_error (pfile, "attempt to use poisoned \"%s\"", hp->name); return hp->type == NT_MACRO;
return 0;
}
return (hp->type != T_VOID);
} }
/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack. /* Allocate a new cpp_buffer for PFILE, and push it on the input
If BUFFER != NULL, then use the LENGTH characters in BUFFER buffer stack. If BUFFER != NULL, then use the LENGTH characters in
as the new input buffer. BUFFER as the new input buffer. Return the new buffer, or NULL on
Return the new buffer, or NULL on failure. */ failure. */
cpp_buffer * cpp_buffer *
cpp_push_buffer (pfile, buffer, length) cpp_push_buffer (pfile, buffer, length)
...@@ -1498,15 +1625,18 @@ cpp_push_buffer (pfile, buffer, length) ...@@ -1498,15 +1625,18 @@ cpp_push_buffer (pfile, buffer, length)
cpp_fatal (pfile, "#include nested too deeply"); cpp_fatal (pfile, "#include nested too deeply");
return NULL; return NULL;
} }
if (pfile->cur_context > 0)
if (pfile->context->prev)
{ {
cpp_ice (pfile, "buffer pushed with contexts stacked"); 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); new = xobnew (pfile->buffer_ob, cpp_buffer);
/* Clears, amongst other things, if_stack and mi_cmacro. */
memset (new, 0, sizeof (cpp_buffer)); memset (new, 0, sizeof (cpp_buffer));
pfile->lexer_pos.output_line = 1;
new->line_base = new->buf = new->cur = buffer; new->line_base = new->buf = new->cur = buffer;
new->rlimit = buffer + length; new->rlimit = buffer + length;
new->prev = buf; new->prev = buf;
...@@ -1514,6 +1644,7 @@ cpp_push_buffer (pfile, buffer, length) ...@@ -1514,6 +1644,7 @@ cpp_push_buffer (pfile, buffer, length)
/* No read ahead or extra char initially. */ /* No read ahead or extra char initially. */
new->read_ahead = EOF; new->read_ahead = EOF;
new->extra_char = EOF; new->extra_char = EOF;
pfile->state.skip_newlines = 1;
CPP_BUFFER (pfile) = new; CPP_BUFFER (pfile) = new;
return new; return new;
...@@ -1535,7 +1666,7 @@ cpp_pop_buffer (pfile) ...@@ -1535,7 +1666,7 @@ cpp_pop_buffer (pfile)
obstack_free (pfile->buffer_ob, buf); obstack_free (pfile->buffer_ob, buf);
pfile->buffer_stack_depth--; 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); (*pfile->cb.leave_file) (pfile);
return CPP_BUFFER (pfile); return CPP_BUFFER (pfile);
...@@ -1543,25 +1674,22 @@ cpp_pop_buffer (pfile) ...@@ -1543,25 +1674,22 @@ cpp_pop_buffer (pfile)
#define obstack_chunk_alloc xmalloc #define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free #define obstack_chunk_free free
#define DSC(x) U x, sizeof x - 1
void void
_cpp_init_stacks (pfile) _cpp_init_stacks (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int i; int i;
struct spec_nodes *s; cpp_hashnode *node;
pfile->buffer_ob = xnew (struct obstack); pfile->buffer_ob = xnew (struct obstack);
obstack_init (pfile->buffer_ob); obstack_init (pfile->buffer_ob);
/* Perhaps not the ideal place to put this. */ /* Register the directives. */
pfile->spec_nodes = s = xnew (struct spec_nodes); for (i = 1; i < N_DIRECTIVES; i++)
s->n_L = cpp_lookup (pfile, DSC("L")); {
s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__")); node = cpp_lookup (pfile, dtable[i - 1].name, dtable[i - 1].length);
s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__")); node->directive_index = i;
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);
} }
void void
......
...@@ -34,11 +34,21 @@ typedef struct cpp_reader cpp_reader; ...@@ -34,11 +34,21 @@ typedef struct cpp_reader cpp_reader;
#endif #endif
typedef struct cpp_buffer cpp_buffer; typedef struct cpp_buffer cpp_buffer;
typedef struct cpp_options cpp_options; typedef struct cpp_options cpp_options;
typedef struct cpp_printer cpp_printer;
typedef struct cpp_token cpp_token; typedef struct cpp_token cpp_token;
typedef struct cpp_toklist cpp_toklist;
typedef struct cpp_string cpp_string; typedef struct cpp_string cpp_string;
typedef struct cpp_hashnode cpp_hashnode; 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 /* The first two groups, apart from '=', can appear in preprocessor
expressions. This allows a lookup table to be implemented in expressions. This allows a lookup table to be implemented in
...@@ -114,7 +124,6 @@ typedef struct cpp_hashnode cpp_hashnode; ...@@ -114,7 +124,6 @@ typedef struct cpp_hashnode cpp_hashnode;
OP(CPP_SCOPE, "::") \ OP(CPP_SCOPE, "::") \
OP(CPP_DEREF_STAR, "->*") \ OP(CPP_DEREF_STAR, "->*") \
OP(CPP_DOT_STAR, ".*") \ OP(CPP_DOT_STAR, ".*") \
OP(CPP_DEFINED, "defined") /* #if */ \
\ \
TK(CPP_NAME, SPELL_IDENT) /* word */ \ TK(CPP_NAME, SPELL_IDENT) /* word */ \
TK(CPP_INT, SPELL_STRING) /* 23 */ \ TK(CPP_INT, SPELL_STRING) /* 23 */ \
...@@ -131,9 +140,10 @@ typedef struct cpp_hashnode cpp_hashnode; ...@@ -131,9 +140,10 @@ typedef struct cpp_hashnode cpp_hashnode;
TK(CPP_HEADER_NAME, SPELL_STRING) /* <stdio.h> in #include */ \ TK(CPP_HEADER_NAME, SPELL_STRING) /* <stdio.h> in #include */ \
\ \
TK(CPP_COMMENT, SPELL_STRING) /* Only if output comments. */ \ 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_MACRO_ARG, SPELL_NONE) /* Macro argument. */ \
TK(CPP_PLACEMARKER, SPELL_NONE) /* Placemarker token. */ \ 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 OP(e, s) e,
#define TK(e, s) e, #define TK(e, s) e,
...@@ -145,6 +155,10 @@ enum cpp_ttype ...@@ -145,6 +155,10 @@ enum cpp_ttype
#undef OP #undef OP
#undef TK #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. */ /* Payload of a NUMBER, FLOAT, STRING, or COMMENT token. */
struct cpp_string struct cpp_string
{ {
...@@ -154,19 +168,17 @@ struct cpp_string ...@@ -154,19 +168,17 @@ struct cpp_string
/* Flags for the cpp_token structure. */ /* Flags for the cpp_token structure. */
#define PREV_WHITE (1 << 0) /* If whitespace before this token. */ #define PREV_WHITE (1 << 0) /* If whitespace before this token. */
#define BOL (1 << 1) /* Beginning of logical line. */ #define DIGRAPH (1 << 1) /* If it was a digraph. */
#define DIGRAPH (1 << 2) /* If it was a digraph. */ #define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */
#define STRINGIFY_ARG (1 << 3) /* If macro argument to be stringified. */ #define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */
#define PASTE_LEFT (1 << 4) /* If on LHS of a ## operator. */ #define NAMED_OP (1 << 4) /* C++ named operators, also "defined". */
#define PASTED (1 << 5) /* The result of a ## operator. */ #define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */
#define NAMED_OP (1 << 6) /* C++ named operators, also "defined". */ #define VARARGS_FIRST STRINGIFY_ARG /* First token of varargs expansion. */
/* A preprocessing token. This has been carefully packed and should /* 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 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 */ ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */
unsigned char flags; /* flags - see above */ unsigned char flags; /* flags - see above */
...@@ -180,37 +192,58 @@ struct cpp_token ...@@ -180,37 +192,58 @@ struct cpp_token
} val; } val;
}; };
/* cpp_toklist flags. */ /* The position of a token in the current file. */
#define VAR_ARGS (1 << 0) struct cpp_lexer_pos
#define BEG_OF_FILE (1 << 1) {
unsigned int line;
struct directive; /* These are deliberately incomplete. */ unsigned int output_line;
struct answer; unsigned short col;
struct macro_args; };
struct cpp_context;
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 */ cpp_token token;
unsigned int tokens_used; /* tokens used */ cpp_lexer_pos pos;
unsigned int tokens_cap; /* tokens allocated */ };
unsigned char *namebuf; /* names buffer */ /* Token lookahead. */
unsigned int name_used; /* _bytes_ used */ struct cpp_lookahead
unsigned int name_cap; /* _bytes_ allocated */ {
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. */ /* Memory pools. */
const struct directive *directive; 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 */ typedef struct toklist toklist;
unsigned int line; /* starting line number */ 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 */ /* For a macro context, these are the macro and its arguments. */
unsigned short flags; cpp_macro *macro;
}; };
/* A standalone character. We may want to make it unsigned for the /* A standalone character. We may want to make it unsigned for the
...@@ -257,9 +290,6 @@ struct cpp_buffer ...@@ -257,9 +290,6 @@ struct cpp_buffer
char warned_cplusplus_comments; char warned_cplusplus_comments;
}; };
struct file_name_map_list;
struct htab;
/* Maximum nesting of cpp_buffers. We use a static limit, partly for /* Maximum nesting of cpp_buffers. We use a static limit, partly for
efficiency, and partly to limit runaway recursion. */ efficiency, and partly to limit runaway recursion. */
#define CPP_STACK_MAX 200 #define CPP_STACK_MAX 200
...@@ -448,10 +478,6 @@ struct lexer_state ...@@ -448,10 +478,6 @@ struct lexer_state
/* Nonzero if first token on line is CPP_HASH. */ /* Nonzero if first token on line is CPP_HASH. */
unsigned char in_directive; 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. */ /* Nonzero if in a directive that takes angle-bracketed headers. */
unsigned char angled_headers; unsigned char angled_headers;
...@@ -459,24 +485,38 @@ struct lexer_state ...@@ -459,24 +485,38 @@ struct lexer_state
all directives apart from #define. */ all directives apart from #define. */
unsigned char save_comments; 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; unsigned char skip_newlines;
/* Nonzero if we're in the subroutine lex_line. */
unsigned char in_lex_line;
/* Nonzero if we're mid-comment. */ /* Nonzero if we're mid-comment. */
unsigned char lexing_comment; unsigned char lexing_comment;
/* Tells parse_number we saw a leading period. */ /* Nonzero if lexing __VA_ARGS__ is valid. */
unsigned char seen_dot; 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 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 struct cpp_reader
{ {
...@@ -486,70 +526,76 @@ struct cpp_reader ...@@ -486,70 +526,76 @@ struct cpp_reader
/* Lexer state. */ /* Lexer state. */
struct lexer_state 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; unsigned int errors;
/* Line and column where a newline was first seen in a string /* Line and column where a newline was first seen in a string
constant (multi-line strings). */ constant (multi-line strings). */
unsigned int mls_line; cpp_lexer_pos mlstring_pos;
unsigned int mls_column;
/* Buffer to hold macro definition string. */
unsigned char *macro_buffer;
unsigned int macro_buffer_len;
/* Current depth in #include directives that use <...>. */ /* Current depth in #include directives that use <...>. */
unsigned int system_include_depth; unsigned int system_include_depth;
/* Current depth of buffer stack. */ /* Current depth of buffer stack. */
unsigned int buffer_stack_depth; unsigned int buffer_stack_depth;
/* Current depth in #include directives. */ /* Current depth in #include directives. */
unsigned int include_depth; 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; 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; struct splay_tree_s *all_include_files;
/* Chain of `actual directory' file_name_list entries, /* Chain of `actual directory' file_name_list entries, for ""
for "" inclusion. */ inclusion. */
struct file_name_list *actual_dirs; struct file_name_list *actual_dirs;
/* Current maximum length of directory names in the search path /* Current maximum length of directory names in the search path
for include files. (Altered as we get more of them.) */ for include files. (Altered as we get more of them.) */
unsigned int max_include_len; 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. */ /* Date and time tokens. Calculated together if either is requested. */
cpp_token *date; cpp_token date;
cpp_token *time; 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;
/* Buffer of -M output. */ /* Buffer of -M output. */
struct deps *deps; struct deps *deps;
...@@ -572,17 +618,21 @@ struct cpp_reader ...@@ -572,17 +618,21 @@ struct cpp_reader
void (*leave_file) PARAMS ((cpp_reader *)); void (*leave_file) PARAMS ((cpp_reader *));
void (*rename_file) PARAMS ((cpp_reader *)); void (*rename_file) PARAMS ((cpp_reader *));
void (*include) PARAMS ((cpp_reader *, const unsigned char *, 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 (*define) PARAMS ((cpp_reader *, cpp_hashnode *));
void (*undef) PARAMS ((cpp_reader *, cpp_hashnode *)); void (*undef) PARAMS ((cpp_reader *, cpp_hashnode *));
void (*poison) PARAMS ((cpp_reader *)); 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 *)); void (*def_pragma) PARAMS ((cpp_reader *));
} cb; } cb;
/* User visible options. */ /* User visible options. */
struct cpp_options opts; 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 /* Nonzero means we have printed (while error reporting) a list of
containing files that matches the current status. */ containing files that matches the current status. */
unsigned char input_stack_listing_current; unsigned char input_stack_listing_current;
...@@ -596,28 +646,6 @@ struct cpp_reader ...@@ -596,28 +646,6 @@ struct cpp_reader
/* True if we are skipping a failed conditional group. */ /* True if we are skipping a failed conditional group. */
unsigned char skipping; 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 #define CPP_FATAL_LIMIT 1000
...@@ -633,28 +661,41 @@ struct cpp_printer ...@@ -633,28 +661,41 @@ struct cpp_printer
/* Name under which this program was invoked. */ /* Name under which this program was invoked. */
extern const char *progname; extern const char *progname;
/* The structure of a node in the hash table. The hash table /* The structure of a node in the hash table. The hash table has
has entries for all tokens defined by #define commands (type T_MACRO), entries for all identifiers: either macros defined by #define
plus some special tokens like __LINE__ (these each have their own commands (type NT_MACRO), assertions created with #assert
type, and the appropriate code is run when that type of node is seen. (NT_ASSERTION), or neither of the above (NT_VOID). Builtin macros
It does not contain control words like "#define", which are recognized like __LINE__ are flagged NODE_BUILTIN. Poisioned identifiers are
by a separate piece of code. */ flagged NODE_POISONED. NODE_OPERATOR (C++ only) indicates an
identifier that behaves like an operator such as "xor".
/* different flavors of hash nodes */ 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 enum node_type
{ {
T_VOID = 0, /* no definition yet */ NT_VOID = 0, /* No definition yet. */
T_SPECLINE, /* `__LINE__' */ NT_MACRO, /* A macro of some form. */
T_DATE, /* `__DATE__' */ NT_ASSERTION /* Predicate for #assert. */
T_FILE, /* `__FILE__' */ };
T_BASE_FILE, /* `__BASE_FILE__' */
T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ /* Different flavors of builtin macro. */
T_TIME, /* `__TIME__' */ enum builtin_type
T_STDC, /* `__STDC__' */ {
T_OPERATOR, /* operator with a name; val.code is token type */ BT_SPECLINE = 0, /* `__LINE__' */
T_POISON, /* poisoned identifier */ BT_DATE, /* `__DATE__' */
T_MACRO, /* a macro, either object-like or function-like */ BT_FILE, /* `__FILE__' */
T_ASSERTION /* predicate for #assert */ 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 /* There is a slot in the hashnode for use by front ends when integrated
...@@ -665,47 +706,56 @@ union tree_node; ...@@ -665,47 +706,56 @@ union tree_node;
struct cpp_hashnode struct cpp_hashnode
{ {
const unsigned char *name; /* null-terminated name */
unsigned int hash; /* cached hash value */ unsigned int hash; /* cached hash value */
unsigned short length; /* length of name */ unsigned short length; /* length of name excluding null */
ENUM_BITFIELD(node_type) type : 8; /* node type */ 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 union
{ {
const cpp_toklist *expansion; /* a macro's replacement list. */ cpp_macro *macro; /* a macro. */
struct answer *answers; /* answers to an assertion. */ 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; } value;
union tree_node *fe_value; /* front end 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 void cpp_init PARAMS ((void));
extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **)); extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **)); extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **));
extern void cpp_reader_init PARAMS ((cpp_reader *)); 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 *, extern void cpp_register_pragma PARAMS ((cpp_reader *,
const char *, const char *, const char *, const char *,
void (*) PARAMS ((cpp_reader *)))); void (*) PARAMS ((cpp_reader *))));
extern void cpp_register_pragma_space PARAMS ((cpp_reader *, const char *)); extern void cpp_register_pragma_space PARAMS ((cpp_reader *, const char *));
extern int cpp_start_read PARAMS ((cpp_reader *, cpp_printer *, const char *)); extern int cpp_start_read PARAMS ((cpp_reader *, const char *));
extern void cpp_output_tokens PARAMS ((cpp_reader *, cpp_printer *, extern void cpp_finish PARAMS ((cpp_reader *));
unsigned int));
extern void cpp_finish PARAMS ((cpp_reader *, cpp_printer *));
extern void cpp_cleanup PARAMS ((cpp_reader *)); extern void cpp_cleanup PARAMS ((cpp_reader *));
extern int cpp_avoid_paste PARAMS ((cpp_reader *, const cpp_token *,
extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *)); 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_define PARAMS ((cpp_reader *, const char *));
extern void cpp_assert 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_undef PARAMS ((cpp_reader *, const char *));
extern void cpp_unassert 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 *, extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
const unsigned char *, long)); const unsigned char *, long));
extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *)); 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 *, ...@@ -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_error_from_errno PARAMS ((cpp_reader *, const char *));
extern void cpp_notice_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 */ /* 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 *, extern int cpp_ideq PARAMS ((const cpp_token *,
const char *)); const char *));
extern void cpp_printf PARAMS ((cpp_reader *, cpp_printer *, extern void cpp_output_line PARAMS ((cpp_reader *, FILE *));
const char *, ...)); extern void cpp_output_token PARAMS ((const cpp_token *, FILE *));
extern const char *cpp_type2name PARAMS ((enum cpp_ttype));
extern void cpp_output_list PARAMS ((cpp_reader *, FILE *,
const cpp_toklist *,
const cpp_token *));
/* In cpphash.c */ /* In cpphash.c */
extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *, extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *,
const unsigned char *, size_t)); const unsigned char *, size_t));
extern void cpp_forall_identifiers PARAMS ((cpp_reader *, extern void cpp_forall_identifiers PARAMS ((cpp_reader *,
int (*) PARAMS ((cpp_reader *, int (*) PARAMS ((cpp_reader *,
cpp_hashnode *)))); cpp_hashnode *))));
/* In cppmacro.c */ /* In cppmacro.c */
extern void cpp_dump_definition PARAMS ((cpp_reader *, FILE *, extern void cpp_scan_buffer_nooutput PARAMS ((cpp_reader *));
const cpp_hashnode *)); extern void cpp_start_lookahead PARAMS ((cpp_reader *));
extern void cpp_stop_lookahead PARAMS ((cpp_reader *, int));
/* In cppfiles.c */ /* In cppfiles.c */
extern int cpp_included PARAMS ((cpp_reader *, const char *)); extern int cpp_included PARAMS ((cpp_reader *, const char *));
...@@ -773,6 +814,64 @@ extern int cpp_read_file 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 void cpp_make_system_header PARAMS ((cpp_reader *, cpp_buffer *, int));
extern const char *cpp_syshdr_flags PARAMS ((cpp_reader *, cpp_buffer *)); 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 #ifdef __cplusplus
} }
#endif #endif
......
/* 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, Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
1999, 2000 Free Software Foundation, Inc. 1999, 2000 Free Software Foundation, Inc.
Written by Per Bothner, 1994. Written by Per Bothner, 1994.
...@@ -25,573 +25,1521 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -25,573 +25,1521 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "config.h" #include "config.h"
#include "system.h" #include "system.h"
#include "intl.h" /* for _("<command line>") below. */
#include "cpplib.h" #include "cpplib.h"
#include "cpphash.h" #include "cpphash.h"
/* Stores basic information about a macro, before it is allocated. */ struct cpp_macro
struct macro_info
{ {
const cpp_token *first_param; /* First parameter token. */ cpp_hashnode **params; /* Parameters, if any. */
const cpp_token *first; /* First expansion token. */ cpp_token *expansion; /* First token of replacement list. */
unsigned int paramlen; /* Length of parameter names. */ const char *file; /* Defined in file name. */
unsigned int len; /* Length of token strings. */ unsigned int line; /* Starting line number. */
unsigned int ntokens; /* Number of tokens in expansion. */ unsigned int count; /* Number of tokens in expansion. */
short paramc; /* Number of parameters. */ unsigned short paramc; /* Number of parameters. */
unsigned char flags; 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 *)); /* Macro expansion. */
static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
static void lock_pools PARAMS ((cpp_reader *));
static int parse_define PARAMS((cpp_reader *, struct macro_info *)); static void unlock_pools PARAMS ((cpp_reader *));
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp, static int enter_macro_context PARAMS ((cpp_reader *, cpp_token *));
const cpp_toklist *)); static void builtin_macro PARAMS ((cpp_reader *, cpp_token *));
static const cpp_toklist * save_expansion PARAMS((cpp_reader *, static cpp_context *push_arg_context PARAMS ((cpp_reader *, macro_arg *));
struct macro_info *)); static enum cpp_ttype parse_arg PARAMS ((cpp_reader *, macro_arg *, int));
static unsigned int find_param PARAMS ((const cpp_token *, static macro_arg *parse_args PARAMS ((cpp_reader *, const cpp_hashnode *));
const cpp_token *)); static cpp_context *next_context PARAMS ((cpp_reader *));
static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *)); 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 *, static void check_trad_stringification PARAMS ((cpp_reader *,
const struct macro_info *, const cpp_macro *,
const cpp_string *)); const cpp_string *));
/* These are all the tokens that can have something pasted after them. /* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a
Comma is included in the list only to support the GNU varargs extension CPP_STRING token containing TEXT in quoted form. */
(where you write a ## b and a disappears if b is an empty rest argument). static void
CPP_OTHER is included because of Objective C's use of '@'. */ make_string_token (pool, token, text, len)
#define CAN_PASTE_AFTER(type) \ cpp_pool *pool;
((type) <= CPP_LAST_EQ || (type) == CPP_COLON || (type) == CPP_HASH \ cpp_token *token;
|| (type) == CPP_DEREF || (type) == CPP_DOT || (type) == CPP_NAME \ const U_CHAR *text;
|| (type) == CPP_INT || (type) == CPP_FLOAT || (type) == CPP_NUMBER \ unsigned int len;
|| (type) == CPP_MACRO_ARG || (type) == CPP_PLACEMARKER \ {
|| (type) == CPP_COMMA || (type) == CPP_OTHER) U_CHAR *buf = _cpp_pool_alloc (pool, len * 4);
/* Scans for a given token, returning the parameter number if found, token->type = CPP_STRING;
or 0 if not found. Scans from FIRST to TOKEN - 1 or the first token->val.str.text = buf;
CPP_CLOSE_PAREN for TOKEN. */ token->val.str.len = quote_string (buf, text, len) - buf;
static unsigned int token->flags = 0;
find_param (first, token) }
const cpp_token *first, *token;
{ /* Allocates and converts a temporary token to a CPP_NUMBER token,
unsigned int param = 0; evaluating to NUMBER. */
static void
for (; first < token && first->type != CPP_CLOSE_PAREN; first++) make_number_token (pfile, token, number)
if (first->type == CPP_NAME || first->type == CPP_DEFINED) 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++; const char *file;
if (first->val.node == token->val.node)
return param; 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 /* Used by cpperror.c to obtain the correct line and column to report
replacement list of a variable-arguments macro. TOKEN is assumed in a diagnostic. */
to be of type CPP_NAME. */ const cpp_lexer_pos *
static int cpp_get_line (pfile)
is__va_args__ (pfile, token)
cpp_reader *pfile; cpp_reader *pfile;
const cpp_token *token;
{ {
if (!CPP_PEDANTIC (pfile) /* Within a macro expansion, return the position of the outermost
|| token->val.node != pfile->spec_nodes->n__VA_ARGS__) invocation. */
return 0; if (pfile->context->prev)
return &pfile->macro_pos;
return &pfile->lexer_pos;
}
cpp_pedwarn_with_line (pfile, token->line, token->col, static void
"\"%s\" is only valid in the replacement list of a function-like macro", lock_pools (pfile)
token->val.node->name); cpp_reader *pfile;
return 1; {
_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 static void
null-terminated names, and whether the macro is a variable-argument unlock_pools (pfile)
one. FIRST is the token immediately after the open parenthesis, cpp_reader *pfile;
INFO stores the data. {
_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 static void
count_params (pfile, info) paste_payloads (pfile, lhs, rhs)
cpp_reader *pfile; cpp_reader *pfile;
struct macro_info *info; cpp_token *lhs;
const cpp_token *rhs;
{ {
unsigned int prev_ident = 0; unsigned int total_len = cpp_token_len (lhs) + cpp_token_len (rhs);
const cpp_token *token; 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; /* Paste the spellings and null terminate. */
info->paramlen = 0; end = cpp_spell_token (pfile, rhs, cpp_spell_token (pfile, lhs, result));
info->flags = 0; *end = '\0';
info->first = info->first_param; /* Not a ')' indicating success. */ 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: lhs->flags |= NAMED_OP;
cpp_error_with_line (pfile, token->line, token->col, lhs->type = lhs->val.node->value.operator;
"token may not appear in macro parameter list"); }
return; }
else
case CPP_EOF: {
missing_paren: lhs->val.str.text = result;
cpp_error_with_line (pfile, token->line, token->col, lhs->val.str.len = total_len;
"missing ')' in macro parameter list"); }
return; }
case CPP_COMMENT: /* Adds backslashes before all backslashes and double quotes appearing
continue; /* Ignore -C comments. */ 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 if (c == '\\' || c == '"')
parameter name. */ {
case CPP_NAME: *dest++ = '\\';
if (prev_ident) *dest++ = c;
}
else
{
if (ISPRINT (c))
*dest++ = c;
else
{ {
cpp_error_with_line (pfile, token->line, token->col, sprintf ((char *) dest, "\\%03o", c);
"macro parameters must be comma-separated"); dest += 4;
return;
} }
}
}
/* Constraint 6.10.3.5 */ return dest;
if (is__va_args__ (pfile, token)) }
return;
/* Constraint 6.10.3.6 - duplicate parameter names. */ /* Convert a token sequence to a single string token according to the
if (find_param (info->first, token)) rules of the ISO C #-operator. */
{ static void
cpp_error_with_line (pfile, token->line, token->col, stringify_arg (pfile, arg)
"duplicate macro parameter \"%s\"", cpp_reader *pfile;
token->val.node->name); macro_arg *arg;
return; {
} 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; /* Loop, reading in the argument's tokens. */
info->paramc++; for (i = 0; i < arg->count; i++)
info->paramlen += token->val.node->length + 1; {
continue; unsigned char *dest;
const cpp_token *token = &arg->first[i];
unsigned int len = cpp_token_len (token);
case CPP_CLOSE_PAREN: escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
if (prev_ident || info->paramc == 0) || token->type == CPP_CHAR || token->type == CPP_WCHAR
break; || token->type == CPP_OSTRING);
/* Fall through to pick up the error. */ if (escape_it)
case CPP_COMMA: /* Worst case is each char is octal. */
if (!prev_ident) len *= 4;
{ len++; /* Room for initial space. */
cpp_error_with_line (pfile, token->line, token->col,
"parameter name expected");
return;
}
prev_ident = 0;
continue;
case CPP_ELLIPSIS: dest = &start[total_len];
/* Convert ISO-style var_args to named varargs by changing if (dest + len > POOL_LIMIT (pool))
the ellipsis into an identifier with name __VA_ARGS__. {
This simplifies other handling. */ _cpp_next_chunk (pool, len, (unsigned char **) &start);
if (!prev_ident) dest = &start[total_len];
{ }
cpp_token *tok = (cpp_token *) token;
tok->type = CPP_NAME; prev_white |= token->flags & PREV_WHITE;
tok->val.node = pfile->spec_nodes->n__VA_ARGS__; if (token->type == CPP_PLACEMARKER)
continue;
info->paramc++; /* No leading white space. */
info->paramlen += tok->val.node->length + 1; if (prev_white)
{
prev_white = 0;
if (total_len > 0)
*dest++ = ' ';
}
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) if (escape_it)
cpp_pedwarn (pfile, {
"C89 does not permit anon varargs macros"); unsigned char *buf = (unsigned char *) xmalloc (len);
}
else 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)) /* Do nothing special about , ## <whatever> if
cpp_pedwarn (pfile, <whatever> came from a variable argument, because the
"ISO C does not permit named varargs parameters"); 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; lhs->type = type;
token++; lhs->flags &= ~DIGRAPH;
if (token->type == CPP_CLOSE_PAREN) if (digraph)
break; lhs->flags |= DIGRAPH;
goto missing_paren;
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. */ /* Empty arguments become a single placemarker token. */
info->first = token + 1; if (arg->count == 0)
if (!pfile->save_parameter_spellings) {
info->paramlen = 0; arg->first->type = CPP_PLACEMARKER;
return; 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 /* Parse the arguments making up a macro invocation. */
filled in appropriately. */ 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 static int
parse_define (pfile, info) enter_macro_context (pfile, token)
cpp_reader *pfile; cpp_reader *pfile;
struct macro_info *info; cpp_token *token;
{ {
const cpp_token *token; cpp_context *context;
int prev_white = 0; cpp_macro *macro;
unsigned char flags;
struct toklist list;
/* The first token after the macro's name. */ macro = token->val.node->value.macro;
token = _cpp_get_token (pfile); if (macro->disabled)
{
token->flags |= NO_EXPAND;
return 1;
}
/* Constraint 6.10.3.5 */ /* Save the position of the outermost macro invocation. */
if (is__va_args__ (pfile, token - 1)) if (!pfile->context->prev)
return 1; {
pfile->macro_pos = pfile->lexer_pos;
lock_pools (pfile);
}
while (token->type == CPP_COMMENT) if (macro->fun_like && !funlike_invocation_p (pfile, token->val.node, &list))
token++, prev_white = 1; {
prev_white |= token->flags & PREV_WHITE; 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. */ context->list.first = macro->expansion;
info->first_param = token + 1; context->list.limit = macro->expansion + macro->count;
count_params (pfile, info);
if (info->first[-1].type != CPP_CLOSE_PAREN)
return 1;
} }
else 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. */ result = xnew (cpp_context);
info->paramc = -1; prev->next = result;
info->paramlen = 0; result->prev = prev;
info->flags = 0; result->next = 0;
info->first = token;
if (!prev_white && token->type != CPP_EOF)
cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name");
} }
/* Count tokens in expansion. We drop paste tokens, and stringize pfile->context = result;
tokens, so don't count them. */ return result;
info->ntokens = info->len = 0; }
for (token = info->first; token->type != CPP_EOF; token++)
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 capacity *= 2;
function-like macros, but not at the ends. Constraint arg->expanded = (cpp_token *)
6.10.3.3.1 */ xrealloc (arg->expanded, capacity * sizeof (cpp_token));
if (token == info->first || token[1].type == CPP_EOF) }
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, _cpp_pop_context (pfile);
"'##' cannot appear at either end of a macro expansion"); continue;
return 1;
} }
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; continue;
} }
else if (token->type == CPP_HASH) else if (token->type == CPP_DHASH)
{ {
/* Stringifying #, but a normal character in object-like /* Handle directives. */
macros. Must come before a parameter name. Constraint if (_cpp_handle_directive (pfile, token->flags & PREV_WHITE))
6.10.3.2.1. */ continue;
if (info->paramc >= 0) /* This is in fact an assembler #. */
{ if (pfile->skipping)
if (token[1].type == CPP_NAME continue;
&& find_param (info->first_param, token + 1)) token->type = CPP_HASH;
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;
}
}
} }
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 */ la->cap += la->cap + 8;
if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token)) la->tokens = (cpp_token_with_pos *)
return 1; xrealloc (la->tokens, la->cap * sizeof (cpp_token_with_pos));
} }
info->ntokens++;
if (TOKEN_SPELL (token) == SPELL_STRING) twp = &la->tokens[la->count++];
info->len += token->val.str.len; twp->token = *token;
twp->pos = *cpp_get_line (pfile);
} }
return 0;
} }
/* Returns non-zero if a macro redefinition is trivial. */ static void
static int take_lookahead_token (pfile, token)
check_macro_redefinition (pfile, hp, list2)
cpp_reader *pfile; cpp_reader *pfile;
cpp_hashnode *hp; cpp_token *token;
const cpp_toklist *list2;
{ {
const cpp_toklist *list1; cpp_lookahead *la = pfile->la_read;
cpp_token_with_pos *twp = &la->tokens[la->cur];
if (hp->type != T_MACRO) *token = twp->token;
return ! pfile->done_initializing; pfile->lexer_pos = twp->pos;
/* Clear the whitespace and BOL flags of the first tokens. They get if (++la->cur == la->count)
altered during macro expansion, but is not significant here. */ release_lookahead (pfile);
list1 = hp->value.expansion; }
list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
if (!_cpp_equiv_toklists (list1, list2)) /* Moves the lookahead at the front of the read list to the free store. */
return 0; static void
release_lookahead (pfile)
cpp_reader *pfile;
{
cpp_lookahead *la = pfile->la_read;
if (CPP_OPTION (pfile, pedantic) pfile->la_read = la->next;
&& list1->paramc > 0 la->next = pfile->la_unused;
&& (list1->params_len != list2->params_len pfile->la_unused = la;
|| memcmp (list1->namebuf, list2->namebuf, list1->params_len))) unlock_pools (pfile);
return 0; }
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 /* Free memory associated with a lookahead list. */
correct. */ static void
struct toklist_dummy free_lookahead (la)
cpp_lookahead *la;
{ {
cpp_toklist list; if (la->tokens)
cpp_token first_token; free ((PTR) la->tokens);
}; free ((PTR) la);
}
/* Allocate space to hold the token list, its tokens, their text, and /* Free all the lookaheads of a cpp_reader. */
the parameter names if needed. Empty expansions are stored as a void
single placemarker token. _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 /* Allocate a lookahead and move it to the front of the write list. */
reasons. Therefore, this token list cannot be expanded like a void
normal token list. Try to do so, and you lose. */ cpp_start_lookahead (pfile)
static cpp_toklist *
alloc_macro (pfile, info)
cpp_reader *pfile; cpp_reader *pfile;
struct macro_info *info;
{ {
unsigned int size; cpp_lookahead *la = alloc_lookahead (pfile);
struct toklist_dummy *dummy;
cpp_toklist *list;
/* Empty macros become a single placemarker token. */ la->next = pfile->la_write;
if (info->ntokens == 0) pfile->la_write = la;
info->ntokens = 1;
size = sizeof (struct toklist_dummy); la->pos = *cpp_get_line (pfile);
size += (info->ntokens - 1) * sizeof(cpp_token);
size += info->len + info->paramlen;
dummy = (struct toklist_dummy *) xmalloc (size); /* Don't allow memory pools to be re-used whilst we're reading ahead. */
list = (cpp_toklist *) dummy; lock_pools (pfile);
}
/* Initialize the monster. */
list->tokens = &dummy->first_token;
list->tokens_used = list->tokens_cap = info->ntokens;
list->namebuf = (unsigned char *) &list->tokens[info->ntokens]; /* Stop reading ahead - either step back, or drop the read ahead. */
list->name_used = list->name_cap = info->len + info->paramlen; void
cpp_stop_lookahead (pfile, drop)
cpp_reader *pfile;
int drop;
{
cpp_lookahead *la = pfile->la_write;
list->directive = 0; pfile->la_write = la->next;
list->line = pfile->token_list.line; la->next = pfile->la_read;
list->file = pfile->token_list.file; pfile->la_read = la;
list->params_len = info->paramlen;
list->paramc = info->paramc;
list->flags = info->flags;
return list; if (drop || la->count == 0)
release_lookahead (pfile);
else
pfile->lexer_pos = la->pos;
} }
/* Free the definition of macro H. */ /* Push a single token back to the front of the queue. Only to be
used by cpplib, and only then when necessary. POS is the position
to report for the preceding token. */
void
_cpp_push_token (pfile, token, pos)
cpp_reader *pfile;
const cpp_token *token;
const cpp_lexer_pos *pos;
{
cpp_start_lookahead (pfile);
save_lookahead_token (pfile, token);
cpp_stop_lookahead (pfile, 0);
pfile->lexer_pos = *pos;
}
/* #define directive parsing and handling. */
/* Returns non-zero if a macro redefinition is trivial. */
static int
check_macro_redefinition (pfile, node, macro2)
cpp_reader *pfile;
const cpp_hashnode *node;
const cpp_macro *macro2;
{
const cpp_macro *macro1;
unsigned int i;
if (node->type != NT_MACRO || node->flags & NODE_BUILTIN)
return ! pfile->done_initializing;
macro1 = node->value.macro;
/* The quick failures. */
if (macro1->count != macro2->count
|| macro1->paramc != macro2->paramc
|| macro1->fun_like != macro2->fun_like
|| macro1->var_args != macro2->var_args)
return 0;
/* Check each token. */
for (i = 0; i < macro1->count; i++)
if (! _cpp_equiv_tokens (&macro1->expansion[i], &macro2->expansion[i]))
return 0;
/* Check parameter spellings. */
for (i = 0; i < macro1->paramc; i++)
if (macro1->params[i] != macro2->params[i])
return 0;
return 1;
}
/* Free the definition of hashnode H. */
void void
_cpp_free_definition (h) _cpp_free_definition (h)
cpp_hashnode *h; cpp_hashnode *h;
{ {
if (h->type == T_MACRO) /* Macros and assertions no longer have anything to free. */
free ((PTR) h->value.expansion); h->type = NT_VOID;
else if (h->type == T_ASSERTION) /* 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) dest = &macro->params[macro->paramc];
{
next = temp->next; /* Check we have room for the parameters. */
FREE_ANSWER (temp); if ((unsigned char *) (dest + 1) >= POOL_LIMIT (&pfile->macro_pool))
} {
_cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_hashnode *),
(unsigned char **) &macro->params);
dest = &macro->params[macro->paramc];
} }
h->type = T_VOID; *dest = node;
h->value.expansion = NULL; node->arg_index = ++macro->paramc;
return 0;
} }
/* Copy the tokens of the expansion, beginning with info->first until static int
CPP_EOF. INFO contains information about the macro. parse_params (pfile, 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)
cpp_reader *pfile; cpp_reader *pfile;
struct macro_info *info; cpp_macro *macro;
{ {
const cpp_token *token; cpp_token token;
cpp_toklist *list; unsigned int prev_ident = 0;
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;
}
dest = list->tokens; macro->params = (cpp_hashnode **) POOL_FRONT (&pfile->macro_pool);
for (token = info->first; token->type != CPP_EOF; token++) 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: case CPP_NAME:
if (list->paramc == -1) if (prev_ident)
break; {
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. */ case CPP_CLOSE_PAREN:
param_no = find_param (info->first_param, token); if (prev_ident || macro->paramc == 0)
if (param_no == 0)
break; break;
dest->val.aux = param_no - 1;
dest->type = CPP_MACRO_ARG; /* Fall through to pick up the error. */
if (token[-1].type == CPP_HASH) case CPP_COMMA:
dest->flags = token[-1].flags | STRINGIFY_ARG; if (!prev_ident)
else {
dest->flags = token->flags; /* Particularly PREV_WHITE. */ cpp_error (pfile, "parameter name missing");
/* Turn off PREV_WHITE if we immediately follow a paste. return 0;
That way, even if the paste turns out to be invalid, there }
will be no space between the two tokens in the output. */ prev_ident = 0;
if (token[-1].type == CPP_PASTE)
dest->flags &= ~PREV_WHITE;
dest++;
continue; continue;
case CPP_PASTE: case CPP_ELLIPSIS:
/* Set the paste flag on the token to our left, unless there macro->var_args = 1;
is no possible token to which it might be pasted. That if (!prev_ident)
is critical for correct operation under some circumstances; {
see gcc.dg/cpp/paste6.c. */ save_parameter (pfile, macro, pfile->spec_nodes.n__VA_ARGS__);
if (CAN_PASTE_AFTER (dest[-1].type) || (dest[-1].flags & NAMED_OP)) pfile->state.va_args_ok = 1;
dest[-1].flags |= PASTE_LEFT; if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic))
else if (CPP_OPTION (pfile, warn_paste)) cpp_pedwarn (pfile,
cpp_warning_with_line (pfile, dest[-1].line, dest[-1].col, "C89 does not permit anonymous variable arguments");
"nothing can be pasted after this token"); }
continue; else if (CPP_OPTION (pfile, pedantic))
cpp_pedwarn (pfile,
"ISO C does not permit named variable arguments");
case CPP_HASH: /* We're at the end, and just expect a closing parenthesis. */
/* Stringifying #. Constraint 6.10.3.2.1 */ _cpp_lex_token (pfile, &token);
if (list->paramc >= 0 && token[1].type == CPP_NAME if (token.type == CPP_CLOSE_PAREN)
&& find_param (info->first_param, token + 1)) break;
continue; /* Fall through. */
break;
case CPP_STRING: case CPP_EOF:
case CPP_CHAR: cpp_error (pfile, "missing ')' in macro parameter list");
if (CPP_WTRADITIONAL (pfile) && list->paramc > 0) return 0;
check_trad_stringification (pfile, info, &token->val.str);
break;
default:
break;
} }
/* Copy the token. */ /* Success. Commit the parameter array. */
*dest = *token; POOL_COMMIT (&pfile->macro_pool,
if (TOKEN_SPELL (token) == SPELL_STRING) macro->paramc * sizeof (cpp_hashnode *));
{ return 1;
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++;
} }
}
/* Lex a token from a macro's replacement list. Translate it to a
CPP_MACRO_ARG if appropriate. */
static cpp_token *
lex_expansion_token (pfile, macro)
cpp_reader *pfile;
cpp_macro *macro;
{
cpp_token *token = &macro->expansion[macro->count];
/* Empty macros become a single placemarker token. */ /* Check we have room for the token. */
if (dest == list->tokens) if ((unsigned char *) (token + 1) >= POOL_LIMIT (&pfile->macro_pool))
{ {
dest->type = CPP_PLACEMARKER; _cpp_next_chunk (&pfile->macro_pool, sizeof (cpp_token),
dest->flags = 0; (unsigned char **) &macro->expansion);
dest->val.aux = 0; token = &macro->expansion[macro->count];
} }
return list; macro->count++;
_cpp_lex_token (pfile, token);
/* Is this an argument? */
if (token->type == CPP_NAME && token->val.node->arg_index)
{
token->type = CPP_MACRO_ARG;
token->val.aux = token->val.node->arg_index;
}
else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0
&& (token->type == CPP_STRING || token->type == CPP_CHAR))
check_trad_stringification (pfile, macro, &token->val.str);
return token;
} }
/* Parse a macro and save its expansion. Returns non-zero on success. */ /* Parse a macro and save its expansion. Returns non-zero on success. */
int int
_cpp_create_definition (pfile, hp) _cpp_create_definition (pfile, node)
cpp_reader *pfile; cpp_reader *pfile;
cpp_hashnode *hp; cpp_hashnode *node;
{ {
struct macro_info info; cpp_macro *macro;
const cpp_toklist *list; 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)) /* Setting it here means we don't catch leading comments. */
return 0; pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
list = save_expansion (pfile, &info);
/* Check for a redefinition. Redefinition of a macro is allowed if for (;;)
and only if the old and new definitions are the same. {
(6.10.3 paragraph 2). */ /* 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); cpp_pedwarn_with_line (pfile, pfile->directive_pos.line,
if (pfile->done_initializing && hp->type == T_MACRO) 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, cpp_pedwarn_with_file_and_line (pfile,
hp->value.expansion->file, node->value.macro->file,
hp->value.expansion->line, 1, node->value.macro->line, 1,
"this is the location of the previous definition"); "this is the location of the previous definition");
} }
_cpp_free_definition (hp); _cpp_free_definition (node);
} }
/* Enter definition in hash table. */ /* Enter definition in hash table. */
hp->type = T_MACRO; node->type = NT_MACRO;
hp->value.expansion = list; 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 /* Warn if a token in `string' matches one of the function macro
arguments in `info'. This function assumes that the macro is a arguments in `info'. This function assumes that the macro is a
function macro and not an object macro. */ function macro and not an object macro. */
static void static void
check_trad_stringification (pfile, info, string) check_trad_stringification (pfile, macro, string)
cpp_reader *pfile; cpp_reader *pfile;
const struct macro_info *info; const cpp_macro *macro;
const cpp_string *string; const cpp_string *string;
{ {
unsigned int i, len;
const U_CHAR *p, *q, *limit = string->text + string->len; const U_CHAR *p, *q, *limit = string->text + string->len;
/* Loop over the string. */ /* Loop over the string. */
for (p = string->text; p < limit; p = q) for (p = string->text; p < limit; p = q)
{ {
const cpp_token *token;
/* Find the start of an identifier. */ /* Find the start of an identifier. */
while (p < limit && !is_idstart (*p)) while (p < limit && !is_idstart (*p))
p++; p++;
...@@ -600,23 +1548,130 @@ check_trad_stringification (pfile, info, string) ...@@ -600,23 +1548,130 @@ check_trad_stringification (pfile, info, string)
q = p; q = p;
while (q < limit && is_idchar (*q)) while (q < limit && is_idchar (*q))
q++; q++;
len = q - p;
/* Loop over the function macro arguments to see if the /* Loop over the function macro arguments to see if the
identifier inside the string matches one of them. */ identifier inside the string matches one of them. */
for (token = info->first_param; token < info->first; token++) for (i = 0; i < macro->paramc; i++)
{ {
/* Skip the commas in between the arguments. */ const cpp_hashnode *node = macro->params[i];
if (token->type != CPP_NAME)
continue;
if (token->val.node->length == (q - p) if (node->length == len && !memcmp (p, node->name, len))
&& !memcmp (p, token->val.node->name, (q - p)))
{ {
cpp_warning (pfile, cpp_warning (pfile,
"macro arg \"%.*s\" would be stringified with -traditional.", "macro argument \"%s\" would be stringified with -traditional.",
(int) (q - p), p); node->name);
break; break;
} }
} }
} }
} }
/* Returns the expansion of a macro, in a format suitable to be read
back in again, and therefore also for DWARF 2 debugging info.
Caller is expected to generate the "#define NAME" bit. The
returned text is temporary, and automatically freed later. */
const unsigned char *
cpp_macro_definition (pfile, node)
cpp_reader *pfile;
const cpp_hashnode *node;
{
unsigned int i, len;
const cpp_macro *macro = node->value.macro;
unsigned char *buffer;
if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
{
cpp_ice (pfile, "invalid hash type %d in dump_definition", node->type);
return 0;
}
/* Calculate length. */
len = 1; /* ' ' */
if (macro->fun_like)
{
len += 3; /* "()" plus possible final "." of ellipsis. */
for (i = 0; i < macro->paramc; i++)
len += macro->params[i]->length + 2; /* ", " */
}
if (macro->count > 1 || macro->expansion[0].type != CPP_PLACEMARKER)
{
for (i = 0; i < macro->count; i++)
{
cpp_token *token = &macro->expansion[i];
if (token->type == CPP_MACRO_ARG)
len += macro->params[token->val.aux - 1]->length;
else
len += cpp_token_len (token); /* Includes room for ' '. */
if (token->flags & STRINGIFY_ARG)
len++; /* "#" */
if (token->flags & PASTE_LEFT)
len += 3; /* " ##" */
}
}
if (len > pfile->macro_buffer_len)
pfile->macro_buffer = (U_CHAR *) xrealloc (pfile->macro_buffer, len);
buffer = pfile->macro_buffer;
/* Parameter names. */
if (macro->fun_like)
{
*buffer++ = '(';
for (i = 0; i < macro->paramc; i++)
{
cpp_hashnode *param = macro->params[i];
if (param != pfile->spec_nodes.n__VA_ARGS__)
{
memcpy (buffer, param->name, param->length);
buffer += param->length;
}
if (i + 1 < macro->paramc)
*buffer++ = ',', *buffer++ = ' ';
else if (macro->var_args)
*buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
}
*buffer++ = ')';
}
/* Expansion tokens. */
if (macro->count > 1 || macro->expansion[0].type != CPP_PLACEMARKER)
{
*buffer++ = ' ';
for (i = 0; i < macro->count; i++)
{
cpp_token *token = &macro->expansion[i];
if (token->flags & PREV_WHITE)
*buffer++ = ' ';
if (token->flags & STRINGIFY_ARG)
*buffer++ = '#';
if (token->type == CPP_MACRO_ARG)
{
len = macro->params[token->val.aux - 1]->length;
memcpy (buffer, macro->params[token->val.aux - 1]->name, len);
buffer += len;
}
else
buffer = cpp_spell_token (pfile, token, buffer);
if (token->flags & PASTE_LEFT)
{
*buffer++ = ' ';
*buffer++ = '#';
*buffer++ = '#';
/* Next has PREV_WHITE; see _cpp_create_definition. */
}
}
}
*buffer = '\0';
return pfile->macro_buffer;
}
...@@ -25,29 +25,45 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -25,29 +25,45 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "cpplib.h" #include "cpplib.h"
#include "intl.h" #include "intl.h"
const char *progname; /* Encapsulates state used to convert the stream of tokens coming from
cpp_get_token back into a text file. */
cpp_reader parse_in; struct printer
cpp_printer parse_out; {
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 **)); 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 /* Callback routines for the parser. Most of these are active only
in specific modes. */ in specific modes. */
static void cb_define PARAMS ((cpp_reader *, cpp_hashnode *)); static void cb_define PARAMS ((cpp_reader *, cpp_hashnode *));
static void cb_undef PARAMS ((cpp_reader *, cpp_hashnode *)); static void cb_undef PARAMS ((cpp_reader *, cpp_hashnode *));
static void cb_include PARAMS ((cpp_reader *, const unsigned char *, static void cb_include PARAMS ((cpp_reader *, const unsigned char *,
const unsigned char *, unsigned int, int)); const cpp_token *));
static void cb_ident PARAMS ((cpp_reader *, const cpp_string *));
static void cb_ident PARAMS ((cpp_reader *, const unsigned char *,
unsigned int));
static void cb_enter_file PARAMS ((cpp_reader *)); static void cb_enter_file PARAMS ((cpp_reader *));
static void cb_leave_file PARAMS ((cpp_reader *)); static void cb_leave_file PARAMS ((cpp_reader *));
static void cb_rename_file PARAMS ((cpp_reader *)); static void cb_rename_file PARAMS ((cpp_reader *));
static void cb_def_pragma PARAMS ((cpp_reader *)); static void cb_def_pragma PARAMS ((cpp_reader *));
static void do_pragma_implementation 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 int
main (argc, argv) main (argc, argv)
...@@ -56,7 +72,6 @@ main (argc, argv) ...@@ -56,7 +72,6 @@ main (argc, argv)
{ {
char *p; char *p;
cpp_reader *pfile = &parse_in; cpp_reader *pfile = &parse_in;
cpp_printer *print;
int argi = 1; /* Next argument to handle. */ int argi = 1; /* Next argument to handle. */
p = argv[0] + strlen (argv[0]); p = argv[0] + strlen (argv[0]);
...@@ -83,8 +98,7 @@ main (argc, argv) ...@@ -83,8 +98,7 @@ main (argc, argv)
/* Open the output now. We must do so even if no_output is on, /* Open the output now. We must do so even if no_output is on,
because there may be other output than from the actual because there may be other output than from the actual
preprocessing (e.g. from -dM). */ preprocessing (e.g. from -dM). */
print = cpp_printer_init (pfile, &parse_out); if (printer_init (pfile))
if (! print)
return (FATAL_EXIT_CODE); return (FATAL_EXIT_CODE);
/* Set callbacks. */ /* Set callbacks. */
...@@ -116,134 +130,260 @@ main (argc, argv) ...@@ -116,134 +130,260 @@ main (argc, argv)
cpp_register_pragma(pfile, 0, "implementation", do_pragma_implementation); cpp_register_pragma(pfile, 0, "implementation", do_pragma_implementation);
cpp_register_pragma(pfile, "GCC", "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); return (FATAL_EXIT_CODE);
if (CPP_OPTION (pfile, no_output)) if (CPP_BUFFER (pfile))
while (CPP_BUFFER (pfile) != NULL) {
cpp_scan_buffer_nooutput (pfile); if (CPP_OPTION (pfile, no_output))
else cpp_scan_buffer_nooutput (pfile);
while (CPP_BUFFER (pfile) != NULL) else
cpp_scan_buffer (pfile, print); scan_buffer (pfile);
}
/* -dM command line option. */
if (CPP_OPTION (pfile, dump_macros) == dump_only) if (CPP_OPTION (pfile, dump_macros) == dump_only)
cpp_forall_identifiers (pfile, dump_macros_helper); cpp_forall_identifiers (pfile, dump_macro);
cpp_finish (pfile, print); cpp_finish (pfile);
cpp_cleanup (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) if (parse_in.errors)
return (FATAL_EXIT_CODE); return (FATAL_EXIT_CODE);
return (SUCCESS_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 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; cpp_reader *pfile;
const unsigned char *str; unsigned int line;
unsigned int len; 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); maybe_print_line (cpp_get_line (pfile)->output_line);
parse_out.lineno++; fprintf (print.outf, "#ident \"%.*s\"\n", (int) str->len, str->text);
print.lineno++;
} }
static void static void
cb_define (pfile, hash) cb_define (pfile, node)
cpp_reader *pfile; cpp_reader *pfile;
cpp_hashnode *hash; cpp_hashnode *node;
{ {
if (pfile->done_initializing) 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) if (CPP_OPTION (pfile, debug_output)
|| CPP_OPTION (pfile, dump_macros) == dump_definitions) || CPP_OPTION (pfile, dump_macros) == dump_definitions)
cpp_dump_definition (pfile, parse_out.outf, hash); fputs ((const char *) cpp_macro_definition (pfile, node), print.outf);
putc ('\n', parse_out.outf);
parse_out.lineno++; putc ('\n', print.outf);
print.lineno++;
} }
} }
static void static void
cb_undef (pfile, hash) cb_undef (pfile, node)
cpp_reader *pfile; cpp_reader *pfile;
cpp_hashnode *hash; cpp_hashnode *node;
{ {
if (pfile->done_initializing) if (pfile->done_initializing)
{ {
cpp_printf (pfile, &parse_out, "#undef %s\n", hash->name); maybe_print_line (cpp_get_line (pfile)->output_line);
parse_out.lineno++; fprintf (print.outf, "#undef %s\n", node->name);
print.lineno++;
} }
} }
static void static void
cb_include (pfile, dir, str, len, ab) cb_include (pfile, dir, header)
cpp_reader *pfile; cpp_reader *pfile ATTRIBUTE_UNUSED;
const unsigned char *dir; const unsigned char *dir;
const unsigned char *str; const cpp_token *header;
unsigned int len;
int ab;
{ {
int l, r; maybe_print_line (cpp_get_line (pfile)->output_line);
if (ab) fprintf (print.outf, "#%s %s\n", dir, cpp_token_as_text (pfile, header));
l = '<', r = '>'; print.lineno++;
else
l = '"', r = '"';
cpp_printf (pfile, &parse_out, "#%s %c%.*s%c\n", dir, l, (int) len, str, r);
parse_out.lineno++;
} }
static void static void
cb_enter_file (pfile) cb_enter_file (pfile)
cpp_reader *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, move_printer (pfile, 1, pfile->done_initializing ? " 1": "");
pfile->done_initializing ? " 1" : "",
cpp_syshdr_flags (pfile, ip));
parse_out.lineno = 1;
parse_out.last_fname = ip->nominal_fname;
} }
static void static void
cb_leave_file (pfile) cb_leave_file (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_buffer *ip = CPP_BUFFER (pfile); move_printer (pfile, pfile->buffer->lineno + 1, " 2");
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;
} }
static void static void
cb_rename_file (pfile) cb_rename_file (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_buffer *ip = CPP_BUFFER (pfile); move_printer (pfile, pfile->buffer->lineno + 1, "");
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;
} }
static void static void
cb_def_pragma (pfile) cb_def_pragma (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_printf (pfile, &parse_out, "#pragma "); maybe_print_line (cpp_get_line (pfile)->output_line);
cpp_output_list (pfile, parse_out.outf, &pfile->token_list, fputs ("#pragma ", print.outf);
pfile->first_directive_token + 2); cpp_output_line (pfile, print.outf);
putc ('\n', parse_out.outf); print.lineno++;
parse_out.lineno++;
} }
static void static void
...@@ -252,47 +392,54 @@ do_pragma_implementation (pfile) ...@@ -252,47 +392,54 @@ do_pragma_implementation (pfile)
{ {
/* Be quiet about `#pragma implementation' for a file only if it hasn't /* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */ been included yet. */
const cpp_token *tok = cpp_get_token (pfile); cpp_token token;
char *copy;
if (tok->type != CPP_EOF) cpp_start_lookahead (pfile);
{ cpp_get_token (pfile, &token);
if (tok->type != CPP_STRING || cpp_get_token (pfile)->type != CPP_EOF) cpp_stop_lookahead (pfile, 0);
{
cpp_error (pfile, "malformed #pragma implementation");
return;
}
/* Make a NUL-terminated copy of the string. */ /* If it's not a string, pass it through and let the front end complain. */
copy = alloca (tok->val.str.len + 1); if (token.type == CPP_STRING)
memcpy (copy, tok->val.str.text, tok->val.str.len); {
copy[tok->val.str.len] = '\0'; /* Make a NUL-terminated copy of the string. */
char *filename = alloca (token.val.str.len + 1);
if (cpp_included (pfile, copy)) memcpy (filename, token.val.str.text, token.val.str.len);
filename[token.val.str.len] = '\0';
if (cpp_included (pfile, filename))
cpp_warning (pfile, cpp_warning (pfile,
"#pragma implementation for %s appears after file is included", "#pragma GCC implementation for \"%s\" appears after file is included",
copy); 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) 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. */ /* Dump out the hash table. */
static int static int
dump_macros_helper (pfile, hp) dump_macro (pfile, node)
cpp_reader *pfile; 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); fprintf (print.outf, "#define %s", node->name);
cpp_dump_definition (pfile, parse_out.outf, hp); fputs ((const char *) cpp_macro_definition (pfile, node), print.outf);
putc ('\n', parse_out.outf); putc ('\n', print.outf);
parse_out.lineno++; print.lineno++;
} }
return 1; return 1;
} }
/* 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);
}
...@@ -517,8 +517,9 @@ recognized_extern (name) ...@@ -517,8 +517,9 @@ recognized_extern (name)
'f' for other function declarations. */ 'f' for other function declarations. */
void void
recognized_function (fname, kind, have_arg_list, file_seen) recognized_function (fname, line, kind, have_arg_list, file_seen)
const cpp_token *fname; const cpp_token *fname;
unsigned int line;
int kind; /* One of 'f' 'F' or 'I' */ int kind; /* One of 'f' 'F' or 'I' */
int have_arg_list; int have_arg_list;
const char *file_seen; const char *file_seen;
...@@ -566,7 +567,7 @@ recognized_function (fname, kind, have_arg_list, file_seen) ...@@ -566,7 +567,7 @@ recognized_function (fname, kind, have_arg_list, file_seen)
partial_count++; partial_count++;
partial = (struct partial_proto *) partial = (struct partial_proto *)
obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto)); obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
partial->line_seen = fname->line; partial->line_seen = line;
partial->fn = fn; partial->fn = fn;
fn->partial = partial; fn->partial = partial;
partial->next = partial_proto_list; partial->next = partial_proto_list;
...@@ -622,7 +623,7 @@ read_scan_file (in_fname, argc, argv) ...@@ -622,7 +623,7 @@ read_scan_file (in_fname, argc, argv)
if (CPP_FATAL_ERRORS (&scan_in)) if (CPP_FATAL_ERRORS (&scan_in))
exit (FATAL_EXIT_CODE); 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); exit (FATAL_EXIT_CODE);
/* We are scanning a system header, so mark it as such. */ /* We are scanning a system header, so mark it as such. */
...@@ -647,15 +648,16 @@ read_scan_file (in_fname, argc, argv) ...@@ -647,15 +648,16 @@ read_scan_file (in_fname, argc, argv)
/* Scan the macro expansion of "getchar();". */ /* Scan the macro expansion of "getchar();". */
for (;;) 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); cpp_pop_buffer (&scan_in);
if (CPP_BUFFER (&scan_in) == buf) if (CPP_BUFFER (&scan_in) == buf)
break; break;
} }
else if (cpp_ideq (t, "_filbuf")) else if (cpp_ideq (&t, "_filbuf"))
seen_filbuf++; seen_filbuf++;
} }
if (seen_filbuf) if (seen_filbuf)
......
...@@ -582,7 +582,6 @@ cpplex.c ...@@ -582,7 +582,6 @@ cpplex.c
cpplib.c cpplib.c
cpplib.h cpplib.h
cppmain.c cppmain.c
cppoutput.c
cppspec.c cppspec.c
#crtstuff.c is part of the GCC library #crtstuff.c is part of the GCC library
cse.c cse.c
......
...@@ -45,7 +45,11 @@ skip_to_closing_brace (pfile) ...@@ -45,7 +45,11 @@ skip_to_closing_brace (pfile)
int nesting = 1; int nesting = 1;
for (;;) 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) if (token == CPP_EOF)
break; break;
if (token == CPP_OPEN_BRACE) if (token == CPP_OPEN_BRACE)
...@@ -84,17 +88,16 @@ scan_decls (pfile, argc, argv) ...@@ -84,17 +88,16 @@ scan_decls (pfile, argc, argv)
char **argv ATTRIBUTE_UNUSED; char **argv ATTRIBUTE_UNUSED;
{ {
int saw_extern, saw_inline; int saw_extern, saw_inline;
const cpp_token *prev_id; cpp_token token, prev_id;
const cpp_token *token;
new_statement: new_statement:
token = cpp_get_token (pfile); cpp_get_token (pfile, &token);
handle_statement: handle_statement:
current_extern_C = 0; current_extern_C = 0;
saw_extern = 0; saw_extern = 0;
saw_inline = 0; saw_inline = 0;
if (token->type == CPP_OPEN_BRACE) if (token.type == CPP_OPEN_BRACE)
{ {
/* Pop an 'extern "C"' nesting level, if appropriate. */ /* Pop an 'extern "C"' nesting level, if appropriate. */
if (extern_C_braces_length if (extern_C_braces_length
...@@ -103,12 +106,12 @@ scan_decls (pfile, argc, argv) ...@@ -103,12 +106,12 @@ scan_decls (pfile, argc, argv)
brace_nesting--; brace_nesting--;
goto new_statement; goto new_statement;
} }
if (token->type == CPP_OPEN_BRACE) if (token.type == CPP_OPEN_BRACE)
{ {
brace_nesting++; brace_nesting++;
goto new_statement; goto new_statement;
} }
if (token->type == CPP_EOF) if (token.type == CPP_EOF)
{ {
cpp_pop_buffer (pfile); cpp_pop_buffer (pfile);
if (CPP_BUFFER (pfile) == NULL) if (CPP_BUFFER (pfile) == NULL)
...@@ -116,15 +119,15 @@ scan_decls (pfile, argc, argv) ...@@ -116,15 +119,15 @@ scan_decls (pfile, argc, argv)
goto new_statement; goto new_statement;
} }
if (token->type == CPP_SEMICOLON) if (token.type == CPP_SEMICOLON)
goto new_statement; goto new_statement;
if (token->type != CPP_NAME) if (token.type != CPP_NAME)
goto new_statement; goto new_statement;
prev_id = 0; prev_id.type = CPP_EOF;
for (;;) for (;;)
{ {
switch (token->type) switch (token.type)
{ {
default: default:
goto handle_statement; goto handle_statement;
...@@ -136,11 +139,11 @@ scan_decls (pfile, argc, argv) ...@@ -136,11 +139,11 @@ scan_decls (pfile, argc, argv)
case CPP_COMMA: case CPP_COMMA:
case CPP_SEMICOLON: 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; break;
/* ... fall through ... */ /* ... fall through ... */
case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE: case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE:
...@@ -154,60 +157,61 @@ scan_decls (pfile, argc, argv) ...@@ -154,60 +157,61 @@ scan_decls (pfile, argc, argv)
case CPP_OPEN_PAREN: case CPP_OPEN_PAREN:
/* Looks like this is the start of a formal parameter list. */ /* Looks like this is the start of a formal parameter list. */
if (prev_id) if (prev_id.type != CPP_EOF)
{ {
int nesting = 1; int nesting = 1;
int have_arg_list = 0; int have_arg_list = 0;
for (;;) for (;;)
{ {
token = cpp_get_token (pfile); cpp_get_token (pfile, &token);
if (token->type == CPP_OPEN_PAREN) if (token.type == CPP_OPEN_PAREN)
nesting++; nesting++;
else if (token->type == CPP_CLOSE_PAREN) else if (token.type == CPP_CLOSE_PAREN)
{ {
nesting--; nesting--;
if (nesting == 0) if (nesting == 0)
break; break;
} }
else if (token->type == CPP_EOF) else if (token.type == CPP_EOF)
break; break;
else if (token->type == CPP_NAME else if (token.type == CPP_NAME
|| token->type == CPP_ELLIPSIS) || token.type == CPP_ELLIPSIS)
have_arg_list = 1; have_arg_list = 1;
} }
recognized_function (prev_id, recognized_function (&prev_id,
cpp_get_line (pfile)->line,
(saw_inline ? 'I' (saw_inline ? 'I'
: in_extern_C_brace || current_extern_C : in_extern_C_brace || current_extern_C
? 'F' : 'f'), have_arg_list, ? 'F' : 'f'), have_arg_list,
CPP_BUFFER (pfile)->nominal_fname); CPP_BUFFER (pfile)->nominal_fname);
token = cpp_get_token (pfile); cpp_get_token (pfile, &token);
if (token->type == CPP_OPEN_BRACE) if (token.type == CPP_OPEN_BRACE)
{ {
/* skip body of (normally) inline function */ /* skip body of (normally) inline function */
skip_to_closing_brace (pfile); skip_to_closing_brace (pfile);
goto new_statement; goto new_statement;
} }
if (token->type == CPP_SEMICOLON) if (token.type == CPP_SEMICOLON)
goto new_statement; goto new_statement;
} }
break; break;
case CPP_NAME: case CPP_NAME:
/* "inline" and "extern" are recognized but skipped */ /* "inline" and "extern" are recognized but skipped */
if (cpp_ideq (token, "inline")) if (cpp_ideq (&token, "inline"))
{ {
saw_inline = 1; saw_inline = 1;
} }
else if (cpp_ideq (token, "extern")) else if (cpp_ideq (&token, "extern"))
{ {
saw_extern = 1; saw_extern = 1;
token = cpp_get_token (pfile); cpp_get_token (pfile, &token);
if (token->type == CPP_STRING if (token.type == CPP_STRING
&& token->val.str.len == 1 && token.val.str.len == 1
&& token->val.str.text[0] == 'C') && token.val.str.text[0] == 'C')
{ {
current_extern_C = 1; current_extern_C = 1;
token = cpp_get_token (pfile); cpp_get_token (pfile, &token);
if (token->type == CPP_OPEN_BRACE) if (token.type == CPP_OPEN_BRACE)
{ {
brace_nesting++; brace_nesting++;
extern_C_braces[extern_C_braces_length++] extern_C_braces[extern_C_braces_length++]
...@@ -223,6 +227,6 @@ scan_decls (pfile, argc, argv) ...@@ -223,6 +227,6 @@ scan_decls (pfile, argc, argv)
prev_id = token; prev_id = token;
break; break;
} }
token = cpp_get_token (pfile); cpp_get_token (pfile, &token);
} }
} }
...@@ -60,7 +60,8 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int)); ...@@ -60,7 +60,8 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int));
extern int scan_string _PARAMS((FILE *, sstring *, int)); extern int scan_string _PARAMS((FILE *, sstring *, int));
extern int read_upto _PARAMS((FILE *, sstring *, int)); extern int read_upto _PARAMS((FILE *, sstring *, int));
extern unsigned long hash _PARAMS((const char *)); 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 *)); const char *));
extern void recognized_extern _PARAMS((const struct cpp_token *)); extern void recognized_extern _PARAMS((const struct cpp_token *));
extern unsigned int hashstr _PARAMS((const char *, unsigned int)); extern unsigned int hashstr _PARAMS((const char *, unsigned int));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment