Commit 041c3194 by Zack Weinberg

top level:

2000-07-03  Zack Weinberg  <zack@wolery.cumb.org>

	* fix-header.c (struct partial_proto): Remove unnecessary fields.
	(recognized_extern, recognized_function, read_scan_file):
	Update for new scheme.
	(check_protection): It's still a multiple include guard even
	if it doesn't always trigger.
	* scan-decls.c (skip_to_closing_brace, scan_decls): Update for
	new scheme.
	* scan.h: Declare struct cpp_token.  Update prototypes.

2000-07-03  Neil Booth  <neilb@earthling.net>
	    Zack Weinberg  <zack@wolery.cumb.org>

	Complete overhaul of the lexer and macro expander.

	* cpphash.c (object_defn, funct_defn, push_macro_expansion,
	arg, arglist, argdata, reflist, collect_objlike_expansion,
	collect_funlike_expansion, collect_params,
	warn_trad_stringify, trad_stringify, duplicate_arg_p, add_pat,
	unsafe_chars, macarg, compare_defs, special_symbol,
	scan_arguments, stringify, funlike_macroexpand,
	_cpp_quote_string, monthnames): Delete.
	(cpp_lookup, _cpp_free_definition, dump_funlike_macro,
	_cpp_create_definition, _cpp_dump_definition,
	dump_hash_helper): Adjust.
	(find_param, count_params, parse_define, var_args_str,
	check_macro_redefinition, save_expansion): New.

	* cpplex.c (skip_block_comment, skip_line_comment, parse_name,
        parse_string, output_line_command, trigraph_replace,
        lex_line, cpp_push_buffer, cpp_pop_buffer, cpp_output_tokens,
        cpp_scan_buffer_nooutput, cpp_scan_buffer, cpp_free_toklist,
        cpp_idcmp, _cpp_get_directive_token, _cpp_init_input_buffer,
	_cpp_skip_rest_of_line): Modify.

        (maybe_macroexpand, skip_comment, copy_comment, skip_string,
	find_position, null_warning, bump_column, expand_name_space,
	pedantic_whitespace, _cpp_output_list, _cpp_slice_toklist,
	_cpp_squeeze_toklist, _cpp_scan_until, _cpp_skip_hspace,
	_cpp_parse_name, _cpp_lex_token, cpp_get_non_space_token,
	_cpp_prescan): Delete.

	(dump_param_spelling, process_directive, lex_next,
        is_macro_disabled, stringify_arg, expand_context_stack,
        output_token, make_string_token, alloc_number_token,
        special_symbol, duplicate_token, maybe_paste_with_next,
        can_paste, prevent_macro_expansion, restore_macro_expansion,
        get_temp_token, release_temp_tokens, quote_string,
        token_names, token_spellings, _cpp_expand_name_space,
        _cpp_glue_header_name, _cpp_reserve_name_space,
        digraph_spellings, trigraph_ok, skip_whitespace, save_comment,
        placemarker_token, eof_token, cpp_context, macro_args,
        get_raw_token, parse_arg, parse_args, save_token,
        push_arg_context, push_macro_context, pop_context,
        do_pop_context, free_macro_args, _cpp_get_line,
        _cpp_run_directive): New.

	* cpplib.c (validate_else, parse_include, push_conditional,
	pass_thru_directive, read_line_number, parse_ifdef,
	detect_if_not_defined, _cpp_check_directive, do_define,
	do_undef, do_include, do_import, do_include_next, do_error,
	do_warning, do_ident, do_pragma, pragma_dispatch, gcc_pragmas,
	top_pragmas, do_pragma_gcc, do_pragma_implementation,
	do_pragma_poison, do_pragma_system_header,
	do_pragma_dependency, do_sccs, do_ifdef, do_ifndef, do_else,
	dl_elif, do_endif, _cpp_unwind_if_stack, do_assert,
	do_unassert, cpp_define, cpp_undef, cpp_assert, cpp_unassert,
	cpp_defined): Update for new scheme.
	(strtoul_for_line, get_define_node, dump_macro_name,
	_cpp_check_linemarker, _cpp_parse_assertion): New.
	(_cpp_handle_directive, do_pragma_default): Delete.

	* cpphash.h (struct predicate): Now struct answer.
	(enum spell_type, struct token_spelling, struct directive,
	directive_handler): New.
	Update prototypes.  Remove unused macros.
	* cpplib.h: Update prototypes.  Remove unused macros,
	structure definitions, and fields.

	* cpperror.c (print_containing_files, v_message): Adjust.
	* cppexp.c (parse_assertion, lex, parse_escape,
	_cpp_parse_expr): Adjust.
	* cppfiles.c (open_include_file, _cpp_execute_include,
	_cpp_compare_file_date, cpp_read_file, read_include_file):
	Adjust.
	* cppinit.c (dump_special_to_buffer): Delete.
	(append_include_chain, merge_include_chains, cpp_reader_init,
	cpp_cleanup, initialize_builtins, builtin_array, cpp_start_read,
	cpp_finish, handle_option, print_help): Adjust.
	* cppmain.c (main): Adjust.

testsuite:
2000-07-03  Zack Weinberg  <zack@wolery.cumb.org>

	* testsuite/gcc.dg/cpp/19951025-1.c: Adjust regexps.
	* testsuite/gcc.dg/cpp/19990703-1.c: Likewise.
	* testsuite/gcc.dg/cpp/20000625-1.c: Likewise.
	* testsuite/gcc.dg/cpp/20000625-2.c: Likewise.

	* testsuite/gcc.dg/cpp/macro1.c,
	testsuite/gcc.dg/cpp/paste1.c, testsuite/gcc.dg/cpp/paste2.c,
	testsuite/gcc.dg/cpp/paste3.c, testsuite/gcc.dg/cpp/paste4.c,
	testsuite/gcc.dg/cpp/strify1.c,
	testsuite/gcc.dg/cpp/strify2.c: New tests.

From-SVN: r34859
parent 4f647814
2000-07-03 Zack Weinberg <zack@wolery.cumb.org>
* fix-header.c (struct partial_proto): Remove unnecessary fields.
(recognized_extern, recognized_function, read_scan_file):
Update for new scheme.
(check_protection): It's still a multiple include guard even
if it doesn't always trigger.
* scan-decls.c (skip_to_closing_brace, scan_decls): Update for
new scheme.
* scan.h: Declare struct cpp_token. Update prototypes.
2000-07-03 Neil Booth <neilb@earthling.net>
Zack Weinberg <zack@wolery.cumb.org>
Complete overhaul of the lexer and macro expander.
* cpphash.c (object_defn, funct_defn, push_macro_expansion,
arg, arglist, argdata, reflist, collect_objlike_expansion,
collect_funlike_expansion, collect_params,
warn_trad_stringify, trad_stringify, duplicate_arg_p, add_pat,
unsafe_chars, macarg, compare_defs, special_symbol,
scan_arguments, stringify, funlike_macroexpand,
_cpp_quote_string, monthnames): Delete.
(cpp_lookup, _cpp_free_definition, dump_funlike_macro,
_cpp_create_definition, _cpp_dump_definition,
dump_hash_helper): Adjust.
(find_param, count_params, parse_define, var_args_str,
check_macro_redefinition, save_expansion): New.
* cpplex.c (skip_block_comment, skip_line_comment, parse_name,
parse_string, output_line_command, trigraph_replace,
lex_line, cpp_push_buffer, cpp_pop_buffer, cpp_output_tokens,
cpp_scan_buffer_nooutput, cpp_scan_buffer, cpp_free_toklist,
cpp_idcmp, _cpp_get_directive_token, _cpp_init_input_buffer,
_cpp_skip_rest_of_line): Modify.
(maybe_macroexpand, skip_comment, copy_comment, skip_string,
find_position, null_warning, bump_column, expand_name_space,
pedantic_whitespace, _cpp_output_list, _cpp_slice_toklist,
_cpp_squeeze_toklist, _cpp_scan_until, _cpp_skip_hspace,
_cpp_parse_name, _cpp_lex_token, cpp_get_non_space_token,
_cpp_prescan): Delete.
(dump_param_spelling, process_directive, lex_next,
is_macro_disabled, stringify_arg, expand_context_stack,
output_token, make_string_token, alloc_number_token,
special_symbol, duplicate_token, maybe_paste_with_next,
can_paste, prevent_macro_expansion, restore_macro_expansion,
get_temp_token, release_temp_tokens, quote_string,
token_names, token_spellings, _cpp_expand_name_space,
_cpp_glue_header_name, _cpp_reserve_name_space,
digraph_spellings, trigraph_ok, skip_whitespace, save_comment,
placemarker_token, eof_token, cpp_context, macro_args,
get_raw_token, parse_arg, parse_args, save_token,
push_arg_context, push_macro_context, pop_context,
do_pop_context, free_macro_args, _cpp_get_line,
_cpp_run_directive): New.
* cpplib.c (validate_else, parse_include, push_conditional,
pass_thru_directive, read_line_number, parse_ifdef,
detect_if_not_defined, _cpp_check_directive, do_define,
do_undef, do_include, do_import, do_include_next, do_error,
do_warning, do_ident, do_pragma, pragma_dispatch, gcc_pragmas,
top_pragmas, do_pragma_gcc, do_pragma_implementation,
do_pragma_poison, do_pragma_system_header,
do_pragma_dependency, do_sccs, do_ifdef, do_ifndef, do_else,
dl_elif, do_endif, _cpp_unwind_if_stack, do_assert,
do_unassert, cpp_define, cpp_undef, cpp_assert, cpp_unassert,
cpp_defined): Update for new scheme.
(strtoul_for_line, get_define_node, dump_macro_name,
_cpp_check_linemarker, _cpp_parse_assertion): New.
(_cpp_handle_directive, do_pragma_default): Delete.
* cpphash.h (struct predicate): Now struct answer.
(enum spell_type, struct token_spelling, struct directive,
directive_handler): New.
Update prototypes. Remove unused macros.
* cpplib.h: Update prototypes. Remove unused macros,
structure definitions, and fields.
* cpperror.c (print_containing_files, v_message): Adjust.
* cppexp.c (parse_assertion, lex, parse_escape,
_cpp_parse_expr): Adjust.
* cppfiles.c (open_include_file, _cpp_execute_include,
_cpp_compare_file_date, cpp_read_file, read_include_file):
Adjust.
* cppinit.c (dump_special_to_buffer): Delete.
(append_include_chain, merge_include_chains, cpp_reader_init,
cpp_cleanup, initialize_builtins, builtin_array, cpp_start_read,
cpp_finish, handle_option, print_help): Adjust.
* cppmain.c (main): Adjust.
2000-07-03 Zack Weinberg <zack@wolery.cumb.org>
* cppspec.c (lang_specific_driver): Use double quotes in error
message.
......
......@@ -58,23 +58,27 @@ print_containing_files (pfile, ip)
if (first)
{
first = 0;
/* N.B. The current line in each outer source file is one
greater than the line of the #include, so we must
subtract one to correct for that. */
fprintf (stderr, _("In file included from %s:%u"),
ip->nominal_fname, CPP_BUF_LINE (ip));
ip->nominal_fname, CPP_BUF_LINE (ip) - 1);
}
else
/* Translators note: this message is used in conjunction
with "In file included from %s:%ld" and some other
tricks. We want something like this:
In file included from sys/select.h:123,
from sys/types.h:234,
from userfile.c:31:
bits/select.h:45: <error message here>
| In file included from sys/select.h:123,
| from sys/types.h:234,
| from userfile.c:31:
| bits/select.h:45: <error message here>
with all the "from"s lined up.
The trailing comma is at the beginning of this message,
and the trailing colon is not translated. */
fprintf (stderr, _(",\n from %s:%u"),
ip->nominal_fname, CPP_BUF_LINE (ip));
ip->nominal_fname, CPP_BUF_LINE (ip) - 1);
}
if (first == 0)
fputs (":\n", stderr);
......@@ -111,17 +115,14 @@ v_message (pfile, is_error, file, line, col, msg, ap)
const char *msg;
va_list ap;
{
cpp_buffer *ip = cpp_file_buffer (pfile);
cpp_buffer *ip = CPP_BUFFER (pfile);
if (ip)
{
if (file == NULL)
file = ip->nominal_fname;
if (line == 0)
{
line = CPP_BUF_LINE (ip);
col = CPP_BUF_COL (ip);
}
line = _cpp_get_line (pfile, &col);
print_containing_files (pfile, ip);
print_file_and_line (file, line,
CPP_OPTION (pfile, show_column) ? col : 0);
......@@ -132,8 +133,12 @@ v_message (pfile, is_error, file, line, col, msg, ap)
switch (is_error)
{
case 0:
fprintf (stderr, _("warning: "));
break;
if (! CPP_OPTION (pfile, warnings_are_errors))
{
fprintf (stderr, _("warning: "));
break;
}
/* else fall through */
case 1:
if (pfile->errors < CPP_FATAL_LIMIT)
pfile->errors++;
......
......@@ -394,74 +394,22 @@ parse_assertion (pfile)
cpp_reader *pfile;
{
struct operation op;
struct answer *answer;
cpp_hashnode *hp;
struct predicate *pred;
cpp_toklist query;
enum cpp_ttype type;
U_CHAR *tok;
size_t len;
unsigned int old_written;
int specific = 0;
old_written = CPP_WRITTEN (pfile);
CPP_PUTC (pfile, '#');
pfile->no_macro_expand++;
type = _cpp_get_directive_token (pfile);
if (type == CPP_VSPACE)
SYNTAX_ERROR ("assertion without predicate");
else if (type != CPP_NAME)
SYNTAX_ERROR ("assertion predicate is not an identifier");
tok = pfile->token_buffer + old_written;
len = CPP_WRITTEN (pfile) - old_written;
hp = cpp_lookup (pfile, tok, len);
/* Look ahead for an open paren. */
_cpp_skip_hspace (pfile);
if (CPP_BUF_PEEK (CPP_BUFFER (pfile)) == '(')
op.op = ERROR;
hp = _cpp_parse_assertion (pfile, &answer);
if (hp)
{
if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN)
CPP_ICE ("impossible token, expecting ( in parse_assertion");
_cpp_init_toklist (&query, NO_DUMMY_TOKEN);
specific = 1;
if (_cpp_scan_until (pfile, &query, CPP_CLOSE_PAREN) != CPP_CLOSE_PAREN)
SYNTAX_ERROR ("missing close paren on assertion answer");
if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
CPP_ICE ("impossible token, expecting ) in parse_assertion");
}
/* If we get here, the syntax is valid. */
op.op = INT;
op.value = (hp->type == T_ASSERTION &&
(answer == 0 || *find_answer (hp, &answer->list) != 0));
/* If we get here, the syntax is valid. */
op.op = INT;
op.value = 0;
/* Has this predicate been asserted at all? */
if (hp->type == T_ASSERTION)
{
if (specific)
{
for (pred = hp->value.pred; pred; pred = pred->next)
if (_cpp_equiv_toklists (&query, &pred->answer))
{
op.value = 1;
break;
}
_cpp_free_toklist (&query);
}
else
op.value = 1;
if (answer)
FREE_ANSWER (answer);
}
out:
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
return op;
syntax_error:
if (specific)
_cpp_free_toklist (&query);
op.op = ERROR;
goto out;
}
struct token
......@@ -480,8 +428,6 @@ static const struct token tokentab2[] =
{"!=", NOTEQUAL},
{"<=", LEQ},
{">=", GEQ},
{"++", ERROR},
{"--", ERROR},
{NULL, ERROR}
};
......@@ -496,16 +442,20 @@ lex (pfile, skip_evaluation)
enum cpp_ttype token;
struct operation op;
U_CHAR *tok_start, *tok_end;
long old_written;
long old_written = CPP_WRITTEN (pfile);
old_written = CPP_WRITTEN (pfile);
retry:
token = _cpp_get_directive_token (pfile);
tok_start = pfile->token_buffer + old_written;
tok_end = CPP_PWRITTEN (pfile);
CPP_SET_WRITTEN (pfile, old_written);
switch (token)
{
case CPP_PLACEMARKER:
CPP_SET_WRITTEN (pfile, old_written);
goto retry;
case CPP_EOF: /* Should not happen ... */
case CPP_VSPACE:
op.op = 0;
......@@ -524,6 +474,7 @@ lex (pfile, skip_evaluation)
return parse_charconst (pfile, tok_start, tok_end);
case CPP_NAME:
/* FIXME: could this not overflow the tok_start buffer? */
if (!ustrncmp (tok_start, U"defined", 7))
return parse_defined (pfile);
......@@ -539,7 +490,16 @@ lex (pfile, skip_evaluation)
case CPP_HASH:
return parse_assertion (pfile);
case CPP_OTHER:
case CPP_AND_AND: op.op = ANDAND; return op;
case CPP_OR_OR: op.op = OROR; return op;
case CPP_LSHIFT: op.op = LSH; return op;
case CPP_RSHIFT: op.op = RSH; return op;
case CPP_EQ_EQ: op.op = EQUAL; return op;
case CPP_NOT_EQ: op.op = NOTEQUAL; return op;
case CPP_LESS_EQ: op.op = LEQ; return op;
case CPP_GREATER_EQ:op.op = GEQ; return op;
default:
/* See if it is a special token of length 2. */
if (tok_start + 2 == tok_end)
{
......@@ -553,8 +513,6 @@ lex (pfile, skip_evaluation)
op.op = toktab->token;
return op;
}
/* fall through */
default:
op.op = *tok_start;
return op;
}
......@@ -612,7 +570,7 @@ parse_escape (pfile, string_ptr, result_mask)
case 'e':
case 'E':
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, '\\%c'", c);
cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c);
return TARGET_ESC;
case 'f':
return TARGET_FF;
......@@ -844,9 +802,7 @@ _cpp_parse_expr (pfile)
char buff[5];
/* Save parser state and set it to something sane. */
int save_only_seen_white = pfile->only_seen_white;
int save_skipping = pfile->skipping;
pfile->only_seen_white = 0;
pfile->skipping = 0;
/* We've finished when we try to reduce this. */
......@@ -875,7 +831,8 @@ _cpp_parse_expr (pfile)
case ERROR:
goto syntax_error;
default:
SYNTAX_ERROR ("invalid character in #if");
SYNTAX_ERROR2 ("invalid character '%s' in #if",
op_to_str (op.op, buff));
push_immediate:
case INT:
......@@ -1168,7 +1125,6 @@ _cpp_parse_expr (pfile)
if (stack != init_stack)
free (stack);
CPP_SET_WRITTEN (pfile, old_written);
pfile->only_seen_white = save_only_seen_white;
pfile->skipping = save_skipping;
return result;
}
......@@ -180,7 +180,7 @@ open_include_file (pfile, filename)
#ifdef EACCES
if (errno == EACCES)
{
cpp_error (pfile, "included file `%s' exists but is not readable",
cpp_error (pfile, "included file \"%s\" exists but is not readable",
filename);
}
#endif
......@@ -360,16 +360,16 @@ cpp_make_system_header (pfile, pbuf, flag)
#define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
void
_cpp_execute_include (pfile, f, len, no_reinclude, search_start)
_cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets)
cpp_reader *pfile;
U_CHAR *f;
const U_CHAR *f;
unsigned int len;
int no_reinclude;
struct file_name_list *search_start;
int angle_brackets;
{
struct include_file *inc;
char *fname = (char *)f;
int angle_brackets = fname[0] == '<';
char *fname;
if (!search_start)
{
......@@ -387,9 +387,8 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start)
return;
}
/* Remove quote marks. */
fname++;
len -= 2;
fname = alloca (len + 1);
memcpy (fname, f, len);
fname[len] = '\0';
inc = find_include_file (pfile, fname, search_start);
......@@ -470,32 +469,27 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start)
if F cannot be located or dated, 1, if it is newer and 0 if older. */
int
_cpp_compare_file_date (pfile, f, len, search_start)
_cpp_compare_file_date (pfile, f, len, angle_brackets)
cpp_reader *pfile;
U_CHAR *f;
const U_CHAR *f;
unsigned int len;
struct file_name_list *search_start;
int angle_brackets;
{
char *fname = (char *)f;
int angle_brackets = fname[0] == '<';
char *fname;
struct file_name_list *search_start;
struct include_file *inc;
struct include_file *current_include = cpp_file_buffer (pfile)->inc;
struct include_file *current_include = CPP_BUFFER (pfile)->inc;
if (!search_start)
{
if (angle_brackets)
search_start = CPP_OPTION (pfile, bracket_include);
else if (CPP_OPTION (pfile, ignore_srcdir))
search_start = CPP_OPTION (pfile, quote_include);
else
search_start = CPP_BUFFER (pfile)->actual_dir;
}
if (angle_brackets)
search_start = CPP_OPTION (pfile, bracket_include);
else if (CPP_OPTION (pfile, ignore_srcdir))
search_start = CPP_OPTION (pfile, quote_include);
else
search_start = CPP_BUFFER (pfile)->actual_dir;
/* Remove quote marks. */
fname++;
len -= 2;
fname = alloca (len + 1);
memcpy (fname, f, len);
fname[len] = '\0';
inc = find_include_file (pfile, fname, search_start);
if (!inc)
......@@ -534,6 +528,12 @@ cpp_read_file (pfile, fname)
f = open_include_file (pfile, fname);
if (f == NULL)
{
cpp_error_from_errno (pfile, fname);
return 0;
}
return read_include_file (pfile, f);
}
......@@ -550,12 +550,17 @@ read_include_file (pfile, inc)
cpp_buffer *fp;
int fd = inc->fd;
/* Ensures we dump our current line before entering an include file. */
if (CPP_BUFFER (pfile) && pfile->printer)
cpp_output_tokens (pfile, pfile->printer,
CPP_BUF_LINE (CPP_BUFFER (pfile)));
fp = cpp_push_buffer (pfile, NULL, 0);
if (fp == 0)
goto push_fail;
if (fstat (fd, &st) < 0)
if (fd < 0 || fstat (fd, &st) < 0)
goto perror_fail;
inc->date = st.st_mtime;
......@@ -622,9 +627,6 @@ read_include_file (pfile, inc)
if (length == 0)
inc->cmacro = NEVER_REREAD;
else
/* Temporary - I hope. */
length = _cpp_prescan (pfile, fp, length);
fp->rlimit = fp->buf + length;
fp->cur = fp->buf;
......@@ -637,13 +639,13 @@ read_include_file (pfile, inc)
fp->actual_dir = actual_directory (pfile, inc->name);
pfile->input_stack_listing_current = 0;
pfile->only_seen_white = 2;
return 1;
perror_fail:
cpp_error_from_errno (pfile, inc->name);
/* Do not try to read this file again. */
close (fd);
if (fd != -1)
close (fd);
inc->fd = -1;
inc->cmacro = NEVER_REREAD;
fail:
......
......@@ -31,75 +31,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef abort
/* Structure allocated for every #define. For a simple replacement
such as
#define foo bar
we allocate an object_defn structure; the expansion field points
to the replacement text. For a function-like macro we allocate a
funct_defn structure; nargs is the number of arguments - it can be zero,
e.g.
#define getchar() getc (stdin)
When there are args, the expansion is the replacement text with the
args squashed out, and the reflist is a list describing how to
build the output from the input: e.g., "3 chars, then the 1st arg,
then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
The chars here come from the expansion. Whatever is left of the
expansion after the last arg-occurrence is copied after that arg.
Note that the reflist can be arbitrarily long---
its length depends on the number of times the arguments appear in
the replacement text, not how many args there are. Example:
#define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
pattern list
{ (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
where (x, y) means (nchars, argno).
Note that EMPTY and IDENTITY macros have object_defn structures too,
but they're just used to hold the file, line, and column. The
expansion field will be NULL. */
struct object_defn
{
const U_CHAR *expansion;
unsigned int length;
const char *file; /* File, line, column of definition */
int line;
int col;
};
struct reflist
{
const struct reflist *next;
char stringify; /* nonzero if this arg was preceded by a
# operator. */
char raw_before; /* Nonzero if a ## operator before arg. */
char raw_after; /* Nonzero if a ## operator after arg. */
char rest_args; /* Nonzero if this arg. absorbs the rest */
int nchars; /* Number of literal chars to copy before
this arg occurrence. */
int argno; /* Number of arg to substitute (origin-0) */
};
struct funct_defn
{
int nargs;
int length; /* length of expansion string */
const U_CHAR *expansion;
char rest_args; /* Nonzero if last arg. absorbs the rest */
const struct reflist *pattern;
/* Names of macro args, concatenated in order with \0 between
them. The only use of this is that we warn on redefinition if
this differs between the old and new definitions. */
U_CHAR *argnames;
const char *file; /* File, line, column of definition */
int line;
int col;
};
/* This is the second argument to eq_HASHNODE. */
struct hashdummy
{
......@@ -107,96 +38,30 @@ struct hashdummy
unsigned short length;
};
/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */
#define HASHSIZE 500
static unsigned int hash_HASHNODE PARAMS ((const void *));
static int eq_HASHNODE PARAMS ((const void *, const void *));
static void del_HASHNODE PARAMS ((void *));
static cpp_hashnode *make_HASHNODE PARAMS ((const U_CHAR *, size_t,
enum node_type, unsigned int));
static void dump_funlike_macro PARAMS ((cpp_reader *,
const struct funct_defn *));
static int dump_hash_helper PARAMS ((void **, void *));
static void push_macro_expansion PARAMS ((cpp_reader *, const U_CHAR *,
int, cpp_hashnode *));
static int unsafe_chars PARAMS ((cpp_reader *, int, int));
static enum cpp_ttype macarg PARAMS ((cpp_reader *, int));
static void special_symbol PARAMS ((cpp_reader *, cpp_hashnode *));
static int compare_defs PARAMS ((cpp_reader *,
const struct funct_defn *,
const struct funct_defn *));
static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */
#define HASHSIZE 500
/* The arglist structure is built by collect_params to tell
collect_funlike_expansion where the argument names begin. That is,
for a define like "#define f(x,y,z) foo+x-bar*y", the arglist would
contain pointers to the strings x, y, and z.
collect_funlike_expansion would then build a funct_defn node, with
reflist nodes pointing to the places x, y, and z had appeared.
The arglist is just convenience data passed between these two
routines. It is not kept around after the current #define has been
processed and entered into the hash table. */
static const cpp_token *count_params PARAMS ((cpp_reader *,
const cpp_token *,
cpp_toklist *));
static cpp_toklist *parse_define PARAMS((cpp_reader *));
static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
const cpp_toklist *));
static int save_expansion PARAMS((cpp_reader *, cpp_toklist *,
const cpp_token *, const cpp_token *));
static unsigned int find_param PARAMS ((const cpp_token *,
const cpp_token *));
struct arg
{
const U_CHAR *name;
unsigned int len;
char rest_arg;
};
struct arglist
{
U_CHAR *namebuf;
const struct arg *argv;
int argc;
};
static struct object_defn *
collect_objlike_expansion PARAMS ((cpp_reader *, cpp_toklist *));
static struct funct_defn *
collect_funlike_expansion PARAMS ((cpp_reader *, cpp_toklist *,
struct arglist *, unsigned int));
static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *,
struct arglist *));
static void warn_trad_stringify PARAMS ((cpp_reader *, const U_CHAR *, size_t,
unsigned int, const struct arg *));
static unsigned int trad_stringify PARAMS ((cpp_reader *, const U_CHAR *,
size_t,
unsigned int, const struct arg *,
struct reflist **,
struct reflist **, unsigned int));
static int duplicate_arg_p PARAMS ((U_CHAR *, U_CHAR *));
static void add_pat PARAMS ((struct reflist **, struct reflist **,
unsigned int, unsigned int, int, int, int, int));
/* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length).
`expanded' points to the argument's macro-expansion
(its length is `expand_length').
`stringified_length' is the length the argument would have
if stringified. */
/* raw and expanded are relative to ARG_BASE */
#define ARG_BASE ((pfile)->token_buffer)
struct argdata
{
/* Strings relative to pfile->token_buffer */
long raw, expanded, stringified;
int raw_length, expand_length;
int stringified_length;
};
static void scan_arguments PARAMS ((cpp_reader *,
const struct funct_defn *,
struct argdata *, const U_CHAR *));
static void stringify PARAMS ((cpp_reader *, struct argdata *));
static void funlike_macroexpand PARAMS ((cpp_reader *, cpp_hashnode *,
struct argdata *));
static const unsigned char var_args_str[] = "__VA_ARGS__";
/* Calculate hash of a string of length LEN. */
unsigned int
......@@ -297,7 +162,8 @@ cpp_lookup (pfile, name, len)
return *slot;
new = make_HASHNODE (name, len, T_VOID, hash);
new->value.cpval = NULL;
new->value.expansion = NULL;
*slot = new;
return new;
}
......@@ -317,1521 +183,419 @@ void
_cpp_free_definition (h)
cpp_hashnode *h;
{
if (h->type == T_XCONST)
free ((PTR) h->value.cpval);
else if (h->type == T_MACRO)
{
if (h->value.odefn->expansion)
free ((PTR) h->value.odefn->expansion);
free ((PTR) h->value.odefn);
}
else if (h->type == T_FMACRO)
{
const struct funct_defn *d = h->value.fdefn;
const struct reflist *ap, *nextap;
for (ap = d->pattern; ap != NULL; ap = nextap)
{
nextap = ap->next;
free ((PTR) ap);
}
if (d->argnames)
free ((PTR) d->argnames);
free ((PTR) d);
}
h->value.cpval = NULL;
}
/* Create pat nodes. */
static void
add_pat (pat, endpat, nchars, argno, raw_before, raw_after, strize, rest)
struct reflist **pat, **endpat;
unsigned int nchars;
unsigned int argno;
int raw_before, raw_after, strize, rest;
{
struct reflist *tpat;
tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
tpat->next = NULL;
tpat->raw_before = raw_before;
tpat->raw_after = raw_after;
tpat->stringify = strize;
tpat->rest_args = rest;
tpat->argno = argno;
tpat->nchars = nchars;
if (*endpat == NULL)
*pat = tpat;
else
(*endpat)->next = tpat;
*endpat = tpat;
}
/* Issue warnings for macro argument names seen inside strings. */
static void
warn_trad_stringify (pfile, p, len, argc, argv)
cpp_reader *pfile;
const U_CHAR *p;
size_t len;
unsigned int argc;
const struct arg *argv;
{
const U_CHAR *limit;
unsigned int i;
limit = p + len;
for (;;)
{
while (p < limit && !is_idstart (*p)) p++;
if (p >= limit)
break;
for (i = 0; i < argc; i++)
if (!ustrncmp (p, argv[i].name, argv[i].len)
&& ! is_idchar (p[argv[i].len]))
{
cpp_warning (pfile,
"macro argument \"%s\" would be stringified in traditional C",
argv[i].name);
break;
}
p++;
while (p < limit && is_idchar (*p)) p++;
if (p >= limit)
break;
}
if (h->type == T_MACRO)
_cpp_free_toklist (h->value.expansion);
h->value.expansion = NULL;
}
/* Generate pat nodes for macro arguments seen inside strings. */
/* Scans for a given token, returning the parameter number if found,
or 0 if not found. Scans from FIRST to TOKEN - 1 or the first
CPP_CLOSE_PAREN for TOKEN. */
static unsigned int
trad_stringify (pfile, base, len, argc, argv, pat, endpat, last)
cpp_reader *pfile;
const U_CHAR *base;
size_t len;
unsigned int argc;
const struct arg *argv;
struct reflist **pat, **endpat;
unsigned int last;
{
const U_CHAR *p, *limit;
unsigned int i;
p = base;
limit = base + len;
for (;;)
{
proceed:
while (p < limit && !is_idstart (*p)) p++;
if (p >= limit)
break;
for (i = 0; i < argc; i++)
if (!ustrncmp (p, argv[i].name, argv[i].len)
&& ! is_idchar (p[argv[i].len]))
{
if (CPP_WTRADITIONAL (pfile))
cpp_warning (pfile, "macro argument \"%s\" is stringified",
argv[i].name);
/* Write out the string up to this point, and add a pat
node for the argument. Note that the argument is NOT
stringified. */
CPP_PUTS (pfile, base, p - base);
add_pat (pat, endpat, CPP_WRITTEN (pfile) - last, i /* argno */,
!is_hspace (p[-1]) /* raw_before */,
!is_hspace (p[argv[i].len]) /* raw_after */,
0 /* strize */,
argv[i].rest_arg);
last = CPP_WRITTEN (pfile);
base = p + argv[i].len;
p = base;
goto proceed;
}
p++;
while (p < limit && is_idchar (*p)) p++;
if (p >= limit)
break;
}
CPP_PUTS (pfile, base, p - base);
return last;
}
/* Read a replacement list for an object-like macro, and build the
object_defn structure. LIST contains the replacement list,
beginning at 1. */
static struct object_defn *
collect_objlike_expansion (pfile, list)
cpp_reader *pfile;
cpp_toklist *list;
find_param (first, token)
const cpp_token *first, *token;
{
struct object_defn *defn;
unsigned int i;
unsigned int start;
int last_was_paste = 0;
U_CHAR *exp;
size_t len;
/* We copy the expansion text into the token_buffer, then out to
its proper home. */
start = CPP_WRITTEN (pfile);
CPP_PUTS (pfile, "\r ", 2);
for (i = 1; i < list->tokens_used; i++)
{
switch (TOK_TYPE (list, i))
{
case CPP_PASTE:
/* ## is not special if it appears right after another ##;
nor is it special if -traditional. */
if (last_was_paste || CPP_TRADITIONAL (pfile))
break;
if (i == 1)
cpp_error (pfile, "`##' at start of macro definition");
last_was_paste = 1;
continue;
default:;
}
if (i > 1 && !last_was_paste && TOK_PREV_WHITE (list, i))
CPP_PUTC (pfile, ' ');
CPP_PUTS (pfile, TOK_NAME (list, i), TOK_LEN (list, i));
last_was_paste = 0;
}
if (last_was_paste)
cpp_error (pfile, "`##' at end of macro definition");
CPP_PUTS (pfile, "\r ", 2);
len = CPP_WRITTEN (pfile) - start;
CPP_SET_WRITTEN (pfile, start);
unsigned int param = 0;
if (len <= 4)
cpp_ice (pfile, "empty object-like macro went through full #define");
exp = (U_CHAR *) xmalloc (len + 1);
memcpy (exp, pfile->token_buffer + start, len);
exp[len] = '\0';
defn = (struct object_defn *) xmalloc (sizeof (struct object_defn));
defn->length = len;
defn->expansion = exp;
for (; first < token && first->type != CPP_CLOSE_PAREN; first++)
if (first->type == CPP_NAME)
{
param++;
if (first->val.name.len == token->val.name.len
&& !memcmp (first->val.name.text, token->val.name.text,
token->val.name.len))
return param;
}
return defn;
return 0;
}
/* Read a replacement list for a function-like macro, and build the
funct_defn structure. LIST contains the replacement list,
beginning at REPLACEMENT. ARGLIST specifies the formal parameters
to look for in the text of the definition. */
static struct funct_defn *
collect_funlike_expansion (pfile, list, arglist, replacement)
/* Counts the parameters to a function like macro, and saves their
spellings if necessary. Returns the token that we stopped scanning
at; if it's type isn't CPP_CLOSE_PAREN there was an error, which
has been reported. */
static const cpp_token *
count_params (pfile, first, list)
cpp_reader *pfile;
const cpp_token *first;
cpp_toklist *list;
struct arglist *arglist;
unsigned int replacement;
{
struct funct_defn *defn;
struct reflist *pat = 0, *endpat = 0;
enum cpp_ttype token;
unsigned int start, last;
unsigned int i;
int j, argc;
size_t len;
const struct arg *argv;
const U_CHAR *tok;
U_CHAR *exp;
enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START;
argv = arglist->argv;
argc = arglist->argc;
/* We copy the expansion text into the token_buffer, then out to
its proper home. */
last = start = CPP_WRITTEN (pfile);
CPP_PUTS (pfile, "\r ", 2);
for (i = replacement; i < list->tokens_used; i++)
unsigned int params_len = 0, prev_ident = 0;
unsigned int line = pfile->token_list.line;
const cpp_token *token, *temp;
list->paramc = 0;
for (token = first;; token++)
{
token = TOK_TYPE (list, i);
tok = TOK_NAME (list, i);
len = TOK_LEN (list, i);
switch (token)
switch (token->type)
{
case CPP_HASH:
/* # is special in function-like macros with no args.
(6.10.3.2 para 1.) However, it is not special after
PASTE. (Implied by 6.10.3.3 para 4.) Nor is it special
if -traditional. */
if (last_token == PASTE || CPP_TRADITIONAL (pfile))
break;
last_token = STRIZE;
continue;
case CPP_PASTE:
/* ## is not special if it appears right after another ##;
nor is it special if -traditional. */
if (last_token == PASTE || CPP_TRADITIONAL (pfile))
break;
if (last_token == START)
cpp_error (pfile, "`##' at start of macro definition");
else if (last_token == ARG)
/* If the last token was an argument, mark it raw_after. */
endpat->raw_after = 1;
else if (last_token == STRIZE)
/* Oops - that wasn't a stringify operator. */
CPP_PUTC (pfile, '#');
last_token = PASTE;
continue;
default:;
}
case CPP_EOF:
cpp_error_with_line (pfile, line, token->col,
"missing ')' in macro parameter list");
goto out;
if (last_token != PASTE && last_token != START
&& TOK_PREV_WHITE (list, i))
CPP_PUTC (pfile, ' ');
if (last_token == ARG && CPP_TRADITIONAL (pfile)
&& !TOK_PREV_WHITE (list, i))
endpat->raw_after = 1;
case CPP_COMMENT:
continue; /* Ignore -C comments. */
switch (token)
{
case CPP_STRING:
case CPP_CHAR:
if (argc == 0)
goto norm;
if (CPP_TRADITIONAL (pfile))
case CPP_NAME:
if (prev_ident)
{
last = trad_stringify (pfile, tok, len, argc, argv,
&pat, &endpat, last);
break;
cpp_error_with_line (pfile, line, token->col,
"macro parameters must be comma-separated");
goto out;
}
else
/* Constraint 6.10.3.5 */
if (token->val.name.len == sizeof (var_args_str) - 1
&& !ustrncmp (token->val.name.text, var_args_str,
sizeof (var_args_str) - 1))
{
if (CPP_WTRADITIONAL (pfile))
warn_trad_stringify (pfile, tok, len, argc, argv);
goto norm;
cpp_error_with_line (pfile, line, token->col,
"\"%s\" is not a valid parameter name",
var_args_str);
goto out;
}
case CPP_NAME:
for (j = 0; j < argc; j++)
if (argv[j].len == len
&& !ustrncmp (tok, argv[j].name, argv[j].len))
goto addref;
params_len += token->val.name.len + 1;
prev_ident = 1;
list->paramc++;
/* fall through */
default:
norm:
if (last_token == STRIZE)
/* Constraint 6.10.3.6 - duplicate parameter names. */
if (find_param (first, token))
{
/* This is a mandatory diagnostic (6.10.3.2 para 1), but
in assembly language # may have some other
significance we don't know about, so suppress the
warning. */
if (! CPP_OPTION (pfile, lang_asm))
cpp_pedwarn (pfile,
"# is not followed by a macro argument name");
if (TOK_PREV_WHITE (list, i))
CPP_ADJUST_WRITTEN (pfile, -1);
if (TOK_PREV_WHITE (list, i-1))
CPP_PUTC (pfile, ' ');
CPP_PUTC (pfile, '#');
if (TOK_PREV_WHITE (list, i))
CPP_PUTC (pfile, ' ');
cpp_error_with_line (pfile, line, token->col,
"duplicate macro parameter \"%.*s\"",
(int) token->val.name.len,
token->val.name.text);
goto out;
}
CPP_PUTS (pfile, tok, len);
last_token = NORM;
}
continue;
addref:
{
int raw_before = (last_token == PASTE
|| (CPP_TRADITIONAL (pfile)
&& ! TOK_PREV_WHITE (list, j)));
add_pat (&pat, &endpat,
CPP_WRITTEN (pfile) - last /* nchars */, j /* argno */,
raw_before, 0 /* raw_after */,
(last_token == STRIZE), argv[j].rest_arg);
last = CPP_WRITTEN (pfile);
}
last_token = ARG;
}
break;
if (last_token == STRIZE)
cpp_error (pfile, "`#' is not followed by a macro argument name");
else if (last_token == PASTE)
cpp_error (pfile, "`##' at end of macro definition");
CPP_PUTS (pfile, "\r ", 2);
len = CPP_WRITTEN (pfile) - start;
CPP_SET_WRITTEN (pfile, start);
exp = (U_CHAR *) xmalloc (len + 1);
memcpy (exp, pfile->token_buffer + start, len);
exp[len] = '\0';
defn = (struct funct_defn *) xmalloc (sizeof (struct funct_defn));
defn->length = len;
defn->expansion = exp;
defn->pattern = pat;
defn->rest_args = argc && argv[argc - 1].rest_arg;
defn->nargs = argc;
defn->argnames = arglist->namebuf;
if (argv)
free ((PTR) argv);
return defn;
}
default:
cpp_error_with_line (pfile, line, token->col,
"illegal token in macro parameter list");
goto out;
/* Is argument NEW, which has just been added to the argument list,
a duplicate of a previous argument name? */
static int
duplicate_arg_p (args, new)
U_CHAR *args, *new;
{
size_t newlen = ustrlen (new) + 1;
size_t oldlen;
case CPP_CLOSE_PAREN:
if (prev_ident || list->paramc == 0)
goto scanned;
while (args < new)
{
oldlen = ustrlen (args) + 1;
if (!memcmp (args, new, MIN (oldlen, newlen)))
return 1;
args += oldlen;
}
return 0;
}
/* Fall through to pick up the error. */
case CPP_COMMA:
if (!prev_ident)
{
cpp_error_with_line (pfile, line, token->col,
"missing parameter name");
goto out;
}
prev_ident = 0;
break;
static unsigned int
collect_params (pfile, list, arglist)
cpp_reader *pfile;
cpp_toklist *list;
struct arglist *arglist;
{
struct arg *argv = 0;
const U_CHAR *tok;
U_CHAR *namebuf, *p;
unsigned int len, argslen;
unsigned int argc, a, i, j;
/* The formal parameters list starts at token 1. */
if (TOK_TYPE (list, 1) != CPP_OPEN_PAREN)
{
cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters",
TOK_TYPE (list, 1), CPP_OPEN_PAREN);
return 0;
}
case CPP_ELLIPSIS:
/* Convert ISO-style var_args to named varargs by changing
the ellipsis into an identifier with name __VA_ARGS__.
This simplifies other handling. We can safely have its
text outside list->namebuf because there is no reason to
extend the size of the list's namebuf (and thus change
the pointer) in do_define. */
if (!prev_ident)
{
cpp_token *tok = (cpp_token *) token;
/* Scan once and count the number of parameters; also check for
syntax errors here. */
argc = 0;
argslen = 0;
for (i = 2; i < list->tokens_used; i++)
switch (TOK_TYPE (list, i))
{
case CPP_NAME:
argslen += TOK_LEN (list, i) + 1;
argc++;
break;
case CPP_COMMA:
break;
case CPP_CLOSE_PAREN:
goto scanned;
case CPP_VSPACE:
case CPP_EOF:
cpp_ice (pfile, "impossible token in macro argument list");
return 0;
default:
cpp_error_with_line (pfile, list->line, TOK_COL (list, i),
"illegal token in macro argument list");
return 0;
case CPP_ELLIPSIS:
if (TOK_TYPE (list, i-1) != CPP_NAME)
{
argslen += sizeof "__VA_ARGS__";
argc++;
}
i++;
if (TOK_TYPE (list, i) != CPP_CLOSE_PAREN)
{
cpp_error_with_line (pfile, list->line, TOK_COL (list, i),
"another parameter follows \"...\"");
return 0;
}
goto scanned;
}
cpp_error_with_line (pfile, list->line, TOK_COL (list, i-1),
"missing right paren in macro argument list");
return 0;
tok->type = CPP_NAME;
tok->val.name.len = sizeof (var_args_str) - 1;
tok->val.name.text = var_args_str; /* Safe. */
list->paramc++;
scanned:
if (argc == 0) /* function-like macro, no arguments */
{
arglist->argc = 0;
arglist->argv = 0;
arglist->namebuf = 0;
return i + 1;
}
if (argslen == 0)
{
cpp_ice (pfile, "collect_params: argc=%d argslen=0", argc);
return 0;
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
cpp_pedwarn (pfile,
"C89 does not permit anon varargs macros");
}
else if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile,
"ISO C does not permit named varargs parameters");
list->flags |= VAR_ARGS;
token++;
if (token->type == CPP_CLOSE_PAREN)
goto scanned;
cpp_error_with_line (pfile, line, token->col,
"')' expected after \"...\"");
goto out;
}
}
/* Now allocate space and copy the suckers. */
argv = (struct arg *) xmalloc (argc * sizeof (struct arg));
namebuf = (U_CHAR *) xmalloc (argslen);
p = namebuf;
a = 0;
for (j = 2; j < i; j++)
switch (TOK_TYPE (list, j))
{
case CPP_NAME:
tok = TOK_NAME (list, j);
len = TOK_LEN (list, j);
memcpy (p, tok, len);
p[len] = '\0';
if (duplicate_arg_p (namebuf, p))
{
cpp_error (pfile, "duplicate macro argument name \"%s\"", tok);
a++;
break;
}
if (CPP_PEDANTIC (pfile) && CPP_OPTION (pfile, c99)
&& len == sizeof "__VA_ARGS__" - 1
&& !ustrcmp (p, U"__VA_ARGS__"))
cpp_pedwarn (pfile,
"C99 does not permit use of __VA_ARGS__ as a macro argument name");
argv[a].len = len;
argv[a].name = p;
argv[a].rest_arg = 0;
p += len + 1;
a++;
break;
case CPP_COMMA:
break;
case CPP_ELLIPSIS:
if (TOK_TYPE (list, j-1) != CPP_NAME)
{
if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
cpp_pedwarn (pfile, "C89 does not permit varargs macros");
argv[a].len = sizeof "__VA_ARGS__" - 1;
argv[a].name = p;
argv[a].rest_arg = 1;
strcpy ((char *)p, "__VA_ARGS__");
}
else
scanned:
/* Store the null-terminated parameter spellings of a function, to
provide pedantic warnings to satisfy 6.10.3.2, or for use when
dumping macro definitions. */
if (list->paramc > 0 && pfile->save_parameter_spellings)
{
U_CHAR *buf;
_cpp_reserve_name_space (list, params_len);
list->params_len = list->name_used = params_len;
buf = list->namebuf;
for (temp = first; temp <= token; temp++)
if (temp->type == CPP_NAME)
{
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile,
"ISO C does not permit named varargs macros");
argv[a-1].rest_arg = 1;
memcpy (buf, temp->val.name.text, temp->val.name.len);
buf += temp->val.name.len;
*buf++ = '\0';
}
break;
default:
cpp_ice (pfile, "collect_params: impossible token type %d",
TOK_TYPE (list, j));
}
}
arglist->argc = argc;
arglist->argv = argv;
arglist->namebuf = namebuf;
return i + 1;
out:
return token;
}
/* Create a definition for a macro. The replacement text (including
formal parameters if present) is in LIST. If FUNLIKE is true, this
is a function-like macro. */
int
_cpp_create_definition (pfile, list, hp)
/* Parses a #define directive. Returns null pointer on error. */
static cpp_toklist *
parse_define (pfile)
cpp_reader *pfile;
cpp_toklist *list;
cpp_hashnode *hp;
{
struct funct_defn *fdefn = 0;
struct object_defn *odefn = 0;
enum node_type ntype;
int ok;
/* Special-case a few simple and common idioms:
#define TOKEN // nothing
#define TOKEN TOKEN
Might also be good to special-case these:
#define FUNC() // nothing
#define FUNC(a, b, ...) // nothing
#define FUNC(a, b, c) FUNC(a, b, c) */
if (list->tokens_used == 1)
ntype = T_EMPTY; /* Empty definition of object-like macro. */
else if (list->tokens_used == 2 && TOK_TYPE (list, 1) == CPP_NAME
&& TOK_LEN (list, 0) == TOK_LEN (list, 1)
&& !ustrncmp (TOK_NAME (list, 0), TOK_NAME (list, 1),
TOK_LEN (list, 0)))
ntype = T_IDENTITY; /* Object like macro defined to itself. */
/* The macro is function-like only if the next character,
with no intervening whitespace, is '('. */
else if (TOK_TYPE (list, 1) == CPP_OPEN_PAREN
&& ! TOK_PREV_WHITE (list, 1))
{
struct arglist args;
int replacement;
const cpp_token *token, *first_param;
cpp_toklist *list;
int prev_white = 0;
replacement = collect_params (pfile, list, &args);
if (replacement == 0)
return 0;
fdefn = collect_funlike_expansion (pfile, list, &args, replacement);
if (fdefn == 0)
return 0;
while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
prev_white = 1;
ntype = T_FMACRO;
}
/* Allocate the expansion's list. It will go in the hash table. */
list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
_cpp_init_toklist (list, 0);
first_param = token + 1;
list->paramc = -1; /* Object-like macro. */
/* Otherwise it is an object-like macro, and C99 requires
whitespace after the name (6.10.3 para 3). */
else
if (!prev_white && !(token->flags & PREV_WHITE))
{
if (! TOK_PREV_WHITE (list, 1))
cpp_pedwarn (pfile,
"The C standard requires whitespace after #define %s",
hp->name);
odefn = collect_objlike_expansion (pfile, list);
if (odefn == 0)
return 0;
ntype = T_MACRO;
}
if (ntype == T_EMPTY || ntype == T_IDENTITY)
{
odefn = xmalloc (sizeof (struct object_defn));
odefn->length = 0;
odefn->expansion = 0;
}
/* Check for a redefinition, and its legality. Redefining a macro
of whatever stripe is ok if the definitions are the same.
Redefining a built-in _constant_ (T_CONST or T_XCONST) is ok only
with -D. Otherwise a redefinition is not ok. */
switch (hp->type)
{
case T_VOID: ok = 1; break;
default: ok = 0; break;
case T_MACRO:
ok = (ntype == hp->type
&& odefn->length == hp->value.odefn->length
&& !ustrncmp (odefn->expansion, hp->value.odefn->expansion,
odefn->length));
break;
case T_FMACRO:
ok = (ntype == hp->type
&& !compare_defs (pfile, fdefn, hp->value.fdefn));
break;
case T_IDENTITY:
case T_EMPTY:
ok = (ntype == hp->type);
break;
case T_CONST:
case T_XCONST:
ok = ! pfile->done_initializing;
break;
}
/* Print the warning or error if it's not ok. */
if (! ok)
{
cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
if (pfile->done_initializing)
if (token->type == CPP_OPEN_PAREN)
{
const char *file;
unsigned int line, col;
if (hp->type == T_FMACRO)
{
file = hp->value.fdefn->file;
line = hp->value.fdefn->line;
col = hp->value.fdefn->col;
}
else
{
file = hp->value.odefn->file;
line = hp->value.odefn->line;
col = hp->value.odefn->col;
}
cpp_pedwarn_with_file_and_line (pfile, file, line, col,
"this is the location of the previous definition");
token = count_params (pfile, first_param, list);
if (token->type != CPP_CLOSE_PAREN)
goto error;
token++;
}
else if (token->type != CPP_EOF)
cpp_pedwarn (pfile,
"ISO C requires whitespace after the macro name");
}
/* And replace the old definition (if any). */
_cpp_free_definition (hp);
hp->type = ntype;
if (ntype == T_FMACRO)
if (save_expansion (pfile, list, token, first_param))
{
fdefn->file = CPP_BUFFER (pfile)->nominal_fname;
fdefn->line = list->line;
fdefn->col = TOK_COL (list, 0);
hp->value.fdefn = fdefn;
}
else
{
odefn->file = CPP_BUFFER (pfile)->nominal_fname;
odefn->line = list->line;
odefn->col = TOK_COL (list, 0);
hp->value.odefn = odefn;
}
return 1;
}
/*
* Parse a macro argument and append the info on PFILE's token_buffer.
* REST_ARGS means to absorb the rest of the args.
* Return nonzero to indicate a syntax error.
*/
static enum cpp_ttype
macarg (pfile, rest_args)
cpp_reader *pfile;
int rest_args;
{
int paren = 0;
enum cpp_ttype token;
/* Try to parse as much of the argument as exists at this
input stack level. */
for (;;)
{
token = cpp_get_token (pfile);
switch (token)
{
case CPP_EOF:
/* We've hit end of file; this is an error.
Caller will report it. */
return token;
case CPP_OPEN_PAREN:
paren++;
break;
case CPP_CLOSE_PAREN:
if (--paren < 0)
goto found;
break;
case CPP_COMMA:
/* if we've returned to lowest level and
we aren't absorbing all args */
if (paren == 0 && rest_args == 0)
goto found;
break;
found:
/* Remove ',' or ')' from argument buffer. */
CPP_ADJUST_WRITTEN (pfile, -1);
return token;
default:;
}
error:
_cpp_free_toklist (list);
list = 0;
}
}
static const char * const monthnames[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
/* Place into PFILE a quoted string representing the string SRC.
Caller must reserve enough space in pfile->token_buffer. */
void
_cpp_quote_string (pfile, src)
cpp_reader *pfile;
const U_CHAR *src;
{
U_CHAR c;
CPP_PUTC_Q (pfile, '\"');
for (;;)
switch ((c = *src++))
{
default:
if (ISPRINT (c))
CPP_PUTC_Q (pfile, c);
else
{
sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
break;
case '\"':
case '\\':
CPP_PUTC_Q (pfile, '\\');
CPP_PUTC_Q (pfile, c);
break;
case '\0':
CPP_PUTC_Q (pfile, '\"');
return;
}
return list;
}
/*
* expand things like __FILE__. Place the expansion into the output
* buffer *without* rescanning.
*/
#define DSC(str) (const U_CHAR *)str, sizeof str - 1
static void
special_symbol (pfile, hp)
cpp_reader *pfile;
cpp_hashnode *hp;
{
const U_CHAR *buf;
cpp_buffer *ip;
size_t len;
switch (hp->type)
{
case T_FILE:
case T_BASE_FILE:
ip = cpp_file_buffer (pfile);
if (ip == NULL)
{
CPP_PUTS (pfile, "\"\"", 2);
return;
}
if (hp->type == T_BASE_FILE)
while (CPP_PREV_BUFFER (ip) != NULL)
ip = CPP_PREV_BUFFER (ip);
buf = (const U_CHAR *) ip->nominal_fname;
len = ustrlen (buf);
CPP_RESERVE (pfile, 3 + 4 * len);
_cpp_quote_string (pfile, buf);
return;
case T_INCLUDE_LEVEL:
{
int true_indepth = 0;
ip = cpp_file_buffer (pfile);
while (ip)
{
true_indepth++;
ip = CPP_PREV_BUFFER (ip);
}
CPP_RESERVE (pfile, 10);
sprintf ((char *)CPP_PWRITTEN (pfile), "%d", true_indepth);
len = ustrlen (CPP_PWRITTEN (pfile));
CPP_ADJUST_WRITTEN (pfile, len);
return;
}
case T_STDC:
#ifdef STDC_0_IN_SYSTEM_HEADERS
ip = cpp_file_buffer (pfile);
if (ip && ip->inc->sysp
&& !cpp_defined (pfile, DSC("__STRICT_ANSI__")))
{
CPP_PUTC (pfile, '0');
return;
}
#endif
constant:
buf = hp->value.cpval;
if (!buf || *buf == '\0')
return;
len = ustrlen (buf);
CPP_PUTS (pfile, buf, len);
return;
case T_SPECLINE:
ip = cpp_file_buffer (pfile);
if (ip == NULL)
{
CPP_PUTC (pfile, '0');
return;
}
CPP_RESERVE (pfile, 10);
sprintf ((char *)CPP_PWRITTEN (pfile), "%u", CPP_BUF_LINE (ip));
len = ustrlen (CPP_PWRITTEN (pfile));
CPP_ADJUST_WRITTEN (pfile, len);
return;
case T_DATE:
case T_TIME:
/* Generate both __DATE__ and __TIME__, stuff them into their
respective hash nodes, and mark the nodes T_XCONST 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);
cpp_hashnode *d, *t;
if (hp->type == T_DATE)
d = hp, t = cpp_lookup (pfile, DSC("__TIME__"));
else
t = hp, d = cpp_lookup (pfile, DSC("__DATE__"));
d->value.cpval = xmalloc (sizeof "'Oct 11 1347'");
sprintf ((char *)d->value.cpval, "\"%s %2d %4d\"",
monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
d->type = T_XCONST;
t->value.cpval = xmalloc (sizeof "'12:34:56'");
sprintf ((char *)t->value.cpval, "\"%02d:%02d:%02d\"",
tb->tm_hour, tb->tm_min, tb->tm_sec);
t->type = T_XCONST;
goto constant;
}
case T_POISON:
cpp_error (pfile, "attempt to use poisoned `%s'.", hp->name);
CPP_PUTC (pfile, '0');
break;
default:
cpp_ice (pfile, "invalid special hash type");
return;
}
}
#undef DSC
/* Expand a macro call.
HP points to the symbol that is the macro being called.
Put the result of expansion onto the input stack
so that subsequent input by our caller will use it.
If macro wants arguments, caller has already verified that
an argument list follows; arguments come from the input stack. */
void
_cpp_macroexpand (pfile, hp)
static int
check_macro_redefinition (pfile, hp, list2)
cpp_reader *pfile;
cpp_hashnode *hp;
const cpp_toklist *list2;
{
const struct funct_defn *defn;
struct argdata *args;
unsigned int old_written;
int i;
/* Object like macro - most common case. */
if (hp->type == T_MACRO)
{
push_macro_expansion (pfile, hp->value.odefn->expansion,
hp->value.odefn->length, hp);
return;
}
/* Or might it be a constant string? */
if (hp->type == T_CONST || hp->type == T_XCONST)
{
const U_CHAR *cpval = hp->value.cpval;
if (cpval && *cpval != '\0')
push_macro_expansion (pfile, cpval, ustrlen (cpval), hp);
return;
}
/* Or a special symbol? */
if (hp->type != T_FMACRO)
{
U_CHAR *xbuf;
unsigned int len;
old_written = CPP_WRITTEN (pfile);
special_symbol (pfile, hp);
len = CPP_WRITTEN (pfile) - old_written;
CPP_SET_WRITTEN (pfile, old_written);
if (len == 0)
return;
xbuf = (U_CHAR *) xmalloc (len + 1);
memcpy (xbuf, CPP_PWRITTEN (pfile), len);
xbuf[len] = '\0';
push_macro_expansion (pfile, xbuf, len, hp);
return;
}
/* Okay, it's a full-on function-like macro... */
old_written = CPP_WRITTEN (pfile);
defn = hp->value.fdefn;
args = alloca (MAX (defn->nargs, 1) * sizeof (struct argdata));
for (i = 0; i < MAX (defn->nargs, 1); i++)
{
args[i].raw = args[i].expanded = 0;
args[i].raw_length = 0;
args[i].expand_length = args[i].stringified_length = -1;
}
const cpp_toklist *list1;
pfile->output_escapes++;
scan_arguments (pfile, defn, args, hp->name);
if (hp->type != T_MACRO)
return ! pfile->done_initializing;
/* If macro wants zero args, we parsed the arglist for checking only.
Read directly from the macro definition. */
if (defn->nargs == 0 || defn->pattern == 0)
{
/* If the defn is the empty string, don't bother pushing it. */
if (defn->length > 4)
push_macro_expansion (pfile, defn->expansion, defn->length, hp);
}
else
funlike_macroexpand (pfile, hp, args);
/* Clear the whitespace and BOL flags of the first tokens. They get
altered during macro expansion, but is not significant here. */
list1 = hp->value.expansion;
list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
CPP_SET_WRITTEN (pfile, old_written);
pfile->output_escapes--;
}
if (!_cpp_equiv_toklists (list1, list2))
return 0;
static void
scan_arguments (pfile, defn, args, name)
cpp_reader *pfile;
const struct funct_defn *defn;
struct argdata *args;
const U_CHAR *name;
{
enum cpp_ttype token;
unsigned int start_line, start_column;
unsigned int nargs = defn->nargs;
unsigned int i;
cpp_buffer *ip = cpp_file_buffer (pfile);
if (ip)
{
start_line = CPP_BUF_LINE (ip);
start_column = CPP_BUF_COL (ip);
}
else
start_line = start_column = 0;
/* Parse all the macro args that are supplied. I counts them. The
first NARGS args are stored in ARGS. The rest are discarded. If
rest_args is set then we assume macarg absorbed the rest of the
args. */
i = 0;
/* Skip over the opening parenthesis. */
CPP_OPTION (pfile, discard_comments)++;
pfile->no_macro_expand++;
pfile->no_directives++;
token = cpp_get_non_space_token (pfile);
if (token != CPP_OPEN_PAREN)
cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)",
token);
CPP_ADJUST_WRITTEN (pfile, -1);
token = CPP_EOF;
do
{
if (i < MAX (nargs, 1))
{
args[i].raw = CPP_WRITTEN (pfile);
token = macarg (pfile, (i == nargs - 1 && defn->rest_args));
args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
}
else
token = macarg (pfile, 0);
if (token == CPP_EOF)
cpp_error_with_line (pfile, start_line, start_column,
"unterminated macro call");
i++;
}
while (token == CPP_COMMA);
CPP_OPTION (pfile, discard_comments)--;
pfile->no_macro_expand--;
pfile->no_directives--;
if (token != CPP_CLOSE_PAREN)
return;
/* foo ( ) is equivalent to foo () unless foo takes exactly one
argument, in which case the former is allowed and the latter
is not. XXX C99 is silent on this rule, but it seems
inconsistent to me. */
if (i == 1 && nargs == 0)
{
register U_CHAR *bp = ARG_BASE + args[0].raw;
register U_CHAR *lim = bp + args[0].raw_length;
while (bp != lim && is_space(*bp))
bp++;
if (bp == lim)
i = 0;
}
if (CPP_OPTION (pfile, pedantic)
&& list1->paramc > 0
&& (list1->params_len != list2->params_len
|| memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
return 0;
/* Don't output an error message if we have already output one for
a parse error above. */
if (nargs == 0 && i > 0)
{
cpp_error (pfile, "arguments given to macro `%s'", name);
}
else if (i < nargs)
{
/* traditional C allows foo() if foo wants one argument. */
if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile))
;
/* the rest args token is allowed to absorb 0 tokens */
else if (i == nargs - 1 && defn->rest_args)
;
else if (i == 0)
cpp_error (pfile, "macro `%s' used without args", name);
else if (i == 1)
cpp_error (pfile, "macro `%s' used with just one arg", name);
else
cpp_error (pfile, "macro `%s' used with only %d args", name, i);
}
else if (i > nargs)
{
cpp_error (pfile, "macro `%s' used with too many (%d) args", name, i);
}
return 1;
}
static void
stringify (pfile, arg)
/* Copy the tokens of the expansion. Change the type of macro
arguments 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 non-zero on error. */
static int
save_expansion (pfile, list, first, first_param)
cpp_reader *pfile;
struct argdata *arg;
cpp_toklist *list;
const cpp_token *first;
const cpp_token *first_param;
{
int arglen = arg->raw_length;
int escaped = 0;
int in_string = 0;
int c;
int i;
/* Initially need_space is -1. Otherwise, 1 means the previous
character was a space, but we suppressed it; 0 means the previous
character was a non-space. */
int need_space = -1;
i = 0;
arg->stringified = CPP_WRITTEN (pfile);
CPP_PUTC (pfile, '\"'); /* insert beginning quote */
for (; i < arglen; i++)
const cpp_token *token;
cpp_token *dest;
unsigned int len, ntokens;
unsigned char *buf;
/* Count tokens in expansion. We drop paste tokens, and stringize
tokens, so don't count them. */
ntokens = len = 0;
for (token = first; token->type != CPP_EOF; token++)
{
c = (ARG_BASE + arg->raw)[i];
const char *msg;
if (!in_string)
if (token->type == CPP_PASTE)
{
/* Delete "\r " and "\r-" escapes. */
if (c == '\r')
{
i++;
continue;
}
/* Internal sequences of whitespace are replaced by one
space except within a string or char token. */
else if (is_space(c))
/* Token-paste ##, but is a normal token if traditional. */
if (! CPP_TRADITIONAL (pfile))
{
if (need_space == 0)
need_space = 1;
msg = "\"##\" cannot appear at either end of a macro expansion";
/* Constraint 6.10.3.3.1 */
if (token == first || token[1].type == CPP_EOF)
goto error;
continue;
}
else if (need_space > 0)
CPP_PUTC (pfile, ' ');
need_space = 0;
}
if (escaped)
escaped = 0;
else
else if (token->type == CPP_HASH)
{
if (c == '\\')
escaped = 1;
if (in_string)
/* Stringifying #, but is a normal character if traditional,
or in object-like macros. Constraint 6.10.3.2.1. */
if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile))
{
if (c == in_string)
in_string = 0;
if (token[1].type == CPP_NAME
&& find_param (first_param, token + 1))
continue;
if (! CPP_OPTION (pfile, lang_asm))
{
msg = "'#' is not followed by a macro parameter";
error:
cpp_error_with_line (pfile, token->line, token->col, msg);
return 1;
}
}
else if (c == '\"' || c == '\'')
in_string = c;
}
/* Escape these chars */
if (c == '\"' || (in_string && c == '\\'))
CPP_PUTC (pfile, '\\');
if (ISPRINT (c))
CPP_PUTC (pfile, c);
else
{
CPP_RESERVE (pfile, 4);
sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", (unsigned int) c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
ntokens++;
if (token_spellings[token->type].type > SPELL_NONE)
len += token->val.name.len;
}
CPP_PUTC (pfile, '\"'); /* insert ending quote */
arg->stringified_length = CPP_WRITTEN (pfile) - arg->stringified;
}
static void
funlike_macroexpand (pfile, hp, args)
cpp_reader *pfile;
cpp_hashnode *hp;
struct argdata *args;
{
const struct funct_defn *defn = hp->value.fdefn;
register U_CHAR *xbuf;
int xbuf_len;
const U_CHAR *exp = defn->expansion;
int offset; /* offset in expansion, copied a piece at a time */
int totlen; /* total amount of exp buffer filled so far */
const struct reflist *ap, *last_ap;
int i;
/* Compute length in characters of the macro's expansion.
Also count number of times each arg is used. */
xbuf_len = defn->length;
for (ap = defn->pattern; ap != NULL; ap = ap->next)
{
if (ap->stringify)
{
/* Stringify if it hasn't already been */
if (args[ap->argno].stringified_length < 0)
stringify (pfile, &args[ap->argno]);
xbuf_len += args[ap->argno].stringified_length;
}
else if (ap->raw_before || ap->raw_after)
/* Add 4 for two \r-space markers to prevent
token concatenation. */
xbuf_len += args[ap->argno].raw_length + 4;
else
{
/* We have an ordinary (expanded) occurrence of the arg.
So compute its expansion, if we have not already. */
if (args[ap->argno].expand_length < 0)
{
args[ap->argno].expanded = CPP_WRITTEN (pfile);
_cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw,
args[ap->argno].raw_length);
/* Allocate space to hold the tokens. Empty expansions are stored
as a single placemarker token. */
if (ntokens == 0)
ntokens++;
_cpp_expand_token_space (list, ntokens);
if (len > 0)
_cpp_expand_name_space (list, len);
args[ap->argno].expand_length
= CPP_WRITTEN (pfile) - args[ap->argno].expanded;
}
dest = list->tokens;
buf = list->namebuf + list->name_used;
for (token = first; token->type != CPP_EOF; token++)
{
unsigned int param_no;
/* Add 4 for two \r-space markers to prevent
token concatenation. */
xbuf_len += args[ap->argno].expand_length + 4;
}
}
switch (token->type)
{
case CPP_NAME:
if (list->paramc == -1)
break;
xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
/* Check if the name is a macro parameter. */
param_no = find_param (first_param, token);
if (param_no == 0)
break;
dest->val.aux = param_no - 1;
/* Generate in XBUF the complete expansion with arguments
substituted in. TOTLEN is the total size generated so far.
OFFSET is the index in the definition of where we are copying
from. */
offset = totlen = 0;
for (last_ap = NULL, ap = defn->pattern; ap != NULL;
last_ap = ap, ap = ap->next)
{
register struct argdata *arg = &args[ap->argno];
int count_before = totlen;
/* Add chars to XBUF. */
i = ap->nchars;
memcpy (&xbuf[totlen], &exp[offset], i);
totlen += i;
offset += i;
/* If followed by an empty rest arg with concatenation,
delete the last run of nonwhite chars. */
if (arg->raw_length == 0 && totlen > count_before
&& ((ap->rest_args && ap->raw_before)
|| (last_ap != NULL && last_ap->rest_args
&& last_ap->raw_after)))
{
/* Delete final whitespace. */
while (totlen > count_before && is_space(xbuf[totlen - 1]))
totlen--;
dest->type = CPP_MACRO_ARG;
if (token[-1].type == CPP_HASH && ! CPP_TRADITIONAL (pfile))
dest->flags = token[-1].flags | STRINGIFY_ARG;
else
dest->flags = token->flags; /* Particularly PREV_WHITE. */
/* Delete the nonwhites before them. */
while (totlen > count_before && !is_space(xbuf[totlen - 1]))
totlen--;
}
if ((int) param_no == list->paramc && list->flags & VAR_ARGS
&& dest != list->tokens && dest[-1].flags & PASTE_LEFT)
dest[-1].flags |= GNU_VARARGS;
dest++;
continue;
if (ap->stringify != 0)
{
memcpy (xbuf + totlen, ARG_BASE + arg->stringified,
arg->stringified_length);
totlen += arg->stringified_length;
}
else if (ap->raw_before || ap->raw_after)
{
U_CHAR *p1 = ARG_BASE + arg->raw;
U_CHAR *l1 = p1 + arg->raw_length;
if (ap->raw_before)
{
/* Arg is concatenated before: delete leading whitespace,
whitespace markers, and no-reexpansion markers. */
while (p1 < l1)
{
if (is_space(p1[0]))
p1++;
else if (p1[0] == '\r')
p1 += 2;
else
break;
}
}
if (ap->raw_after)
case CPP_PASTE:
if (! CPP_TRADITIONAL (pfile))
{
/* Arg is concatenated after: delete trailing whitespace,
whitespace markers, and no-reexpansion markers. */
while (p1 < l1)
{
if (is_space(l1[-1]))
l1--;
else if (l1[-1] == '\r')
l1--;
else if (l1[-1] == '-')
{
if (l1 != p1 + 1 && l1[-2] == '\r')
l1 -= 2;
else
break;
}
else
break;
}
dest[-1].flags |= PASTE_LEFT;
continue;
}
break;
/* Delete any no-reexpansion marker that precedes
an identifier at the beginning of the argument. */
if (p1 + 2 <= l1 && p1[0] == '\r' && p1[1] == '-')
p1 += 2;
case CPP_HASH:
/* Stringifying #. Constraint 6.10.3.2.1 */
if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile)
&& token[1].type == CPP_NAME
&& find_param (first_param, token + 1))
continue;
break;
memcpy (xbuf + totlen, p1, l1 - p1);
totlen += l1 - p1;
default:
break;
}
else
{
U_CHAR *expanded = ARG_BASE + arg->expanded;
if (!ap->raw_before && totlen > 0 && arg->expand_length
&& unsafe_chars (pfile, xbuf[totlen - 1], expanded[0]))
{
xbuf[totlen++] = '\r';
xbuf[totlen++] = ' ';
}
memcpy (xbuf + totlen, expanded, arg->expand_length);
totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length
&& unsafe_chars (pfile, xbuf[totlen - 1], exp[offset]))
{
xbuf[totlen++] = '\r';
xbuf[totlen++] = ' ';
}
/* Copy the token. */
*dest = *token;
if (token_spellings[token->type].type > SPELL_NONE)
{
memcpy (buf, token->val.name.text, token->val.name.len);
dest->val.name.text = buf;
buf += dest->val.name.len;
}
dest++;
}
/* if there is anything left of the definition
after handling the arg list, copy that in too. */
for (i = offset; i < defn->length; i++)
xbuf[totlen++] = exp[i];
xbuf[totlen] = 0;
if (totlen > xbuf_len)
/* Just die - we've trashed the heap at this point. */
abort ();
/* Now put the expansion on the input stack
so our caller will commence reading from it. */
push_macro_expansion (pfile, xbuf, totlen, hp);
/* Overload buffer->mapped to indicate that xbuf needs to be freed. */
CPP_BUFFER (pfile)->mapped = 1;
}
/* Return 1 iff a token ending in C1 followed directly by a token C2
could cause mis-tokenization. */
static int
unsafe_chars (pfile, c1, c2)
cpp_reader *pfile;
int c1, c2;
{
/* If c2 is EOF, that's always safe. */
if (c2 == EOF)
return 0;
switch (c1)
if (dest == list->tokens)
{
case EOF:
/* We don't know what the previous character was. We do know
that it can't have been an idchar (or else it would have been
pasted with the idchars of the macro name), and there are a
number of second characters for which it doesn't matter what
the first was. */
if (is_idchar (c2) || c2 == '\'' || c2 == '\"'
|| c2 == '(' || c2 == '[' || c2 == '{'
|| c2 == ')' || c2 == ']' || c2 == '}')
return 0;
return 1;
case '+': case '-':
if (c2 == c1 || c2 == '=')
return 1;
goto letter;
case 'e': case 'E': case 'p': case 'P':
if (c2 == '-' || c2 == '+')
return 1; /* could extend a pre-processing number */
goto letter;
case '$':
if (CPP_OPTION (pfile, dollars_in_ident))
goto letter;
return 0;
case 'L':
if (c2 == '\'' || c2 == '\"')
return 1; /* Could turn into L"xxx" or L'xxx'. */
goto letter;
case '.': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '8': case '9':
case '_': case 'a': case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'q': case 'r': case 's':
case 't': case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z': case 'A': case 'B': case 'C': case 'D': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'M':
case 'N': case 'O': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
letter:
/* We're in the middle of either a name or a pre-processing number. */
return (is_idchar(c2) || c2 == '.');
case '<': case '>': case '!': case '%': case '#': case ':':
case '^': case '&': case '|': case '*': case '/': case '=':
return (c2 == c1 || c2 == '=');
dest->type = CPP_PLACEMARKER;
dest->flags = 0;
}
list->tokens_used = ntokens;
list->line = pfile->token_list.line;
list->file = pfile->token_list.file;
list->name_used = len;
return 0;
}
static void
push_macro_expansion (pfile, xbuf, len, hp)
int
_cpp_create_definition (pfile, hp)
cpp_reader *pfile;
const U_CHAR *xbuf;
int len;
cpp_hashnode *hp;
{
cpp_buffer *mbuf;
int advance_cur = 0;
/* The first chars of the expansion should be a "\r " added by
collect_expansion. This is to prevent accidental token-pasting
between the text preceding the macro invocation, and the macro
expansion text.
We would like to avoid adding unneeded spaces (for the sake of
tools that use cpp, such as imake). In some common cases we can
tell that it is safe to omit the space. */
if (xbuf[0] == '\r' && xbuf[1] == ' '
&& !unsafe_chars (pfile, EOF, xbuf[2]))
advance_cur = 1;
/* Likewise, avoid the extra space at the end of the macro expansion
if this is safe. We can do a better job here since we can know
what the next char will be. */
if (len >= 3 && xbuf[len-2] == '\r' && xbuf[len-1] == ' '
&& !unsafe_chars (pfile, xbuf[len-3], CPP_BUF_PEEK (CPP_BUFFER (pfile))))
len -= 2;
/* If the total expansion is "\r \r ", we must not trim both escapes. */
if (len == 2 && advance_cur)
advance_cur = 0;
mbuf = cpp_push_buffer (pfile, xbuf, len);
if (mbuf == NULL)
return;
if (advance_cur)
mbuf->cur += 2;
mbuf->macro = hp;
mbuf->has_escapes = 1;
/* In C89, a macro cannot be expanded recursively. Traditional C
permits it, but any use in an object-like macro must lead to
infinite recursion, so always follow C89 in object-like macros.
Likewise, in a function-like macro it must cause infinite
recursion unless we are actually doing something with the
arguments.
Even that criterion is too weak. The only example known where
macro recursion isn't infinite is:
#define bar(x,y) foo(x(y, 0))
bar(bar, baz)
which expands to foo(bar(baz, 0)) in C89 and
foo(foo(baz(0, 0)) in K+R. This looks pathological to me.
If someone has a real-world example I would love to see it. */
if (hp->type != T_FMACRO
|| hp->value.fdefn->nargs == 0
|| hp->value.fdefn->pattern == 0
|| !CPP_TRADITIONAL (pfile))
hp->disabled = 1;
}
cpp_toklist *list;
/* Return zero if two funct_defns are isomorphic. */
list = parse_define (pfile);
if (!list)
return 0;
static int
compare_defs (pfile, d1, d2)
cpp_reader *pfile;
const struct funct_defn *d1, *d2;
{
const struct reflist *a1, *a2;
if (d1->nargs != d2->nargs)
return 1;
if (ustrcmp (d1->expansion, d2->expansion))
return 1;
if (CPP_PEDANTIC (pfile)
&& d1->argnames && d2->argnames)
/* Check for a redefinition. Redefinition of a macro is allowed if
and only if the old and new definitions are the same.
(6.10.3 paragraph 2). */
if (hp->type != T_VOID)
{
U_CHAR *arg1 = d1->argnames;
U_CHAR *arg2 = d2->argnames;
size_t len;
int i = d1->nargs;
while (i--)
if (!check_macro_redefinition (pfile, hp, list))
{
len = ustrlen (arg1) + 1;
if (ustrcmp (arg1, arg2))
return 1;
arg1 += len;
arg2 += len;
cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
if (pfile->done_initializing && hp->type == T_MACRO)
cpp_pedwarn_with_file_and_line (pfile,
hp->value.expansion->file,
hp->value.expansion->line, 1,
"this is the location of the previous definition");
}
_cpp_free_definition (hp);
}
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next)
{
if (a1->nchars != a2->nchars
|| a1->argno != a2->argno
|| a1->stringify != a2->stringify
|| a1->raw_before != a2->raw_before
|| a1->raw_after != a2->raw_after)
return 1;
}
if (a1 != a2)
return 1;
return 0;
/* Enter definition in hash table. */
hp->type = T_MACRO;
hp->value.expansion = list;
return 1;
}
/* Dump the definition of macro MACRO on stdout. The format is suitable
......@@ -1846,97 +610,56 @@ _cpp_dump_definition (pfile, hp)
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
CPP_PUTS_Q (pfile, hp->name, hp->length);
if (hp->type == T_EMPTY)
/* do nothing */;
else if (hp->type == T_FMACRO)
dump_funlike_macro (pfile, hp->value.fdefn);
else
if (hp->type == T_MACRO)
{
CPP_PUTC_Q (pfile, ' ');
if (hp->type == T_IDENTITY)
CPP_PUTS (pfile, hp->name, hp->length);
else if (hp->type == T_MACRO)
if (hp->value.expansion->paramc >= 0)
dump_funlike_macro (pfile, hp);
else
{
/* The first and last two characters of a macro expansion are
always "\r "; this needs to be trimmed out.
So we need length-4 chars of space, plus one for the NUL. */
CPP_RESERVE (pfile, hp->value.odefn->length - 4 + 1);
CPP_PUTS_Q (pfile, hp->value.odefn->expansion + 2,
hp->value.odefn->length - 4);
const cpp_toklist *list = hp->value.expansion;
list->tokens[0].flags &= ~BOL;
list->tokens[0].flags |= PREV_WHITE;
_cpp_dump_list (pfile, list, list->tokens, 1);
}
else
cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
}
else
cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type);
if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
CPP_PUTC (pfile, '\n');
}
static void
dump_funlike_macro (pfile, defn)
dump_funlike_macro (pfile, node)
cpp_reader *pfile;
const struct funct_defn *defn;
cpp_hashnode *node;
{
const struct reflist *r;
const U_CHAR **argv = (const U_CHAR **) alloca (defn->nargs *
sizeof(const U_CHAR *));
int *argl = (int *) alloca (defn->nargs * sizeof(int));
const U_CHAR *x;
int i;
/* First extract the argument list. */
x = defn->argnames;
for (i = 0; i < defn->nargs; i++)
{
argv[i] = x;
argl[i] = ustrlen (x);
x += argl[i] + 1;
}
/* Now print out the argument list. */
int i = 0;
const cpp_toklist * list = node->value.expansion;
const U_CHAR *param;
param = list->namebuf;
CPP_PUTC_Q (pfile, '(');
for (i = 0; i < defn->nargs; i++)
for (i = 0; i++ < list->paramc;)
{
CPP_RESERVE (pfile, argl[i] + 2);
if (!(i == defn->nargs-1 && defn->rest_args
&& !ustrcmp (argv[i], U"__VA_ARGS__")))
CPP_PUTS_Q (pfile, argv[i], argl[i]);
if (i < defn->nargs-1)
CPP_PUTS_Q (pfile, ", ", 2);
}
if (defn->rest_args)
CPP_PUTS (pfile, "...", 3);
CPP_PUTS (pfile, ") ", 2);
unsigned int len;
/* Now the definition. */
x = defn->expansion;
for (r = defn->pattern; r; r = r->next)
{
i = r->nchars;
if (*x == '\r') x += 2, i -= 2;
/* i chars for macro text, plus the length of the macro
argument name, plus one for a stringify marker, plus two for
each concatenation marker. */
CPP_RESERVE (pfile,
i + argl[r->argno] + r->stringify
+ (r->raw_before + r->raw_after) * 2);
if (i > 0) CPP_PUTS_Q (pfile, x, i);
if (r->raw_before)
CPP_PUTS_Q (pfile, "##", 2);
if (r->stringify)
CPP_PUTC_Q (pfile, '#');
CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]);
if (r->raw_after && !(r->next && r->next->nchars == 0
&& r->next->raw_before))
CPP_PUTS_Q (pfile, "##", 2);
x += i;
len = ustrlen (param);
CPP_PUTS (pfile, param, len);
if (i < list->paramc)
CPP_PUTS(pfile, ", ", 2);
else if (list->flags & VAR_ARGS)
{
if (!ustrcmp (param, var_args_str))
pfile->limit -= sizeof (var_args_str) - 1;
CPP_PUTS (pfile, "...", 3);
}
param += len + 1;
}
i = defn->length - (x - defn->expansion) - 2;
if (*x == '\r') x += 2, i -= 2;
if (i > 0) CPP_PUTS (pfile, x, i);
CPP_PUTC (pfile, ')');
list->tokens[0].flags &= ~BOL;
list->tokens[0].flags |= PREV_WHITE;
_cpp_dump_list (pfile, list, list->tokens, 1);
}
/* Dump out the hash table. */
......@@ -1948,8 +671,7 @@ dump_hash_helper (h, p)
cpp_hashnode *hp = (cpp_hashnode *)*h;
cpp_reader *pfile = (cpp_reader *)p;
if (hp->type == T_MACRO || hp->type == T_FMACRO
|| hp->type == T_IDENTITY || hp->type == T_EMPTY)
if (hp->type == T_MACRO)
_cpp_dump_definition (pfile, hp);
return 1;
}
......
......@@ -25,11 +25,60 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
typedef unsigned char U_CHAR;
#define U (const U_CHAR *) /* Intended use: U"string" */
/* Structure used for assertion predicates. */
struct predicate
/* Order here matters. Those beyond SPELL_NONE store their spelling
in the token list, and it's length in the token->val.name.len. */
enum spell_type
{
struct predicate *next;
struct cpp_toklist answer;
SPELL_OPERATOR = 0,
SPELL_CHAR,
SPELL_NONE,
SPELL_IDENT,
SPELL_STRING
};
struct token_spelling
{
ENUM_BITFIELD(spell_type) type : CHAR_BIT;
const U_CHAR *spelling;
};
extern const struct token_spelling token_spellings[];
/* 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. */
#define COND (1 << 0)
#define EXPAND (1 << 1)
#define INCL (1 << 2)
#define COMMENTS (1 << 3)
/* Defines one #-directive, including how to handle it. */
typedef int (*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. */
......@@ -105,12 +154,6 @@ extern unsigned char _cpp_IStable[256];
/* Macros. */
/* One character lookahead in the input buffer. Note that if this
returns EOF, it does *not* necessarily mean the file's end has been
reached. */
#define CPP_BUF_PEEK(BUFFER) \
((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur : EOF)
/* Make sure PFILE->token_buffer has space for at least N more characters. */
#define CPP_RESERVE(PFILE, N) \
(CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \
......@@ -127,53 +170,15 @@ extern unsigned char _cpp_IStable[256];
/* Append character CH to PFILE's output buffer. Make space if need be. */
#define CPP_PUTC(PFILE, CH) (CPP_RESERVE (PFILE, 1), CPP_PUTC_Q (PFILE, CH))
/* Advance the current line by one. */
#define CPP_BUMP_BUFFER_LINE(PBUF) ((PBUF)->lineno++,\
(PBUF)->line_base = (PBUF)->cur)
#define CPP_BUMP_LINE(PFILE) CPP_BUMP_BUFFER_LINE(CPP_BUFFER(PFILE))
#define CPP_BUMP_BUFFER_LINE_CUR(PBUF, CUR) ((PBUF)->lineno++,\
(PBUF)->line_base = CUR)
#define CPP_BUMP_LINE_CUR(PFILE, CUR) \
CPP_BUMP_BUFFER_LINE_CUR(CPP_BUFFER(PFILE), CUR)
#define CPP_PREV_BUFFER(BUFFER) ((BUFFER)->prev)
/* Are we in column 1 right now? Used mainly for -traditional handling
of directives. */
#define CPP_IN_COLUMN_1(PFILE) \
(CPP_BUFFER (PFILE)->cur - CPP_BUFFER (PFILE)->line_base == 1)
#define CPP_PRINT_DEPS(PFILE) CPP_OPTION (PFILE, print_deps)
#define CPP_TRADITIONAL(PFILE) CPP_OPTION (PFILE, traditional)
#define CPP_IN_SYSTEM_HEADER(PFILE) (cpp_file_buffer (PFILE)->inc->sysp)
#define CPP_IN_SYSTEM_HEADER(PFILE) (CPP_BUFFER (PFILE)->inc->sysp)
#define CPP_PEDANTIC(PF) \
(CPP_OPTION (PF, pedantic) && !CPP_IN_SYSTEM_HEADER (PF))
#define CPP_WTRADITIONAL(PF) \
(CPP_OPTION (PF, warn_traditional) && !CPP_IN_SYSTEM_HEADER (PF))
/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion.
(Note that it is false while we're expanding macro *arguments*.) */
#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->macro != NULL)
/* Remember the current position of PFILE so it may be returned to
after looking ahead a bit.
Note that when you set a mark, you _must_ return to that mark. You
may not forget about it and continue parsing. You may not pop a
buffer with an active mark. You may not call CPP_BUMP_LINE while a
mark is active. */
#define CPP_SET_BUF_MARK(IP) ((IP)->mark = (IP)->cur)
#define CPP_GOTO_BUF_MARK(IP) ((IP)->cur = (IP)->mark, (IP)->mark = 0)
#define CPP_SET_MARK(PFILE) CPP_SET_BUF_MARK(CPP_BUFFER(PFILE))
#define CPP_GOTO_MARK(PFILE) CPP_GOTO_BUF_MARK(CPP_BUFFER(PFILE))
/* ACTIVE_MARK_P is true if there's a live mark in the buffer. */
#define ACTIVE_MARK_P(PFILE) (CPP_BUFFER (PFILE)->mark != 0)
/* Are mark and point adjacent characters? Used mostly to deal with
the somewhat annoying semantic of #define. */
#define ADJACENT_TO_MARK(PFILE) \
(CPP_BUFFER(PFILE)->cur - CPP_BUFFER(PFILE)->mark == 1)
/* Flags for _cpp_init_toklist. */
#define DUMMY_TOKEN 0
#define NO_DUMMY_TOKEN 1
......@@ -181,22 +186,19 @@ extern unsigned char _cpp_IStable[256];
/* In cpphash.c */
extern unsigned int _cpp_calc_hash PARAMS ((const U_CHAR *, size_t));
extern void _cpp_free_definition PARAMS ((cpp_hashnode *));
extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_toklist *,
cpp_hashnode *));
extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *));
extern void _cpp_dump_definition PARAMS ((cpp_reader *, cpp_hashnode *));
extern void _cpp_quote_string PARAMS ((cpp_reader *, const U_CHAR *));
extern void _cpp_macroexpand PARAMS ((cpp_reader *, cpp_hashnode *));
extern void _cpp_init_macro_hash PARAMS ((cpp_reader *));
extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *));
/* In cppfiles.c */
extern void _cpp_simplify_pathname PARAMS ((char *));
extern void _cpp_execute_include PARAMS ((cpp_reader *, U_CHAR *,
extern void _cpp_execute_include PARAMS ((cpp_reader *, const U_CHAR *,
unsigned int, int,
struct file_name_list *));
extern int _cpp_compare_file_date PARAMS ((cpp_reader *, U_CHAR *,
unsigned int,
struct file_name_list *));
struct file_name_list *,
int));
extern int _cpp_compare_file_date PARAMS ((cpp_reader *, const U_CHAR *,
unsigned int, int));
extern void _cpp_init_include_table PARAMS ((cpp_reader *));
extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *));
......@@ -204,40 +206,46 @@ extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *));
extern int _cpp_parse_expr PARAMS ((cpp_reader *));
/* In cpplex.c */
extern void _cpp_parse_name PARAMS ((cpp_reader *, int));
extern void _cpp_skip_rest_of_line PARAMS ((cpp_reader *));
extern void _cpp_skip_hspace PARAMS ((cpp_reader *));
extern void _cpp_expand_to_buffer PARAMS ((cpp_reader *,
const unsigned char *, int));
extern int _cpp_parse_assertion PARAMS ((cpp_reader *));
extern enum cpp_ttype _cpp_lex_token PARAMS ((cpp_reader *));
extern ssize_t _cpp_prescan PARAMS ((cpp_reader *, cpp_buffer *,
ssize_t));
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 enum cpp_ttype _cpp_get_directive_token
PARAMS ((cpp_reader *));
extern enum cpp_ttype _cpp_get_define_token
PARAMS ((cpp_reader *));
extern enum cpp_ttype _cpp_scan_until PARAMS ((cpp_reader *, cpp_toklist *,
enum cpp_ttype));
extern void _cpp_init_toklist PARAMS ((cpp_toklist *, int));
extern void _cpp_clear_toklist PARAMS ((cpp_toklist *));
extern void _cpp_free_toklist PARAMS ((cpp_toklist *));
extern void _cpp_slice_toklist PARAMS ((cpp_toklist *,
const cpp_token *,
const cpp_token *));
extern void _cpp_squeeze_toklist PARAMS ((cpp_toklist *));
extern void _cpp_free_toklist PARAMS ((const cpp_toklist *));
extern int _cpp_equiv_tokens PARAMS ((const cpp_token *,
const cpp_token *));
extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *,
const cpp_toklist *));
extern void _cpp_expand_token_space PARAMS ((cpp_toklist *, unsigned int));
extern void _cpp_reserve_name_space PARAMS ((cpp_toklist *, unsigned int));
extern void _cpp_expand_name_space PARAMS ((cpp_toklist *, unsigned int));
extern void _cpp_dump_list PARAMS ((cpp_reader *,
const cpp_toklist *,
const cpp_token *, int));
extern int _cpp_equiv_tokens PARAMS ((const cpp_token *,
const cpp_token *));
extern void _cpp_run_directive PARAMS ((cpp_reader *,
const struct directive *,
const char *, size_t));
extern unsigned int _cpp_get_line PARAMS ((cpp_reader *,
unsigned int *));
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 *));
/* In cpplib.c */
extern int _cpp_handle_directive PARAMS ((cpp_reader *));
extern const struct directive *_cpp_check_directive
PARAMS ((cpp_reader *, const cpp_token *, int));
extern const struct directive *_cpp_check_linemarker
PARAMS ((cpp_reader *, const cpp_token *, int));
extern void _cpp_unwind_if_stack PARAMS ((cpp_reader *, cpp_buffer *));
extern void _cpp_check_directive PARAMS ((cpp_toklist *, cpp_token *));
extern cpp_hashnode * _cpp_parse_assertion PARAMS ((cpp_reader *,
struct answer **));
extern struct answer** find_answer PARAMS ((cpp_hashnode *,
const cpp_toklist *));
/* Utility routines and macros. */
#define xnew(T) (T *) xmalloc (sizeof(T))
......
......@@ -215,8 +215,6 @@ static void append_include_chain PARAMS ((cpp_reader *,
char *, int, int));
static void merge_include_chains PARAMS ((cpp_reader *));
static void dump_special_to_buffer PARAMS ((cpp_reader *, const U_CHAR *,
size_t));
static void initialize_dependency_output PARAMS ((cpp_reader *));
static void initialize_standard_includes PARAMS ((cpp_reader *));
static void new_pending_directive PARAMS ((struct cpp_pending *,
......@@ -345,7 +343,7 @@ append_include_chain (pfile, pend, dir, path, cxx_aware)
if (errno != ENOENT)
cpp_notice_from_errno (pfile, dir);
else if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring nonexistent directory `%s'\n"), dir);
fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
return;
}
......@@ -442,7 +440,7 @@ merge_include_chains (pfile)
&& cur->dev == other->dev)
{
if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"),
fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
cur->name);
prev->next = cur->next;
......@@ -462,7 +460,7 @@ merge_include_chains (pfile)
&& cur->dev == other->dev)
{
if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"),
fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
cur->name);
prev->next = cur->next;
......@@ -481,7 +479,7 @@ merge_include_chains (pfile)
if (quote == qtail)
{
if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"),
fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
quote->name);
free (quote->name);
......@@ -495,7 +493,7 @@ merge_include_chains (pfile)
cur = cur->next;
cur->next = brack;
if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"),
fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
qtail->name);
free (qtail->name);
......@@ -513,24 +511,6 @@ merge_include_chains (pfile)
}
/* Write out a #define command for the special named MACRO_NAME
to PFILE's token_buffer. */
static void
dump_special_to_buffer (pfile, macro_name, macro_len)
cpp_reader *pfile;
const U_CHAR *macro_name;
size_t macro_len;
{
static const char define_directive[] = "#define ";
CPP_RESERVE (pfile, sizeof(define_directive) + macro_len);
CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1);
CPP_PUTS_Q (pfile, macro_name, macro_len);
CPP_PUTC_Q (pfile, ' ');
_cpp_expand_to_buffer (pfile, macro_name, macro_len);
CPP_PUTC (pfile, '\n');
}
/* Initialize a cpp_reader structure. */
void
cpp_reader_init (pfile)
......@@ -545,6 +525,7 @@ cpp_reader_init (pfile)
CPP_OPTION (pfile, dollars_in_ident) = 1;
CPP_OPTION (pfile, cplusplus_comments) = 1;
CPP_OPTION (pfile, warn_import) = 1;
CPP_OPTION (pfile, warn_paste) = 1;
CPP_OPTION (pfile, discard_comments) = 1;
CPP_OPTION (pfile, show_column) = 1;
CPP_OPTION (pfile, tabstop) = 8;
......@@ -596,25 +577,19 @@ cpp_cleanup (pfile)
pfile->token_buffer = NULL;
}
if (pfile->input_buffer)
{
free (pfile->input_buffer);
pfile->input_buffer = NULL;
pfile->input_buffer_len = 0;
}
if (pfile->deps)
deps_free (pfile->deps);
htab_delete (pfile->hashtab);
splay_tree_delete (pfile->all_include_files);
_cpp_free_temp_tokens (pfile);
}
/* This structure defines one built-in macro. A node of type TYPE will
be entered in the macro hash table under the name NAME, with value
VALUE (if any). FLAGS tweaks the behavior a little:
DUMP write debug info for this macro
VALUE (if any). Two values are not compile time constants, so we tag
them in the FLAGS field instead:
VERS value is the global version_string, quoted
ULP value is the global user_label_prefix
*/
......@@ -622,18 +597,17 @@ cpp_cleanup (pfile)
struct builtin
{
const U_CHAR *name;
const U_CHAR *value;
const char *value;
unsigned short type;
unsigned short flags;
unsigned int len;
};
#define DUMP 0x01
#define VERS 0x02
#define ULP 0x04
#define VERS 0x01
#define ULP 0x02
#define B(n, t) { U n, 0, t, 0, sizeof n - 1 }
#define C(n, v) { U n, U v, T_CONST, DUMP, sizeof n - 1 }
#define X(n, v, t, f) { U n, U v, t, DUMP|f, sizeof n - 1 }
#define B(n, t) { U n, 0, t, 0, sizeof n - 1 }
#define C(n, v) { U n, v, T_MACRO, 0, sizeof n - 1 }
#define X(n, f) { U n, 0, T_MACRO, f, sizeof n - 1 }
static const struct builtin builtin_array[] =
{
B("__TIME__", T_TIME),
......@@ -642,10 +616,10 @@ static const struct builtin builtin_array[] =
B("__BASE_FILE__", T_BASE_FILE),
B("__LINE__", T_SPECLINE),
B("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL),
B("__STDC__", T_STDC),
X("__VERSION__", 0, T_XCONST, VERS),
X("__USER_LABEL_PREFIX__", 0, T_CONST, ULP),
X("__STDC__", "1", T_STDC, 0),
X("__VERSION__", VERS),
X("__USER_LABEL_PREFIX__", ULP),
C("__REGISTER_PREFIX__", REGISTER_PREFIX),
C("__HAVE_BUILTIN_SETJMP__", "1"),
#ifndef NO_BUILTIN_SIZE_TYPE
......@@ -671,35 +645,47 @@ initialize_builtins (pfile)
cpp_reader *pfile;
{
const struct builtin *b;
const U_CHAR *val;
cpp_hashnode *hp;
for(b = builtin_array; b < builtin_array_end; b++)
{
if (b->type == T_STDC && CPP_TRADITIONAL (pfile))
continue;
if (b->flags & ULP)
val = (const U_CHAR *) user_label_prefix;
else if (b->flags & VERS)
if (b->type == T_MACRO)
{
val = (const U_CHAR *) xmalloc (strlen (version_string) + 3);
sprintf ((char *)val, "\"%s\"", version_string);
const char *val;
char *str;
if (b->flags & VERS)
{
/* Allocate enough space for 'name="value"\0'. */
str = xmalloc (b->len + strlen (version_string) + 4);
sprintf (str, "%s=\"%s\"", b->name, version_string);
}
else
{
if (b->flags & ULP)
val = user_label_prefix;
else
val = b->value;
/* Allocate enough space for "name=value\0". */
str = xmalloc (b->len + strlen (val) + 2);
sprintf(str, "%s=%s", b->name, val);
}
cpp_define (pfile, str);
}
else
val = b->value;
hp = cpp_lookup (pfile, b->name, b->len);
hp->value.cpval = val;
hp->type = b->type;
{
cpp_hashnode *hp;
if (b->type == T_STDC && CPP_TRADITIONAL (pfile))
continue;
if ((b->flags & DUMP) && CPP_OPTION (pfile, debug_output))
dump_special_to_buffer (pfile, b->name, b->len);
hp = cpp_lookup (pfile, b->name, b->len);
hp->type = b->type;
}
}
}
#undef DUMP
#undef STDC
#undef VERS
#undef ULP
#undef builtin_array_end
/* Another subroutine of cpp_start_read. This one sets up to do
dependency-file output. */
......@@ -889,6 +875,13 @@ cpp_start_read (pfile, print, fname)
if (CPP_OPTION (pfile, cplusplus))
CPP_OPTION (pfile, warn_traditional) = 0;
/* Do not warn about illegal token pasting if -traditional,
-lang-fortran, or -lang-asm. */
if (CPP_OPTION (pfile, traditional)
|| CPP_OPTION (pfile, lang_fortran)
|| CPP_OPTION (pfile, lang_asm))
CPP_OPTION (pfile, warn_paste) = 0;
/* Set this if it hasn't been set already. */
if (user_label_prefix == NULL)
user_label_prefix = USER_LABEL_PREFIX;
......@@ -898,6 +891,16 @@ cpp_start_read (pfile, print, fname)
if (CPP_OPTION (pfile, preprocessed))
pfile->no_macro_expand++;
/* 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 IStable. This doesn't do anything if we were compiled
with a compiler that supports C99 designated initializers. */
init_IStable ();
......@@ -946,13 +949,12 @@ cpp_start_read (pfile, print, fname)
as line 0. */
CPP_BUFFER (pfile)->lineno = 0;
if (print)
{
print->lineno = 0;
print->last_fname = CPP_BUFFER (pfile)->nominal_fname;
print->last_id = pfile->include_depth;
print->written = CPP_WRITTEN (pfile);
print->lineno = 0;
}
/* Install __LINE__, etc. */
......@@ -968,10 +970,13 @@ cpp_start_read (pfile, print, fname)
p = q;
}
pfile->done_initializing = 1;
pfile->only_seen_white = 2;
/* Now flush any output recorded during initialization, and advance
to line 1 of the main input file. */
CPP_BUFFER (pfile)->lineno = 1;
if (print && ! CPP_OPTION (pfile, no_output))
cpp_output_tokens (pfile, print);
cpp_output_tokens (pfile, print, 1);
/* The -imacros files can be scanned now, but the -include files
have to be pushed onto the include stack and processed later,
......@@ -992,7 +997,7 @@ cpp_start_read (pfile, print, fname)
{
if (cpp_read_file (pfile, p->arg)
&& print && ! CPP_OPTION (pfile, no_output))
cpp_output_tokens (pfile, print);
cpp_output_tokens (pfile, print, 1); /* record entry to file */
q = p->next;
free (p);
p = q;
......@@ -1073,7 +1078,7 @@ cpp_finish (pfile, print)
/* Flush any pending output. */
if (print)
{
cpp_output_tokens (pfile, print);
cpp_output_tokens (pfile, print, print->lineno);
if (ferror (print->outf) || fclose (print->outf))
cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname));
}
......@@ -1753,6 +1758,8 @@ handle_option (pfile, argc, argv)
CPP_OPTION (pfile, warn_undef) = 1;
else if (!strcmp (argv[i], "-Wimport"))
CPP_OPTION (pfile, warn_import) = 1;
else if (!strcmp (argv[i], "-Wpaste"))
CPP_OPTION (pfile, warn_paste) = 1;
else if (!strcmp (argv[i], "-Werror"))
CPP_OPTION (pfile, warnings_are_errors) = 1;
else if (!strcmp (argv[i], "-Wno-traditional"))
......@@ -1767,6 +1774,8 @@ handle_option (pfile, argc, argv)
CPP_OPTION (pfile, warn_undef) = 0;
else if (!strcmp (argv[i], "-Wno-import"))
CPP_OPTION (pfile, warn_import) = 0;
else if (!strcmp (argv[i], "-Wno-paste"))
CPP_OPTION (pfile, warn_paste) = 0;
else if (!strcmp (argv[i], "-Wno-error"))
CPP_OPTION (pfile, warnings_are_errors) = 0;
break;
......@@ -1836,10 +1845,10 @@ Switches:\n\
(dirs specified with -isystem will still be used)\n\
-nostdinc++ Do not search system include directories for C++\n\
-o <file> Put output into <file>\n\
-pedantic Issue all warnings demanded by strict ANSI C\n\
-pedantic Issue all warnings demanded by strict ISO C\n\
-pedantic-errors Issue -pedantic warnings as errors instead\n\
-traditional Follow K&R pre-processor behaviour\n\
-trigraphs Support ANSI C trigraphs\n\
-trigraphs Support ISO C trigraphs\n\
-lang-c Assume that the input sources are in C\n\
-lang-c89 Assume that the input sources are in C89\n\
-lang-c++ Assume that the input sources are in C++\n\
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -27,23 +27,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "intl.h"
#include "symcat.h"
/* `struct directive' defines one #-directive, including how to handle it. */
struct directive
{
directive_handler func; /* Function to handle directive. */
const U_CHAR *name; /* Name of directive. */
unsigned short length; /* Length of name. */
unsigned short flags; /* Flags describing this directive. */
};
/* Stack of conditionals currently in progress
(including both successful and failing conditionals). */
struct if_stack
{
struct if_stack *next;
int lineno; /* line number where condition started */
unsigned int lineno; /* line number where condition started */
unsigned int colno; /* and column */
int was_skipping; /* value of pfile->skipping before this if */
const cpp_hashnode *cmacro; /* macro name for #ifndef around entire file */
int type; /* type of last directive seen in this group */
......@@ -51,30 +42,26 @@ struct if_stack
/* Forward declarations. */
static void validate_else PARAMS ((cpp_reader *, const U_CHAR *));
static unsigned int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int));
static void push_conditional PARAMS ((cpp_reader *, int, int,
const cpp_hashnode *));
static void pass_thru_directive PARAMS ((const U_CHAR *, size_t,
cpp_reader *, int));
static int read_line_number PARAMS ((cpp_reader *, int *));
static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *));
static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *));
/* Values for the flags field of the table below. KANDR and COND
directives come from traditional (K&R) C. The difference is, if we
care about it while skipping a failed conditional block, its origin
is COND. STDC89 directives come from the 1989 C standard.
EXTENSION directives are extensions, with origins noted below. */
static void validate_else PARAMS ((cpp_reader *, const U_CHAR *));
static int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int,
const U_CHAR **, unsigned int *,
int *));
static void push_conditional PARAMS ((cpp_reader *, int, int,
const cpp_hashnode *));
static void pass_thru_directive PARAMS ((cpp_reader *));
static int read_line_number PARAMS ((cpp_reader *, int *));
static int strtoul_for_line PARAMS ((const U_CHAR *, unsigned int,
unsigned long *));
#define KANDR 0
#define COND 1
#define STDC89 2
#define EXTENSION 3
static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *));
static const cpp_hashnode *detect_if_not_defined
PARAMS ((cpp_reader *));
static cpp_hashnode *get_define_node PARAMS ((cpp_reader *));
static void dump_macro_name PARAMS ((cpp_reader *, cpp_hashnode *));
#define ORIGIN_MASK 3
#define ORIGIN(f) ((f) & ORIGIN_MASK)
#define TRAD_DIRECT_P(f) (ORIGIN (f) == KANDR || ORIGIN (f) == COND)
/* Utility. */
#define str_match(sym, len, str) \
((len) == (sizeof (str) - 1) && !ustrncmp ((sym), U(str), sizeof (str) - 1))
/* This is the table of directive handlers. It is ordered by
frequency of occurrence; the numbers at the end are directive
......@@ -88,31 +75,31 @@ static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *));
/* #sccs is not always recognized. */
#ifdef SCCS_DIRECTIVE
# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION) /* 0 - SVR2? */
# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION, 0)
#else
# define SCCS_ENTRY /* nothing */
#endif
#define DIRECTIVE_TABLE \
D(define, T_DEFINE = 0, KANDR) /* 270554 */ \
D(include, T_INCLUDE, KANDR | SYNTAX_INCLUDE) /* 52262 */ \
D(endif, T_ENDIF, COND) /* 45855 */ \
D(ifdef, T_IFDEF, COND) /* 22000 */ \
D(if, T_IF, COND) /* 18162 */ \
D(else, T_ELSE, COND) /* 9863 */ \
D(ifndef, T_IFNDEF, COND) /* 9675 */ \
D(undef, T_UNDEF, KANDR) /* 4837 */ \
D(line, T_LINE, KANDR) /* 2465 */ \
D(elif, T_ELIF, COND) /* 610 */ \
D(error, T_ERROR, STDC89) /* 475 */ \
D(pragma, T_PRAGMA, STDC89) /* 195 */ \
D(warning, T_WARNING, EXTENSION) /* 22 GNU */ \
D(include_next, T_INCLUDE_NEXT, EXTENSION | SYNTAX_INCLUDE) /* 19 GNU */ \
D(ident, T_IDENT, EXTENSION) /* 11 SVR4 */ \
D(import, T_IMPORT, EXTENSION | SYNTAX_INCLUDE) /* 0 ObjC */ \
D(assert, T_ASSERT, EXTENSION) /* 0 SVR4 */ \
D(unassert, T_UNASSERT, EXTENSION) /* 0 SVR4 */ \
SCCS_ENTRY
#define DIRECTIVE_TABLE \
D(define, T_DEFINE = 0, KANDR, COMMENTS) /* 270554 */ \
D(include, T_INCLUDE, KANDR, EXPAND | INCL) /* 52262 */ \
D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \
D(ifdef, T_IFDEF, KANDR, COND) /* 22000 */ \
D(if, T_IF, KANDR, COND | EXPAND) /* 18162 */ \
D(else, T_ELSE, KANDR, COND) /* 9863 */ \
D(ifndef, T_IFNDEF, KANDR, COND) /* 9675 */ \
D(undef, T_UNDEF, KANDR, 0) /* 4837 */ \
D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \
D(elif, T_ELIF, KANDR, COND | EXPAND) /* 610 */ \
D(error, T_ERROR, STDC89, 0) /* 475 */ \
D(pragma, T_PRAGMA, STDC89, 0) /* 195 */ \
D(warning, T_WARNING, EXTENSION, 0) /* 22 GNU */ \
D(include_next, T_INCLUDE_NEXT, EXTENSION, EXPAND | INCL) /* 19 GNU */ \
D(ident, T_IDENT, EXTENSION, 0) /* 11 SVR4 */ \
D(import, T_IMPORT, EXTENSION, EXPAND | INCL) /* 0 ObjC */ \
D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \
D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \
SCCS_ENTRY /* 0 SVR2? */
/* Use the table to generate a series of prototypes, an enum for the
directive names, and an array of directive handlers. */
......@@ -122,11 +109,11 @@ SCCS_ENTRY
pointers to functions returning void. */
/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */
#define D(name, t, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *));
#define D(name, t, o, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *));
DIRECTIVE_TABLE
#undef D
#define D(n, tag, f) tag,
#define D(n, tag, o, f) tag,
enum
{
DIRECTIVE_TABLE
......@@ -135,9 +122,9 @@ enum
#undef D
/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */
#define D(name, t, flags) \
#define D(name, t, origin, flags) \
{ CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \
sizeof STRINGX(name) - 1, flags },
sizeof STRINGX(name) - 1, origin, flags },
static const struct directive dtable[] =
{
DIRECTIVE_TABLE
......@@ -147,292 +134,237 @@ DIRECTIVE_TABLE
/* Check if a token's name matches that of a known directive. Put in
this file to save exporting dtable and other unneeded information. */
void
_cpp_check_directive (list, token)
cpp_toklist *list;
cpp_token *token;
const struct directive *
_cpp_check_directive (pfile, token, bol)
cpp_reader *pfile;
const cpp_token *token;
int bol;
{
const U_CHAR *name = token->val.name.text;
size_t len = token->val.name.len;
unsigned int i;
list->dirno = -1;
list->flags &= ~SYNTAX_INCLUDE;
/* If we are rescanning preprocessed input, don't obey any directives
other than # nnn. */
if (CPP_OPTION (pfile, preprocessed))
return 0;
for (i = 0; i < N_DIRECTIVES; i++)
if (dtable[i].length == len && !ustrncmp (dtable[i].name, name, len))
if (dtable[i].length == len && !memcmp (dtable[i].name, name, len))
{
list->dirno = i;
if (dtable[i].flags & SYNTAX_INCLUDE)
list->flags |= SYNTAX_INCLUDE;
break;
/* If we are skipping a failed conditional group, all non-conditional
directives are ignored. */
if (pfile->skipping && !(dtable[i].flags & COND))
return 0;
/* In -traditional mode, a directive is ignored unless its #
is in column 1. */
if (!bol && dtable[i].origin == KANDR && CPP_WTRADITIONAL (pfile))
cpp_warning (pfile, "traditional C ignores #%s with the # indented",
dtable[i].name);
if (!bol && CPP_TRADITIONAL (pfile))
return 0;
/* Issue -pedantic warnings for extended directives. */
if (CPP_PEDANTIC (pfile) && dtable[i].origin == EXTENSION)
cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name);
/* -Wtraditional gives warnings about directives with inappropriate
indentation of #. */
if (bol && dtable[i].origin != KANDR && CPP_WTRADITIONAL (pfile))
cpp_warning (pfile,
"suggest hiding #%s from traditional C with an indented #",
dtable[i].name);
return &dtable[i];
}
}
/* Handle a possible # directive.
'#' has already been read. */
return 0;
}
int
_cpp_handle_directive (pfile)
const struct directive *
_cpp_check_linemarker (pfile, token, bol)
cpp_reader *pfile;
const cpp_token *token ATTRIBUTE_UNUSED;
int bol;
{
int i;
int hash_at_bol;
unsigned int len;
U_CHAR *ident;
long old_written = CPP_WRITTEN (pfile);
enum cpp_ttype tok;
if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
{
cpp_ice (pfile, "handle_directive called on macro buffer");
return 0;
}
/* -traditional directives are recognized only with the # in column 1. */
hash_at_bol = CPP_IN_COLUMN_1 (pfile);
/* Scan the next token, then pretend we didn't. */
CPP_SET_MARK (pfile);
pfile->no_macro_expand++;
tok = _cpp_get_directive_token (pfile);
pfile->no_macro_expand--;
ident = pfile->token_buffer + old_written;
len = CPP_PWRITTEN (pfile) - ident;
CPP_SET_WRITTEN (pfile, old_written);
CPP_GOTO_MARK (pfile);
/* # followed by a number is equivalent to #line. Do not recognize
this form in assembly language source files or skipped
conditional groups. Complain about this form if we're being
pedantic, but not if this is regurgitated input (preprocessed or
fed back in by the C++ frontend). */
if (tok == CPP_NUMBER)
{
if (pfile->skipping || CPP_OPTION (pfile, lang_asm))
return 0;
if (CPP_PEDANTIC (pfile)
&& CPP_BUFFER (pfile)->inc
&& ! CPP_OPTION (pfile, preprocessed))
cpp_pedwarn (pfile, "# followed by integer");
i = T_LINE;
goto process_directive;
}
if (pfile->skipping || CPP_OPTION (pfile, lang_asm))
return 0;
/* If we are rescanning preprocessed input, don't obey any directives
other than # nnn. */
else if (CPP_OPTION (pfile, preprocessed))
if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc
&& ! CPP_OPTION (pfile, preprocessed))
cpp_pedwarn (pfile, "# followed by integer");
/* In -traditional mode, a directive is ignored unless its #
is in column 1. */
if (!bol && CPP_WTRADITIONAL (pfile))
cpp_warning (pfile, "traditional C ignores #%s with the # indented",
dtable[T_LINE].name);
if (!bol && CPP_TRADITIONAL (pfile))
return 0;
return &dtable[T_LINE];
}
/* A line of just # becomes blank. */
else if (tok == CPP_VSPACE)
return 1;
static void
dump_macro_name (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
CPP_PUTS (pfile, "#define ", sizeof "#define " - 1);
CPP_PUTS (pfile, node->name, node->length);
}
/* A NAME token might in fact be a directive! */
else if (tok == CPP_NAME)
{
for (i = 0; i < N_DIRECTIVES; i++)
{
if (dtable[i].length == len
&& !ustrncmp (dtable[i].name, ident, len))
goto real_directive;
}
/* Don't complain about invalid 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 (!pfile->skipping && !CPP_OPTION (pfile, lang_asm))
cpp_error (pfile, "invalid preprocessing directive #%.*s",
(int) len, ident);
return 0;
}
/* And anything else means the # wasn't a directive marker. */
else
return 0;
/* Pass the current directive through to the output file. */
static void
pass_thru_directive (pfile)
cpp_reader *pfile;
{
/* XXX This output may be genuinely needed even when there is no
printer. */
if (! pfile->printer)
return;
/* Flush first (temporary). */
cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line);
_cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 1);
}
real_directive:
static cpp_hashnode *
get_define_node (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node;
const cpp_token *token;
const U_CHAR *sym;
unsigned int len;
/* If we are skipping a failed conditional group, all non-conditional
directives are ignored. */
if (pfile->skipping && ORIGIN (dtable[i].flags) != COND)
return 0;
/* Skip any -C comments. */
while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
;
/* In -traditional mode, a directive is ignored unless its # is in
column 1. */
if (CPP_TRADITIONAL (pfile) && !hash_at_bol)
if (token->type != CPP_NAME)
{
if (CPP_WTRADITIONAL (pfile))
cpp_warning (pfile, "ignoring #%s because of its indented #",
dtable[i].name);
cpp_error_with_line (pfile, pfile->token_list.line, token->col,
"macro names must be identifiers");
return 0;
}
/* no_directives is set when we are parsing macro arguments. Directives
in macro arguments are undefined behavior (C99 6.10.3.11); this
implementation chooses to make them hard errors. */
if (pfile->no_directives)
/* That identifier is not allowed to be "defined". See predefined
macro names (6.10.8.4). */
len = token->val.name.len;
sym = token->val.name.text;
if (str_match (sym, len, "defined"))
{
cpp_error (pfile, "#%s may not be used inside a macro argument",
dtable[i].name);
_cpp_skip_rest_of_line (pfile);
return 1;
cpp_error_with_line (pfile, pfile->token_list.line, token->col,
"\"defined\" is not a legal macro name");
return 0;
}
/* Issue -pedantic warnings for extended directives. */
if (CPP_PEDANTIC (pfile) && ORIGIN (dtable[i].flags) == EXTENSION)
cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name);
/* -Wtraditional gives warnings about directives with inappropriate
indentation of #. */
if (CPP_WTRADITIONAL (pfile))
node = cpp_lookup (pfile, sym, len);
/* Check for poisoned identifiers now. */
if (node->type == T_POISON)
{
if (!hash_at_bol && TRAD_DIRECT_P (dtable[i].flags))
cpp_warning (pfile, "traditional C ignores #%s with the # indented",
dtable[i].name);
else if (hash_at_bol && ! TRAD_DIRECT_P (dtable[i].flags))
cpp_warning (pfile,
"suggest hiding #%s from traditional C with an indented #",
dtable[i].name);
cpp_error (pfile, "attempt to use poisoned \"%.*s\"", (int) len, sym);
return 0;
}
/* Unfortunately, it's necessary to scan the directive name again,
now we know we're going to consume it. FIXME. */
pfile->no_macro_expand++;
_cpp_get_directive_token (pfile);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
process_directive:
(void) (*dtable[i].func) (pfile);
return 1;
}
/* Pass a directive through to the output file.
BUF points to the contents of the directive, as a contiguous string.
LEN is the length of the string pointed to by BUF.
KEYWORD is the keyword-table entry for the directive. */
static void
pass_thru_directive (buf, len, pfile, keyword)
const U_CHAR *buf;
size_t len;
cpp_reader *pfile;
int keyword;
{
const struct directive *kt = &dtable[keyword];
register unsigned klen = kt->length;
CPP_RESERVE (pfile, 1 + klen + len);
CPP_PUTC_Q (pfile, '#');
CPP_PUTS_Q (pfile, kt->name, klen);
if (len != 0 && buf[0] != ' ')
CPP_PUTC_Q (pfile, ' ');
CPP_PUTS_Q (pfile, buf, len);
return node;
}
/* Process a #define command. */
static int
do_define (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node;
int len;
const U_CHAR *sym;
cpp_toklist *list = &pfile->directbuf;
pfile->no_macro_expand++;
CPP_OPTION (pfile, discard_comments)++;
if ((node = get_define_node (pfile)))
if (_cpp_create_definition (pfile, node))
{
if (CPP_OPTION (pfile, debug_output)
|| CPP_OPTION (pfile, dump_macros) == dump_definitions)
_cpp_dump_definition (pfile, node);
else if (CPP_OPTION (pfile, dump_macros) == dump_names)
dump_macro_name (pfile, node);
}
return 0;
}
/* Remove the definition of a symbol from the symbol table. */
static int
do_undef (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node = get_define_node (pfile);
_cpp_scan_until (pfile, list, CPP_VSPACE);
if (cpp_get_token (pfile)->type != CPP_EOF)
cpp_pedwarn (pfile, "junk on line after #undef");
/* First token on the line must be a NAME. There may not be any
tokens in the list (if we had #define all by itself on a line). */
if (list->tokens_used == 0
|| TOK_TYPE (list, 0) != CPP_NAME)
/* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
is not currently defined as a macro name. */
if (node && node->type != T_VOID)
{
cpp_error_with_line (pfile, list->line, TOK_COL (list, 0),
"#define must be followed by an identifier");
goto out;
}
/* If we are generating additional info for debugging (with -g) we
need to pass through all effective #undef commands. */
if (CPP_OPTION (pfile, debug_output)
|| CPP_OPTION (pfile, dump_macros) == dump_definitions
|| CPP_OPTION (pfile, dump_macros) == dump_names)
pass_thru_directive (pfile);
sym = TOK_NAME (list, 0);
len = TOK_LEN (list, 0);
if (node->type != T_MACRO)
cpp_warning (pfile, "undefining \"%s\"", node->name);
/* That NAME is not allowed to be "defined". (Not clear if the
standard requires this.) */
if (len == 7 && !ustrncmp (sym, U"defined", 7))
{
cpp_error_with_line (pfile, list->line, TOK_COL (list, 0),
"\"defined\" is not a legal macro name");
goto out;
_cpp_free_definition (node);
node->type = T_VOID;
}
node = cpp_lookup (pfile, sym, len);
/* Check for poisoned identifiers now. All other checks
are done in cpphash.c. */
if (node->type == T_POISON)
{
cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
goto out;
}
if (_cpp_create_definition (pfile, list, node) == 0)
goto out;
if (CPP_OPTION (pfile, debug_output)
|| CPP_OPTION (pfile, dump_macros) == dump_definitions)
_cpp_dump_definition (pfile, node);
else if (CPP_OPTION (pfile, dump_macros) == dump_names)
pass_thru_directive (sym, len, pfile, T_DEFINE);
out:
pfile->no_macro_expand--;
CPP_OPTION (pfile, discard_comments)--;
return 0;
}
/* Handle #include and #import. */
static unsigned int
parse_include (pfile, name, trail)
static int
parse_include (pfile, dir, trail, strp, lenp, abp)
cpp_reader *pfile;
const U_CHAR *name;
const U_CHAR *dir;
int trail;
const U_CHAR **strp;
unsigned int *lenp;
int *abp;
{
long old_written = CPP_WRITTEN (pfile);
enum cpp_ttype token;
int len;
pfile->parsing_include_directive++;
token = _cpp_get_directive_token (pfile);
pfile->parsing_include_directive--;
const cpp_token *name = cpp_get_token (pfile);
len = CPP_WRITTEN (pfile) - old_written;
if (token != CPP_STRING)
if (name->type != CPP_STRING && name->type != CPP_HEADER_NAME)
{
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", name);
CPP_SET_WRITTEN (pfile, old_written);
_cpp_skip_rest_of_line (pfile);
return 0;
if (name->type == CPP_LESS)
name = _cpp_glue_header_name (pfile);
else
{
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
return 1;
}
}
if (!trail && _cpp_get_directive_token (pfile) != CPP_VSPACE)
if (name->val.name.len == 0)
{
cpp_error (pfile, "junk at end of #%s", name);
_cpp_skip_rest_of_line (pfile);
cpp_error (pfile, "empty file name in #%s", dir);
return 1;
}
CPP_SET_WRITTEN (pfile, old_written);
if (len == 0)
cpp_error (pfile, "empty file name in #%s", name);
if (!trail && cpp_get_token (pfile)->type != CPP_EOF)
cpp_error (pfile, "junk at end of #%s", dir);
return len;
*lenp = name->val.name.len;
*strp = name->val.name.text;
*abp = (name->type == CPP_HEADER_NAME);
return 0;
}
static int
......@@ -440,19 +372,15 @@ do_include (pfile)
cpp_reader *pfile;
{
unsigned int len;
U_CHAR *token;
const U_CHAR *str;
int ab;
len = parse_include (pfile, dtable[T_INCLUDE].name, 0);
if (len == 0)
if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab))
return 0;
token = (U_CHAR *) alloca (len + 1);
memcpy (token, CPP_PWRITTEN (pfile), len);
token[len] = '\0';
if (CPP_OPTION (pfile, dump_includes))
pass_thru_directive (token, len, pfile, T_INCLUDE);
_cpp_execute_include (pfile, token, len, 0, 0);
_cpp_execute_include (pfile, str, len, 0, 0, ab);
if (CPP_OPTION (pfile, dump_includes))
pass_thru_directive (pfile);
return 0;
}
......@@ -461,7 +389,8 @@ do_import (pfile)
cpp_reader *pfile;
{
unsigned int len;
U_CHAR *token;
const U_CHAR *str;
int ab;
if (CPP_OPTION (pfile, warn_import)
&& !CPP_IN_SYSTEM_HEADER (pfile) && !pfile->import_warning)
......@@ -471,17 +400,12 @@ do_import (pfile)
"#import is obsolete, use an #ifndef wrapper in the header file");
}
len = parse_include (pfile, dtable[T_IMPORT].name, 0);
if (len == 0)
if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab))
return 0;
token = (U_CHAR *) alloca (len + 1);
memcpy (token, CPP_PWRITTEN (pfile), len);
token[len] = '\0';
if (CPP_OPTION (pfile, dump_includes))
pass_thru_directive (token, len, pfile, T_IMPORT);
_cpp_execute_include (pfile, token, len, 1, 0);
_cpp_execute_include (pfile, str, len, 1, 0, ab);
if (CPP_OPTION (pfile, dump_includes))
pass_thru_directive (pfile);
return 0;
}
......@@ -490,32 +414,35 @@ do_include_next (pfile)
cpp_reader *pfile;
{
unsigned int len;
U_CHAR *token;
const U_CHAR *str;
struct file_name_list *search_start = 0;
int ab;
len = parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0);
if (len == 0)
if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab))
return 0;
token = (U_CHAR *) alloca (len + 1);
memcpy (token, CPP_PWRITTEN (pfile), len);
token[len] = '\0';
if (CPP_OPTION (pfile, dump_includes))
pass_thru_directive (token, len, pfile, T_INCLUDE_NEXT);
/* For #include_next, skip in the search path past the dir in which the
containing file was found. Treat files specified using an absolute path
as if there are no more directories to search. Treat the primary source
file like any other included source, but generate a warning. */
/* For #include_next, skip in the search path past the dir in which
the current file was found. If this is the last directory in the
search path, don't include anything. If the current file was
specified with an absolute path, use the normal search logic. If
this is the primary source file, use the normal search logic and
generate a warning. */
if (CPP_PREV_BUFFER (CPP_BUFFER (pfile)))
{
if (CPP_BUFFER (pfile)->inc->foundhere)
search_start = CPP_BUFFER (pfile)->inc->foundhere->next;
{
search_start = CPP_BUFFER (pfile)->inc->foundhere->next;
if (!search_start)
return 0;
}
}
else
cpp_warning (pfile, "#include_next in primary source file");
_cpp_execute_include (pfile, token, len, 0, search_start);
_cpp_execute_include (pfile, str, len, 0, search_start, ab);
if (CPP_OPTION (pfile, dump_includes))
pass_thru_directive (pfile);
return 0;
}
......@@ -529,27 +456,47 @@ read_line_number (pfile, num)
cpp_reader *pfile;
int *num;
{
long save_written = CPP_WRITTEN (pfile);
U_CHAR *p;
enum cpp_ttype token = _cpp_get_directive_token (pfile);
p = pfile->token_buffer + save_written;
const cpp_token *tok = cpp_get_token (pfile);
enum cpp_ttype type = tok->type;
const U_CHAR *p = tok->val.name.text;
unsigned int len = tok->val.name.len;
if (token == CPP_NUMBER && p + 1 == CPP_PWRITTEN (pfile)
&& p[0] >= '1' && p[0] <= '4')
if (type == CPP_NUMBER && len == 1 && p[0] >= '1' && p[0] <= '4')
{
*num = p[0] - '0';
CPP_SET_WRITTEN (pfile, save_written);
return 1;
}
else
{
if (token != CPP_VSPACE && token != CPP_EOF)
if (type != CPP_VSPACE && type != CPP_EOF)
cpp_error (pfile, "invalid format #line");
CPP_SET_WRITTEN (pfile, save_written);
return 0;
}
}
/* Another subroutine of do_line. Convert a number in STR, of length
LEN, to binary; store it in NUMP, and return 0 if the number was
legal, 1 if not. Temporary, hopefully. */
static int
strtoul_for_line (str, len, nump)
const U_CHAR *str;
unsigned int len;
unsigned long *nump;
{
unsigned long reg = 0;
U_CHAR c;
while (len--)
{
c = *str++;
if (!ISDIGIT (c))
return 1;
reg *= 10;
reg += c - '0';
}
*nump = reg;
return 0;
}
/* Interpret #line command.
Note that the filename string (if any) is treated as if it were an
include filename. That means no escape handling. */
......@@ -559,156 +506,92 @@ do_line (pfile)
cpp_reader *pfile;
{
cpp_buffer *ip = CPP_BUFFER (pfile);
unsigned int new_lineno;
long old_written = CPP_WRITTEN (pfile);
enum cpp_ttype token;
char *x;
token = _cpp_get_directive_token (pfile);
unsigned long new_lineno, old_lineno;
/* C99 raised the minimum limit on #line numbers. */
unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
int action_number = 0;
enum cpp_ttype type;
const U_CHAR *str;
char *fname;
unsigned int len;
const cpp_token *tok;
if (token != CPP_NUMBER)
{
cpp_error (pfile, "token after #line is not an integer");
goto bad_line_directive;
}
tok = cpp_get_token (pfile);
type = tok->type;
str = tok->val.name.text;
len = tok->val.name.len;
CPP_PUTC (pfile, '\0'); /* not terminated for us */
new_lineno = strtoul ((const char *) (pfile->token_buffer + old_written),
&x, 10);
if (x[0] != '\0')
if (type != CPP_NUMBER || strtoul_for_line (str, len, &new_lineno))
{
cpp_error (pfile, "token after #line is not an integer");
goto bad_line_directive;
cpp_error (pfile, "token after #line is not a positive integer");
goto done;
}
CPP_SET_WRITTEN (pfile, old_written);
if (CPP_PEDANTIC (pfile) && (new_lineno <= 0 || new_lineno > 32767))
cpp_pedwarn (pfile, "line number out of range in #line");
token = _cpp_get_directive_token (pfile);
if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
cpp_pedwarn (pfile, "line number out of range");
if (token == CPP_STRING)
{
U_CHAR *fname = pfile->token_buffer + old_written + 1;
U_CHAR *end_name = CPP_PWRITTEN (pfile) - 1;
int action_number = 0;
if (read_line_number (pfile, &action_number))
{
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "garbage at end of #line");
old_lineno = ip->lineno;
ip->lineno = new_lineno;
tok = cpp_get_token (pfile);
type = tok->type;
str = tok->val.name.text;
len = tok->val.name.len;
/* This is somewhat questionable: change the buffer stack
depth so that output_line_command thinks we've stacked
another buffer. */
if (action_number == 1)
{
pfile->buffer_stack_depth++;
cpp_make_system_header (pfile, ip, 0);
read_line_number (pfile, &action_number);
}
else if (action_number == 2)
{
pfile->buffer_stack_depth--;
cpp_make_system_header (pfile, ip, 0);
read_line_number (pfile, &action_number);
}
if (action_number == 3)
{
cpp_make_system_header (pfile, ip, 1);
read_line_number (pfile, &action_number);
}
if (action_number == 4)
{
cpp_make_system_header (pfile, ip, 2);
read_line_number (pfile, &action_number);
}
}
*end_name = '\0';
if (strcmp ((const char *)fname, ip->nominal_fname))
{
if (!strcmp ((const char *)fname, ip->inc->name))
ip->nominal_fname = ip->inc->name;
else
ip->nominal_fname = _cpp_fake_include (pfile, (const char *)fname);
}
}
else if (token != CPP_VSPACE && token != CPP_EOF)
if (type == CPP_VSPACE || type == CPP_EOF)
goto done;
else if (type != CPP_STRING)
{
cpp_error (pfile, "second token after #line is not a string");
goto bad_line_directive;
ip->lineno = old_lineno; /* malformed #line should have no effect */
goto done;
}
/* The Newline at the end of this line remains to be processed.
To put the next line at the specified line number,
we must store a line number now that is one less. */
ip->lineno = new_lineno - 1;
CPP_SET_WRITTEN (pfile, old_written);
return 0;
bad_line_directive:
_cpp_skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written);
return 0;
}
fname = alloca (len + 1);
memcpy (fname, str, len);
fname[len] = '\0';
if (strcmp (fname, ip->nominal_fname))
{
if (!strcmp (fname, ip->inc->name))
ip->nominal_fname = ip->inc->name;
else
ip->nominal_fname = _cpp_fake_include (pfile, fname);
}
/* Remove the definition of a symbol from the symbol table.
According to the C standard, it is not an error to undef
something that has no definitions. */
static int
do_undef (pfile)
cpp_reader *pfile;
{
int len;
cpp_hashnode *hp;
U_CHAR *name;
long here = CPP_WRITTEN (pfile);
enum cpp_ttype token;
if (read_line_number (pfile, &action_number) == 0)
return 0;
pfile->no_macro_expand++;
token = _cpp_get_directive_token (pfile);
pfile->no_macro_expand--;
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "garbage at end of #line");
if (token != CPP_NAME)
/* This is somewhat questionable: change the buffer stack
depth so that output_line_command thinks we've stacked
another buffer. */
if (action_number == 1)
{
cpp_error (pfile, "token after #undef is not an identifier");
_cpp_skip_rest_of_line (pfile);
return 0;
pfile->buffer_stack_depth++;
cpp_make_system_header (pfile, ip, 0);
read_line_number (pfile, &action_number);
}
len = CPP_WRITTEN (pfile) - here;
token = _cpp_get_directive_token (pfile);
if (token != CPP_VSPACE)
{
cpp_pedwarn (pfile, "junk on line after #undef");
_cpp_skip_rest_of_line (pfile);
}
name = pfile->token_buffer + here;
CPP_SET_WRITTEN (pfile, here);
hp = cpp_lookup (pfile, name, len);
if (hp->type == T_VOID)
; /* Not defined in the first place - do nothing. */
else if (hp->type == T_POISON)
cpp_error (pfile, "cannot undefine poisoned \"%s\"", hp->name);
else
else if (action_number == 2)
{
/* If we are generating additional info for debugging (with -g) we
need to pass through all effective #undef commands. */
if (CPP_OPTION (pfile, debug_output))
pass_thru_directive (hp->name, len, pfile, T_UNDEF);
if (hp->type != T_MACRO && hp->type != T_FMACRO
&& hp->type != T_EMPTY && hp->type != T_IDENTITY)
cpp_warning (pfile, "undefining `%s'", hp->name);
_cpp_free_definition (hp);
hp->type = T_VOID;
pfile->buffer_stack_depth--;
cpp_make_system_header (pfile, ip, 0);
read_line_number (pfile, &action_number);
}
if (action_number == 3)
{
cpp_make_system_header (pfile, ip, 1);
read_line_number (pfile, &action_number);
}
if (action_number == 4)
{
cpp_make_system_header (pfile, ip, 2);
read_line_number (pfile, &action_number);
}
return 0;
done:
return 0;
}
......@@ -722,14 +605,14 @@ static int
do_error (pfile)
cpp_reader *pfile;
{
const U_CHAR *text, *limit;
U_CHAR *text, *limit;
_cpp_skip_hspace (pfile);
text = CPP_BUFFER (pfile)->cur;
_cpp_skip_rest_of_line (pfile);
limit = CPP_BUFFER (pfile)->cur;
text = pfile->limit;
_cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0);
limit = pfile->limit;
pfile->limit = text;
cpp_error (pfile, "%.*s", (int)(limit - text), text);
cpp_error (pfile, "#error %.*s", (int)(limit - text), text);
return 0;
}
......@@ -742,14 +625,13 @@ static int
do_warning (pfile)
cpp_reader *pfile;
{
const U_CHAR *text, *limit;
U_CHAR *text, *limit;
_cpp_skip_hspace (pfile);
text = CPP_BUFFER (pfile)->cur;
_cpp_skip_rest_of_line (pfile);
limit = CPP_BUFFER (pfile)->cur;
cpp_warning (pfile, "#warning %.*s", (int)(limit - text), text);
text = pfile->limit;
_cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0);
limit = pfile->limit;
pfile->limit = text;
cpp_warning (pfile, "%.*s", (int)(limit - text), text);
return 0;
}
......@@ -759,21 +641,17 @@ static int
do_ident (pfile)
cpp_reader *pfile;
{
long old_written = CPP_WRITTEN (pfile);
CPP_PUTS (pfile, "#ident ", 7);
/* Next token should be a string constant. */
if (_cpp_get_directive_token (pfile) == CPP_STRING)
if (cpp_get_token (pfile)->type == CPP_STRING)
/* And then a newline. */
if (_cpp_get_directive_token (pfile) == CPP_VSPACE)
/* Good - ship it. */
return 0;
if (cpp_get_token (pfile)->type == CPP_VSPACE)
{
/* Good - ship it. */
pass_thru_directive (pfile);
return 0;
}
cpp_error (pfile, "invalid #ident");
_cpp_skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); /* discard directive */
return 0;
}
......@@ -792,17 +670,17 @@ do_ident (pfile)
They return 1 if the token buffer is to be popped, 0 if not. */
struct pragma_entry
{
char const *name;
const char *name;
int (*handler) PARAMS ((cpp_reader *));
};
static int pragma_dispatch
PARAMS ((cpp_reader *, const struct pragma_entry *, U_CHAR *, size_t));
PARAMS ((cpp_reader *, const struct pragma_entry *,
const U_CHAR *, size_t));
static int do_pragma_once PARAMS ((cpp_reader *));
static int do_pragma_implementation PARAMS ((cpp_reader *));
static int do_pragma_poison PARAMS ((cpp_reader *));
static int do_pragma_system_header PARAMS ((cpp_reader *));
static int do_pragma_default PARAMS ((cpp_reader *));
static int do_pragma_gcc PARAMS ((cpp_reader *));
static int do_pragma_dependency PARAMS ((cpp_reader *));
......@@ -811,9 +689,8 @@ static const struct pragma_entry top_pragmas[] =
{"once", do_pragma_once},
{"implementation", do_pragma_implementation},
{"poison", do_pragma_poison},
{"system_header", do_pragma_system_header},
{"GCC", do_pragma_gcc},
{NULL, do_pragma_default}
{NULL, NULL}
};
static const struct pragma_entry gcc_pragmas[] =
......@@ -822,74 +699,41 @@ static const struct pragma_entry gcc_pragmas[] =
{"poison", do_pragma_poison},
{"system_header", do_pragma_system_header},
{"dependency", do_pragma_dependency},
{NULL, do_pragma_default}
{NULL, NULL}
};
static int pragma_dispatch (pfile, table, p, len)
cpp_reader *pfile;
const struct pragma_entry *table;
U_CHAR *p;
const U_CHAR *p;
size_t len;
{
for (; table->name; table++)
if (strlen (table->name) == len && !memcmp (p, table->name, len))
return (*table->handler) (pfile);
return (*table->handler) (pfile);
return 0;
}
static int
do_pragma (pfile)
cpp_reader *pfile;
{
long here, key;
U_CHAR *buf;
const cpp_token *tok;
int pop;
enum cpp_ttype token;
size_t len;
here = CPP_WRITTEN (pfile);
CPP_PUTS (pfile, "#pragma ", 8);
key = CPP_WRITTEN (pfile);
pfile->no_macro_expand++;
token = _cpp_get_directive_token (pfile);
if (token != CPP_NAME)
tok = cpp_get_token (pfile);
if (tok->type == CPP_EOF)
return 0;
else if (tok->type != CPP_NAME)
{
if (token == CPP_VSPACE)
goto empty;
else
goto skip;
cpp_error (pfile, "malformed #pragma directive");
return 0;
}
buf = pfile->token_buffer + key;
len = CPP_WRITTEN (pfile) - key;
CPP_PUTC (pfile, ' ');
pop = pragma_dispatch (pfile, top_pragmas, buf, len);
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
goto skip;
if (pop)
CPP_SET_WRITTEN (pfile, here);
pfile->no_macro_expand--;
return 0;
skip:
cpp_error (pfile, "malformed #pragma directive");
_cpp_skip_rest_of_line (pfile);
empty:
CPP_SET_WRITTEN (pfile, here);
pfile->no_macro_expand--;
return 0;
}
static int
do_pragma_default (pfile)
cpp_reader *pfile;
{
while (_cpp_get_directive_token (pfile) != CPP_VSPACE)
CPP_PUTC (pfile, ' ');
pop = pragma_dispatch (pfile, top_pragmas,
tok->val.name.text, tok->val.name.len);
if (!pop)
pass_thru_directive (pfile);
return 0;
}
......@@ -897,21 +741,16 @@ static int
do_pragma_gcc (pfile)
cpp_reader *pfile;
{
long key;
enum cpp_ttype token;
U_CHAR *buf;
size_t len;
key = CPP_WRITTEN (pfile);
token = _cpp_get_directive_token (pfile);
if (token != CPP_NAME)
return token == CPP_VSPACE;
buf = pfile->token_buffer + key;
len = CPP_WRITTEN (pfile) - key;
CPP_PUTC (pfile, ' ');
const cpp_token *tok;
tok = cpp_get_token (pfile);
if (tok->type == CPP_EOF)
return 1;
else if (tok->type != CPP_NAME)
return 0;
return pragma_dispatch (pfile, gcc_pragmas, buf, len);
return pragma_dispatch (pfile, gcc_pragmas,
tok->val.name.text, tok->val.name.len);
}
static int
......@@ -939,27 +778,22 @@ do_pragma_implementation (pfile)
{
/* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */
enum cpp_ttype token;
long written = CPP_WRITTEN (pfile);
U_CHAR *name;
const cpp_token *tok = cpp_get_token (pfile);
char *copy;
size_t len;
token = _cpp_get_directive_token (pfile);
if (token == CPP_VSPACE)
if (tok->type == CPP_EOF)
return 0;
else if (token != CPP_STRING)
else if (tok->type != CPP_STRING
|| cpp_get_token (pfile)->type != CPP_EOF)
{
cpp_error (pfile, "malformed #pragma implementation");
return 1;
}
/* Trim the leading and trailing quote marks from the string. */
name = pfile->token_buffer + written + 1;
len = CPP_PWRITTEN (pfile) - name;
copy = alloca (len);
memcpy (copy, name, len - 1);
copy[len - 1] = '\0';
/* Make a NUL-terminated copy of the string. */
copy = alloca (tok->val.name.len + 1);
memcpy (copy, tok->val.name.text, tok->val.name.len);
copy[tok->val.name.len] = '\0';
if (cpp_included (pfile, copy))
cpp_warning (pfile,
......@@ -974,11 +808,8 @@ do_pragma_poison (pfile)
{
/* Poison these symbols so that all subsequent usage produces an
error message. */
U_CHAR *p;
const cpp_token *tok;
cpp_hashnode *hp;
long written;
size_t len;
enum cpp_ttype token;
int writeit;
/* As a rule, don't include #pragma poison commands in output,
......@@ -989,31 +820,25 @@ do_pragma_poison (pfile)
for (;;)
{
written = CPP_WRITTEN (pfile);
token = _cpp_get_directive_token (pfile);
if (token == CPP_VSPACE)
tok = cpp_get_token (pfile);
if (tok->type == CPP_EOF)
break;
if (token != CPP_NAME)
if (tok->type != CPP_NAME)
{
cpp_error (pfile, "invalid #pragma poison directive");
_cpp_skip_rest_of_line (pfile);
return 1;
}
p = pfile->token_buffer + written;
len = CPP_PWRITTEN (pfile) - p;
hp = cpp_lookup (pfile, p, len);
hp = cpp_lookup (pfile, tok->val.name.text, tok->val.name.len);
if (hp->type == T_POISON)
; /* It is allowed to poison the same identifier twice. */
else
{
if (hp->type != T_VOID)
cpp_warning (pfile, "poisoning existing macro `%s'", hp->name);
cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name);
_cpp_free_definition (hp);
hp->type = T_POISON;
}
if (writeit)
CPP_PUTC (pfile, ' ');
}
return !writeit;
}
......@@ -1028,7 +853,7 @@ static int
do_pragma_system_header (pfile)
cpp_reader *pfile;
{
cpp_buffer *ip = cpp_file_buffer (pfile);
cpp_buffer *ip = CPP_BUFFER (pfile);
if (CPP_PREV_BUFFER (ip) == NULL)
cpp_warning (pfile, "#pragma system_header outside include file");
else
......@@ -1044,33 +869,37 @@ static int
do_pragma_dependency (pfile)
cpp_reader *pfile;
{
U_CHAR *original_name, *name;
unsigned len;
int ordering;
len = parse_include (pfile, (const U_CHAR *)"pragma dependency", 1);
original_name = (U_CHAR *) alloca (len + 1);
name = (U_CHAR *) alloca (len + 1);
memcpy (original_name, CPP_PWRITTEN (pfile), len);
memcpy (name, CPP_PWRITTEN (pfile), len);
original_name[len] = name[len] = 0;
ordering = _cpp_compare_file_date (pfile, name, len, 0);
const U_CHAR *name;
unsigned int len;
int ordering, ab;
char left, right;
if (parse_include (pfile, U"pragma dependency", 1, &name, &len, &ab))
return 1;
left = ab ? '<' : '"';
right = ab ? '>' : '"';
ordering = _cpp_compare_file_date (pfile, name, len, ab);
if (ordering < 0)
cpp_warning (pfile, "cannot find source %s", original_name);
cpp_warning (pfile, "cannot find source %c%s%c", left, name, right);
else if (ordering > 0)
{
const U_CHAR *text, *limit;
_cpp_skip_hspace (pfile);
text = CPP_BUFFER (pfile)->cur;
_cpp_skip_rest_of_line (pfile);
limit = CPP_BUFFER (pfile)->cur;
const cpp_token *msg = cpp_get_token (pfile);
cpp_warning (pfile, "current file is older than %s", original_name);
if (limit != text)
cpp_warning (pfile, "%.*s", (int)(limit - text), text);
cpp_warning (pfile, "current file is older than %c%s%c",
left, name, right);
if (msg->type != CPP_EOF)
{
U_CHAR *text, *limit;
text = pfile->limit;
_cpp_dump_list (pfile, &pfile->token_list, msg, 0);
limit = pfile->limit;
pfile->limit = text;
cpp_warning (pfile, "%.*s", (int)(limit - text), text);
}
}
_cpp_skip_rest_of_line (pfile);
return 1;
}
......@@ -1078,9 +907,8 @@ do_pragma_dependency (pfile)
#ifdef SCCS_DIRECTIVE
static int
do_sccs (pfile)
cpp_reader *pfile;
cpp_reader *pfile ATTRIBUTE_UNUSED;
{
_cpp_skip_rest_of_line (pfile);
return 0;
}
#endif
......@@ -1096,117 +924,76 @@ static const cpp_hashnode *
detect_if_not_defined (pfile)
cpp_reader *pfile;
{
const cpp_hashnode *cmacro = 0;
enum cpp_ttype token;
unsigned int base_offset;
unsigned int token_offset;
unsigned int need_rparen = 0;
unsigned int token_len;
if (pfile->skipping || pfile->only_seen_white != 2)
return NULL;
/* Save state required for restore. */
pfile->no_macro_expand++;
CPP_SET_MARK (pfile);
base_offset = CPP_WRITTEN (pfile);
/* Look for `!', */
if (_cpp_get_directive_token (pfile) != CPP_OTHER
|| CPP_WRITTEN (pfile) != (size_t) base_offset + 1
|| CPP_PWRITTEN (pfile)[-1] != '!')
goto restore;
/* ...then `defined', */
token_offset = CPP_WRITTEN (pfile);
token = _cpp_get_directive_token (pfile);
if (token != CPP_NAME)
goto restore;
if (ustrncmp (pfile->token_buffer + token_offset, U"defined", 7))
goto restore;
/* ...then an optional '(' and the name, */
token_offset = CPP_WRITTEN (pfile);
token = _cpp_get_directive_token (pfile);
if (token == CPP_OPEN_PAREN)
{
token_offset = CPP_WRITTEN (pfile);
need_rparen = 1;
token = _cpp_get_directive_token (pfile);
}
if (token != CPP_NAME)
goto restore;
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_len = CPP_WRITTEN (pfile) - token_offset;
token++;
if (token->type != CPP_NAME
|| !str_match (token->val.name.text, token->val.name.len, "defined"))
return 0;
token++;
if (token->type == CPP_OPEN_PAREN)
token++;
/* ...then the ')', if necessary, */
if (need_rparen && _cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
goto restore;
if (token->type != CPP_NAME)
return 0;
/* ...and make sure there's nothing else on the line. */
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
goto restore;
cmacro = cpp_lookup (pfile, token->val.name.text, token->val.name.len);
/* We have a legitimate controlling macro for this header. */
cmacro = cpp_lookup (pfile, pfile->token_buffer + token_offset, token_len);
if (token[-1].type == CPP_OPEN_PAREN)
{
token++;
if (token->type != CPP_CLOSE_PAREN)
return 0;
}
restore:
CPP_SET_WRITTEN (pfile, base_offset);
pfile->no_macro_expand--;
CPP_GOTO_MARK (pfile);
token++;
if (token->type != CPP_EOF)
return 0;
return cmacro;
}
/* Parse an #ifdef or #ifndef directive. Returns 1 for defined, 0 for
not defined; the macro tested is left in the token buffer (but
popped). */
/* 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;
{
U_CHAR *ident;
const U_CHAR *ident;
unsigned int len;
enum cpp_ttype token;
long old_written = CPP_WRITTEN (pfile);
enum cpp_ttype type;
const cpp_hashnode *node = 0;
pfile->no_macro_expand++;
token = _cpp_get_directive_token (pfile);
pfile->no_macro_expand--;
ident = pfile->token_buffer + old_written;
len = CPP_WRITTEN (pfile) - old_written;
const cpp_token *token = cpp_get_token (pfile);
type = token->type;
ident = token->val.name.text;
len = token->val.name.len;
if (token == CPP_VSPACE)
if (!CPP_TRADITIONAL (pfile))
{
if (! CPP_TRADITIONAL (pfile))
if (type == CPP_EOF)
cpp_pedwarn (pfile, "#%s with no argument", name);
goto done;
}
else if (token == CPP_NAME)
{
node = cpp_lookup (pfile, ident, len);
}
else
{
if (! CPP_TRADITIONAL (pfile))
cpp_error (pfile, "#%s with invalid 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 (!CPP_TRADITIONAL (pfile))
{
if (_cpp_get_directive_token (pfile) == CPP_VSPACE)
goto done;
cpp_pedwarn (pfile, "garbage at end of #%s", name);
}
_cpp_skip_rest_of_line (pfile);
done:
CPP_SET_WRITTEN (pfile, old_written); /* Pop */
if (type == CPP_NAME)
node = cpp_lookup (pfile, ident, len);
if (node && node->type == T_POISON)
cpp_error (pfile, "attempt to use poisoned identifier \"%s\"", node->name);
return node;
}
......@@ -1217,14 +1004,15 @@ do_ifdef (pfile)
cpp_reader *pfile;
{
int def = 0;
const cpp_hashnode *node = parse_ifdef (pfile, dtable[T_IFDEF].name);
if (node)
const cpp_hashnode *node = 0;
if (! pfile->skipping)
{
if (node->type == T_POISON)
cpp_error (pfile, "attempt to use poisoned `%s'", node->name);
else
def = (node->type != T_VOID);
node = parse_ifdef (pfile, dtable[T_IFDEF].name);
if (node)
def = (node->type != T_VOID && node->type != T_POISON);
}
push_conditional (pfile, !def, T_IFDEF, 0);
return 0;
}
......@@ -1236,21 +1024,19 @@ static int
do_ifndef (pfile)
cpp_reader *pfile;
{
int start_of_file;
int start_of_file = 0;
int def = 0;
const cpp_hashnode *cmacro;
const cpp_hashnode *cmacro = 0;
start_of_file = pfile->only_seen_white == 2;
cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
if (cmacro)
if (! pfile->skipping)
{
if (cmacro->type == T_POISON)
cpp_error (pfile, "attempt to use poisoned `%s'", cmacro->name);
else
def = (cmacro->type != T_VOID);
start_of_file = (pfile->token_list.flags & BEG_OF_FILE);
cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
if (cmacro)
def = cmacro->type != T_VOID;
}
push_conditional (pfile, def, T_IFNDEF,
start_of_file ? cmacro : 0);
push_conditional (pfile, def, T_IFNDEF, start_of_file ? cmacro : 0);
return 0;
}
......@@ -1282,7 +1068,6 @@ do_else (pfile)
cpp_reader *pfile;
{
struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
validate_else (pfile, dtable[T_ELSE].name);
if (ifs == NULL)
......@@ -1293,13 +1078,13 @@ do_else (pfile)
if (ifs->type == T_ELSE)
{
cpp_error (pfile, "#else after #else");
cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here");
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
if it has a #else clause. */
ifs->cmacro = 0;
ifs->type = T_ELSE;
if (! ifs->was_skipping)
{
......@@ -1330,24 +1115,24 @@ do_elif (pfile)
if (ifs->type == T_ELSE)
{
cpp_error (pfile, "#elif after #else");
cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here");
cpp_error_with_line (pfile, ifs->lineno, ifs->colno,
"the conditional began here");
}
ifs->type = T_ELIF;
if (ifs->was_skipping)
_cpp_skip_rest_of_line (pfile);
else if (pfile->skipping != 1)
return 0; /* Don't evaluate a nested #if */
if (pfile->skipping != 1)
{
_cpp_skip_rest_of_line (pfile);
pfile->skipping = 2; /* one block succeeded, so don't do any others */
return 0;
}
else
pfile->skipping = ! _cpp_parse_expr (pfile);
pfile->skipping = ! _cpp_parse_expr (pfile);
return 0;
}
/* #endif pops the if stack and resets pfile->skipping. */
static int
......@@ -1370,6 +1155,7 @@ do_endif (pfile)
return 0;
}
/* Push an if_stack entry and set pfile->skipping accordingly.
If this is a #ifndef starting at the beginning of a file,
CMACRO is the macro name tested by the #ifndef. */
......@@ -1384,7 +1170,7 @@ push_conditional (pfile, skip, type, cmacro)
struct if_stack *ifs;
ifs = (struct if_stack *) xmalloc (sizeof (struct if_stack));
ifs->lineno = CPP_BUFFER (pfile)->lineno;
ifs->lineno = _cpp_get_line (pfile, &ifs->colno);
ifs->next = CPP_BUFFER (pfile)->if_stack;
ifs->cmacro = cmacro;
ifs->was_skipping = pfile->skipping;
......@@ -1404,19 +1190,11 @@ validate_else (pfile, directive)
cpp_reader *pfile;
const U_CHAR *directive;
{
if (CPP_PEDANTIC (pfile))
{
long old_written = CPP_WRITTEN (pfile);
pfile->no_macro_expand++;
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
CPP_SET_WRITTEN (pfile, old_written);
pfile->no_macro_expand--;
}
_cpp_skip_rest_of_line (pfile);
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 macro buffer. 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,
issuing error messages. Then force skipping off. */
void
......@@ -1428,7 +1206,7 @@ _cpp_unwind_if_stack (pfile, pbuf)
for (ifs = pbuf->if_stack; ifs; ifs = nifs)
{
cpp_error_with_line (pfile, ifs->lineno, 1, "unterminated #%s",
cpp_error_with_line (pfile, ifs->lineno, ifs->colno, "unterminated #%s",
dtable[ifs->type].name);
nifs = ifs->next;
free (ifs);
......@@ -1436,173 +1214,210 @@ _cpp_unwind_if_stack (pfile, pbuf)
pfile->skipping = 0;
}
#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0)
#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0)
static int
do_assert (pfile)
/* Parses an assertion, returning a pointer to the hash node of the
predicate, or 0 on error. If an answer was supplied, it is
allocated and placed in ANSWERP, otherwise it is set to 0. We use
_cpp_get_raw_token, since we cannot assume tokens are consecutive
in a #if statement (we may be in a macro), and we don't want to
macro expand. */
cpp_hashnode *
_cpp_parse_assertion (pfile, answerp)
cpp_reader *pfile;
struct answer **answerp;
{
long old_written;
struct answer *answer = 0;
cpp_toklist *list;
U_CHAR *sym;
size_t len;
cpp_hashnode *hp;
struct predicate *pred = 0;
enum cpp_ttype type;
const cpp_token *token, *predicate;
const struct directive *d = pfile->token_list.directive;
unsigned int len = 0;
old_written = CPP_WRITTEN (pfile);
pfile->no_macro_expand++;
predicate = _cpp_get_raw_token (pfile);
if (predicate->type == CPP_EOF)
{
cpp_error (pfile, "assertion without predicate");
return 0;
}
else if (predicate->type != CPP_NAME)
{
cpp_error (pfile, "predicate must be an identifier");
return 0;
}
CPP_PUTC (pfile, '#'); /* force token out of macro namespace */
type = _cpp_get_directive_token (pfile);
if (type == CPP_VSPACE)
ERROR ("#assert without predicate");
else if (type != CPP_NAME)
ERROR ("assertion predicate is not an identifier");
token = _cpp_get_raw_token (pfile);
if (token->type != CPP_OPEN_PAREN)
{
/* #unassert and #if are OK without predicate. */
if (d == &dtable[T_UNASSERT])
{
if (token->type == CPP_EOF)
goto lookup_node;
}
else if (d != &dtable[T_ASSERT])
{
_cpp_push_token (pfile, token);
goto lookup_node;
}
cpp_error (pfile, "missing '(' after predicate");
return 0;
}
sym = pfile->token_buffer + old_written;
len = CPP_WRITTEN (pfile) - old_written;
hp = cpp_lookup (pfile, sym, len);
/* Allocate a struct answer, and copy the answer to it. */
answer = (struct answer *) xmalloc (sizeof (struct answer));
list = &answer->list;
_cpp_init_toklist (list, NO_DUMMY_TOKEN);
if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN)
ERROR ("missing token-sequence in #assert");
for (;;)
{
cpp_token *dest;
pred = (struct predicate *) xmalloc (sizeof (struct predicate));
_cpp_init_toklist (&pred->answer, NO_DUMMY_TOKEN);
token = _cpp_get_raw_token (pfile);
if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN)
!= CPP_CLOSE_PAREN)
ERROR ("missing close paren in #assert");
if (token->type == CPP_EOF)
{
cpp_error (pfile, "missing ')' to complete answer");
goto error;
}
if (token->type == CPP_CLOSE_PAREN)
break;
if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
ICE ("impossible token, expecting ) in do_assert");
/* Copy the token. */
_cpp_expand_token_space (list, 1);
dest = &list->tokens[list->tokens_used++];
*dest = *token;
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
ERROR ("junk at end of #assert");
if (token_spellings[token->type].type > SPELL_NONE)
{
_cpp_expand_name_space (list, token->val.name.len);
dest->val.name.text = list->namebuf + list->name_used;
memcpy (list->namebuf + list->name_used,
token->val.name.text, token->val.name.len);
list->name_used += token->val.name.len;
}
}
if (hp->type == T_ASSERTION)
if (list->tokens_used == 0)
{
/* Check for reassertion. */
const struct predicate *old;
for (old = hp->value.pred; old; old = old->next)
if (_cpp_equiv_toklists (&pred->answer, &old->answer))
/* We used to warn about this, but SVR4 cc doesn't, so let's
match that (also consistent with #define). goto error will
clean up. */
goto error;
pred->next = hp->value.pred;
cpp_error (pfile, "predicate's answer is empty");
goto error;
}
else
/* Drop whitespace at start. */
list->tokens[0].flags &= ~PREV_WHITE;
if ((d == &dtable[T_ASSERT] || d == &dtable[T_UNASSERT])
&& token[1].type != CPP_EOF)
{
hp->type = T_ASSERTION;
pred->next = 0;
cpp_error (pfile, "junk at end of assertion");
goto error;
}
_cpp_squeeze_toklist (&pred->answer);
hp->value.pred = pred;
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
return 0;
lookup_node:
*answerp = answer;
len = predicate->val.name.len + 1;
sym = alloca (len);
/* Prefix '#' to get it out of macro namespace. */
sym[0] = '#';
memcpy (sym + 1, predicate->val.name.text, len);
return cpp_lookup (pfile, sym, len);
error:
_cpp_skip_rest_of_line (pfile);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
if (pred)
{
_cpp_free_toklist (&pred->answer);
free (pred);
}
FREE_ANSWER (answer);
return 0;
}
static int
do_unassert (pfile)
cpp_reader *pfile;
/* Returns a pointer to the pointer to the answer in the answer chain,
or a pointer to NULL if the answer is not in the chain. */
struct answer **
find_answer (node, candidate)
cpp_hashnode *node;
const cpp_toklist *candidate;
{
long old_written;
U_CHAR *sym;
size_t len;
cpp_hashnode *hp;
cpp_toklist ans;
enum cpp_ttype type;
int specific = 0;
struct answer **result;
old_written = CPP_WRITTEN (pfile);
pfile->no_macro_expand++;
for (result = &node->value.answers; *result; result = &(*result)->next)
if (_cpp_equiv_toklists (&(*result)->list, candidate))
break;
CPP_PUTC (pfile, '#'); /* force token out of macro namespace */
if (_cpp_get_directive_token (pfile) != CPP_NAME)
ERROR ("#unassert must be followed by an identifier");
sym = pfile->token_buffer + old_written;
len = CPP_WRITTEN (pfile) - old_written;
hp = cpp_lookup (pfile, sym, len);
return result;
}
type = _cpp_get_directive_token (pfile);
if (type == CPP_OPEN_PAREN)
#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0)
#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0)
static int
do_assert (pfile)
cpp_reader *pfile;
{
struct answer *new_answer;
cpp_hashnode *node;
node = _cpp_parse_assertion (pfile, &new_answer);
if (node)
{
specific = 1;
_cpp_init_toklist (&ans, NO_DUMMY_TOKEN);
if (_cpp_scan_until (pfile, &ans, CPP_CLOSE_PAREN)
!= CPP_CLOSE_PAREN)
ERROR ("missing close paren in #unassert");
if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
ICE ("impossible token, expecting ) in do_unassert");
new_answer->next = 0;
new_answer->list.line = pfile->token_list.line;
new_answer->list.file = pfile->token_list.file;
type = _cpp_get_directive_token (pfile);
if (node->type == T_ASSERTION)
{
if (*find_answer (node, &new_answer->list))
goto err;
new_answer->next = node->value.answers;
}
node->type = T_ASSERTION;
node->value.answers = new_answer;
}
return 0;
if (type != CPP_VSPACE)
ERROR ("junk at end of #unassert");
if (hp->type != T_ASSERTION)
/* Not an error to #unassert something that isn't asserted.
goto error to clean up. */
goto error;
err:
cpp_warning (pfile, "\"%.*s\" re-asserted",
node->length - 1, node->name + 1);
FREE_ANSWER (new_answer);
return 0;
}
if (specific)
{
/* Find this specific answer and remove it. */
struct predicate *o, *p;
for (p = NULL, o = hp->value.pred; o; p = o, o = o->next)
if (_cpp_equiv_toklists (&ans, &o->answer))
{
if (p)
p->next = o->next;
else
hp->value.pred = o->next;
_cpp_free_toklist (&o->answer);
free (o);
break;
}
}
else
static int
do_unassert (pfile)
cpp_reader *pfile;
{
cpp_hashnode *node;
struct answer *answer, *temp, *next;
node = _cpp_parse_assertion (pfile, &answer);
if (node)
{
struct predicate *o, *p;
for (o = hp->value.pred; o; o = p)
/* It isn't an error to #unassert something that isn't asserted. */
if (node->type == T_ASSERTION)
{
p = o->next;
_cpp_free_toklist ((cpp_toklist *) &o->answer);
free (o);
if (answer)
{
struct answer **p = find_answer (node, &answer->list);
temp = *p;
if (temp)
{
*p = temp->next;
FREE_ANSWER (temp);
}
if (node->value.answers == 0)
node->type = T_VOID;
}
else
{
for (temp = node->value.answers; temp; temp = next)
{
next = temp->next;
FREE_ANSWER (temp);
}
node->type = T_VOID;
}
}
hp->value.pred = NULL;
}
if (hp->value.pred == NULL)
hp->type = T_VOID; /* Last answer for this predicate deleted. */
error:
_cpp_skip_rest_of_line (pfile);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
if (specific)
_cpp_free_toklist (&ans);
if (answer)
FREE_ANSWER (answer);
}
return 0;
}
......@@ -1643,11 +1458,7 @@ cpp_define (pfile, str)
strcpy (&buf[count-4], " 1\n");
}
if (cpp_push_buffer (pfile, (U_CHAR *)buf, count - 1) != NULL)
{
do_define (pfile);
cpp_pop_buffer (pfile);
}
_cpp_run_directive (pfile, &dtable[T_DEFINE], buf, count - 1);
}
/* Process MACRO as if it appeared as the body of an #undef. */
......@@ -1656,17 +1467,7 @@ cpp_undef (pfile, macro)
cpp_reader *pfile;
const char *macro;
{
/* Copy the string so we can append a newline. */
size_t len = strlen (macro);
char *buf = (char *) alloca (len + 2);
memcpy (buf, macro, len);
buf[len] = '\n';
buf[len + 1] = '\0';
if (cpp_push_buffer (pfile, (U_CHAR *)buf, len + 1) != NULL)
{
do_undef (pfile);
cpp_pop_buffer (pfile);
}
_cpp_run_directive (pfile, &dtable[T_UNDEF], macro, strlen (macro));
}
/* Process the string STR as if it appeared as the body of a #assert. */
......@@ -1675,11 +1476,7 @@ cpp_assert (pfile, str)
cpp_reader *pfile;
const char *str;
{
if (cpp_push_buffer (pfile, (const U_CHAR *)str, strlen (str)) != NULL)
{
do_assert (pfile);
cpp_pop_buffer (pfile);
}
_cpp_run_directive (pfile, &dtable[T_ASSERT], str, strlen (str));
}
/* Process STR as if it appeared as the body of an #unassert. */
......@@ -1688,11 +1485,7 @@ cpp_unassert (pfile, str)
cpp_reader *pfile;
const char *str;
{
if (cpp_push_buffer (pfile, (const U_CHAR *)str, strlen (str)) != NULL)
{
do_unassert (pfile);
cpp_pop_buffer (pfile);
}
_cpp_run_directive (pfile, &dtable[T_UNASSERT], str, strlen (str));
}
/* Determine whether the identifier ID, of length LEN, is a defined macro. */
......@@ -1705,7 +1498,7 @@ cpp_defined (pfile, id, len)
cpp_hashnode *hp = cpp_lookup (pfile, id, len);
if (hp->type == T_POISON)
{
cpp_error (pfile, "attempt to use poisoned `%s'", hp->name);
cpp_error (pfile, "attempt to use poisoned \"%s\"", hp->name);
return 0;
}
return (hp->type != T_VOID);
......
......@@ -108,7 +108,8 @@ typedef struct cpp_hashnode cpp_hashnode;
T(CPP_DOT_STAR, ".*") \
T(CPP_MIN, "<?") /* extension */ \
T(CPP_MAX, ">?") \
C(CPP_OTHER, 0) /* stray punctuation */ \
T(CPP_PLACEMARKER, "") /* Placemarker token. */ \
C(CPP_OTHER, 0) /* stray punctuation */ \
\
I(CPP_NAME, 0) /* word */ \
I(CPP_INT, 0) /* 23 */ \
......@@ -121,15 +122,11 @@ typedef struct cpp_hashnode cpp_hashnode;
\
I(CPP_COMMENT, 0) /* Only if output comments. */ \
N(CPP_MACRO_ARG, 0) /* Macro argument. */ \
N(CPP_SUBLIST, 0) /* Sublist. */ \
N(CPP_EOF, 0) /* End of file. */ \
N(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \
I(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \
\
/* Obsolete - will be removed when no code uses them still. */ \
T(CPP_VSPACE, "\n") /* End of line. */ \
N(CPP_HSPACE, 0) /* Horizontal white space. */ \
N(CPP_DIRECTIVE, 0) /* #define and the like */ \
N(CPP_MACRO, 0) /* Like a NAME, but expanded. */
T(CPP_VSPACE, "\n") /* End of line. */
#define T(e, s) e,
#define I(e, s) e,
......@@ -154,49 +151,42 @@ struct cpp_name
const unsigned char *text;
};
/* Accessor macros for token lists - all expect you have a
list and an index. */
#define TOK_TYPE(l_, i_) ((l_)->tokens[i_].type)
#define TOK_FLAGS(l_, i_) ((l_)->tokens[i_].flags)
#define TOK_AUX(l_, i_) ((l_)->tokens[i_].aux)
#define TOK_COL(l_, i_) ((l_)->tokens[i_].col)
#define TOK_INT(l_, i_) ((l_)->tokens[i_].val.integer)
#define TOK_NAME(l_, i_) ((l_)->tokens[i_].val.name.text)
#define TOK_LEN(l_, i_) ((l_)->tokens[i_].val.name.len)
#define TOK_PREV_WHITE(l_, i_) (TOK_FLAGS(l_, i_) & PREV_WHITESPACE)
/* Flags for the cpp_token structure. */
#define PREV_WHITESPACE 1 /* If whitespace before this token. */
#define BOL 2 /* Beginning of line. */
#define DIGRAPH 4 /* If it was a digraph. */
#define UNSIGNED_INT 8 /* If int preprocessing token unsigned. */
#define PREV_WHITE (1 << 0) /* If whitespace before this token. */
#define BOL (1 << 1) /* Beginning of logical line. */
#define DIGRAPH (1 << 2) /* If it was a digraph. */
#define STRINGIFY_ARG (1 << 3) /* If macro argument to be stringified. */
#define PASTE_LEFT (1 << 4) /* If on LHS of a ## operator. */
#define PASTED (1 << 5) /* The result of a ## operator. */
#define GNU_VARARGS (1 << 6) /* GNU ## kludge. */
/* A preprocessing token. This has been carefully packed and should
occupy 16 bytes on both 32- and 64-bit hosts. */
occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */
struct cpp_token
{
unsigned short col; /* starting column of this token */
ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* node type */
unsigned char flags; /* flags - see above */
unsigned int aux; /* CPP_OTHER character. Hash of a
NAME, or something - see uses
in the code */
unsigned int line; /* starting line number of this token */
unsigned short col; /* starting column of this token */
ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */
unsigned char flags; /* flags - see above */
union
{
struct cpp_name name; /* a string */
HOST_WIDEST_INT integer; /* an integer */
HOST_WIDEST_INT integer; /* an integer */
struct cpp_name name; /* a string */
unsigned int aux; /* argument no. for a CPP_MACRO_ARG, or
character represented by CPP_OTHER. */
} val;
};
/* General flags. */
#define LIST_OFFSET (1 << 0)
/* Directive flags. */
#define SYNTAX_INCLUDE (1 << 8)
/* cpp_toklist flags. */
#define LIST_OFFSET (1 << 0)
#define VAR_ARGS (1 << 1)
#define BEG_OF_FILE (1 << 2)
typedef int (*directive_handler) PARAMS ((cpp_reader *));
struct directive; /* These are deliberately incomplete. */
struct answer;
struct macro_args;
struct cpp_context;
struct cpp_toklist
{
......@@ -208,11 +198,15 @@ struct cpp_toklist
unsigned int name_used; /* _bytes_ used */
unsigned int name_cap; /* _bytes_ allocated */
/* If the list represents a directive, this points to it. */
const struct directive *directive;
const char *file; /* in file name */
unsigned int line; /* starting line number */
/* The handler to call after lexing the rest of this line.
-1 for none */
short dirno;
unsigned short params_len; /* length of macro parameter names. */
short int paramc; /* no. of macro params (-1 = obj-like). */
/* Per-list flags, see above */
unsigned short flags;
......@@ -224,12 +218,12 @@ struct cpp_buffer
const unsigned char *rlimit; /* end of valid data */
const unsigned char *buf; /* entire buffer */
const unsigned char *line_base; /* start of current line */
const unsigned char *mark; /* Saved position for lengthy backtrack. */
struct cpp_buffer *prev;
/* Filename specified with #line command. */
const char *nominal_fname;
/* Actual directory of this file, used only for "" includes */
struct file_name_list *actual_dir;
......@@ -237,10 +231,6 @@ struct cpp_buffer
to record control macros. */
struct include_file *inc;
/* If the buffer is the expansion of a macro, this points to the
macro's hash table entry. */
struct cpp_hashnode *macro;
/* Value of if_stack at start of this file.
Used to prohibit unmatched #endif (etc) in an include file. */
struct if_stack *if_stack;
......@@ -248,29 +238,13 @@ struct cpp_buffer
/* Line number at line_base (above). */
unsigned int lineno;
/* True if buffer contains escape sequences.
Currently there are two kinds:
"\r-" means following identifier should not be macro-expanded.
"\r " means a token-separator. This turns into " " in final output
if not stringizing and needed to separate tokens; otherwise nothing.
Any other two-character sequence beginning with \r is an error.
If this is NOT set, then \r is a one-character escape meaning backslash
newline. This is guaranteed not to occur in the middle of a token.
The two interpretations of \r do not conflict, because the two-character
escapes are used only in macro buffers, and backslash-newline is removed
from macro expansion text in collect_expansion and/or macarg. */
char has_escapes;
/* True if we have already warned about C++ comments in this file.
The warning happens only for C89 extended mode with -pedantic on,
or for -Wtraditional, and only once per file (otherwise it would
be far too noisy). */
char warned_cplusplus_comments;
/* In a file buffer, true if this buffer's data is mmapped
(currently never the case). In a macro buffer, true if this
buffer's data must be freed. */
/* True if this buffer's data is mmapped. */
char mapped;
};
......@@ -354,7 +328,7 @@ struct cpp_options
/* Nonzero means don't copy comments into the output file. */
unsigned char discard_comments;
/* Nonzero means process the ANSI trigraph sequences. */
/* Nonzero means process the ISO trigraph sequences. */
unsigned char trigraphs;
/* Nonzero means print the names of included files rather than the
......@@ -396,6 +370,10 @@ struct cpp_options
with the # indented from the beginning of the line. */
unsigned char warn_traditional;
/* Nonzero means warn if ## is applied to two tokens that cannot be
pasted together. */
unsigned char warn_paste;
/* Nonzero means turn warnings into errors. */
unsigned char warnings_are_errors;
......@@ -417,7 +395,7 @@ struct cpp_options
/* Zero means dollar signs are punctuation. */
unsigned char dollars_in_ident;
/* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */
/* Nonzero means try to imitate old fashioned non-ISO preprocessor. */
unsigned char traditional;
/* Nonzero means warn if undefined identifiers are evaluated in an #if. */
......@@ -460,19 +438,18 @@ struct cpp_options
unsigned char show_column;
};
/* A cpp_reader encapsulates the "state" of a pre-processor run.
Applying cpp_get_token repeatedly yields a stream of pre-processor
tokens. Usually, there is only one cpp_reader object active. */
struct cpp_reader
{
/* HACK FIXME. Maybe make into cpp_printer printer later. */
cpp_printer *printer;
/* Top of buffer stack. */
cpp_buffer *buffer;
/* Token list used by get_directive_token. */
cpp_toklist directbuf;
/* A buffer used for both for cpp_get_token's output, and also internally. */
unsigned char *token_buffer;
/* Allocated size of token_buffer. CPP_RESERVE allocates space. */
......@@ -483,8 +460,9 @@ struct cpp_reader
/* Error counter for exit code */
unsigned int errors;
/* Line where a newline was first seen in a string constant. */
/* Line and column where a newline was first seen in a string constant. */
unsigned int multiline_string_line;
unsigned int multiline_string_column;
/* Current depth in #include directives that use <...>. */
unsigned int system_include_depth;
......@@ -509,19 +487,46 @@ struct cpp_reader
for include files. (Altered as we get more of them.) */
unsigned int max_include_len;
/* Potential controlling macro for the current buffer. This is only
live between the #endif and the end of file, and there can only
be one at a time, so it is per-reader not per-buffer. */
const cpp_hashnode *potential_control_macro;
/* Token column position adjustment owing to tabs in whitespace. */
unsigned int col_adjust;
/* Token list used to store logical lines with new lexer. */
cpp_toklist token_list;
/* Temporary token store. */
cpp_token **temp_tokens;
unsigned int temp_cap;
unsigned int temp_alloced;
unsigned int temp_used;
/* Date and time tokens. Calculated together if either is requested. */
cpp_token *date;
cpp_token *time;
/* The # of a the current directive. It may not be first in line if
we append, and finding it is tedious. */
const cpp_token *first_directive_token;
/* Context stack. Used for macro expansion and for determining
which macros are disabled. */
unsigned int context_cap;
unsigned int cur_context;
unsigned int no_expand_level;
unsigned int paste_level;
struct cpp_context *contexts;
/* Current arguments when scanning arguments. Used for pointer
fix-up. */
struct macro_args *args;
/* Buffer of -M output. */
struct deps *deps;
/* A buffer used only by read_and_prescan (in cppfiles.c), which is
allocated once per cpp_reader object to keep it off the stack. */
unsigned char *input_buffer;
size_t input_buffer_len;
/* User visible options. */
struct cpp_options opts;
......@@ -532,31 +537,24 @@ struct cpp_reader
/* If non-zero, macros are not expanded. */
unsigned char no_macro_expand;
/* If non-zero, directives cause a hard error. Used when parsing
macro arguments. */
unsigned char no_directives;
/* We're printed a warning recommending against using #import. */
unsigned char import_warning;
/* If true, characters between '<' and '>' are a single (string) token. */
unsigned char parsing_include_directive;
/* True if escape sequences (as described for has_escapes in
parse_buffer) should be emitted. */
unsigned char output_escapes;
/* 0: Have seen non-white-space on this line.
1: Only seen white space so far on this line.
2: Only seen white space so far in this file. */
unsigned char only_seen_white;
/* True after cpp_start_read completes. Used to inhibit some
warnings while parsing the command line. */
unsigned char done_initializing;
/* True if we are skipping a failed conditional group. */
unsigned char skipping;
/* Do we need to save paramter spellings. */
unsigned char save_parameter_spellings;
/* If we're in lex_line. */
unsigned char in_lex_line;
/* True if output_line_command needs to output a newline. */
unsigned char need_newline;
};
/* struct cpp_printer encapsulates state used to convert the stream of
......@@ -611,13 +609,8 @@ enum node_type
T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
T_TIME, /* `__TIME__' */
T_STDC, /* `__STDC__' */
T_CONST, /* Constant string, used by `__SIZE_TYPE__' etc */
T_XCONST, /* Ditto, but the string is malloced memory */
T_POISON, /* poisoned identifier */
T_MACRO, /* object-like macro */
T_FMACRO, /* function-like macro */
T_IDENTITY, /* macro defined to itself */
T_EMPTY, /* macro defined to nothing */
T_MACRO, /* a macro, either object-like or function-like */
T_ASSERTION /* predicate for #assert */
};
......@@ -634,11 +627,10 @@ struct cpp_hashnode
ENUM_BITFIELD(node_type) type : 8; /* node type */
char disabled; /* macro turned off for rescan? */
union {
const unsigned char *cpval; /* some predefined macros */
const struct object_defn *odefn; /* #define foo bar */
const struct funct_defn *fdefn; /* #define foo(x) bar(x) */
struct predicate *pred; /* #assert */
union
{
const cpp_toklist *expansion; /* a macro's replacement list. */
struct answer *answers; /* answers to an assertion. */
} value;
union tree_node *fe_value; /* front end value */
......@@ -646,23 +638,17 @@ struct cpp_hashnode
const unsigned char name[1]; /* name[length] */
};
extern void _cpp_lex_file PARAMS((cpp_reader *));
extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
extern enum cpp_ttype cpp_get_token PARAMS ((cpp_reader *));
extern enum cpp_ttype cpp_get_non_space_token PARAMS ((cpp_reader *));
extern void cpp_reader_init PARAMS ((cpp_reader *));
extern cpp_printer *cpp_printer_init PARAMS ((cpp_reader *, cpp_printer *));
extern int cpp_start_read PARAMS ((cpp_reader *, cpp_printer *, const char *));
extern void cpp_output_tokens PARAMS ((cpp_reader *, cpp_printer *));
extern void cpp_output_list PARAMS ((cpp_reader *, cpp_printer *,
const cpp_toklist *));
extern void cpp_output_tokens PARAMS ((cpp_reader *, cpp_printer *,
unsigned int));
extern void cpp_finish PARAMS ((cpp_reader *, cpp_printer *));
extern void cpp_cleanup PARAMS ((cpp_reader *));
extern cpp_buffer *cpp_file_buffer PARAMS((cpp_reader *));
extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *));
extern void cpp_define PARAMS ((cpp_reader *, const char *));
extern void cpp_assert PARAMS ((cpp_reader *, const char *));
extern void cpp_undef PARAMS ((cpp_reader *, const char *));
......
......@@ -68,6 +68,7 @@ main (argc, argv)
print = cpp_printer_init (pfile, &parse_out);
if (! print)
return (FATAL_EXIT_CODE);
pfile->printer = print;
if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname)))
return (FATAL_EXIT_CODE);
......
......@@ -432,8 +432,6 @@ write_lbrac ()
struct partial_proto
{
struct partial_proto *next;
char *fname; /* name of function */
char *rtype; /* return type */
struct fn_decl *fn;
int line_seen;
};
......@@ -497,15 +495,13 @@ recognized_macro (fname)
}
void
recognized_extern (name, name_length, type, type_length)
const char *name;
const char *type ATTRIBUTE_UNUSED;
int name_length, type_length ATTRIBUTE_UNUSED;
recognized_extern (name)
const cpp_token *name;
{
switch (special_file_handling)
{
case errno_h:
if (name_length == 5 && strncmp (name, "errno", 5) == 0 && !seen_errno)
if (!cpp_idcmp (name->val.name.text, name->val.name.len, "errno"))
seen_errno = 1, required_other--;
break;
......@@ -515,25 +511,17 @@ recognized_extern (name, name_length, type, type_length)
}
/* Called by scan_decls if it saw a function definition for a function
named FNAME, with return type RTYPE, and argument list ARGS,
in source file FILE_SEEN on line LINE_SEEN.
KIND is 'I' for an inline function;
'F' if a normal function declaration preceded by 'extern "C"'
(or nested inside 'extern "C"' braces); or
named FNAME, in source file FILE_SEEN on line LINE_SEEN. KIND is
'I' for an inline function; 'F' if a normal function declaration
preceded by 'extern "C"' (or nested inside 'extern "C"' braces); or
'f' for other function declarations. */
void
recognized_function (fname, fname_length,
kind, rtype, rtype_length,
have_arg_list, file_seen, line_seen)
const char *fname;
int fname_length;
recognized_function (fname, kind, have_arg_list, file_seen)
const cpp_token *fname;
int kind; /* One of 'f' 'F' or 'I' */
const char *rtype;
int rtype_length;
int have_arg_list;
const char *file_seen;
int line_seen;
{
struct partial_proto *partial;
int i;
......@@ -543,7 +531,8 @@ recognized_function (fname, fname_length,
missing_extern_C_count++;
#endif
fn = lookup_std_proto (fname, fname_length);
fn = lookup_std_proto ((const char *)fname->val.name.text,
fname->val.name.len);
/* Remove the function from the list of required function. */
if (fn)
......@@ -577,12 +566,7 @@ recognized_function (fname, fname_length,
partial_count++;
partial = (struct partial_proto *)
obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
partial->fname = obstack_alloc (&scan_file_obstack, fname_length + 1);
bcopy (fname, partial->fname, fname_length);
partial->fname[fname_length] = 0;
partial->rtype = obstack_alloc (&scan_file_obstack, rtype_length + 1);
sprintf (partial->rtype, "%.*s", rtype_length, rtype);
partial->line_seen = line_seen;
partial->line_seen = fname->line;
partial->fn = fn;
fn->partial = partial;
partial->next = partial_proto_list;
......@@ -590,7 +574,7 @@ recognized_function (fname, fname_length,
if (verbose)
{
fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
inc_filename, partial->fname);
inc_filename, fn->fname);
}
}
......@@ -646,19 +630,12 @@ read_scan_file (in_fname, argc, argv)
for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
check_macro_names (&scan_in, cur_symbols->names);
if (verbose && (scan_in.errors + warnings) > 0)
fprintf (stderr, "(%s: %d errors and %d warnings from cpp)\n",
inc_filename, scan_in.errors, warnings);
if (scan_in.errors)
exit (SUCCESS_EXIT_CODE);
/* Traditionally, getc and putc are defined in terms of _filbuf and _flsbuf.
If so, those functions are also required. */
if (special_file_handling == stdio_h
&& (fn = lookup_std_proto ("_filbuf", 7)) != NULL)
{
static const unsigned char getchar_call[] = "getchar();";
int old_written = CPP_WRITTEN (&scan_in);
int seen_filbuf = 0;
cpp_buffer *buf = CPP_BUFFER (&scan_in);
if (cpp_push_buffer (&scan_in, getchar_call,
......@@ -668,14 +645,17 @@ read_scan_file (in_fname, argc, argv)
/* Scan the macro expansion of "getchar();". */
for (;;)
{
enum cpp_ttype token = cpp_get_token (&scan_in);
int length = CPP_WRITTEN (&scan_in) - old_written;
unsigned char *id = scan_in.token_buffer + old_written;
CPP_SET_WRITTEN (&scan_in, old_written);
if (token == CPP_EOF && CPP_BUFFER (&scan_in) == buf)
break;
if (token == CPP_NAME && cpp_idcmp (id, length, "_filbuf") == 0)
const cpp_token *t = cpp_get_token (&scan_in);
if (t->type == CPP_EOF)
{
cpp_pop_buffer (&scan_in);
if (CPP_BUFFER (&scan_in) == buf)
break;
}
else if (t->type == CPP_NAME && cpp_idcmp (t->val.name.text,
t->val.name.len,
"_filbuf") == 0)
seen_filbuf++;
}
if (seen_filbuf)
......@@ -1030,8 +1010,6 @@ check_protection (ifndef_line, endif_line)
}
else if (!strcmp (buf.base, "define"))
{
if (if_nesting != 1)
goto skip_to_eol;
c = inf_skip_spaces (c);
c = inf_scan_ident (&buf, c);
if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
......
......@@ -45,7 +45,7 @@ skip_to_closing_brace (pfile)
int nesting = 1;
for (;;)
{
enum cpp_ttype token = cpp_get_token (pfile);
enum cpp_ttype token = cpp_get_token (pfile)->type;
if (token == CPP_EOF)
break;
if (token == CPP_OPEN_BRACE)
......@@ -84,24 +84,17 @@ scan_decls (pfile, argc, argv)
char **argv ATTRIBUTE_UNUSED;
{
int saw_extern, saw_inline;
int start_written;
/* If declarator_start is non-zero, it marks the start of the current
declarator. If it is zero, we are either still parsing the
decl-specs, or prev_id_start marks the start of the declarator. */
int declarator_start;
int prev_id_start, prev_id_end = 0;
enum cpp_ttype token;
const cpp_token *prev_id;
const cpp_token *token;
new_statement:
CPP_SET_WRITTEN (pfile, 0);
start_written = 0;
token = cpp_get_token (pfile);
handle_statement:
current_extern_C = 0;
saw_extern = 0;
saw_inline = 0;
if (token == CPP_OPEN_BRACE)
if (token->type == CPP_OPEN_BRACE)
{
/* Pop an 'extern "C"' nesting level, if appropriate. */
if (extern_C_braces_length
......@@ -110,120 +103,112 @@ scan_decls (pfile, argc, argv)
brace_nesting--;
goto new_statement;
}
if (token == CPP_OPEN_BRACE)
if (token->type == CPP_OPEN_BRACE)
{
brace_nesting++;
goto new_statement;
}
if (token == CPP_EOF)
if (token->type == CPP_EOF)
{
cpp_pop_buffer (pfile);
if (CPP_BUFFER (pfile) == NULL)
return 0;
else
goto new_statement;
goto new_statement;
}
if (token == CPP_SEMICOLON)
if (token->type == CPP_SEMICOLON)
goto new_statement;
if (token != CPP_NAME)
if (token->type != CPP_NAME)
goto new_statement;
prev_id_start = 0;
declarator_start = 0;
prev_id = 0;
for (;;)
{
switch (token)
switch (token->type)
{
default:
goto handle_statement;
case CPP_MULT:
case CPP_AND:
case CPP_PLACEMARKER:
/* skip */
break;
case CPP_COMMA:
case CPP_SEMICOLON:
if (prev_id && saw_extern)
{
recognized_extern (prev_id);
}
if (token->type == CPP_COMMA)
break;
/* ... fall through ... */
case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE:
goto new_statement;
case CPP_EOF:
cpp_pop_buffer (pfile);
if (CPP_BUFFER (pfile) == NULL)
return 0;
break;
case CPP_OPEN_PAREN:
/* Looks like this is the start of a formal parameter list. */
if (prev_id_start)
if (prev_id)
{
int nesting = 1;
int have_arg_list = 0;
cpp_buffer *fbuf = cpp_file_buffer (pfile);
unsigned int func_lineno = CPP_BUF_LINE (fbuf);
for (;;)
{
token = cpp_get_token (pfile);
if (token == CPP_OPEN_PAREN)
if (token->type == CPP_OPEN_PAREN)
nesting++;
else if (token == CPP_CLOSE_PAREN)
else if (token->type == CPP_CLOSE_PAREN)
{
nesting--;
if (nesting == 0)
break;
}
else if (token == CPP_EOF)
else if (token->type == CPP_EOF)
break;
else if (token == CPP_NAME || token == CPP_ELLIPSIS)
else if (token->type == CPP_NAME
|| token->type == CPP_ELLIPSIS)
have_arg_list = 1;
}
recognized_function (pfile->token_buffer + prev_id_start,
prev_id_end - prev_id_start,
recognized_function (prev_id,
(saw_inline ? 'I'
: in_extern_C_brace || current_extern_C
? 'F' : 'f'),
pfile->token_buffer, prev_id_start,
have_arg_list,
fbuf->nominal_fname, func_lineno);
token = cpp_get_non_space_token (pfile);
if (token == CPP_OPEN_BRACE)
? 'F' : 'f'), have_arg_list,
CPP_BUFFER (pfile)->nominal_fname);
token = cpp_get_token (pfile);
if (token->type == CPP_OPEN_BRACE)
{
/* skip body of (normally) inline function */
skip_to_closing_brace (pfile);
goto new_statement;
}
goto maybe_handle_comma;
if (token->type == CPP_SEMICOLON)
goto new_statement;
}
break;
case CPP_OTHER:
if (CPP_WRITTEN (pfile) == (size_t) start_written + 1
&& (CPP_PWRITTEN (pfile)[-1] == '*'
|| CPP_PWRITTEN (pfile)[-1] == '&'))
declarator_start = start_written;
else
goto handle_statement;
break;
case CPP_COMMA:
case CPP_SEMICOLON:
if (prev_id_start && saw_extern)
{
recognized_extern (pfile->token_buffer + prev_id_start,
prev_id_end - prev_id_start,
pfile->token_buffer,
prev_id_start);
}
/* ... fall through ... */
maybe_handle_comma:
if (token != CPP_COMMA)
goto new_statement;
/* Handle multiple declarators in a single declaration,
as in: extern char *strcpy (), *strcat (), ... ; */
if (declarator_start == 0)
declarator_start = prev_id_start;
CPP_SET_WRITTEN (pfile, declarator_start);
break;
case CPP_NAME:
/* "inline" and "extern" are recognized but skipped */
if (!cpp_idcmp (pfile->token_buffer,
CPP_WRITTEN (pfile), "inline"))
if (!cpp_idcmp (token->val.name.text, token->val.name.len, "inline"))
{
saw_inline = 1;
CPP_SET_WRITTEN (pfile, start_written);
}
else if (!cpp_idcmp (pfile->token_buffer,
CPP_WRITTEN (pfile), "extern"))
else if (!cpp_idcmp (token->val.name.text,
token->val.name.len, "extern"))
{
saw_extern = 1;
CPP_SET_WRITTEN (pfile, start_written);
token = cpp_get_non_space_token (pfile);
if (token == CPP_STRING
&& strcmp (pfile->token_buffer, "\"C\"") == 0)
token = cpp_get_token (pfile);
if (token->type == CPP_STRING
&& !cpp_idcmp (token->val.name.text,
token->val.name.len, "C"))
{
CPP_SET_WRITTEN (pfile, start_written);
current_extern_C = 1;
token = cpp_get_non_space_token (pfile);
if (token == CPP_OPEN_BRACE)
token = cpp_get_token (pfile);
if (token->type == CPP_OPEN_BRACE)
{
brace_nesting++;
extern_C_braces[extern_C_braces_length++]
......@@ -236,29 +221,9 @@ scan_decls (pfile, argc, argv)
break;
}
/* This may be the name of a variable or function. */
prev_id_start = start_written;
prev_id_end = CPP_WRITTEN (pfile);
break;
case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE: case CPP_DIRECTIVE:
goto new_statement; /* handle_statement? */
case CPP_EOF:
if (CPP_BUFFER (pfile) == NULL)
return 0;
/* else fall through */
case CPP_HSPACE: case CPP_VSPACE: case CPP_COMMENT:
/* Skip initial white space. */
if (start_written == 0)
CPP_SET_WRITTEN (pfile, 0);
prev_id = token;
break;
default:
prev_id_start = 0;
}
start_written = CPP_WRITTEN (pfile);
token = cpp_get_token (pfile);
}
}
......@@ -50,6 +50,8 @@ struct fn_decl
struct partial_proto *partial;
};
struct cpp_token;
extern int lineno;
extern void sstring_append _PARAMS((sstring *, sstring *));
extern void make_sstring_space _PARAMS((sstring *, int));
......@@ -58,8 +60,9 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int));
extern int scan_string _PARAMS((FILE *, sstring *, int));
extern int read_upto _PARAMS((FILE *, sstring *, int));
extern unsigned long hash _PARAMS((const char *));
extern void recognized_function _PARAMS((const char *, int, int, const char *, int, int, const char *, int));
extern void recognized_extern _PARAMS((const char *, int, const char *, int));
extern void recognized_function _PARAMS((const struct cpp_token *, int, int,
const char *));
extern void recognized_extern _PARAMS((const struct cpp_token *));
extern unsigned int hashstr _PARAMS((const char *, unsigned int));
struct cpp_reader;
......
2000-07-03 Zack Weinberg <zack@wolery.cumb.org>
* testsuite/gcc.dg/cpp/19951025-1.c: Adjust regexps.
* testsuite/gcc.dg/cpp/19990703-1.c: Likewise.
* testsuite/gcc.dg/cpp/20000625-1.c: Likewise.
* testsuite/gcc.dg/cpp/20000625-2.c: Likewise.
* testsuite/gcc.dg/cpp/macro1.c,
testsuite/gcc.dg/cpp/paste1.c, testsuite/gcc.dg/cpp/paste2.c,
testsuite/gcc.dg/cpp/paste3.c, testsuite/gcc.dg/cpp/paste4.c,
testsuite/gcc.dg/cpp/strify1.c,
testsuite/gcc.dg/cpp/strify2.c: New tests.
2000-07-03 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/20000703-1.c: New test.
......
/* { dg-do preprocess } */
/* { dg-error "include expects" "" { target *-*-* } 4 } */
/* { dg-warning "no newline" "" { target *-*-* } 5 } */
/* { dg-error "newline at end" "" { target *-*-* } 4 } */
#include /\
......@@ -14,7 +14,7 @@
int
main(void)
{
char *x = SP1(0,MZ);
char *x = SP1(0,MZ); /* { dg-warning "valid preprocessing token" "" } */
char *y = "0-0"; /* should be the expansion of SP1(0,MZ) */
if(strcmp(x, y))
......
......@@ -11,6 +11,6 @@ main(void)
{
goto socket;
ENTRY(socket)
ENTRY(socket) /* { dg-warning "valid preprocessing token" "" } */
return 0;
}
......@@ -7,6 +7,7 @@
#define xstr(x) #x
const char a[] = str(symbol_version(getrlimit, GLIBC_2.0));
/* { dg-warning "valid preprocessing token" "" { target *-*-* } 9 } */
const char b[] = str(getrlimit@GLIBC_2.0);
const char c[] = "getrlimit@GLIBC_2.0";
......
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do run } */
/* Tests various macros are correctly expanded. */
extern int puts (const char *);
extern void abort (void);
#define err(str) do { puts(str); abort(); } while (0)
#define j(x, y) x + y
#define k(x, y) j(x + 2, y +
int q(int x) {return x + 40;}
int B(int x) {return x + 20;}
int foo(int x) {return x + 10;}
int bar(int x, int y) {return x + y;}
int baz(int x, int y) {return x + y;}
int toupper(int x) {return x + 32;}
int main (int argc, char *argv[])
{
#define q(x) x
if (q(q)(2) != 42)
err ("q");
#define A(x) B(x)
if (A(A(2)) != 42)
err ("A");
#define E(x) A x
#define F (22)
if (E(F) != 42)
err ("E(F)");
#define COMMA ,
#define NASTY(a) j(a 37)
if (NASTY (5 COMMA) != 42)
err ("NASTY");
#define bar(x, y) foo(x(y, 0))
#define apply(x, y) foo(x(y, 22))
#define bam bar
if (bar(bar, 32) != 42) /* foo(bar(32, 0)). */
err ("bar bar");
if (bar(bam, 32) != 42) /* Same. */
err ("bar bam");
if (apply(bar, baz) != 42) /* foo(foo(baz(22, 0))). */
err ("apply bar baz");
#define __tobody(c, f) f (c)
#define toupper(c) __tobody (c, toupper)
if (toupper (10) != 42) /* toupper (10). */
err ("toupper");
/* This looks like it has too many ')', but it hasn't. */
if (k(1, 4) 35) != 42)
err ("k");
/*#define B(x) Z B(x)
#define XEXP(RTX, N) RTX->fld[N].rtx
#define PATTERN(INSN) XEXP(INSN, 3)
#define COST(X) XEXP (XEXP (x, 0), 0)
#define M(a) OK M (a)
#define stpcpy(a) M(a)
#define C(x) A(x)
XEXP (PATTERN (insn), i);
XEXP (XEXP (insn, 3), i);
COST (b)*/
return 0;
}
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do preprocess } */
/* Test operator ## semantics. */
#define bad1 ## owt /* { dg-error "cannot" "## at objlike start" } */
#define bad2 owt ## /* { dg-error "cannot" "## at objlike end" } */
#define bad3(x) ## x /* { dg-error "cannot" "## at funlike start" } */
#define bad4(x) x ## /* { dg-error "cannot" "## at funlike end" } */
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do run } */
/* { dg-options "-std=c99 -pedantic-errors" } */
/* Test ## behaviour and corner cases thoroughly. The macro expander
failed many of these during development. */
#include <string.h>
#ifndef __WCHAR_TYPE__
#define __WCHAR_TYPE__ int
#endif
typedef __WCHAR_TYPE__ wchar_t;
extern int puts (const char *);
extern void abort (void);
#define err(str) do { puts(str); abort(); } while (0)
#define EMPTY
#define str(x) #x
#define xstr(x) str(x)
#define glue(x, y) x ## y
#define xglue(x, y) glue (x, y)
#define glue3(x, y, z) x ## y ## z
#define glue_var(x, ...) x ## __VA_ARGS__
#define __muldi3 __NDW(mul, 3 = 50)
#define __NDW(a,b) __ ## a ## di ## b
#define m3 NDW()
#define NDW(x) m3 ## x = 50
#define five 5
#define fifty int fif ## ty
/* Defines a function called glue, returning what it is passed. */
int glue (glue,) (int x)
{
return x;
}
int main ()
{
/* m3 and __muldi3 would sometimes cause an infinite loop. Ensure
we only expand fifty once. */
fifty = 50, m3, __muldi3;
/* General glue and macro expanding test. */
int five0 = xglue (glue (fi, ve), 0);
/* Tests only first and last tokens are pasted, and pasting to form
the != operator. Should expand to: if (five0 != 50). */
if (glue3 (fi, ve0 !,= glue (EMPTY 5, 0)))
err ("five0 != 50");
/* Test varags pasting, and pasting to form the >> operator. */
if (glue_var(50 >, > 1 != 25))
err ("Operator >> pasting");
/* The LHS should not attempt to expand twice, and thus becomes a
call to the function glue, but the RHS should fully expand. */
if (glue (gl, ue) (12) != glue (xgl, ue) (1, 2))
err ("Recursive macros");
/* Test placemarker pasting. The glued lines should all appear
neatly in the same column and below each other, though we don't
test that here. */
{
int glue3(a, b, ) = 1, glue3(a,,) = 1;
glue3(a, , b)++;
glue3(, a, b)++;
glue3(,a,)++;
glue3(,,a)++;
if (a != 3 || ab != 3 glue3(,,))
err ("Placemarker pasting");
}
/* Test that macros in arguments are not expanded. */
{
int glue (EMPTY,1) = 123, glue (T, EMPTY) = 123;
if (EMPTY1 != 123 || TEMPTY != 123)
err ("Pasted arguments macro expanding");
}
/* Test various paste combinations. */
{
const wchar_t* wc_array = glue(L, "wide string");
wchar_t wc = glue(L, 'w');
const char * hh = xstr(xglue(glue(%, :), glue(%, :)));
int array glue (<, :) 1 glue (:, >) = glue(<, %) 1 glue(%, >);
int x = 4;
if (array[0] != 1)
err ("Digraph pasting");
x glue (>>, =) 1; /* 2 */
x glue (<<, =) 1; /* 4 */
x glue (*, =) 2; /* 8 */
x glue (+, =) 100; /* 108 */
x glue (-, =) 50; /* 58 */
x glue (/, =) 2; /* 29 */
x glue (%, =) 20; /* 9 */
x glue (&, =) 254; /* 8 */
x glue (|, =) 16; /* 24 */
x glue (^, =) 18; /* 10 */
if (x != 10 || 0 glue (>, =) 1 glue (|, |) 1 glue (<, =) 0)
err ("Various operator pasting");
if (strcmp (hh, "%:%:"))
err ("Pasted digraph spelling");
if ((glue (., 0) glue (=, =) .0) + (glue3 (1.0e, +, 1) == 10.0) != 2)
err ("Pasted numbers");
}
return 0;
}
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do compile } */
#define plus +
void foo()
{
int a, b = 1;
/* The correct "a = 1 + ++b" will compile.
The incorrect "a = 1 +++b" won't. */
a = 1 plus++b;
}
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do compile } */
/* Since 1.0e and + form the pasted token, 1 is a separate token and
so should be output with a preceding space. The old preprocessor
gets this wrong. */
#define glue(x, y) x ## y
int main ()
{
double d = glue (1.0e, +1); /* { dg-error "floating const|parse error" } */
return 0;
}
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do preprocess } */
/* Test operator # semantics. */
#define OK1 # /* No problem. */
#define OK2(x) x#x /* No problem. */
#define bad1(x) # /* { dg-error "followed by a macro parameter" "#1" } */
#define bad2(x) #y /* { dg-error "followed by a macro parameter" "#2" } */
/* Copyright (C) 2000 Free Software Foundation, Inc. */
/* { dg-do run } */
/* { dg-options "-std=c99 -pedantic-errors" } */
/* Tests a whole bunch of things are correctly stringified. */
extern int strcmp (const char *, const char *);
extern int puts (const char *);
extern void abort (void);
#define err(str) do { puts(str); abort(); } while (0)
#define str(x) #x
#define xstr(x) str(x)
#define strvar(...) #__VA_ARGS__
int main (int argc, char *argv[])
{
str (\); /* { dg-warning "valid string" "str(\)" } */
str (\\\); /* { dg-warning "valid string" "str(\\\)" } */
/* This also serves as a useful test of the value of __INCLUDE_LEVEL. */
if (strcmp (xstr (__INCLUDE_LEVEL__), "0"))
err ("macro expansion");
if (strcmp(str (__INCLUDE_LEVEL__), "__INCLUDE_LEVEL__"))
err ("macro name");
if (strcmp(str ("s\n"), "\"s\\n\""))
err ("quoted string");
if (strcmp (str (a b), "a \200 b"))
err ("unprintable char");
if (strcmp (str ( a b@ c ), "a b@ c"))
err ("internal whitespace");
if (strcmp (str(a \n), "a \n"))
err ("backslash token");
if (strcmp (strvar (foo, bar), "foo, bar"))
err ("variable arguments");
return 0;
}
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