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> 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 * cppspec.c (lang_specific_driver): Use double quotes in error
message. message.
......
...@@ -58,23 +58,27 @@ print_containing_files (pfile, ip) ...@@ -58,23 +58,27 @@ print_containing_files (pfile, ip)
if (first) if (first)
{ {
first = 0; first = 0;
/* N.B. The current line in each outer source file is one
greater than the line of the #include, so we must
subtract one to correct for that. */
fprintf (stderr, _("In file included from %s:%u"), fprintf (stderr, _("In file included from %s:%u"),
ip->nominal_fname, CPP_BUF_LINE (ip)); ip->nominal_fname, CPP_BUF_LINE (ip) - 1);
} }
else else
/* Translators note: this message is used in conjunction /* Translators note: this message is used in conjunction
with "In file included from %s:%ld" and some other with "In file included from %s:%ld" and some other
tricks. We want something like this: tricks. We want something like this:
In file included from sys/select.h:123, | In file included from sys/select.h:123,
from sys/types.h:234, | from sys/types.h:234,
from userfile.c:31: | from userfile.c:31:
bits/select.h:45: <error message here> | bits/select.h:45: <error message here>
with all the "from"s lined up.
The trailing comma is at the beginning of this message, The trailing comma is at the beginning of this message,
and the trailing colon is not translated. */ and the trailing colon is not translated. */
fprintf (stderr, _(",\n from %s:%u"), fprintf (stderr, _(",\n from %s:%u"),
ip->nominal_fname, CPP_BUF_LINE (ip)); ip->nominal_fname, CPP_BUF_LINE (ip) - 1);
} }
if (first == 0) if (first == 0)
fputs (":\n", stderr); fputs (":\n", stderr);
...@@ -111,17 +115,14 @@ v_message (pfile, is_error, file, line, col, msg, ap) ...@@ -111,17 +115,14 @@ v_message (pfile, is_error, file, line, col, msg, ap)
const char *msg; const char *msg;
va_list ap; va_list ap;
{ {
cpp_buffer *ip = cpp_file_buffer (pfile); cpp_buffer *ip = CPP_BUFFER (pfile);
if (ip) if (ip)
{ {
if (file == NULL) if (file == NULL)
file = ip->nominal_fname; file = ip->nominal_fname;
if (line == 0) if (line == 0)
{ line = _cpp_get_line (pfile, &col);
line = CPP_BUF_LINE (ip);
col = CPP_BUF_COL (ip);
}
print_containing_files (pfile, ip); print_containing_files (pfile, ip);
print_file_and_line (file, line, print_file_and_line (file, line,
CPP_OPTION (pfile, show_column) ? col : 0); CPP_OPTION (pfile, show_column) ? col : 0);
...@@ -132,8 +133,12 @@ v_message (pfile, is_error, file, line, col, msg, ap) ...@@ -132,8 +133,12 @@ v_message (pfile, is_error, file, line, col, msg, ap)
switch (is_error) switch (is_error)
{ {
case 0: case 0:
fprintf (stderr, _("warning: ")); if (! CPP_OPTION (pfile, warnings_are_errors))
break; {
fprintf (stderr, _("warning: "));
break;
}
/* else fall through */
case 1: case 1:
if (pfile->errors < CPP_FATAL_LIMIT) if (pfile->errors < CPP_FATAL_LIMIT)
pfile->errors++; pfile->errors++;
......
...@@ -394,74 +394,22 @@ parse_assertion (pfile) ...@@ -394,74 +394,22 @@ parse_assertion (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
struct operation op; struct operation op;
struct answer *answer;
cpp_hashnode *hp; 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. */ op.op = ERROR;
_cpp_skip_hspace (pfile); hp = _cpp_parse_assertion (pfile, &answer);
if (CPP_BUF_PEEK (CPP_BUFFER (pfile)) == '(') if (hp)
{ {
if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN) /* If we get here, the syntax is valid. */
CPP_ICE ("impossible token, expecting ( in parse_assertion"); op.op = INT;
op.value = (hp->type == T_ASSERTION &&
_cpp_init_toklist (&query, NO_DUMMY_TOKEN); (answer == 0 || *find_answer (hp, &answer->list) != 0));
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. */ if (answer)
op.op = INT; FREE_ANSWER (answer);
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;
} }
out:
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
return op; return op;
syntax_error:
if (specific)
_cpp_free_toklist (&query);
op.op = ERROR;
goto out;
} }
struct token struct token
...@@ -480,8 +428,6 @@ static const struct token tokentab2[] = ...@@ -480,8 +428,6 @@ static const struct token tokentab2[] =
{"!=", NOTEQUAL}, {"!=", NOTEQUAL},
{"<=", LEQ}, {"<=", LEQ},
{">=", GEQ}, {">=", GEQ},
{"++", ERROR},
{"--", ERROR},
{NULL, ERROR} {NULL, ERROR}
}; };
...@@ -496,16 +442,20 @@ lex (pfile, skip_evaluation) ...@@ -496,16 +442,20 @@ lex (pfile, skip_evaluation)
enum cpp_ttype token; enum cpp_ttype token;
struct operation op; struct operation op;
U_CHAR *tok_start, *tok_end; 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); token = _cpp_get_directive_token (pfile);
tok_start = pfile->token_buffer + old_written; tok_start = pfile->token_buffer + old_written;
tok_end = CPP_PWRITTEN (pfile); tok_end = CPP_PWRITTEN (pfile);
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
switch (token) switch (token)
{ {
case CPP_PLACEMARKER:
CPP_SET_WRITTEN (pfile, old_written);
goto retry;
case CPP_EOF: /* Should not happen ... */ case CPP_EOF: /* Should not happen ... */
case CPP_VSPACE: case CPP_VSPACE:
op.op = 0; op.op = 0;
...@@ -524,6 +474,7 @@ lex (pfile, skip_evaluation) ...@@ -524,6 +474,7 @@ lex (pfile, skip_evaluation)
return parse_charconst (pfile, tok_start, tok_end); return parse_charconst (pfile, tok_start, tok_end);
case CPP_NAME: case CPP_NAME:
/* FIXME: could this not overflow the tok_start buffer? */
if (!ustrncmp (tok_start, U"defined", 7)) if (!ustrncmp (tok_start, U"defined", 7))
return parse_defined (pfile); return parse_defined (pfile);
...@@ -539,7 +490,16 @@ lex (pfile, skip_evaluation) ...@@ -539,7 +490,16 @@ lex (pfile, skip_evaluation)
case CPP_HASH: case CPP_HASH:
return parse_assertion (pfile); 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. */ /* See if it is a special token of length 2. */
if (tok_start + 2 == tok_end) if (tok_start + 2 == tok_end)
{ {
...@@ -553,8 +513,6 @@ lex (pfile, skip_evaluation) ...@@ -553,8 +513,6 @@ lex (pfile, skip_evaluation)
op.op = toktab->token; op.op = toktab->token;
return op; return op;
} }
/* fall through */
default:
op.op = *tok_start; op.op = *tok_start;
return op; return op;
} }
...@@ -612,7 +570,7 @@ parse_escape (pfile, string_ptr, result_mask) ...@@ -612,7 +570,7 @@ parse_escape (pfile, string_ptr, result_mask)
case 'e': case 'e':
case 'E': case 'E':
if (CPP_PEDANTIC (pfile)) 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; return TARGET_ESC;
case 'f': case 'f':
return TARGET_FF; return TARGET_FF;
...@@ -844,9 +802,7 @@ _cpp_parse_expr (pfile) ...@@ -844,9 +802,7 @@ _cpp_parse_expr (pfile)
char buff[5]; char buff[5];
/* Save parser state and set it to something sane. */ /* Save parser state and set it to something sane. */
int save_only_seen_white = pfile->only_seen_white;
int save_skipping = pfile->skipping; int save_skipping = pfile->skipping;
pfile->only_seen_white = 0;
pfile->skipping = 0; pfile->skipping = 0;
/* We've finished when we try to reduce this. */ /* We've finished when we try to reduce this. */
...@@ -875,7 +831,8 @@ _cpp_parse_expr (pfile) ...@@ -875,7 +831,8 @@ _cpp_parse_expr (pfile)
case ERROR: case ERROR:
goto syntax_error; goto syntax_error;
default: default:
SYNTAX_ERROR ("invalid character in #if"); SYNTAX_ERROR2 ("invalid character '%s' in #if",
op_to_str (op.op, buff));
push_immediate: push_immediate:
case INT: case INT:
...@@ -1168,7 +1125,6 @@ _cpp_parse_expr (pfile) ...@@ -1168,7 +1125,6 @@ _cpp_parse_expr (pfile)
if (stack != init_stack) if (stack != init_stack)
free (stack); free (stack);
CPP_SET_WRITTEN (pfile, old_written); CPP_SET_WRITTEN (pfile, old_written);
pfile->only_seen_white = save_only_seen_white;
pfile->skipping = save_skipping; pfile->skipping = save_skipping;
return result; return result;
} }
...@@ -180,7 +180,7 @@ open_include_file (pfile, filename) ...@@ -180,7 +180,7 @@ open_include_file (pfile, filename)
#ifdef EACCES #ifdef EACCES
if (errno == 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); filename);
} }
#endif #endif
...@@ -360,16 +360,16 @@ cpp_make_system_header (pfile, pbuf, flag) ...@@ -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)) #define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
void void
_cpp_execute_include (pfile, f, len, no_reinclude, search_start) _cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets)
cpp_reader *pfile; cpp_reader *pfile;
U_CHAR *f; const U_CHAR *f;
unsigned int len; unsigned int len;
int no_reinclude; int no_reinclude;
struct file_name_list *search_start; struct file_name_list *search_start;
int angle_brackets;
{ {
struct include_file *inc; struct include_file *inc;
char *fname = (char *)f; char *fname;
int angle_brackets = fname[0] == '<';
if (!search_start) if (!search_start)
{ {
...@@ -387,9 +387,8 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start) ...@@ -387,9 +387,8 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start)
return; return;
} }
/* Remove quote marks. */ fname = alloca (len + 1);
fname++; memcpy (fname, f, len);
len -= 2;
fname[len] = '\0'; fname[len] = '\0';
inc = find_include_file (pfile, fname, search_start); inc = find_include_file (pfile, fname, search_start);
...@@ -470,32 +469,27 @@ _cpp_execute_include (pfile, f, len, no_reinclude, 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. */ if F cannot be located or dated, 1, if it is newer and 0 if older. */
int int
_cpp_compare_file_date (pfile, f, len, search_start) _cpp_compare_file_date (pfile, f, len, angle_brackets)
cpp_reader *pfile; cpp_reader *pfile;
U_CHAR *f; const U_CHAR *f;
unsigned int len; unsigned int len;
struct file_name_list *search_start; int angle_brackets;
{ {
char *fname = (char *)f; char *fname;
int angle_brackets = fname[0] == '<'; struct file_name_list *search_start;
struct include_file *inc; 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);
if (angle_brackets) else if (CPP_OPTION (pfile, ignore_srcdir))
search_start = CPP_OPTION (pfile, bracket_include); search_start = CPP_OPTION (pfile, quote_include);
else if (CPP_OPTION (pfile, ignore_srcdir)) else
search_start = CPP_OPTION (pfile, quote_include); search_start = CPP_BUFFER (pfile)->actual_dir;
else
search_start = CPP_BUFFER (pfile)->actual_dir;
}
/* Remove quote marks. */ fname = alloca (len + 1);
fname++; memcpy (fname, f, len);
len -= 2;
fname[len] = '\0'; fname[len] = '\0';
inc = find_include_file (pfile, fname, search_start); inc = find_include_file (pfile, fname, search_start);
if (!inc) if (!inc)
...@@ -534,6 +528,12 @@ cpp_read_file (pfile, fname) ...@@ -534,6 +528,12 @@ cpp_read_file (pfile, fname)
f = open_include_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); return read_include_file (pfile, f);
} }
...@@ -550,12 +550,17 @@ read_include_file (pfile, inc) ...@@ -550,12 +550,17 @@ read_include_file (pfile, inc)
cpp_buffer *fp; cpp_buffer *fp;
int fd = inc->fd; 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); fp = cpp_push_buffer (pfile, NULL, 0);
if (fp == 0) if (fp == 0)
goto push_fail; goto push_fail;
if (fstat (fd, &st) < 0) if (fd < 0 || fstat (fd, &st) < 0)
goto perror_fail; goto perror_fail;
inc->date = st.st_mtime; inc->date = st.st_mtime;
...@@ -622,9 +627,6 @@ read_include_file (pfile, inc) ...@@ -622,9 +627,6 @@ read_include_file (pfile, inc)
if (length == 0) if (length == 0)
inc->cmacro = NEVER_REREAD; inc->cmacro = NEVER_REREAD;
else
/* Temporary - I hope. */
length = _cpp_prescan (pfile, fp, length);
fp->rlimit = fp->buf + length; fp->rlimit = fp->buf + length;
fp->cur = fp->buf; fp->cur = fp->buf;
...@@ -637,13 +639,13 @@ read_include_file (pfile, inc) ...@@ -637,13 +639,13 @@ read_include_file (pfile, inc)
fp->actual_dir = actual_directory (pfile, inc->name); fp->actual_dir = actual_directory (pfile, inc->name);
pfile->input_stack_listing_current = 0; pfile->input_stack_listing_current = 0;
pfile->only_seen_white = 2;
return 1; return 1;
perror_fail: perror_fail:
cpp_error_from_errno (pfile, inc->name); cpp_error_from_errno (pfile, inc->name);
/* Do not try to read this file again. */ /* Do not try to read this file again. */
close (fd); if (fd != -1)
close (fd);
inc->fd = -1; inc->fd = -1;
inc->cmacro = NEVER_REREAD; inc->cmacro = NEVER_REREAD;
fail: fail:
......
...@@ -31,75 +31,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -31,75 +31,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef abort #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. */ /* This is the second argument to eq_HASHNODE. */
struct hashdummy struct hashdummy
{ {
...@@ -107,96 +38,30 @@ struct hashdummy ...@@ -107,96 +38,30 @@ struct hashdummy
unsigned short length; 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 unsigned int hash_HASHNODE PARAMS ((const void *));
static int eq_HASHNODE PARAMS ((const void *, const void *)); static int eq_HASHNODE PARAMS ((const void *, const void *));
static void del_HASHNODE PARAMS ((void *)); static void del_HASHNODE PARAMS ((void *));
static cpp_hashnode *make_HASHNODE PARAMS ((const U_CHAR *, size_t, static cpp_hashnode *make_HASHNODE PARAMS ((const U_CHAR *, size_t,
enum node_type, unsigned int)); 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 int dump_hash_helper PARAMS ((void **, void *));
static void push_macro_expansion PARAMS ((cpp_reader *, const U_CHAR *, static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *));
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 *));
/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */ static const cpp_token *count_params PARAMS ((cpp_reader *,
#define HASHSIZE 500 const cpp_token *,
cpp_toklist *));
/* The arglist structure is built by collect_params to tell static cpp_toklist *parse_define PARAMS((cpp_reader *));
collect_funlike_expansion where the argument names begin. That is, static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
for a define like "#define f(x,y,z) foo+x-bar*y", the arglist would const cpp_toklist *));
contain pointers to the strings x, y, and z. static int save_expansion PARAMS((cpp_reader *, cpp_toklist *,
collect_funlike_expansion would then build a funct_defn node, with const cpp_token *, const cpp_token *));
reflist nodes pointing to the places x, y, and z had appeared. static unsigned int find_param PARAMS ((const cpp_token *,
const cpp_token *));
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. */
struct arg static const unsigned char var_args_str[] = "__VA_ARGS__";
{
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 *));
/* Calculate hash of a string of length LEN. */ /* Calculate hash of a string of length LEN. */
unsigned int unsigned int
...@@ -297,7 +162,8 @@ cpp_lookup (pfile, name, len) ...@@ -297,7 +162,8 @@ cpp_lookup (pfile, name, len)
return *slot; return *slot;
new = make_HASHNODE (name, len, T_VOID, hash); new = make_HASHNODE (name, len, T_VOID, hash);
new->value.cpval = NULL; new->value.expansion = NULL;
*slot = new; *slot = new;
return new; return new;
} }
...@@ -317,1521 +183,419 @@ void ...@@ -317,1521 +183,419 @@ void
_cpp_free_definition (h) _cpp_free_definition (h)
cpp_hashnode *h; cpp_hashnode *h;
{ {
if (h->type == T_XCONST) if (h->type == T_MACRO)
free ((PTR) h->value.cpval); _cpp_free_toklist (h->value.expansion);
else if (h->type == T_MACRO) h->value.expansion = NULL;
{
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;
}
} }
/* 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 static unsigned int
trad_stringify (pfile, base, len, argc, argv, pat, endpat, last) find_param (first, token)
cpp_reader *pfile; const cpp_token *first, *token;
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;
{ {
struct object_defn *defn; unsigned int param = 0;
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);
if (len <= 4) for (; first < token && first->type != CPP_CLOSE_PAREN; first++)
cpp_ice (pfile, "empty object-like macro went through full #define"); if (first->type == CPP_NAME)
{
exp = (U_CHAR *) xmalloc (len + 1); param++;
memcpy (exp, pfile->token_buffer + start, len); if (first->val.name.len == token->val.name.len
exp[len] = '\0'; && !memcmp (first->val.name.text, token->val.name.text,
token->val.name.len))
defn = (struct object_defn *) xmalloc (sizeof (struct object_defn)); return param;
defn->length = len; }
defn->expansion = exp;
return defn; return 0;
} }
/* Read a replacement list for a function-like macro, and build the /* Counts the parameters to a function like macro, and saves their
funct_defn structure. LIST contains the replacement list, spellings if necessary. Returns the token that we stopped scanning
beginning at REPLACEMENT. ARGLIST specifies the formal parameters at; if it's type isn't CPP_CLOSE_PAREN there was an error, which
to look for in the text of the definition. */ has been reported. */
static const cpp_token *
static struct funct_defn * count_params (pfile, first, list)
collect_funlike_expansion (pfile, list, arglist, replacement)
cpp_reader *pfile; cpp_reader *pfile;
const cpp_token *first;
cpp_toklist *list; cpp_toklist *list;
struct arglist *arglist;
unsigned int replacement;
{ {
struct funct_defn *defn; unsigned int params_len = 0, prev_ident = 0;
struct reflist *pat = 0, *endpat = 0; unsigned int line = pfile->token_list.line;
enum cpp_ttype token; const cpp_token *token, *temp;
unsigned int start, last;
unsigned int i; list->paramc = 0;
int j, argc; for (token = first;; token++)
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++)
{ {
token = TOK_TYPE (list, i); switch (token->type)
tok = TOK_NAME (list, i);
len = TOK_LEN (list, i);
switch (token)
{ {
case CPP_HASH: case CPP_EOF:
/* # is special in function-like macros with no args. cpp_error_with_line (pfile, line, token->col,
(6.10.3.2 para 1.) However, it is not special after "missing ')' in macro parameter list");
PASTE. (Implied by 6.10.3.3 para 4.) Nor is it special goto out;
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:;
}
if (last_token != PASTE && last_token != START case CPP_COMMENT:
&& TOK_PREV_WHITE (list, i)) continue; /* Ignore -C comments. */
CPP_PUTC (pfile, ' ');
if (last_token == ARG && CPP_TRADITIONAL (pfile)
&& !TOK_PREV_WHITE (list, i))
endpat->raw_after = 1;
switch (token) case CPP_NAME:
{ if (prev_ident)
case CPP_STRING:
case CPP_CHAR:
if (argc == 0)
goto norm;
if (CPP_TRADITIONAL (pfile))
{ {
last = trad_stringify (pfile, tok, len, argc, argv, cpp_error_with_line (pfile, line, token->col,
&pat, &endpat, last); "macro parameters must be comma-separated");
break; 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)) cpp_error_with_line (pfile, line, token->col,
warn_trad_stringify (pfile, tok, len, argc, argv); "\"%s\" is not a valid parameter name",
goto norm; var_args_str);
goto out;
} }
case CPP_NAME: params_len += token->val.name.len + 1;
for (j = 0; j < argc; j++) prev_ident = 1;
if (argv[j].len == len list->paramc++;
&& !ustrncmp (tok, argv[j].name, argv[j].len))
goto addref;
/* fall through */ /* Constraint 6.10.3.6 - duplicate parameter names. */
default: if (find_param (first, token))
norm:
if (last_token == STRIZE)
{ {
/* This is a mandatory diagnostic (6.10.3.2 para 1), but cpp_error_with_line (pfile, line, token->col,
in assembly language # may have some other "duplicate macro parameter \"%.*s\"",
significance we don't know about, so suppress the (int) token->val.name.len,
warning. */ token->val.name.text);
if (! CPP_OPTION (pfile, lang_asm)) goto out;
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_PUTS (pfile, tok, len); break;
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;
}
if (last_token == STRIZE) default:
cpp_error (pfile, "`#' is not followed by a macro argument name"); cpp_error_with_line (pfile, line, token->col,
else if (last_token == PASTE) "illegal token in macro parameter list");
cpp_error (pfile, "`##' at end of macro definition"); goto out;
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;
}
/* Is argument NEW, which has just been added to the argument list, case CPP_CLOSE_PAREN:
a duplicate of a previous argument name? */ if (prev_ident || list->paramc == 0)
static int goto scanned;
duplicate_arg_p (args, new)
U_CHAR *args, *new;
{
size_t newlen = ustrlen (new) + 1;
size_t oldlen;
while (args < new) /* Fall through to pick up the error. */
{ case CPP_COMMA:
oldlen = ustrlen (args) + 1; if (!prev_ident)
if (!memcmp (args, new, MIN (oldlen, newlen))) {
return 1; cpp_error_with_line (pfile, line, token->col,
args += oldlen; "missing parameter name");
} goto out;
return 0; }
} prev_ident = 0;
break;
static unsigned int case CPP_ELLIPSIS:
collect_params (pfile, list, arglist) /* Convert ISO-style var_args to named varargs by changing
cpp_reader *pfile; the ellipsis into an identifier with name __VA_ARGS__.
cpp_toklist *list; This simplifies other handling. We can safely have its
struct arglist *arglist; text outside list->namebuf because there is no reason to
{ extend the size of the list's namebuf (and thus change
struct arg *argv = 0; the pointer) in do_define. */
const U_CHAR *tok; if (!prev_ident)
U_CHAR *namebuf, *p; {
unsigned int len, argslen; cpp_token *tok = (cpp_token *) token;
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;
}
/* Scan once and count the number of parameters; also check for tok->type = CPP_NAME;
syntax errors here. */ tok->val.name.len = sizeof (var_args_str) - 1;
argc = 0; tok->val.name.text = var_args_str; /* Safe. */
argslen = 0; list->paramc++;
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;
scanned: if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
if (argc == 0) /* function-like macro, no arguments */ cpp_pedwarn (pfile,
{ "C89 does not permit anon varargs macros");
arglist->argc = 0; }
arglist->argv = 0; else if (CPP_PEDANTIC (pfile))
arglist->namebuf = 0; cpp_pedwarn (pfile,
return i + 1; "ISO C does not permit named varargs parameters");
}
if (argslen == 0) list->flags |= VAR_ARGS;
{ token++;
cpp_ice (pfile, "collect_params: argc=%d argslen=0", argc); if (token->type == CPP_CLOSE_PAREN)
return 0; goto scanned;
cpp_error_with_line (pfile, line, token->col,
"')' expected after \"...\"");
goto out;
}
} }
/* Now allocate space and copy the suckers. */ scanned:
argv = (struct arg *) xmalloc (argc * sizeof (struct arg)); /* Store the null-terminated parameter spellings of a function, to
namebuf = (U_CHAR *) xmalloc (argslen); provide pedantic warnings to satisfy 6.10.3.2, or for use when
p = namebuf; dumping macro definitions. */
a = 0; if (list->paramc > 0 && pfile->save_parameter_spellings)
for (j = 2; j < i; j++) {
switch (TOK_TYPE (list, j)) U_CHAR *buf;
{
case CPP_NAME: _cpp_reserve_name_space (list, params_len);
tok = TOK_NAME (list, j); list->params_len = list->name_used = params_len;
len = TOK_LEN (list, j); buf = list->namebuf;
memcpy (p, tok, len); for (temp = first; temp <= token; temp++)
p[len] = '\0'; if (temp->type == CPP_NAME)
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
{ {
if (CPP_PEDANTIC (pfile)) memcpy (buf, temp->val.name.text, temp->val.name.len);
cpp_pedwarn (pfile, buf += temp->val.name.len;
"ISO C does not permit named varargs macros"); *buf++ = '\0';
argv[a-1].rest_arg = 1;
} }
break; }
default:
cpp_ice (pfile, "collect_params: impossible token type %d",
TOK_TYPE (list, j));
}
arglist->argc = argc; out:
arglist->argv = argv; return token;
arglist->namebuf = namebuf;
return i + 1;
} }
/* Create a definition for a macro. The replacement text (including /* Parses a #define directive. Returns null pointer on error. */
formal parameters if present) is in LIST. If FUNLIKE is true, this static cpp_toklist *
is a function-like macro. */ parse_define (pfile)
int
_cpp_create_definition (pfile, list, hp)
cpp_reader *pfile; cpp_reader *pfile;
cpp_toklist *list;
cpp_hashnode *hp;
{ {
struct funct_defn *fdefn = 0; const cpp_token *token, *first_param;
struct object_defn *odefn = 0; cpp_toklist *list;
enum node_type ntype; int prev_white = 0;
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;
replacement = collect_params (pfile, list, &args); while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
if (replacement == 0) prev_white = 1;
return 0;
fdefn = collect_funlike_expansion (pfile, list, &args, replacement);
if (fdefn == 0)
return 0;
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 if (!prev_white && !(token->flags & PREV_WHITE))
whitespace after the name (6.10.3 para 3). */
else
{ {
if (! TOK_PREV_WHITE (list, 1)) if (token->type == CPP_OPEN_PAREN)
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)
{ {
const char *file; token = count_params (pfile, first_param, list);
unsigned int line, col; if (token->type != CPP_CLOSE_PAREN)
if (hp->type == T_FMACRO) goto error;
{ token++;
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");
} }
else if (token->type != CPP_EOF)
cpp_pedwarn (pfile,
"ISO C requires whitespace after the macro name");
} }
/* And replace the old definition (if any). */ if (save_expansion (pfile, list, token, first_param))
_cpp_free_definition (hp);
hp->type = ntype;
if (ntype == T_FMACRO)
{ {
fdefn->file = CPP_BUFFER (pfile)->nominal_fname; error:
fdefn->line = list->line; _cpp_free_toklist (list);
fdefn->col = TOK_COL (list, 0); 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:;
}
} }
}
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 '\"': return list;
case '\\':
CPP_PUTC_Q (pfile, '\\');
CPP_PUTC_Q (pfile, c);
break;
case '\0':
CPP_PUTC_Q (pfile, '\"');
return;
}
} }
/* static int
* expand things like __FILE__. Place the expansion into the output check_macro_redefinition (pfile, hp, list2)
* 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)
cpp_reader *pfile; cpp_reader *pfile;
cpp_hashnode *hp; cpp_hashnode *hp;
const cpp_toklist *list2;
{ {
const struct funct_defn *defn; const cpp_toklist *list1;
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;
}
pfile->output_escapes++; if (hp->type != T_MACRO)
scan_arguments (pfile, defn, args, hp->name); return ! pfile->done_initializing;
/* If macro wants zero args, we parsed the arglist for checking only. /* Clear the whitespace and BOL flags of the first tokens. They get
Read directly from the macro definition. */ altered during macro expansion, but is not significant here. */
if (defn->nargs == 0 || defn->pattern == 0) list1 = hp->value.expansion;
{ list1->tokens[0].flags &= ~(PREV_WHITE|BOL);
/* If the defn is the empty string, don't bother pushing it. */ list2->tokens[0].flags &= ~(PREV_WHITE|BOL);
if (defn->length > 4)
push_macro_expansion (pfile, defn->expansion, defn->length, hp);
}
else
funlike_macroexpand (pfile, hp, args);
CPP_SET_WRITTEN (pfile, old_written); if (!_cpp_equiv_toklists (list1, list2))
pfile->output_escapes--; return 0;
}
static void if (CPP_OPTION (pfile, pedantic)
scan_arguments (pfile, defn, args, name) && list1->paramc > 0
cpp_reader *pfile; && (list1->params_len != list2->params_len
const struct funct_defn *defn; || memcmp (list1->namebuf, list2->namebuf, list1->params_len)))
struct argdata *args; return 0;
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;
}
/* Don't output an error message if we have already output one for return 1;
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);
}
} }
static void /* Copy the tokens of the expansion. Change the type of macro
stringify (pfile, arg) 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; cpp_reader *pfile;
struct argdata *arg; cpp_toklist *list;
const cpp_token *first;
const cpp_token *first_param;
{ {
int arglen = arg->raw_length; const cpp_token *token;
int escaped = 0; cpp_token *dest;
int in_string = 0; unsigned int len, ntokens;
int c; unsigned char *buf;
int i;
/* Initially need_space is -1. Otherwise, 1 means the previous /* Count tokens in expansion. We drop paste tokens, and stringize
character was a space, but we suppressed it; 0 means the previous tokens, so don't count them. */
character was a non-space. */ ntokens = len = 0;
int need_space = -1; for (token = first; token->type != CPP_EOF; token++)
i = 0;
arg->stringified = CPP_WRITTEN (pfile);
CPP_PUTC (pfile, '\"'); /* insert beginning quote */
for (; i < arglen; i++)
{ {
c = (ARG_BASE + arg->raw)[i]; const char *msg;
if (!in_string) if (token->type == CPP_PASTE)
{ {
/* Delete "\r " and "\r-" escapes. */ /* Token-paste ##, but is a normal token if traditional. */
if (c == '\r') if (! CPP_TRADITIONAL (pfile))
{
i++;
continue;
}
/* Internal sequences of whitespace are replaced by one
space except within a string or char token. */
else if (is_space(c))
{ {
if (need_space == 0) msg = "\"##\" cannot appear at either end of a macro expansion";
need_space = 1; /* Constraint 6.10.3.3.1 */
if (token == first || token[1].type == CPP_EOF)
goto error;
continue; continue;
} }
else if (need_space > 0)
CPP_PUTC (pfile, ' ');
need_space = 0;
} }
else if (token->type == CPP_HASH)
if (escaped)
escaped = 0;
else
{ {
if (c == '\\') /* Stringifying #, but is a normal character if traditional,
escaped = 1; or in object-like macros. Constraint 6.10.3.2.1. */
if (in_string) if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile))
{ {
if (c == in_string) if (token[1].type == CPP_NAME
in_string = 0; && 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 /* Allocate space to hold the tokens. Empty expansions are stored
funlike_macroexpand (pfile, hp, args) as a single placemarker token. */
cpp_reader *pfile; if (ntokens == 0)
cpp_hashnode *hp; ntokens++;
struct argdata *args; _cpp_expand_token_space (list, ntokens);
{ if (len > 0)
const struct funct_defn *defn = hp->value.fdefn; _cpp_expand_name_space (list, len);
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);
args[ap->argno].expand_length dest = list->tokens;
= CPP_WRITTEN (pfile) - args[ap->argno].expanded; 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 switch (token->type)
token concatenation. */ {
xbuf_len += args[ap->argno].expand_length + 4; 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 dest->type = CPP_MACRO_ARG;
substituted in. TOTLEN is the total size generated so far. if (token[-1].type == CPP_HASH && ! CPP_TRADITIONAL (pfile))
OFFSET is the index in the definition of where we are copying dest->flags = token[-1].flags | STRINGIFY_ARG;
from. */ else
offset = totlen = 0; dest->flags = token->flags; /* Particularly PREV_WHITE. */
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--;
/* Delete the nonwhites before them. */ if ((int) param_no == list->paramc && list->flags & VAR_ARGS
while (totlen > count_before && !is_space(xbuf[totlen - 1])) && dest != list->tokens && dest[-1].flags & PASTE_LEFT)
totlen--; dest[-1].flags |= GNU_VARARGS;
} dest++;
continue;
if (ap->stringify != 0) case CPP_PASTE:
{ if (! CPP_TRADITIONAL (pfile))
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)
{ {
/* Arg is concatenated after: delete trailing whitespace, dest[-1].flags |= PASTE_LEFT;
whitespace markers, and no-reexpansion markers. */ continue;
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;
}
} }
break;
/* Delete any no-reexpansion marker that precedes case CPP_HASH:
an identifier at the beginning of the argument. */ /* Stringifying #. Constraint 6.10.3.2.1 */
if (p1 + 2 <= l1 && p1[0] == '\r' && p1[1] == '-') if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile)
p1 += 2; && token[1].type == CPP_NAME
&& find_param (first_param, token + 1))
continue;
break;
memcpy (xbuf + totlen, p1, l1 - p1); default:
totlen += l1 - p1; 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 /* Copy the token. */
&& unsafe_chars (pfile, xbuf[totlen - 1], exp[offset])) *dest = *token;
{ if (token_spellings[token->type].type > SPELL_NONE)
xbuf[totlen++] = '\r'; {
xbuf[totlen++] = ' '; 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 if (dest == list->tokens)
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)
{ {
case EOF: dest->type = CPP_PLACEMARKER;
/* We don't know what the previous character was. We do know dest->flags = 0;
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 == '=');
} }
list->tokens_used = ntokens;
list->line = pfile->token_list.line;
list->file = pfile->token_list.file;
list->name_used = len;
return 0; return 0;
} }
static void int
push_macro_expansion (pfile, xbuf, len, hp) _cpp_create_definition (pfile, hp)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *xbuf;
int len;
cpp_hashnode *hp; cpp_hashnode *hp;
{ {
cpp_buffer *mbuf; cpp_toklist *list;
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;
}
/* Return zero if two funct_defns are isomorphic. */ list = parse_define (pfile);
if (!list)
return 0;
static int /* Check for a redefinition. Redefinition of a macro is allowed if
compare_defs (pfile, d1, d2) and only if the old and new definitions are the same.
cpp_reader *pfile; (6.10.3 paragraph 2). */
const struct funct_defn *d1, *d2;
{ if (hp->type != T_VOID)
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)
{ {
U_CHAR *arg1 = d1->argnames; if (!check_macro_redefinition (pfile, hp, list))
U_CHAR *arg2 = d2->argnames;
size_t len;
int i = d1->nargs;
while (i--)
{ {
len = ustrlen (arg1) + 1; cpp_pedwarn (pfile, "\"%s\" redefined", hp->name);
if (ustrcmp (arg1, arg2)) if (pfile->done_initializing && hp->type == T_MACRO)
return 1; cpp_pedwarn_with_file_and_line (pfile,
arg1 += len; hp->value.expansion->file,
arg2 += len; 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 /* Dump the definition of macro MACRO on stdout. The format is suitable
...@@ -1846,97 +610,56 @@ _cpp_dump_definition (pfile, hp) ...@@ -1846,97 +610,56 @@ _cpp_dump_definition (pfile, hp)
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1); CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1);
CPP_PUTS_Q (pfile, hp->name, hp->length); CPP_PUTS_Q (pfile, hp->name, hp->length);
if (hp->type == T_EMPTY) if (hp->type == T_MACRO)
/* do nothing */;
else if (hp->type == T_FMACRO)
dump_funlike_macro (pfile, hp->value.fdefn);
else
{ {
CPP_PUTC_Q (pfile, ' '); if (hp->value.expansion->paramc >= 0)
dump_funlike_macro (pfile, hp);
if (hp->type == T_IDENTITY) else
CPP_PUTS (pfile, hp->name, hp->length);
else if (hp->type == T_MACRO)
{ {
/* The first and last two characters of a macro expansion are const cpp_toklist *list = hp->value.expansion;
always "\r "; this needs to be trimmed out. list->tokens[0].flags &= ~BOL;
So we need length-4 chars of space, plus one for the NUL. */ list->tokens[0].flags |= PREV_WHITE;
CPP_RESERVE (pfile, hp->value.odefn->length - 4 + 1); _cpp_dump_list (pfile, list, list->tokens, 1);
CPP_PUTS_Q (pfile, hp->value.odefn->expansion + 2,
hp->value.odefn->length - 4);
} }
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) if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing)
CPP_PUTC (pfile, '\n'); CPP_PUTC (pfile, '\n');
} }
static void static void
dump_funlike_macro (pfile, defn) dump_funlike_macro (pfile, node)
cpp_reader *pfile; cpp_reader *pfile;
const struct funct_defn *defn; cpp_hashnode *node;
{ {
const struct reflist *r; int i = 0;
const U_CHAR **argv = (const U_CHAR **) alloca (defn->nargs * const cpp_toklist * list = node->value.expansion;
sizeof(const U_CHAR *)); const U_CHAR *param;
int *argl = (int *) alloca (defn->nargs * sizeof(int));
const U_CHAR *x; param = list->namebuf;
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. */
CPP_PUTC_Q (pfile, '('); CPP_PUTC_Q (pfile, '(');
for (i = 0; i < defn->nargs; i++) for (i = 0; i++ < list->paramc;)
{ {
CPP_RESERVE (pfile, argl[i] + 2); unsigned int len;
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);
/* Now the definition. */ len = ustrlen (param);
x = defn->expansion; CPP_PUTS (pfile, param, len);
for (r = defn->pattern; r; r = r->next) if (i < list->paramc)
{ CPP_PUTS(pfile, ", ", 2);
i = r->nchars; else if (list->flags & VAR_ARGS)
if (*x == '\r') x += 2, i -= 2; {
/* i chars for macro text, plus the length of the macro if (!ustrcmp (param, var_args_str))
argument name, plus one for a stringify marker, plus two for pfile->limit -= sizeof (var_args_str) - 1;
each concatenation marker. */ CPP_PUTS (pfile, "...", 3);
CPP_RESERVE (pfile, }
i + argl[r->argno] + r->stringify param += len + 1;
+ (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;
} }
CPP_PUTC (pfile, ')');
i = defn->length - (x - defn->expansion) - 2; list->tokens[0].flags &= ~BOL;
if (*x == '\r') x += 2, i -= 2; list->tokens[0].flags |= PREV_WHITE;
if (i > 0) CPP_PUTS (pfile, x, i); _cpp_dump_list (pfile, list, list->tokens, 1);
} }
/* Dump out the hash table. */ /* Dump out the hash table. */
...@@ -1948,8 +671,7 @@ dump_hash_helper (h, p) ...@@ -1948,8 +671,7 @@ dump_hash_helper (h, p)
cpp_hashnode *hp = (cpp_hashnode *)*h; cpp_hashnode *hp = (cpp_hashnode *)*h;
cpp_reader *pfile = (cpp_reader *)p; cpp_reader *pfile = (cpp_reader *)p;
if (hp->type == T_MACRO || hp->type == T_FMACRO if (hp->type == T_MACRO)
|| hp->type == T_IDENTITY || hp->type == T_EMPTY)
_cpp_dump_definition (pfile, hp); _cpp_dump_definition (pfile, hp);
return 1; return 1;
} }
......
...@@ -25,11 +25,60 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ...@@ -25,11 +25,60 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
typedef unsigned char U_CHAR; typedef unsigned char U_CHAR;
#define U (const U_CHAR *) /* Intended use: U"string" */ #define U (const U_CHAR *) /* Intended use: U"string" */
/* Structure used for assertion predicates. */ /* Order here matters. Those beyond SPELL_NONE store their spelling
struct predicate in the token list, and it's length in the token->val.name.len. */
enum spell_type
{ {
struct predicate *next; SPELL_OPERATOR = 0,
struct cpp_toklist answer; 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. */ /* List of directories to look for include files in. */
...@@ -105,12 +154,6 @@ extern unsigned char _cpp_IStable[256]; ...@@ -105,12 +154,6 @@ extern unsigned char _cpp_IStable[256];
/* Macros. */ /* 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. */ /* Make sure PFILE->token_buffer has space for at least N more characters. */
#define CPP_RESERVE(PFILE, N) \ #define CPP_RESERVE(PFILE, N) \
(CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \ (CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \
...@@ -127,53 +170,15 @@ extern unsigned char _cpp_IStable[256]; ...@@ -127,53 +170,15 @@ extern unsigned char _cpp_IStable[256];
/* Append character CH to PFILE's output buffer. Make space if need be. */ /* 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)) #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) #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_PRINT_DEPS(PFILE) CPP_OPTION (PFILE, print_deps)
#define CPP_TRADITIONAL(PFILE) CPP_OPTION (PFILE, traditional) #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) \ #define CPP_PEDANTIC(PF) \
(CPP_OPTION (PF, pedantic) && !CPP_IN_SYSTEM_HEADER (PF)) (CPP_OPTION (PF, pedantic) && !CPP_IN_SYSTEM_HEADER (PF))
#define CPP_WTRADITIONAL(PF) \ #define CPP_WTRADITIONAL(PF) \
(CPP_OPTION (PF, warn_traditional) && !CPP_IN_SYSTEM_HEADER (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. */ /* Flags for _cpp_init_toklist. */
#define DUMMY_TOKEN 0 #define DUMMY_TOKEN 0
#define NO_DUMMY_TOKEN 1 #define NO_DUMMY_TOKEN 1
...@@ -181,22 +186,19 @@ extern unsigned char _cpp_IStable[256]; ...@@ -181,22 +186,19 @@ extern unsigned char _cpp_IStable[256];
/* In cpphash.c */ /* In cpphash.c */
extern unsigned int _cpp_calc_hash PARAMS ((const U_CHAR *, size_t)); extern unsigned int _cpp_calc_hash PARAMS ((const U_CHAR *, size_t));
extern void _cpp_free_definition PARAMS ((cpp_hashnode *)); extern void _cpp_free_definition PARAMS ((cpp_hashnode *));
extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_toklist *, extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *));
cpp_hashnode *));
extern void _cpp_dump_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_init_macro_hash PARAMS ((cpp_reader *));
extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *)); extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *));
/* In cppfiles.c */ /* In cppfiles.c */
extern void _cpp_simplify_pathname PARAMS ((char *)); extern void _cpp_simplify_pathname PARAMS ((char *));
extern void _cpp_execute_include PARAMS ((cpp_reader *, U_CHAR *, extern void _cpp_execute_include PARAMS ((cpp_reader *, const U_CHAR *,
unsigned int, int, unsigned int, int,
struct file_name_list *)); struct file_name_list *,
extern int _cpp_compare_file_date PARAMS ((cpp_reader *, U_CHAR *, int));
unsigned int, extern int _cpp_compare_file_date PARAMS ((cpp_reader *, const U_CHAR *,
struct file_name_list *)); unsigned int, int));
extern void _cpp_init_include_table PARAMS ((cpp_reader *)); extern void _cpp_init_include_table PARAMS ((cpp_reader *));
extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *)); 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 *)); ...@@ -204,40 +206,46 @@ extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *));
extern int _cpp_parse_expr PARAMS ((cpp_reader *)); extern int _cpp_parse_expr PARAMS ((cpp_reader *));
/* In cpplex.c */ /* 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_rest_of_line PARAMS ((cpp_reader *));
extern void _cpp_skip_hspace PARAMS ((cpp_reader *)); extern void _cpp_free_temp_tokens 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_init_input_buffer PARAMS ((cpp_reader *)); extern void _cpp_init_input_buffer PARAMS ((cpp_reader *));
extern void _cpp_grow_token_buffer PARAMS ((cpp_reader *, long)); extern void _cpp_grow_token_buffer PARAMS ((cpp_reader *, long));
extern enum cpp_ttype _cpp_get_directive_token extern enum cpp_ttype _cpp_get_directive_token
PARAMS ((cpp_reader *)); 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_init_toklist PARAMS ((cpp_toklist *, int));
extern void _cpp_clear_toklist PARAMS ((cpp_toklist *)); extern void _cpp_clear_toklist PARAMS ((cpp_toklist *));
extern void _cpp_free_toklist PARAMS ((cpp_toklist *)); extern void _cpp_free_toklist PARAMS ((const 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 int _cpp_equiv_tokens PARAMS ((const cpp_token *, extern int _cpp_equiv_tokens PARAMS ((const cpp_token *,
const cpp_token *)); const cpp_token *));
extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *, extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *,
const cpp_toklist *)); const cpp_toklist *));
extern void _cpp_expand_token_space PARAMS ((cpp_toklist *, unsigned int)); 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 */ /* 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_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. */ /* Utility routines and macros. */
#define xnew(T) (T *) xmalloc (sizeof(T)) #define xnew(T) (T *) xmalloc (sizeof(T))
......
...@@ -215,8 +215,6 @@ static void append_include_chain PARAMS ((cpp_reader *, ...@@ -215,8 +215,6 @@ static void append_include_chain PARAMS ((cpp_reader *,
char *, int, int)); char *, int, int));
static void merge_include_chains PARAMS ((cpp_reader *)); 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_dependency_output PARAMS ((cpp_reader *));
static void initialize_standard_includes PARAMS ((cpp_reader *)); static void initialize_standard_includes PARAMS ((cpp_reader *));
static void new_pending_directive PARAMS ((struct cpp_pending *, static void new_pending_directive PARAMS ((struct cpp_pending *,
...@@ -345,7 +343,7 @@ append_include_chain (pfile, pend, dir, path, cxx_aware) ...@@ -345,7 +343,7 @@ append_include_chain (pfile, pend, dir, path, cxx_aware)
if (errno != ENOENT) if (errno != ENOENT)
cpp_notice_from_errno (pfile, dir); cpp_notice_from_errno (pfile, dir);
else if (CPP_OPTION (pfile, verbose)) else if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring nonexistent directory `%s'\n"), dir); fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
return; return;
} }
...@@ -442,7 +440,7 @@ merge_include_chains (pfile) ...@@ -442,7 +440,7 @@ merge_include_chains (pfile)
&& cur->dev == other->dev) && cur->dev == other->dev)
{ {
if (CPP_OPTION (pfile, verbose)) if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"), fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
cur->name); cur->name);
prev->next = cur->next; prev->next = cur->next;
...@@ -462,7 +460,7 @@ merge_include_chains (pfile) ...@@ -462,7 +460,7 @@ merge_include_chains (pfile)
&& cur->dev == other->dev) && cur->dev == other->dev)
{ {
if (CPP_OPTION (pfile, verbose)) if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"), fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
cur->name); cur->name);
prev->next = cur->next; prev->next = cur->next;
...@@ -481,7 +479,7 @@ merge_include_chains (pfile) ...@@ -481,7 +479,7 @@ merge_include_chains (pfile)
if (quote == qtail) if (quote == qtail)
{ {
if (CPP_OPTION (pfile, verbose)) if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"), fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
quote->name); quote->name);
free (quote->name); free (quote->name);
...@@ -495,7 +493,7 @@ merge_include_chains (pfile) ...@@ -495,7 +493,7 @@ merge_include_chains (pfile)
cur = cur->next; cur = cur->next;
cur->next = brack; cur->next = brack;
if (CPP_OPTION (pfile, verbose)) if (CPP_OPTION (pfile, verbose))
fprintf (stderr, _("ignoring duplicate directory `%s'\n"), fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"),
qtail->name); qtail->name);
free (qtail->name); free (qtail->name);
...@@ -513,24 +511,6 @@ merge_include_chains (pfile) ...@@ -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. */ /* Initialize a cpp_reader structure. */
void void
cpp_reader_init (pfile) cpp_reader_init (pfile)
...@@ -545,6 +525,7 @@ cpp_reader_init (pfile) ...@@ -545,6 +525,7 @@ cpp_reader_init (pfile)
CPP_OPTION (pfile, dollars_in_ident) = 1; CPP_OPTION (pfile, dollars_in_ident) = 1;
CPP_OPTION (pfile, cplusplus_comments) = 1; CPP_OPTION (pfile, cplusplus_comments) = 1;
CPP_OPTION (pfile, warn_import) = 1; CPP_OPTION (pfile, warn_import) = 1;
CPP_OPTION (pfile, warn_paste) = 1;
CPP_OPTION (pfile, discard_comments) = 1; CPP_OPTION (pfile, discard_comments) = 1;
CPP_OPTION (pfile, show_column) = 1; CPP_OPTION (pfile, show_column) = 1;
CPP_OPTION (pfile, tabstop) = 8; CPP_OPTION (pfile, tabstop) = 8;
...@@ -596,25 +577,19 @@ cpp_cleanup (pfile) ...@@ -596,25 +577,19 @@ cpp_cleanup (pfile)
pfile->token_buffer = NULL; pfile->token_buffer = NULL;
} }
if (pfile->input_buffer)
{
free (pfile->input_buffer);
pfile->input_buffer = NULL;
pfile->input_buffer_len = 0;
}
if (pfile->deps) if (pfile->deps)
deps_free (pfile->deps); deps_free (pfile->deps);
htab_delete (pfile->hashtab); htab_delete (pfile->hashtab);
splay_tree_delete (pfile->all_include_files); 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 /* 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 be entered in the macro hash table under the name NAME, with value
VALUE (if any). FLAGS tweaks the behavior a little: VALUE (if any). Two values are not compile time constants, so we tag
DUMP write debug info for this macro them in the FLAGS field instead:
VERS value is the global version_string, quoted VERS value is the global version_string, quoted
ULP value is the global user_label_prefix ULP value is the global user_label_prefix
*/ */
...@@ -622,18 +597,17 @@ cpp_cleanup (pfile) ...@@ -622,18 +597,17 @@ cpp_cleanup (pfile)
struct builtin struct builtin
{ {
const U_CHAR *name; const U_CHAR *name;
const U_CHAR *value; const char *value;
unsigned short type; unsigned short type;
unsigned short flags; unsigned short flags;
unsigned int len; unsigned int len;
}; };
#define DUMP 0x01 #define VERS 0x01
#define VERS 0x02 #define ULP 0x02
#define ULP 0x04
#define B(n, t) { U n, 0, t, 0, sizeof n - 1 } #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 C(n, v) { U n, v, T_MACRO, 0, sizeof n - 1 }
#define X(n, v, t, f) { U n, U v, t, DUMP|f, sizeof n - 1 } #define X(n, f) { U n, 0, T_MACRO, f, sizeof n - 1 }
static const struct builtin builtin_array[] = static const struct builtin builtin_array[] =
{ {
B("__TIME__", T_TIME), B("__TIME__", T_TIME),
...@@ -642,10 +616,10 @@ static const struct builtin builtin_array[] = ...@@ -642,10 +616,10 @@ static const struct builtin builtin_array[] =
B("__BASE_FILE__", T_BASE_FILE), B("__BASE_FILE__", T_BASE_FILE),
B("__LINE__", T_SPECLINE), B("__LINE__", T_SPECLINE),
B("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL), B("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL),
B("__STDC__", T_STDC),
X("__VERSION__", 0, T_XCONST, VERS), X("__VERSION__", VERS),
X("__USER_LABEL_PREFIX__", 0, T_CONST, ULP), X("__USER_LABEL_PREFIX__", ULP),
X("__STDC__", "1", T_STDC, 0),
C("__REGISTER_PREFIX__", REGISTER_PREFIX), C("__REGISTER_PREFIX__", REGISTER_PREFIX),
C("__HAVE_BUILTIN_SETJMP__", "1"), C("__HAVE_BUILTIN_SETJMP__", "1"),
#ifndef NO_BUILTIN_SIZE_TYPE #ifndef NO_BUILTIN_SIZE_TYPE
...@@ -671,35 +645,47 @@ initialize_builtins (pfile) ...@@ -671,35 +645,47 @@ initialize_builtins (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const struct builtin *b; const struct builtin *b;
const U_CHAR *val;
cpp_hashnode *hp;
for(b = builtin_array; b < builtin_array_end; b++) for(b = builtin_array; b < builtin_array_end; b++)
{ {
if (b->type == T_STDC && CPP_TRADITIONAL (pfile)) if (b->type == T_MACRO)
continue;
if (b->flags & ULP)
val = (const U_CHAR *) user_label_prefix;
else if (b->flags & VERS)
{ {
val = (const U_CHAR *) xmalloc (strlen (version_string) + 3); const char *val;
sprintf ((char *)val, "\"%s\"", version_string); 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 else
val = b->value; {
cpp_hashnode *hp;
hp = cpp_lookup (pfile, b->name, b->len);
hp->value.cpval = val; if (b->type == T_STDC && CPP_TRADITIONAL (pfile))
hp->type = b->type; continue;
if ((b->flags & DUMP) && CPP_OPTION (pfile, debug_output)) hp = cpp_lookup (pfile, b->name, b->len);
dump_special_to_buffer (pfile, b->name, b->len); hp->type = b->type;
}
} }
} }
#undef DUMP
#undef STDC
#undef VERS #undef VERS
#undef ULP #undef ULP
#undef builtin_array_end
/* Another subroutine of cpp_start_read. This one sets up to do /* Another subroutine of cpp_start_read. This one sets up to do
dependency-file output. */ dependency-file output. */
...@@ -889,6 +875,13 @@ cpp_start_read (pfile, print, fname) ...@@ -889,6 +875,13 @@ cpp_start_read (pfile, print, fname)
if (CPP_OPTION (pfile, cplusplus)) if (CPP_OPTION (pfile, cplusplus))
CPP_OPTION (pfile, warn_traditional) = 0; 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. */ /* Set this if it hasn't been set already. */
if (user_label_prefix == NULL) if (user_label_prefix == NULL)
user_label_prefix = USER_LABEL_PREFIX; user_label_prefix = USER_LABEL_PREFIX;
...@@ -898,6 +891,16 @@ cpp_start_read (pfile, print, fname) ...@@ -898,6 +891,16 @@ cpp_start_read (pfile, print, fname)
if (CPP_OPTION (pfile, preprocessed)) if (CPP_OPTION (pfile, preprocessed))
pfile->no_macro_expand++; 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 /* Set up the IStable. This doesn't do anything if we were compiled
with a compiler that supports C99 designated initializers. */ with a compiler that supports C99 designated initializers. */
init_IStable (); init_IStable ();
...@@ -946,13 +949,12 @@ cpp_start_read (pfile, print, fname) ...@@ -946,13 +949,12 @@ cpp_start_read (pfile, print, fname)
as line 0. */ as line 0. */
CPP_BUFFER (pfile)->lineno = 0; CPP_BUFFER (pfile)->lineno = 0;
if (print) if (print)
{ {
print->lineno = 0;
print->last_fname = CPP_BUFFER (pfile)->nominal_fname; print->last_fname = CPP_BUFFER (pfile)->nominal_fname;
print->last_id = pfile->include_depth; print->last_id = pfile->include_depth;
print->written = CPP_WRITTEN (pfile); print->written = CPP_WRITTEN (pfile);
print->lineno = 0;
} }
/* Install __LINE__, etc. */ /* Install __LINE__, etc. */
...@@ -968,10 +970,13 @@ cpp_start_read (pfile, print, fname) ...@@ -968,10 +970,13 @@ cpp_start_read (pfile, print, fname)
p = q; p = q;
} }
pfile->done_initializing = 1; 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; CPP_BUFFER (pfile)->lineno = 1;
if (print && ! CPP_OPTION (pfile, no_output)) 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 /* The -imacros files can be scanned now, but the -include files
have to be pushed onto the include stack and processed later, have to be pushed onto the include stack and processed later,
...@@ -992,7 +997,7 @@ cpp_start_read (pfile, print, fname) ...@@ -992,7 +997,7 @@ cpp_start_read (pfile, print, fname)
{ {
if (cpp_read_file (pfile, p->arg) if (cpp_read_file (pfile, p->arg)
&& print && ! CPP_OPTION (pfile, no_output)) && print && ! CPP_OPTION (pfile, no_output))
cpp_output_tokens (pfile, print); cpp_output_tokens (pfile, print, 1); /* record entry to file */
q = p->next; q = p->next;
free (p); free (p);
p = q; p = q;
...@@ -1073,7 +1078,7 @@ cpp_finish (pfile, print) ...@@ -1073,7 +1078,7 @@ cpp_finish (pfile, print)
/* Flush any pending output. */ /* Flush any pending output. */
if (print) if (print)
{ {
cpp_output_tokens (pfile, print); cpp_output_tokens (pfile, print, print->lineno);
if (ferror (print->outf) || fclose (print->outf)) if (ferror (print->outf) || fclose (print->outf))
cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname)); cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname));
} }
...@@ -1753,6 +1758,8 @@ handle_option (pfile, argc, argv) ...@@ -1753,6 +1758,8 @@ handle_option (pfile, argc, argv)
CPP_OPTION (pfile, warn_undef) = 1; CPP_OPTION (pfile, warn_undef) = 1;
else if (!strcmp (argv[i], "-Wimport")) else if (!strcmp (argv[i], "-Wimport"))
CPP_OPTION (pfile, warn_import) = 1; CPP_OPTION (pfile, warn_import) = 1;
else if (!strcmp (argv[i], "-Wpaste"))
CPP_OPTION (pfile, warn_paste) = 1;
else if (!strcmp (argv[i], "-Werror")) else if (!strcmp (argv[i], "-Werror"))
CPP_OPTION (pfile, warnings_are_errors) = 1; CPP_OPTION (pfile, warnings_are_errors) = 1;
else if (!strcmp (argv[i], "-Wno-traditional")) else if (!strcmp (argv[i], "-Wno-traditional"))
...@@ -1767,6 +1774,8 @@ handle_option (pfile, argc, argv) ...@@ -1767,6 +1774,8 @@ handle_option (pfile, argc, argv)
CPP_OPTION (pfile, warn_undef) = 0; CPP_OPTION (pfile, warn_undef) = 0;
else if (!strcmp (argv[i], "-Wno-import")) else if (!strcmp (argv[i], "-Wno-import"))
CPP_OPTION (pfile, warn_import) = 0; 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")) else if (!strcmp (argv[i], "-Wno-error"))
CPP_OPTION (pfile, warnings_are_errors) = 0; CPP_OPTION (pfile, warnings_are_errors) = 0;
break; break;
...@@ -1836,10 +1845,10 @@ Switches:\n\ ...@@ -1836,10 +1845,10 @@ Switches:\n\
(dirs specified with -isystem will still be used)\n\ (dirs specified with -isystem will still be used)\n\
-nostdinc++ Do not search system include directories for C++\n\ -nostdinc++ Do not search system include directories for C++\n\
-o <file> Put output into <file>\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\ -pedantic-errors Issue -pedantic warnings as errors instead\n\
-traditional Follow K&R pre-processor behaviour\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-c Assume that the input sources are in C\n\
-lang-c89 Assume that the input sources are in C89\n\ -lang-c89 Assume that the input sources are in C89\n\
-lang-c++ Assume that the input sources are in C++\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. */ ...@@ -27,23 +27,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "intl.h" #include "intl.h"
#include "symcat.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 /* Stack of conditionals currently in progress
(including both successful and failing conditionals). */ (including both successful and failing conditionals). */
struct if_stack struct if_stack
{ {
struct if_stack *next; struct if_stack *next;
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 */ int was_skipping; /* value of pfile->skipping before this if */
const cpp_hashnode *cmacro; /* macro name for #ifndef around entire file */ const cpp_hashnode *cmacro; /* macro name for #ifndef around entire file */
int type; /* type of last directive seen in this group */ int type; /* type of last directive seen in this group */
...@@ -51,30 +42,26 @@ struct if_stack ...@@ -51,30 +42,26 @@ struct if_stack
/* Forward declarations. */ /* Forward declarations. */
static void validate_else PARAMS ((cpp_reader *, const U_CHAR *)); static void validate_else PARAMS ((cpp_reader *, const U_CHAR *));
static unsigned int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int)); static int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int,
static void push_conditional PARAMS ((cpp_reader *, int, int, const U_CHAR **, unsigned int *,
const cpp_hashnode *)); int *));
static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, static void push_conditional PARAMS ((cpp_reader *, int, int,
cpp_reader *, int)); const cpp_hashnode *));
static int read_line_number PARAMS ((cpp_reader *, int *)); static void pass_thru_directive PARAMS ((cpp_reader *));
static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *)); static int read_line_number PARAMS ((cpp_reader *, int *));
static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *)); static int strtoul_for_line PARAMS ((const U_CHAR *, unsigned int,
unsigned long *));
/* 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. */
#define KANDR 0 static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *));
#define COND 1 static const cpp_hashnode *detect_if_not_defined
#define STDC89 2 PARAMS ((cpp_reader *));
#define EXTENSION 3 static cpp_hashnode *get_define_node PARAMS ((cpp_reader *));
static void dump_macro_name PARAMS ((cpp_reader *, cpp_hashnode *));
#define ORIGIN_MASK 3 /* Utility. */
#define ORIGIN(f) ((f) & ORIGIN_MASK) #define str_match(sym, len, str) \
#define TRAD_DIRECT_P(f) (ORIGIN (f) == KANDR || ORIGIN (f) == COND) ((len) == (sizeof (str) - 1) && !ustrncmp ((sym), U(str), sizeof (str) - 1))
/* This is the table of directive handlers. It is ordered by /* This is the table of directive handlers. It is ordered by
frequency of occurrence; the numbers at the end are directive frequency of occurrence; the numbers at the end are directive
...@@ -88,31 +75,31 @@ static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *)); ...@@ -88,31 +75,31 @@ static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *));
/* #sccs is not always recognized. */ /* #sccs is not always recognized. */
#ifdef SCCS_DIRECTIVE #ifdef SCCS_DIRECTIVE
# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION) /* 0 - SVR2? */ # define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION, 0)
#else #else
# define SCCS_ENTRY /* nothing */ # define SCCS_ENTRY /* nothing */
#endif #endif
#define DIRECTIVE_TABLE \ #define DIRECTIVE_TABLE \
D(define, T_DEFINE = 0, KANDR) /* 270554 */ \ D(define, T_DEFINE = 0, KANDR, COMMENTS) /* 270554 */ \
D(include, T_INCLUDE, KANDR | SYNTAX_INCLUDE) /* 52262 */ \ D(include, T_INCLUDE, KANDR, EXPAND | INCL) /* 52262 */ \
D(endif, T_ENDIF, COND) /* 45855 */ \ D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \
D(ifdef, T_IFDEF, COND) /* 22000 */ \ D(ifdef, T_IFDEF, KANDR, COND) /* 22000 */ \
D(if, T_IF, COND) /* 18162 */ \ D(if, T_IF, KANDR, COND | EXPAND) /* 18162 */ \
D(else, T_ELSE, COND) /* 9863 */ \ D(else, T_ELSE, KANDR, COND) /* 9863 */ \
D(ifndef, T_IFNDEF, COND) /* 9675 */ \ D(ifndef, T_IFNDEF, KANDR, COND) /* 9675 */ \
D(undef, T_UNDEF, KANDR) /* 4837 */ \ D(undef, T_UNDEF, KANDR, 0) /* 4837 */ \
D(line, T_LINE, KANDR) /* 2465 */ \ D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \
D(elif, T_ELIF, COND) /* 610 */ \ D(elif, T_ELIF, KANDR, COND | EXPAND) /* 610 */ \
D(error, T_ERROR, STDC89) /* 475 */ \ D(error, T_ERROR, STDC89, 0) /* 475 */ \
D(pragma, T_PRAGMA, STDC89) /* 195 */ \ D(pragma, T_PRAGMA, STDC89, 0) /* 195 */ \
D(warning, T_WARNING, EXTENSION) /* 22 GNU */ \ D(warning, T_WARNING, EXTENSION, 0) /* 22 GNU */ \
D(include_next, T_INCLUDE_NEXT, EXTENSION | SYNTAX_INCLUDE) /* 19 GNU */ \ D(include_next, T_INCLUDE_NEXT, EXTENSION, EXPAND | INCL) /* 19 GNU */ \
D(ident, T_IDENT, EXTENSION) /* 11 SVR4 */ \ D(ident, T_IDENT, EXTENSION, 0) /* 11 SVR4 */ \
D(import, T_IMPORT, EXTENSION | SYNTAX_INCLUDE) /* 0 ObjC */ \ D(import, T_IMPORT, EXTENSION, EXPAND | INCL) /* 0 ObjC */ \
D(assert, T_ASSERT, EXTENSION) /* 0 SVR4 */ \ D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \
D(unassert, T_UNASSERT, EXTENSION) /* 0 SVR4 */ \ D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \
SCCS_ENTRY SCCS_ENTRY /* 0 SVR2? */
/* Use the table to generate a series of prototypes, an enum for the /* Use the table to generate a series of prototypes, an enum for the
directive names, and an array of directive handlers. */ directive names, and an array of directive handlers. */
...@@ -122,11 +109,11 @@ SCCS_ENTRY ...@@ -122,11 +109,11 @@ SCCS_ENTRY
pointers to functions returning void. */ pointers to functions returning void. */
/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */ /* 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 DIRECTIVE_TABLE
#undef D #undef D
#define D(n, tag, f) tag, #define D(n, tag, o, f) tag,
enum enum
{ {
DIRECTIVE_TABLE DIRECTIVE_TABLE
...@@ -135,9 +122,9 @@ enum ...@@ -135,9 +122,9 @@ enum
#undef D #undef D
/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */ /* 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), \ { CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \
sizeof STRINGX(name) - 1, flags }, sizeof STRINGX(name) - 1, origin, flags },
static const struct directive dtable[] = static const struct directive dtable[] =
{ {
DIRECTIVE_TABLE DIRECTIVE_TABLE
...@@ -147,292 +134,237 @@ DIRECTIVE_TABLE ...@@ -147,292 +134,237 @@ DIRECTIVE_TABLE
/* Check if a token's name matches that of a known directive. Put in /* Check if a token's name matches that of a known directive. Put in
this file to save exporting dtable and other unneeded information. */ this file to save exporting dtable and other unneeded information. */
void const struct directive *
_cpp_check_directive (list, token) _cpp_check_directive (pfile, token, bol)
cpp_toklist *list; cpp_reader *pfile;
cpp_token *token; const cpp_token *token;
int bol;
{ {
const U_CHAR *name = token->val.name.text; const U_CHAR *name = token->val.name.text;
size_t len = token->val.name.len; size_t len = token->val.name.len;
unsigned int i; unsigned int i;
list->dirno = -1; /* If we are rescanning preprocessed input, don't obey any directives
list->flags &= ~SYNTAX_INCLUDE; other than # nnn. */
if (CPP_OPTION (pfile, preprocessed))
return 0;
for (i = 0; i < N_DIRECTIVES; i++) 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 we are skipping a failed conditional group, all non-conditional
if (dtable[i].flags & SYNTAX_INCLUDE) directives are ignored. */
list->flags |= SYNTAX_INCLUDE; if (pfile->skipping && !(dtable[i].flags & COND))
break; 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. return 0;
'#' has already been read. */ }
int const struct directive *
_cpp_handle_directive (pfile) _cpp_check_linemarker (pfile, token, bol)
cpp_reader *pfile; 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 /* # followed by a number is equivalent to #line. Do not recognize
this form in assembly language source files or skipped this form in assembly language source files or skipped
conditional groups. Complain about this form if we're being conditional groups. Complain about this form if we're being
pedantic, but not if this is regurgitated input (preprocessed or pedantic, but not if this is regurgitated input (preprocessed or
fed back in by the C++ frontend). */ fed back in by the C++ frontend). */
if (tok == CPP_NUMBER) if (pfile->skipping || CPP_OPTION (pfile, lang_asm))
{ return 0;
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 we are rescanning preprocessed input, don't obey any directives if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc
other than # nnn. */ && ! CPP_OPTION (pfile, preprocessed))
else if (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 0;
return &dtable[T_LINE];
}
/* A line of just # becomes blank. */ static void
else if (tok == CPP_VSPACE) dump_macro_name (pfile, node)
return 1; 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! */ /* Pass the current directive through to the output file. */
else if (tok == CPP_NAME) static void
{ pass_thru_directive (pfile)
for (i = 0; i < N_DIRECTIVES; i++) cpp_reader *pfile;
{ {
if (dtable[i].length == len /* XXX This output may be genuinely needed even when there is no
&& !ustrncmp (dtable[i].name, ident, len)) printer. */
goto real_directive; if (! pfile->printer)
} return;
/* Don't complain about invalid directives in assembly source, /* Flush first (temporary). */
we don't know where the comments are, and # may introduce cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line);
assembler pseudo-ops. Don't complain about invalid directives _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 1);
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;
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 /* Skip any -C comments. */
directives are ignored. */ while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
if (pfile->skipping && ORIGIN (dtable[i].flags) != COND) ;
return 0;
/* In -traditional mode, a directive is ignored unless its # is in if (token->type != CPP_NAME)
column 1. */
if (CPP_TRADITIONAL (pfile) && !hash_at_bol)
{ {
if (CPP_WTRADITIONAL (pfile)) cpp_error_with_line (pfile, pfile->token_list.line, token->col,
cpp_warning (pfile, "ignoring #%s because of its indented #", "macro names must be identifiers");
dtable[i].name);
return 0; return 0;
} }
/* no_directives is set when we are parsing macro arguments. Directives /* That identifier is not allowed to be "defined". See predefined
in macro arguments are undefined behavior (C99 6.10.3.11); this macro names (6.10.8.4). */
implementation chooses to make them hard errors. */ len = token->val.name.len;
if (pfile->no_directives) sym = token->val.name.text;
if (str_match (sym, len, "defined"))
{ {
cpp_error (pfile, "#%s may not be used inside a macro argument", cpp_error_with_line (pfile, pfile->token_list.line, token->col,
dtable[i].name); "\"defined\" is not a legal macro name");
_cpp_skip_rest_of_line (pfile); return 0;
return 1;
} }
/* Issue -pedantic warnings for extended directives. */ node = cpp_lookup (pfile, sym, len);
if (CPP_PEDANTIC (pfile) && ORIGIN (dtable[i].flags) == EXTENSION) /* Check for poisoned identifiers now. */
cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name); if (node->type == T_POISON)
/* -Wtraditional gives warnings about directives with inappropriate
indentation of #. */
if (CPP_WTRADITIONAL (pfile))
{ {
if (!hash_at_bol && TRAD_DIRECT_P (dtable[i].flags)) cpp_error (pfile, "attempt to use poisoned \"%.*s\"", (int) len, sym);
cpp_warning (pfile, "traditional C ignores #%s with the # indented", return 0;
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);
} }
/* Unfortunately, it's necessary to scan the directive name again, return node;
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);
} }
/* Process a #define command. */ /* Process a #define command. */
static int static int
do_define (pfile) do_define (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_hashnode *node; cpp_hashnode *node;
int len;
const U_CHAR *sym;
cpp_toklist *list = &pfile->directbuf;
pfile->no_macro_expand++; if ((node = get_define_node (pfile)))
CPP_OPTION (pfile, discard_comments)++; 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 /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
tokens in the list (if we had #define all by itself on a line). */ is not currently defined as a macro name. */
if (list->tokens_used == 0 if (node && node->type != T_VOID)
|| TOK_TYPE (list, 0) != CPP_NAME)
{ {
cpp_error_with_line (pfile, list->line, TOK_COL (list, 0), /* If we are generating additional info for debugging (with -g) we
"#define must be followed by an identifier"); need to pass through all effective #undef commands. */
goto out; 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); if (node->type != T_MACRO)
len = TOK_LEN (list, 0); cpp_warning (pfile, "undefining \"%s\"", node->name);
/* That NAME is not allowed to be "defined". (Not clear if the _cpp_free_definition (node);
standard requires this.) */ node->type = T_VOID;
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;
} }
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; return 0;
} }
/* Handle #include and #import. */ /* Handle #include and #import. */
static unsigned int static int
parse_include (pfile, name, trail) parse_include (pfile, dir, trail, strp, lenp, abp)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *name; const U_CHAR *dir;
int trail; int trail;
const U_CHAR **strp;
unsigned int *lenp;
int *abp;
{ {
long old_written = CPP_WRITTEN (pfile); const cpp_token *name = cpp_get_token (pfile);
enum cpp_ttype token;
int len;
pfile->parsing_include_directive++;
token = _cpp_get_directive_token (pfile);
pfile->parsing_include_directive--;
len = CPP_WRITTEN (pfile) - old_written; if (name->type != CPP_STRING && name->type != CPP_HEADER_NAME)
if (token != CPP_STRING)
{ {
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", name); if (name->type == CPP_LESS)
CPP_SET_WRITTEN (pfile, old_written); name = _cpp_glue_header_name (pfile);
_cpp_skip_rest_of_line (pfile); else
return 0; {
cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir);
return 1;
}
} }
if (name->val.name.len == 0)
if (!trail && _cpp_get_directive_token (pfile) != CPP_VSPACE)
{ {
cpp_error (pfile, "junk at end of #%s", name); cpp_error (pfile, "empty file name in #%s", dir);
_cpp_skip_rest_of_line (pfile); return 1;
} }
CPP_SET_WRITTEN (pfile, old_written); if (!trail && cpp_get_token (pfile)->type != CPP_EOF)
cpp_error (pfile, "junk at end of #%s", dir);
if (len == 0)
cpp_error (pfile, "empty file name in #%s", name);
return len; *lenp = name->val.name.len;
*strp = name->val.name.text;
*abp = (name->type == CPP_HEADER_NAME);
return 0;
} }
static int static int
...@@ -440,19 +372,15 @@ do_include (pfile) ...@@ -440,19 +372,15 @@ do_include (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
unsigned int len; unsigned int len;
U_CHAR *token; const U_CHAR *str;
int ab;
len = parse_include (pfile, dtable[T_INCLUDE].name, 0); if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab))
if (len == 0)
return 0; 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; return 0;
} }
...@@ -461,7 +389,8 @@ do_import (pfile) ...@@ -461,7 +389,8 @@ do_import (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
unsigned int len; unsigned int len;
U_CHAR *token; const U_CHAR *str;
int ab;
if (CPP_OPTION (pfile, warn_import) if (CPP_OPTION (pfile, warn_import)
&& !CPP_IN_SYSTEM_HEADER (pfile) && !pfile->import_warning) && !CPP_IN_SYSTEM_HEADER (pfile) && !pfile->import_warning)
...@@ -471,17 +400,12 @@ do_import (pfile) ...@@ -471,17 +400,12 @@ do_import (pfile)
"#import is obsolete, use an #ifndef wrapper in the header file"); "#import is obsolete, use an #ifndef wrapper in the header file");
} }
len = parse_include (pfile, dtable[T_IMPORT].name, 0); if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab))
if (len == 0)
return 0; 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; return 0;
} }
...@@ -490,32 +414,35 @@ do_include_next (pfile) ...@@ -490,32 +414,35 @@ do_include_next (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
unsigned int len; unsigned int len;
U_CHAR *token; const U_CHAR *str;
struct file_name_list *search_start = 0; struct file_name_list *search_start = 0;
int ab;
len = parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0); if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab))
if (len == 0)
return 0; 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 /* For #include_next, skip in the search path past the dir in which
containing file was found. Treat files specified using an absolute path the current file was found. If this is the last directory in the
as if there are no more directories to search. Treat the primary source search path, don't include anything. If the current file was
file like any other included source, but generate a warning. */ 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_PREV_BUFFER (CPP_BUFFER (pfile)))
{ {
if (CPP_BUFFER (pfile)->inc->foundhere) 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 else
cpp_warning (pfile, "#include_next in primary source file"); 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; return 0;
} }
...@@ -529,27 +456,47 @@ read_line_number (pfile, num) ...@@ -529,27 +456,47 @@ read_line_number (pfile, num)
cpp_reader *pfile; cpp_reader *pfile;
int *num; int *num;
{ {
long save_written = CPP_WRITTEN (pfile); const cpp_token *tok = cpp_get_token (pfile);
U_CHAR *p; enum cpp_ttype type = tok->type;
enum cpp_ttype token = _cpp_get_directive_token (pfile); const U_CHAR *p = tok->val.name.text;
p = pfile->token_buffer + save_written; unsigned int len = tok->val.name.len;
if (token == CPP_NUMBER && p + 1 == CPP_PWRITTEN (pfile) if (type == CPP_NUMBER && len == 1 && p[0] >= '1' && p[0] <= '4')
&& p[0] >= '1' && p[0] <= '4')
{ {
*num = p[0] - '0'; *num = p[0] - '0';
CPP_SET_WRITTEN (pfile, save_written);
return 1; return 1;
} }
else else
{ {
if (token != CPP_VSPACE && token != CPP_EOF) if (type != CPP_VSPACE && type != CPP_EOF)
cpp_error (pfile, "invalid format #line"); cpp_error (pfile, "invalid format #line");
CPP_SET_WRITTEN (pfile, save_written);
return 0; 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. /* Interpret #line command.
Note that the filename string (if any) is treated as if it were an Note that the filename string (if any) is treated as if it were an
include filename. That means no escape handling. */ include filename. That means no escape handling. */
...@@ -559,156 +506,92 @@ do_line (pfile) ...@@ -559,156 +506,92 @@ do_line (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_buffer *ip = CPP_BUFFER (pfile); cpp_buffer *ip = CPP_BUFFER (pfile);
unsigned int new_lineno; unsigned long new_lineno, old_lineno;
long old_written = CPP_WRITTEN (pfile); /* C99 raised the minimum limit on #line numbers. */
enum cpp_ttype token; unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
char *x; int action_number = 0;
enum cpp_ttype type;
token = _cpp_get_directive_token (pfile); const U_CHAR *str;
char *fname;
unsigned int len;
const cpp_token *tok;
if (token != CPP_NUMBER) tok = cpp_get_token (pfile);
{ type = tok->type;
cpp_error (pfile, "token after #line is not an integer"); str = tok->val.name.text;
goto bad_line_directive; len = tok->val.name.len;
}
CPP_PUTC (pfile, '\0'); /* not terminated for us */ if (type != CPP_NUMBER || strtoul_for_line (str, len, &new_lineno))
new_lineno = strtoul ((const char *) (pfile->token_buffer + old_written),
&x, 10);
if (x[0] != '\0')
{ {
cpp_error (pfile, "token after #line is not an integer"); cpp_error (pfile, "token after #line is not a positive integer");
goto bad_line_directive; 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) old_lineno = ip->lineno;
{ ip->lineno = new_lineno;
U_CHAR *fname = pfile->token_buffer + old_written + 1; tok = cpp_get_token (pfile);
U_CHAR *end_name = CPP_PWRITTEN (pfile) - 1; type = tok->type;
int action_number = 0; str = tok->val.name.text;
len = tok->val.name.len;
if (read_line_number (pfile, &action_number))
{
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "garbage at end of #line");
/* This is somewhat questionable: change the buffer stack if (type == CPP_VSPACE || type == CPP_EOF)
depth so that output_line_command thinks we've stacked goto done;
another buffer. */ else if (type != CPP_STRING)
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)
{ {
cpp_error (pfile, "second token after #line is not a 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. fname = alloca (len + 1);
To put the next line at the specified line number, memcpy (fname, str, len);
we must store a line number now that is one less. */ fname[len] = '\0';
ip->lineno = new_lineno - 1;
CPP_SET_WRITTEN (pfile, old_written); if (strcmp (fname, ip->nominal_fname))
return 0; {
if (!strcmp (fname, ip->inc->name))
bad_line_directive: ip->nominal_fname = ip->inc->name;
_cpp_skip_rest_of_line (pfile); else
CPP_SET_WRITTEN (pfile, old_written); ip->nominal_fname = _cpp_fake_include (pfile, fname);
return 0; }
}
/* Remove the definition of a symbol from the symbol table. if (read_line_number (pfile, &action_number) == 0)
According to the C standard, it is not an error to undef return 0;
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;
pfile->no_macro_expand++; if (CPP_PEDANTIC (pfile))
token = _cpp_get_directive_token (pfile); cpp_pedwarn (pfile, "garbage at end of #line");
pfile->no_macro_expand--;
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"); pfile->buffer_stack_depth++;
_cpp_skip_rest_of_line (pfile); cpp_make_system_header (pfile, ip, 0);
return 0; read_line_number (pfile, &action_number);
} }
len = CPP_WRITTEN (pfile) - here; else if (action_number == 2)
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
{ {
/* If we are generating additional info for debugging (with -g) we pfile->buffer_stack_depth--;
need to pass through all effective #undef commands. */ cpp_make_system_header (pfile, ip, 0);
if (CPP_OPTION (pfile, debug_output)) read_line_number (pfile, &action_number);
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;
} }
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; return 0;
} }
...@@ -722,14 +605,14 @@ static int ...@@ -722,14 +605,14 @@ static int
do_error (pfile) do_error (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const U_CHAR *text, *limit; U_CHAR *text, *limit;
_cpp_skip_hspace (pfile); text = pfile->limit;
text = CPP_BUFFER (pfile)->cur; _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0);
_cpp_skip_rest_of_line (pfile); limit = pfile->limit;
limit = CPP_BUFFER (pfile)->cur; pfile->limit = text;
cpp_error (pfile, "%.*s", (int)(limit - text), text);
cpp_error (pfile, "#error %.*s", (int)(limit - text), text);
return 0; return 0;
} }
...@@ -742,14 +625,13 @@ static int ...@@ -742,14 +625,13 @@ static int
do_warning (pfile) do_warning (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const U_CHAR *text, *limit; U_CHAR *text, *limit;
_cpp_skip_hspace (pfile); text = pfile->limit;
text = CPP_BUFFER (pfile)->cur; _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0);
_cpp_skip_rest_of_line (pfile); limit = pfile->limit;
limit = CPP_BUFFER (pfile)->cur; pfile->limit = text;
cpp_warning (pfile, "%.*s", (int)(limit - text), text);
cpp_warning (pfile, "#warning %.*s", (int)(limit - text), text);
return 0; return 0;
} }
...@@ -759,21 +641,17 @@ static int ...@@ -759,21 +641,17 @@ static int
do_ident (pfile) do_ident (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
long old_written = CPP_WRITTEN (pfile);
CPP_PUTS (pfile, "#ident ", 7);
/* Next token should be a string constant. */ /* 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. */ /* And then a newline. */
if (_cpp_get_directive_token (pfile) == CPP_VSPACE) if (cpp_get_token (pfile)->type == CPP_VSPACE)
/* Good - ship it. */ {
return 0; /* Good - ship it. */
pass_thru_directive (pfile);
return 0;
}
cpp_error (pfile, "invalid #ident"); cpp_error (pfile, "invalid #ident");
_cpp_skip_rest_of_line (pfile);
CPP_SET_WRITTEN (pfile, old_written); /* discard directive */
return 0; return 0;
} }
...@@ -792,17 +670,17 @@ do_ident (pfile) ...@@ -792,17 +670,17 @@ do_ident (pfile)
They return 1 if the token buffer is to be popped, 0 if not. */ They return 1 if the token buffer is to be popped, 0 if not. */
struct pragma_entry struct pragma_entry
{ {
char const *name; const char *name;
int (*handler) PARAMS ((cpp_reader *)); int (*handler) PARAMS ((cpp_reader *));
}; };
static int pragma_dispatch 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_once PARAMS ((cpp_reader *));
static int do_pragma_implementation PARAMS ((cpp_reader *)); static int do_pragma_implementation PARAMS ((cpp_reader *));
static int do_pragma_poison PARAMS ((cpp_reader *)); static int do_pragma_poison PARAMS ((cpp_reader *));
static int do_pragma_system_header 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_gcc PARAMS ((cpp_reader *));
static int do_pragma_dependency PARAMS ((cpp_reader *)); static int do_pragma_dependency PARAMS ((cpp_reader *));
...@@ -811,9 +689,8 @@ static const struct pragma_entry top_pragmas[] = ...@@ -811,9 +689,8 @@ static const struct pragma_entry top_pragmas[] =
{"once", do_pragma_once}, {"once", do_pragma_once},
{"implementation", do_pragma_implementation}, {"implementation", do_pragma_implementation},
{"poison", do_pragma_poison}, {"poison", do_pragma_poison},
{"system_header", do_pragma_system_header},
{"GCC", do_pragma_gcc}, {"GCC", do_pragma_gcc},
{NULL, do_pragma_default} {NULL, NULL}
}; };
static const struct pragma_entry gcc_pragmas[] = static const struct pragma_entry gcc_pragmas[] =
...@@ -822,74 +699,41 @@ static const struct pragma_entry gcc_pragmas[] = ...@@ -822,74 +699,41 @@ static const struct pragma_entry gcc_pragmas[] =
{"poison", do_pragma_poison}, {"poison", do_pragma_poison},
{"system_header", do_pragma_system_header}, {"system_header", do_pragma_system_header},
{"dependency", do_pragma_dependency}, {"dependency", do_pragma_dependency},
{NULL, do_pragma_default} {NULL, NULL}
}; };
static int pragma_dispatch (pfile, table, p, len) static int pragma_dispatch (pfile, table, p, len)
cpp_reader *pfile; cpp_reader *pfile;
const struct pragma_entry *table; const struct pragma_entry *table;
U_CHAR *p; const U_CHAR *p;
size_t len; size_t len;
{ {
for (; table->name; table++) for (; table->name; table++)
if (strlen (table->name) == len && !memcmp (p, table->name, len)) if (strlen (table->name) == len && !memcmp (p, table->name, len))
return (*table->handler) (pfile); return (*table->handler) (pfile);
return (*table->handler) (pfile); return 0;
} }
static int static int
do_pragma (pfile) do_pragma (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
long here, key; const cpp_token *tok;
U_CHAR *buf;
int pop; int pop;
enum cpp_ttype token;
size_t len;
here = CPP_WRITTEN (pfile);
CPP_PUTS (pfile, "#pragma ", 8);
key = CPP_WRITTEN (pfile); tok = cpp_get_token (pfile);
pfile->no_macro_expand++; if (tok->type == CPP_EOF)
token = _cpp_get_directive_token (pfile); return 0;
if (token != CPP_NAME) else if (tok->type != CPP_NAME)
{ {
if (token == CPP_VSPACE) cpp_error (pfile, "malformed #pragma directive");
goto empty; return 0;
else
goto skip;
} }
buf = pfile->token_buffer + key; pop = pragma_dispatch (pfile, top_pragmas,
len = CPP_WRITTEN (pfile) - key; tok->val.name.text, tok->val.name.len);
CPP_PUTC (pfile, ' '); if (!pop)
pass_thru_directive (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, ' ');
return 0; return 0;
} }
...@@ -897,21 +741,16 @@ static int ...@@ -897,21 +741,16 @@ static int
do_pragma_gcc (pfile) do_pragma_gcc (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
long key; const cpp_token *tok;
enum cpp_ttype token;
U_CHAR *buf; tok = cpp_get_token (pfile);
size_t len; if (tok->type == CPP_EOF)
return 1;
key = CPP_WRITTEN (pfile); else if (tok->type != CPP_NAME)
token = _cpp_get_directive_token (pfile); return 0;
if (token != CPP_NAME)
return token == CPP_VSPACE;
buf = pfile->token_buffer + key;
len = CPP_WRITTEN (pfile) - key;
CPP_PUTC (pfile, ' ');
return pragma_dispatch (pfile, gcc_pragmas, buf, len); return pragma_dispatch (pfile, gcc_pragmas,
tok->val.name.text, tok->val.name.len);
} }
static int static int
...@@ -939,27 +778,22 @@ do_pragma_implementation (pfile) ...@@ -939,27 +778,22 @@ do_pragma_implementation (pfile)
{ {
/* Be quiet about `#pragma implementation' for a file only if it hasn't /* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */ been included yet. */
enum cpp_ttype token; const cpp_token *tok = cpp_get_token (pfile);
long written = CPP_WRITTEN (pfile);
U_CHAR *name;
char *copy; char *copy;
size_t len;
token = _cpp_get_directive_token (pfile); if (tok->type == CPP_EOF)
if (token == CPP_VSPACE)
return 0; 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"); cpp_error (pfile, "malformed #pragma implementation");
return 1; return 1;
} }
/* Trim the leading and trailing quote marks from the string. */ /* Make a NUL-terminated copy of the string. */
name = pfile->token_buffer + written + 1; copy = alloca (tok->val.name.len + 1);
len = CPP_PWRITTEN (pfile) - name; memcpy (copy, tok->val.name.text, tok->val.name.len);
copy = alloca (len); copy[tok->val.name.len] = '\0';
memcpy (copy, name, len - 1);
copy[len - 1] = '\0';
if (cpp_included (pfile, copy)) if (cpp_included (pfile, copy))
cpp_warning (pfile, cpp_warning (pfile,
...@@ -974,11 +808,8 @@ do_pragma_poison (pfile) ...@@ -974,11 +808,8 @@ do_pragma_poison (pfile)
{ {
/* Poison these symbols so that all subsequent usage produces an /* Poison these symbols so that all subsequent usage produces an
error message. */ error message. */
U_CHAR *p; const cpp_token *tok;
cpp_hashnode *hp; cpp_hashnode *hp;
long written;
size_t len;
enum cpp_ttype token;
int writeit; int writeit;
/* As a rule, don't include #pragma poison commands in output, /* As a rule, don't include #pragma poison commands in output,
...@@ -989,31 +820,25 @@ do_pragma_poison (pfile) ...@@ -989,31 +820,25 @@ do_pragma_poison (pfile)
for (;;) for (;;)
{ {
written = CPP_WRITTEN (pfile); tok = cpp_get_token (pfile);
token = _cpp_get_directive_token (pfile); if (tok->type == CPP_EOF)
if (token == CPP_VSPACE)
break; break;
if (token != CPP_NAME) if (tok->type != CPP_NAME)
{ {
cpp_error (pfile, "invalid #pragma poison directive"); cpp_error (pfile, "invalid #pragma poison directive");
_cpp_skip_rest_of_line (pfile);
return 1; return 1;
} }
p = pfile->token_buffer + written; hp = cpp_lookup (pfile, tok->val.name.text, tok->val.name.len);
len = CPP_PWRITTEN (pfile) - p;
hp = cpp_lookup (pfile, p, len);
if (hp->type == T_POISON) if (hp->type == T_POISON)
; /* It is allowed to poison the same identifier twice. */ ; /* It is allowed to poison the same identifier twice. */
else else
{ {
if (hp->type != T_VOID) if (hp->type != T_VOID)
cpp_warning (pfile, "poisoning existing macro `%s'", hp->name); cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name);
_cpp_free_definition (hp); _cpp_free_definition (hp);
hp->type = T_POISON; hp->type = T_POISON;
} }
if (writeit)
CPP_PUTC (pfile, ' ');
} }
return !writeit; return !writeit;
} }
...@@ -1028,7 +853,7 @@ static int ...@@ -1028,7 +853,7 @@ static int
do_pragma_system_header (pfile) do_pragma_system_header (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
cpp_buffer *ip = cpp_file_buffer (pfile); cpp_buffer *ip = CPP_BUFFER (pfile);
if (CPP_PREV_BUFFER (ip) == NULL) if (CPP_PREV_BUFFER (ip) == NULL)
cpp_warning (pfile, "#pragma system_header outside include file"); cpp_warning (pfile, "#pragma system_header outside include file");
else else
...@@ -1044,33 +869,37 @@ static int ...@@ -1044,33 +869,37 @@ static int
do_pragma_dependency (pfile) do_pragma_dependency (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
U_CHAR *original_name, *name; const U_CHAR *name;
unsigned len; unsigned int len;
int ordering; int ordering, ab;
char left, right;
len = parse_include (pfile, (const U_CHAR *)"pragma dependency", 1);
original_name = (U_CHAR *) alloca (len + 1); if (parse_include (pfile, U"pragma dependency", 1, &name, &len, &ab))
name = (U_CHAR *) alloca (len + 1); return 1;
memcpy (original_name, CPP_PWRITTEN (pfile), len);
memcpy (name, CPP_PWRITTEN (pfile), len); left = ab ? '<' : '"';
original_name[len] = name[len] = 0; right = ab ? '>' : '"';
ordering = _cpp_compare_file_date (pfile, name, len, 0); ordering = _cpp_compare_file_date (pfile, name, len, ab);
if (ordering < 0) 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) else if (ordering > 0)
{ {
const U_CHAR *text, *limit; const cpp_token *msg = cpp_get_token (pfile);
_cpp_skip_hspace (pfile);
text = CPP_BUFFER (pfile)->cur;
_cpp_skip_rest_of_line (pfile);
limit = CPP_BUFFER (pfile)->cur;
cpp_warning (pfile, "current file is older than %s", original_name); cpp_warning (pfile, "current file is older than %c%s%c",
if (limit != text) left, name, right);
cpp_warning (pfile, "%.*s", (int)(limit - text), text); 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; return 1;
} }
...@@ -1078,9 +907,8 @@ do_pragma_dependency (pfile) ...@@ -1078,9 +907,8 @@ do_pragma_dependency (pfile)
#ifdef SCCS_DIRECTIVE #ifdef SCCS_DIRECTIVE
static int static int
do_sccs (pfile) do_sccs (pfile)
cpp_reader *pfile; cpp_reader *pfile ATTRIBUTE_UNUSED;
{ {
_cpp_skip_rest_of_line (pfile);
return 0; return 0;
} }
#endif #endif
...@@ -1096,117 +924,76 @@ static const cpp_hashnode * ...@@ -1096,117 +924,76 @@ static const cpp_hashnode *
detect_if_not_defined (pfile) detect_if_not_defined (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
const cpp_hashnode *cmacro = 0; const cpp_token *token;
enum cpp_ttype token; cpp_hashnode *cmacro = 0;
unsigned int base_offset;
unsigned int token_offset; /* We are guaranteed that tokens are consecutive and end in CPP_EOF. */
unsigned int need_rparen = 0; token = pfile->first_directive_token + 2;
unsigned int token_len;
if (token->type != CPP_NOT)
if (pfile->skipping || pfile->only_seen_white != 2) return 0;
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;
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 (token->type != CPP_NAME)
if (need_rparen && _cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) return 0;
goto restore;
/* ...and make sure there's nothing else on the line. */ cmacro = cpp_lookup (pfile, token->val.name.text, token->val.name.len);
if (_cpp_get_directive_token (pfile) != CPP_VSPACE)
goto restore;
/* We have a legitimate controlling macro for this header. */ if (token[-1].type == CPP_OPEN_PAREN)
cmacro = cpp_lookup (pfile, pfile->token_buffer + token_offset, token_len); {
token++;
if (token->type != CPP_CLOSE_PAREN)
return 0;
}
restore: token++;
CPP_SET_WRITTEN (pfile, base_offset); if (token->type != CPP_EOF)
pfile->no_macro_expand--; return 0;
CPP_GOTO_MARK (pfile);
return cmacro; return cmacro;
} }
/* Parse an #ifdef or #ifndef directive. Returns 1 for defined, 0 for /* Parse an #ifdef or #ifndef directive. Returns the hash node of the
not defined; the macro tested is left in the token buffer (but macro being tested, and issues various error messages. */
popped). */
static const cpp_hashnode * static const cpp_hashnode *
parse_ifdef (pfile, name) parse_ifdef (pfile, name)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *name; const U_CHAR *name;
{ {
U_CHAR *ident; const U_CHAR *ident;
unsigned int len; unsigned int len;
enum cpp_ttype token; enum cpp_ttype type;
long old_written = CPP_WRITTEN (pfile);
const cpp_hashnode *node = 0; const cpp_hashnode *node = 0;
pfile->no_macro_expand++; const cpp_token *token = cpp_get_token (pfile);
token = _cpp_get_directive_token (pfile); type = token->type;
pfile->no_macro_expand--; ident = token->val.name.text;
len = token->val.name.len;
ident = pfile->token_buffer + old_written;
len = CPP_WRITTEN (pfile) - old_written;
if (token == CPP_VSPACE) if (!CPP_TRADITIONAL (pfile))
{ {
if (! CPP_TRADITIONAL (pfile)) if (type == CPP_EOF)
cpp_pedwarn (pfile, "#%s with no argument", name); cpp_pedwarn (pfile, "#%s with no argument", name);
goto done; else if (type != CPP_NAME)
} cpp_pedwarn (pfile, "#%s with invalid argument", name);
else if (token == CPP_NAME) else if (cpp_get_token (pfile)->type != CPP_EOF)
{ cpp_pedwarn (pfile, "garbage at end of #%s", name);
node = cpp_lookup (pfile, ident, len);
}
else
{
if (! CPP_TRADITIONAL (pfile))
cpp_error (pfile, "#%s with invalid argument", name);
} }
if (!CPP_TRADITIONAL (pfile)) if (type == CPP_NAME)
{ node = cpp_lookup (pfile, ident, len);
if (_cpp_get_directive_token (pfile) == CPP_VSPACE) if (node && node->type == T_POISON)
goto done; cpp_error (pfile, "attempt to use poisoned identifier \"%s\"", node->name);
cpp_pedwarn (pfile, "garbage at end of #%s", name);
}
_cpp_skip_rest_of_line (pfile);
done:
CPP_SET_WRITTEN (pfile, old_written); /* Pop */
return node; return node;
} }
...@@ -1217,14 +1004,15 @@ do_ifdef (pfile) ...@@ -1217,14 +1004,15 @@ do_ifdef (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int def = 0; int def = 0;
const cpp_hashnode *node = parse_ifdef (pfile, dtable[T_IFDEF].name); const cpp_hashnode *node = 0;
if (node)
if (! pfile->skipping)
{ {
if (node->type == T_POISON) node = parse_ifdef (pfile, dtable[T_IFDEF].name);
cpp_error (pfile, "attempt to use poisoned `%s'", node->name); if (node)
else def = (node->type != T_VOID && node->type != T_POISON);
def = (node->type != T_VOID);
} }
push_conditional (pfile, !def, T_IFDEF, 0); push_conditional (pfile, !def, T_IFDEF, 0);
return 0; return 0;
} }
...@@ -1236,21 +1024,19 @@ static int ...@@ -1236,21 +1024,19 @@ static int
do_ifndef (pfile) do_ifndef (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int start_of_file; int start_of_file = 0;
int def = 0; int def = 0;
const cpp_hashnode *cmacro; const cpp_hashnode *cmacro = 0;
start_of_file = pfile->only_seen_white == 2; if (! pfile->skipping)
cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
if (cmacro)
{ {
if (cmacro->type == T_POISON) start_of_file = (pfile->token_list.flags & BEG_OF_FILE);
cpp_error (pfile, "attempt to use poisoned `%s'", cmacro->name); cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name);
else if (cmacro)
def = (cmacro->type != T_VOID); 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; return 0;
} }
...@@ -1282,7 +1068,6 @@ do_else (pfile) ...@@ -1282,7 +1068,6 @@ do_else (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack; struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack;
validate_else (pfile, dtable[T_ELSE].name); validate_else (pfile, dtable[T_ELSE].name);
if (ifs == NULL) if (ifs == NULL)
...@@ -1293,13 +1078,13 @@ do_else (pfile) ...@@ -1293,13 +1078,13 @@ do_else (pfile)
if (ifs->type == T_ELSE) if (ifs->type == T_ELSE)
{ {
cpp_error (pfile, "#else after #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 /* #ifndef can't have its special treatment for containing the whole file
if it has a #else clause. */ if it has a #else clause. */
ifs->cmacro = 0; ifs->cmacro = 0;
ifs->type = T_ELSE; ifs->type = T_ELSE;
if (! ifs->was_skipping) if (! ifs->was_skipping)
{ {
...@@ -1330,24 +1115,24 @@ do_elif (pfile) ...@@ -1330,24 +1115,24 @@ do_elif (pfile)
if (ifs->type == T_ELSE) if (ifs->type == T_ELSE)
{ {
cpp_error (pfile, "#elif after #else"); cpp_error (pfile, "#elif after #else");
cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here"); cpp_error_with_line (pfile, ifs->lineno, ifs->colno,
"the conditional began here");
} }
ifs->type = T_ELIF; ifs->type = T_ELIF;
if (ifs->was_skipping) if (ifs->was_skipping)
_cpp_skip_rest_of_line (pfile); return 0; /* Don't evaluate a nested #if */
else if (pfile->skipping != 1)
if (pfile->skipping != 1)
{ {
_cpp_skip_rest_of_line (pfile);
pfile->skipping = 2; /* one block succeeded, so don't do any others */ 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; return 0;
} }
/* #endif pops the if stack and resets pfile->skipping. */ /* #endif pops the if stack and resets pfile->skipping. */
static int static int
...@@ -1370,6 +1155,7 @@ do_endif (pfile) ...@@ -1370,6 +1155,7 @@ do_endif (pfile)
return 0; return 0;
} }
/* Push an if_stack entry and set pfile->skipping accordingly. /* Push an if_stack entry and set pfile->skipping accordingly.
If this is a #ifndef starting at the beginning of a file, If this is a #ifndef starting at the beginning of a file,
CMACRO is the macro name tested by the #ifndef. */ CMACRO is the macro name tested by the #ifndef. */
...@@ -1384,7 +1170,7 @@ push_conditional (pfile, skip, type, cmacro) ...@@ -1384,7 +1170,7 @@ push_conditional (pfile, skip, type, cmacro)
struct if_stack *ifs; struct if_stack *ifs;
ifs = (struct if_stack *) xmalloc (sizeof (struct if_stack)); 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->next = CPP_BUFFER (pfile)->if_stack;
ifs->cmacro = cmacro; ifs->cmacro = cmacro;
ifs->was_skipping = pfile->skipping; ifs->was_skipping = pfile->skipping;
...@@ -1404,19 +1190,11 @@ validate_else (pfile, directive) ...@@ -1404,19 +1190,11 @@ validate_else (pfile, directive)
cpp_reader *pfile; cpp_reader *pfile;
const U_CHAR *directive; const U_CHAR *directive;
{ {
if (CPP_PEDANTIC (pfile)) if (CPP_PEDANTIC (pfile) && cpp_get_token (pfile)->type != CPP_EOF)
{ cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive);
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);
} }
/* 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, conditional stack till we reach its level at entry to this file,
issuing error messages. Then force skipping off. */ issuing error messages. Then force skipping off. */
void void
...@@ -1428,7 +1206,7 @@ _cpp_unwind_if_stack (pfile, pbuf) ...@@ -1428,7 +1206,7 @@ _cpp_unwind_if_stack (pfile, pbuf)
for (ifs = pbuf->if_stack; ifs; ifs = nifs) 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); dtable[ifs->type].name);
nifs = ifs->next; nifs = ifs->next;
free (ifs); free (ifs);
...@@ -1436,173 +1214,210 @@ _cpp_unwind_if_stack (pfile, pbuf) ...@@ -1436,173 +1214,210 @@ _cpp_unwind_if_stack (pfile, pbuf)
pfile->skipping = 0; pfile->skipping = 0;
} }
#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0) /* Parses an assertion, returning a pointer to the hash node of the
#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0) predicate, or 0 on error. If an answer was supplied, it is
#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0) allocated and placed in ANSWERP, otherwise it is set to 0. We use
static int _cpp_get_raw_token, since we cannot assume tokens are consecutive
do_assert (pfile) 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; cpp_reader *pfile;
struct answer **answerp;
{ {
long old_written; struct answer *answer = 0;
cpp_toklist *list;
U_CHAR *sym; U_CHAR *sym;
size_t len; const cpp_token *token, *predicate;
cpp_hashnode *hp; const struct directive *d = pfile->token_list.directive;
struct predicate *pred = 0; unsigned int len = 0;
enum cpp_ttype type;
old_written = CPP_WRITTEN (pfile); predicate = _cpp_get_raw_token (pfile);
pfile->no_macro_expand++; 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 */ token = _cpp_get_raw_token (pfile);
type = _cpp_get_directive_token (pfile); if (token->type != CPP_OPEN_PAREN)
if (type == CPP_VSPACE) {
ERROR ("#assert without predicate"); /* #unassert and #if are OK without predicate. */
else if (type != CPP_NAME) if (d == &dtable[T_UNASSERT])
ERROR ("assertion predicate is not an identifier"); {
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; /* Allocate a struct answer, and copy the answer to it. */
len = CPP_WRITTEN (pfile) - old_written; answer = (struct answer *) xmalloc (sizeof (struct answer));
hp = cpp_lookup (pfile, sym, len); list = &answer->list;
_cpp_init_toklist (list, NO_DUMMY_TOKEN);
if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN) for (;;)
ERROR ("missing token-sequence in #assert"); {
cpp_token *dest;
pred = (struct predicate *) xmalloc (sizeof (struct predicate)); token = _cpp_get_raw_token (pfile);
_cpp_init_toklist (&pred->answer, NO_DUMMY_TOKEN);
if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN) if (token->type == CPP_EOF)
!= CPP_CLOSE_PAREN) {
ERROR ("missing close paren in #assert"); 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) /* Copy the token. */
ICE ("impossible token, expecting ) in do_assert"); _cpp_expand_token_space (list, 1);
dest = &list->tokens[list->tokens_used++];
*dest = *token;
if (_cpp_get_directive_token (pfile) != CPP_VSPACE) if (token_spellings[token->type].type > SPELL_NONE)
ERROR ("junk at end of #assert"); {
_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. */ cpp_error (pfile, "predicate's answer is empty");
const struct predicate *old; goto error;
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;
} }
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; cpp_error (pfile, "junk at end of assertion");
pred->next = 0; goto error;
} }
_cpp_squeeze_toklist (&pred->answer); lookup_node:
hp->value.pred = pred; *answerp = answer;
pfile->no_macro_expand--; len = predicate->val.name.len + 1;
CPP_SET_WRITTEN (pfile, old_written); sym = alloca (len);
return 0;
/* 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: error:
_cpp_skip_rest_of_line (pfile); FREE_ANSWER (answer);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
if (pred)
{
_cpp_free_toklist (&pred->answer);
free (pred);
}
return 0; return 0;
} }
static int /* Returns a pointer to the pointer to the answer in the answer chain,
do_unassert (pfile) or a pointer to NULL if the answer is not in the chain. */
cpp_reader *pfile; struct answer **
find_answer (node, candidate)
cpp_hashnode *node;
const cpp_toklist *candidate;
{ {
long old_written; struct answer **result;
U_CHAR *sym;
size_t len;
cpp_hashnode *hp;
cpp_toklist ans;
enum cpp_ttype type;
int specific = 0;
old_written = CPP_WRITTEN (pfile); for (result = &node->value.answers; *result; result = &(*result)->next)
pfile->no_macro_expand++; if (_cpp_equiv_toklists (&(*result)->list, candidate))
break;
CPP_PUTC (pfile, '#'); /* force token out of macro namespace */ return result;
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);
type = _cpp_get_directive_token (pfile); #define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0)
if (type == CPP_OPEN_PAREN) #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; new_answer->next = 0;
_cpp_init_toklist (&ans, NO_DUMMY_TOKEN); new_answer->list.line = pfile->token_list.line;
new_answer->list.file = pfile->token_list.file;
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");
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) err:
ERROR ("junk at end of #unassert"); cpp_warning (pfile, "\"%.*s\" re-asserted",
node->length - 1, node->name + 1);
if (hp->type != T_ASSERTION) FREE_ANSWER (new_answer);
/* Not an error to #unassert something that isn't asserted. return 0;
goto error to clean up. */ }
goto error;
if (specific) static int
{ do_unassert (pfile)
/* Find this specific answer and remove it. */ cpp_reader *pfile;
struct predicate *o, *p; {
cpp_hashnode *node;
for (p = NULL, o = hp->value.pred; o; p = o, o = o->next) struct answer *answer, *temp, *next;
if (_cpp_equiv_toklists (&ans, &o->answer))
{ node = _cpp_parse_assertion (pfile, &answer);
if (p) if (node)
p->next = o->next;
else
hp->value.pred = o->next;
_cpp_free_toklist (&o->answer);
free (o);
break;
}
}
else
{ {
struct predicate *o, *p; /* It isn't an error to #unassert something that isn't asserted. */
for (o = hp->value.pred; o; o = p) if (node->type == T_ASSERTION)
{ {
p = o->next; if (answer)
_cpp_free_toklist ((cpp_toklist *) &o->answer); {
free (o); 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) if (answer)
hp->type = T_VOID; /* Last answer for this predicate deleted. */ FREE_ANSWER (answer);
}
error:
_cpp_skip_rest_of_line (pfile);
pfile->no_macro_expand--;
CPP_SET_WRITTEN (pfile, old_written);
if (specific)
_cpp_free_toklist (&ans);
return 0; return 0;
} }
...@@ -1643,11 +1458,7 @@ cpp_define (pfile, str) ...@@ -1643,11 +1458,7 @@ cpp_define (pfile, str)
strcpy (&buf[count-4], " 1\n"); strcpy (&buf[count-4], " 1\n");
} }
if (cpp_push_buffer (pfile, (U_CHAR *)buf, count - 1) != NULL) _cpp_run_directive (pfile, &dtable[T_DEFINE], buf, count - 1);
{
do_define (pfile);
cpp_pop_buffer (pfile);
}
} }
/* Process MACRO as if it appeared as the body of an #undef. */ /* Process MACRO as if it appeared as the body of an #undef. */
...@@ -1656,17 +1467,7 @@ cpp_undef (pfile, macro) ...@@ -1656,17 +1467,7 @@ cpp_undef (pfile, macro)
cpp_reader *pfile; cpp_reader *pfile;
const char *macro; const char *macro;
{ {
/* Copy the string so we can append a newline. */ _cpp_run_directive (pfile, &dtable[T_UNDEF], macro, strlen (macro));
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);
}
} }
/* Process the string STR as if it appeared as the body of a #assert. */ /* Process the string STR as if it appeared as the body of a #assert. */
...@@ -1675,11 +1476,7 @@ cpp_assert (pfile, str) ...@@ -1675,11 +1476,7 @@ cpp_assert (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str; const char *str;
{ {
if (cpp_push_buffer (pfile, (const U_CHAR *)str, strlen (str)) != NULL) _cpp_run_directive (pfile, &dtable[T_ASSERT], str, strlen (str));
{
do_assert (pfile);
cpp_pop_buffer (pfile);
}
} }
/* Process STR as if it appeared as the body of an #unassert. */ /* Process STR as if it appeared as the body of an #unassert. */
...@@ -1688,11 +1485,7 @@ cpp_unassert (pfile, str) ...@@ -1688,11 +1485,7 @@ cpp_unassert (pfile, str)
cpp_reader *pfile; cpp_reader *pfile;
const char *str; const char *str;
{ {
if (cpp_push_buffer (pfile, (const U_CHAR *)str, strlen (str)) != NULL) _cpp_run_directive (pfile, &dtable[T_UNASSERT], str, strlen (str));
{
do_unassert (pfile);
cpp_pop_buffer (pfile);
}
} }
/* Determine whether the identifier ID, of length LEN, is a defined macro. */ /* Determine whether the identifier ID, of length LEN, is a defined macro. */
...@@ -1705,7 +1498,7 @@ cpp_defined (pfile, id, len) ...@@ -1705,7 +1498,7 @@ cpp_defined (pfile, id, len)
cpp_hashnode *hp = cpp_lookup (pfile, id, len); cpp_hashnode *hp = cpp_lookup (pfile, id, len);
if (hp->type == T_POISON) 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 0;
} }
return (hp->type != T_VOID); return (hp->type != T_VOID);
......
...@@ -108,7 +108,8 @@ typedef struct cpp_hashnode cpp_hashnode; ...@@ -108,7 +108,8 @@ typedef struct cpp_hashnode cpp_hashnode;
T(CPP_DOT_STAR, ".*") \ T(CPP_DOT_STAR, ".*") \
T(CPP_MIN, "<?") /* extension */ \ T(CPP_MIN, "<?") /* extension */ \
T(CPP_MAX, ">?") \ 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_NAME, 0) /* word */ \
I(CPP_INT, 0) /* 23 */ \ I(CPP_INT, 0) /* 23 */ \
...@@ -121,15 +122,11 @@ typedef struct cpp_hashnode cpp_hashnode; ...@@ -121,15 +122,11 @@ typedef struct cpp_hashnode cpp_hashnode;
\ \
I(CPP_COMMENT, 0) /* Only if output comments. */ \ I(CPP_COMMENT, 0) /* Only if output comments. */ \
N(CPP_MACRO_ARG, 0) /* Macro argument. */ \ N(CPP_MACRO_ARG, 0) /* Macro argument. */ \
N(CPP_SUBLIST, 0) /* Sublist. */ \
N(CPP_EOF, 0) /* End of file. */ \ 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. */ \ /* Obsolete - will be removed when no code uses them still. */ \
T(CPP_VSPACE, "\n") /* End of line. */ \ 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. */
#define T(e, s) e, #define T(e, s) e,
#define I(e, s) e, #define I(e, s) e,
...@@ -154,49 +151,42 @@ struct cpp_name ...@@ -154,49 +151,42 @@ struct cpp_name
const unsigned char *text; 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. */ /* Flags for the cpp_token structure. */
#define PREV_WHITESPACE 1 /* If whitespace before this token. */ #define PREV_WHITE (1 << 0) /* If whitespace before this token. */
#define BOL 2 /* Beginning of line. */ #define BOL (1 << 1) /* Beginning of logical line. */
#define DIGRAPH 4 /* If it was a digraph. */ #define DIGRAPH (1 << 2) /* If it was a digraph. */
#define UNSIGNED_INT 8 /* If int preprocessing token unsigned. */ #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 /* 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 struct cpp_token
{ {
unsigned short col; /* starting column of this token */ unsigned int line; /* starting line number of this token */
ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* node type */ unsigned short col; /* starting column of this token */
unsigned char flags; /* flags - see above */ ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */
unsigned int aux; /* CPP_OTHER character. Hash of a unsigned char flags; /* flags - see above */
NAME, or something - see uses
in the code */
union 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; } val;
}; };
/* General flags. */ /* cpp_toklist flags. */
#define LIST_OFFSET (1 << 0) #define LIST_OFFSET (1 << 0)
#define VAR_ARGS (1 << 1)
/* Directive flags. */ #define BEG_OF_FILE (1 << 2)
#define SYNTAX_INCLUDE (1 << 8)
typedef int (*directive_handler) PARAMS ((cpp_reader *)); struct directive; /* These are deliberately incomplete. */
struct answer;
struct macro_args;
struct cpp_context;
struct cpp_toklist struct cpp_toklist
{ {
...@@ -208,11 +198,15 @@ struct cpp_toklist ...@@ -208,11 +198,15 @@ struct cpp_toklist
unsigned int name_used; /* _bytes_ used */ unsigned int name_used; /* _bytes_ used */
unsigned int name_cap; /* _bytes_ allocated */ 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 */ unsigned int line; /* starting line number */
/* The handler to call after lexing the rest of this line. unsigned short params_len; /* length of macro parameter names. */
-1 for none */
short dirno; short int paramc; /* no. of macro params (-1 = obj-like). */
/* Per-list flags, see above */ /* Per-list flags, see above */
unsigned short flags; unsigned short flags;
...@@ -224,12 +218,12 @@ struct cpp_buffer ...@@ -224,12 +218,12 @@ struct cpp_buffer
const unsigned char *rlimit; /* end of valid data */ const unsigned char *rlimit; /* end of valid data */
const unsigned char *buf; /* entire buffer */ const unsigned char *buf; /* entire buffer */
const unsigned char *line_base; /* start of current line */ const unsigned char *line_base; /* start of current line */
const unsigned char *mark; /* Saved position for lengthy backtrack. */
struct cpp_buffer *prev; struct cpp_buffer *prev;
/* Filename specified with #line command. */ /* Filename specified with #line command. */
const char *nominal_fname; const char *nominal_fname;
/* Actual directory of this file, used only for "" includes */ /* Actual directory of this file, used only for "" includes */
struct file_name_list *actual_dir; struct file_name_list *actual_dir;
...@@ -237,10 +231,6 @@ struct cpp_buffer ...@@ -237,10 +231,6 @@ struct cpp_buffer
to record control macros. */ to record control macros. */
struct include_file *inc; 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. /* Value of if_stack at start of this file.
Used to prohibit unmatched #endif (etc) in an include file. */ Used to prohibit unmatched #endif (etc) in an include file. */
struct if_stack *if_stack; struct if_stack *if_stack;
...@@ -248,29 +238,13 @@ struct cpp_buffer ...@@ -248,29 +238,13 @@ struct cpp_buffer
/* Line number at line_base (above). */ /* Line number at line_base (above). */
unsigned int lineno; 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. /* True if we have already warned about C++ comments in this file.
The warning happens only for C89 extended mode with -pedantic on, The warning happens only for C89 extended mode with -pedantic on,
or for -Wtraditional, and only once per file (otherwise it would or for -Wtraditional, and only once per file (otherwise it would
be far too noisy). */ be far too noisy). */
char warned_cplusplus_comments; char warned_cplusplus_comments;
/* In a file buffer, true if this buffer's data is mmapped /* 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. */
char mapped; char mapped;
}; };
...@@ -354,7 +328,7 @@ struct cpp_options ...@@ -354,7 +328,7 @@ struct cpp_options
/* Nonzero means don't copy comments into the output file. */ /* Nonzero means don't copy comments into the output file. */
unsigned char discard_comments; unsigned char discard_comments;
/* Nonzero means process the ANSI trigraph sequences. */ /* Nonzero means process the ISO trigraph sequences. */
unsigned char trigraphs; unsigned char trigraphs;
/* Nonzero means print the names of included files rather than the /* Nonzero means print the names of included files rather than the
...@@ -396,6 +370,10 @@ struct cpp_options ...@@ -396,6 +370,10 @@ struct cpp_options
with the # indented from the beginning of the line. */ with the # indented from the beginning of the line. */
unsigned char warn_traditional; 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. */ /* Nonzero means turn warnings into errors. */
unsigned char warnings_are_errors; unsigned char warnings_are_errors;
...@@ -417,7 +395,7 @@ struct cpp_options ...@@ -417,7 +395,7 @@ struct cpp_options
/* Zero means dollar signs are punctuation. */ /* Zero means dollar signs are punctuation. */
unsigned char dollars_in_ident; 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; unsigned char traditional;
/* Nonzero means warn if undefined identifiers are evaluated in an #if. */ /* Nonzero means warn if undefined identifiers are evaluated in an #if. */
...@@ -460,19 +438,18 @@ struct cpp_options ...@@ -460,19 +438,18 @@ struct cpp_options
unsigned char show_column; unsigned char show_column;
}; };
/* A cpp_reader encapsulates the "state" of a pre-processor run. /* A cpp_reader encapsulates the "state" of a pre-processor run.
Applying cpp_get_token repeatedly yields a stream of pre-processor Applying cpp_get_token repeatedly yields a stream of pre-processor
tokens. Usually, there is only one cpp_reader object active. */ tokens. Usually, there is only one cpp_reader object active. */
struct cpp_reader struct cpp_reader
{ {
/* HACK FIXME. Maybe make into cpp_printer printer later. */
cpp_printer *printer;
/* Top of buffer stack. */ /* Top of buffer stack. */
cpp_buffer *buffer; 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. */ /* A buffer used for both for cpp_get_token's output, and also internally. */
unsigned char *token_buffer; unsigned char *token_buffer;
/* Allocated size of token_buffer. CPP_RESERVE allocates space. */ /* Allocated size of token_buffer. CPP_RESERVE allocates space. */
...@@ -483,8 +460,9 @@ struct cpp_reader ...@@ -483,8 +460,9 @@ struct cpp_reader
/* Error counter for exit code */ /* Error counter for exit code */
unsigned int errors; 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_line;
unsigned int multiline_string_column;
/* Current depth in #include directives that use <...>. */ /* Current depth in #include directives that use <...>. */
unsigned int system_include_depth; unsigned int system_include_depth;
...@@ -509,19 +487,46 @@ struct cpp_reader ...@@ -509,19 +487,46 @@ struct cpp_reader
for include files. (Altered as we get more of them.) */ for include files. (Altered as we get more of them.) */
unsigned int max_include_len; unsigned int max_include_len;
/* Potential controlling macro for the current buffer. This is only
live between the #endif and the end of file, and there can only
be one at a time, so it is per-reader not per-buffer. */
const cpp_hashnode *potential_control_macro; const cpp_hashnode *potential_control_macro;
/* Token column position adjustment owing to tabs in whitespace. */ /* Token column position adjustment owing to tabs in whitespace. */
unsigned int col_adjust; 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. */ /* Buffer of -M output. */
struct deps *deps; 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. */ /* User visible options. */
struct cpp_options opts; struct cpp_options opts;
...@@ -532,31 +537,24 @@ struct cpp_reader ...@@ -532,31 +537,24 @@ struct cpp_reader
/* If non-zero, macros are not expanded. */ /* If non-zero, macros are not expanded. */
unsigned char no_macro_expand; 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. */ /* We're printed a warning recommending against using #import. */
unsigned char import_warning; 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 /* True after cpp_start_read completes. Used to inhibit some
warnings while parsing the command line. */ warnings while parsing the command line. */
unsigned char done_initializing; unsigned char done_initializing;
/* True if we are skipping a failed conditional group. */ /* True if we are skipping a failed conditional group. */
unsigned char skipping; 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 /* struct cpp_printer encapsulates state used to convert the stream of
...@@ -611,13 +609,8 @@ enum node_type ...@@ -611,13 +609,8 @@ enum node_type
T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
T_TIME, /* `__TIME__' */ T_TIME, /* `__TIME__' */
T_STDC, /* `__STDC__' */ 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_POISON, /* poisoned identifier */
T_MACRO, /* object-like macro */ T_MACRO, /* a macro, either object-like or function-like */
T_FMACRO, /* function-like macro */
T_IDENTITY, /* macro defined to itself */
T_EMPTY, /* macro defined to nothing */
T_ASSERTION /* predicate for #assert */ T_ASSERTION /* predicate for #assert */
}; };
...@@ -634,11 +627,10 @@ struct cpp_hashnode ...@@ -634,11 +627,10 @@ struct cpp_hashnode
ENUM_BITFIELD(node_type) type : 8; /* node type */ ENUM_BITFIELD(node_type) type : 8; /* node type */
char disabled; /* macro turned off for rescan? */ char disabled; /* macro turned off for rescan? */
union { union
const unsigned char *cpval; /* some predefined macros */ {
const struct object_defn *odefn; /* #define foo bar */ const cpp_toklist *expansion; /* a macro's replacement list. */
const struct funct_defn *fdefn; /* #define foo(x) bar(x) */ struct answer *answers; /* answers to an assertion. */
struct predicate *pred; /* #assert */
} value; } value;
union tree_node *fe_value; /* front end value */ union tree_node *fe_value; /* front end value */
...@@ -646,23 +638,17 @@ struct cpp_hashnode ...@@ -646,23 +638,17 @@ struct cpp_hashnode
const unsigned char name[1]; /* name[length] */ 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 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 void cpp_reader_init PARAMS ((cpp_reader *));
extern cpp_printer *cpp_printer_init PARAMS ((cpp_reader *, cpp_printer *)); extern cpp_printer *cpp_printer_init PARAMS ((cpp_reader *, cpp_printer *));
extern int cpp_start_read PARAMS ((cpp_reader *, cpp_printer *, const char *)); 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_tokens PARAMS ((cpp_reader *, cpp_printer *,
extern void cpp_output_list PARAMS ((cpp_reader *, cpp_printer *, unsigned int));
const cpp_toklist *));
extern void cpp_finish PARAMS ((cpp_reader *, cpp_printer *)); extern void cpp_finish PARAMS ((cpp_reader *, cpp_printer *));
extern void cpp_cleanup PARAMS ((cpp_reader *)); 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_define PARAMS ((cpp_reader *, const char *));
extern void cpp_assert PARAMS ((cpp_reader *, const char *)); extern void cpp_assert PARAMS ((cpp_reader *, const char *));
extern void cpp_undef PARAMS ((cpp_reader *, const char *)); extern void cpp_undef PARAMS ((cpp_reader *, const char *));
......
...@@ -68,6 +68,7 @@ main (argc, argv) ...@@ -68,6 +68,7 @@ main (argc, argv)
print = cpp_printer_init (pfile, &parse_out); print = cpp_printer_init (pfile, &parse_out);
if (! print) if (! print)
return (FATAL_EXIT_CODE); return (FATAL_EXIT_CODE);
pfile->printer = print;
if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname))) if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname)))
return (FATAL_EXIT_CODE); return (FATAL_EXIT_CODE);
......
...@@ -432,8 +432,6 @@ write_lbrac () ...@@ -432,8 +432,6 @@ write_lbrac ()
struct partial_proto struct partial_proto
{ {
struct partial_proto *next; struct partial_proto *next;
char *fname; /* name of function */
char *rtype; /* return type */
struct fn_decl *fn; struct fn_decl *fn;
int line_seen; int line_seen;
}; };
...@@ -497,15 +495,13 @@ recognized_macro (fname) ...@@ -497,15 +495,13 @@ recognized_macro (fname)
} }
void void
recognized_extern (name, name_length, type, type_length) recognized_extern (name)
const char *name; const cpp_token *name;
const char *type ATTRIBUTE_UNUSED;
int name_length, type_length ATTRIBUTE_UNUSED;
{ {
switch (special_file_handling) switch (special_file_handling)
{ {
case errno_h: 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--; seen_errno = 1, required_other--;
break; break;
...@@ -515,25 +511,17 @@ recognized_extern (name, name_length, type, type_length) ...@@ -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 /* Called by scan_decls if it saw a function definition for a function
named FNAME, with return type RTYPE, and argument list ARGS, named FNAME, in source file FILE_SEEN on line LINE_SEEN. KIND is
in source file FILE_SEEN on line LINE_SEEN. 'I' for an inline function; 'F' if a normal function declaration
KIND is 'I' for an inline function; preceded by 'extern "C"' (or nested inside 'extern "C"' braces); or
'F' if a normal function declaration preceded by 'extern "C"'
(or nested inside 'extern "C"' braces); or
'f' for other function declarations. */ 'f' for other function declarations. */
void void
recognized_function (fname, fname_length, recognized_function (fname, kind, have_arg_list, file_seen)
kind, rtype, rtype_length, const cpp_token *fname;
have_arg_list, file_seen, line_seen)
const char *fname;
int fname_length;
int kind; /* One of 'f' 'F' or 'I' */ int kind; /* One of 'f' 'F' or 'I' */
const char *rtype;
int rtype_length;
int have_arg_list; int have_arg_list;
const char *file_seen; const char *file_seen;
int line_seen;
{ {
struct partial_proto *partial; struct partial_proto *partial;
int i; int i;
...@@ -543,7 +531,8 @@ recognized_function (fname, fname_length, ...@@ -543,7 +531,8 @@ recognized_function (fname, fname_length,
missing_extern_C_count++; missing_extern_C_count++;
#endif #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. */ /* Remove the function from the list of required function. */
if (fn) if (fn)
...@@ -577,12 +566,7 @@ recognized_function (fname, fname_length, ...@@ -577,12 +566,7 @@ recognized_function (fname, fname_length,
partial_count++; partial_count++;
partial = (struct partial_proto *) partial = (struct partial_proto *)
obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto)); obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
partial->fname = obstack_alloc (&scan_file_obstack, fname_length + 1); partial->line_seen = fname->line;
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->fn = fn; partial->fn = fn;
fn->partial = partial; fn->partial = partial;
partial->next = partial_proto_list; partial->next = partial_proto_list;
...@@ -590,7 +574,7 @@ recognized_function (fname, fname_length, ...@@ -590,7 +574,7 @@ recognized_function (fname, fname_length,
if (verbose) if (verbose)
{ {
fprintf (stderr, "(%s: %s non-prototype function declaration.)\n", 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) ...@@ -646,19 +630,12 @@ read_scan_file (in_fname, argc, argv)
for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++) for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
check_macro_names (&scan_in, cur_symbols->names); 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. /* Traditionally, getc and putc are defined in terms of _filbuf and _flsbuf.
If so, those functions are also required. */ If so, those functions are also required. */
if (special_file_handling == stdio_h if (special_file_handling == stdio_h
&& (fn = lookup_std_proto ("_filbuf", 7)) != NULL) && (fn = lookup_std_proto ("_filbuf", 7)) != NULL)
{ {
static const unsigned char getchar_call[] = "getchar();"; static const unsigned char getchar_call[] = "getchar();";
int old_written = CPP_WRITTEN (&scan_in);
int seen_filbuf = 0; int seen_filbuf = 0;
cpp_buffer *buf = CPP_BUFFER (&scan_in); cpp_buffer *buf = CPP_BUFFER (&scan_in);
if (cpp_push_buffer (&scan_in, getchar_call, if (cpp_push_buffer (&scan_in, getchar_call,
...@@ -668,14 +645,17 @@ read_scan_file (in_fname, argc, argv) ...@@ -668,14 +645,17 @@ read_scan_file (in_fname, argc, argv)
/* Scan the macro expansion of "getchar();". */ /* Scan the macro expansion of "getchar();". */
for (;;) for (;;)
{ {
enum cpp_ttype token = cpp_get_token (&scan_in); const cpp_token *t = cpp_get_token (&scan_in);
int length = CPP_WRITTEN (&scan_in) - old_written;
unsigned char *id = scan_in.token_buffer + old_written; if (t->type == CPP_EOF)
{
CPP_SET_WRITTEN (&scan_in, old_written); cpp_pop_buffer (&scan_in);
if (token == CPP_EOF && CPP_BUFFER (&scan_in) == buf) if (CPP_BUFFER (&scan_in) == buf)
break; break;
if (token == CPP_NAME && cpp_idcmp (id, length, "_filbuf") == 0) }
else if (t->type == CPP_NAME && cpp_idcmp (t->val.name.text,
t->val.name.len,
"_filbuf") == 0)
seen_filbuf++; seen_filbuf++;
} }
if (seen_filbuf) if (seen_filbuf)
...@@ -1030,8 +1010,6 @@ check_protection (ifndef_line, endif_line) ...@@ -1030,8 +1010,6 @@ check_protection (ifndef_line, endif_line)
} }
else if (!strcmp (buf.base, "define")) else if (!strcmp (buf.base, "define"))
{ {
if (if_nesting != 1)
goto skip_to_eol;
c = inf_skip_spaces (c); c = inf_skip_spaces (c);
c = inf_scan_ident (&buf, c); c = inf_scan_ident (&buf, c);
if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0) if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
......
...@@ -45,7 +45,7 @@ skip_to_closing_brace (pfile) ...@@ -45,7 +45,7 @@ skip_to_closing_brace (pfile)
int nesting = 1; int nesting = 1;
for (;;) for (;;)
{ {
enum cpp_ttype token = cpp_get_token (pfile); enum cpp_ttype token = cpp_get_token (pfile)->type;
if (token == CPP_EOF) if (token == CPP_EOF)
break; break;
if (token == CPP_OPEN_BRACE) if (token == CPP_OPEN_BRACE)
...@@ -84,24 +84,17 @@ scan_decls (pfile, argc, argv) ...@@ -84,24 +84,17 @@ scan_decls (pfile, argc, argv)
char **argv ATTRIBUTE_UNUSED; char **argv ATTRIBUTE_UNUSED;
{ {
int saw_extern, saw_inline; int saw_extern, saw_inline;
int start_written; const cpp_token *prev_id;
/* If declarator_start is non-zero, it marks the start of the current const cpp_token *token;
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;
new_statement: new_statement:
CPP_SET_WRITTEN (pfile, 0);
start_written = 0;
token = cpp_get_token (pfile); token = cpp_get_token (pfile);
handle_statement: handle_statement:
current_extern_C = 0; current_extern_C = 0;
saw_extern = 0; saw_extern = 0;
saw_inline = 0; saw_inline = 0;
if (token == CPP_OPEN_BRACE) if (token->type == CPP_OPEN_BRACE)
{ {
/* Pop an 'extern "C"' nesting level, if appropriate. */ /* Pop an 'extern "C"' nesting level, if appropriate. */
if (extern_C_braces_length if (extern_C_braces_length
...@@ -110,120 +103,112 @@ scan_decls (pfile, argc, argv) ...@@ -110,120 +103,112 @@ scan_decls (pfile, argc, argv)
brace_nesting--; brace_nesting--;
goto new_statement; goto new_statement;
} }
if (token == CPP_OPEN_BRACE) if (token->type == CPP_OPEN_BRACE)
{ {
brace_nesting++; brace_nesting++;
goto new_statement; goto new_statement;
} }
if (token == CPP_EOF) if (token->type == CPP_EOF)
{ {
cpp_pop_buffer (pfile);
if (CPP_BUFFER (pfile) == NULL) if (CPP_BUFFER (pfile) == NULL)
return 0; return 0;
else
goto new_statement; goto new_statement;
} }
if (token == CPP_SEMICOLON) if (token->type == CPP_SEMICOLON)
goto new_statement; goto new_statement;
if (token != CPP_NAME) if (token->type != CPP_NAME)
goto new_statement; goto new_statement;
prev_id_start = 0; prev_id = 0;
declarator_start = 0;
for (;;) 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: case CPP_OPEN_PAREN:
/* Looks like this is the start of a formal parameter list. */ /* Looks like this is the start of a formal parameter list. */
if (prev_id_start) if (prev_id)
{ {
int nesting = 1; int nesting = 1;
int have_arg_list = 0; int have_arg_list = 0;
cpp_buffer *fbuf = cpp_file_buffer (pfile);
unsigned int func_lineno = CPP_BUF_LINE (fbuf);
for (;;) for (;;)
{ {
token = cpp_get_token (pfile); token = cpp_get_token (pfile);
if (token == CPP_OPEN_PAREN) if (token->type == CPP_OPEN_PAREN)
nesting++; nesting++;
else if (token == CPP_CLOSE_PAREN) else if (token->type == CPP_CLOSE_PAREN)
{ {
nesting--; nesting--;
if (nesting == 0) if (nesting == 0)
break; break;
} }
else if (token == CPP_EOF) else if (token->type == CPP_EOF)
break; break;
else if (token == CPP_NAME || token == CPP_ELLIPSIS) else if (token->type == CPP_NAME
|| token->type == CPP_ELLIPSIS)
have_arg_list = 1; have_arg_list = 1;
} }
recognized_function (pfile->token_buffer + prev_id_start, recognized_function (prev_id,
prev_id_end - prev_id_start,
(saw_inline ? 'I' (saw_inline ? 'I'
: in_extern_C_brace || current_extern_C : in_extern_C_brace || current_extern_C
? 'F' : 'f'), ? 'F' : 'f'), have_arg_list,
pfile->token_buffer, prev_id_start, CPP_BUFFER (pfile)->nominal_fname);
have_arg_list, token = cpp_get_token (pfile);
fbuf->nominal_fname, func_lineno); if (token->type == CPP_OPEN_BRACE)
token = cpp_get_non_space_token (pfile);
if (token == CPP_OPEN_BRACE)
{ {
/* skip body of (normally) inline function */ /* skip body of (normally) inline function */
skip_to_closing_brace (pfile); skip_to_closing_brace (pfile);
goto new_statement; goto new_statement;
} }
goto maybe_handle_comma; if (token->type == CPP_SEMICOLON)
goto new_statement;
} }
break; 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: case CPP_NAME:
/* "inline" and "extern" are recognized but skipped */ /* "inline" and "extern" are recognized but skipped */
if (!cpp_idcmp (pfile->token_buffer, if (!cpp_idcmp (token->val.name.text, token->val.name.len, "inline"))
CPP_WRITTEN (pfile), "inline"))
{ {
saw_inline = 1; saw_inline = 1;
CPP_SET_WRITTEN (pfile, start_written);
} }
else if (!cpp_idcmp (pfile->token_buffer, else if (!cpp_idcmp (token->val.name.text,
CPP_WRITTEN (pfile), "extern")) token->val.name.len, "extern"))
{ {
saw_extern = 1; saw_extern = 1;
CPP_SET_WRITTEN (pfile, start_written); token = cpp_get_token (pfile);
token = cpp_get_non_space_token (pfile); if (token->type == CPP_STRING
if (token == CPP_STRING && !cpp_idcmp (token->val.name.text,
&& strcmp (pfile->token_buffer, "\"C\"") == 0) token->val.name.len, "C"))
{ {
CPP_SET_WRITTEN (pfile, start_written);
current_extern_C = 1; current_extern_C = 1;
token = cpp_get_non_space_token (pfile); token = cpp_get_token (pfile);
if (token == CPP_OPEN_BRACE) if (token->type == CPP_OPEN_BRACE)
{ {
brace_nesting++; brace_nesting++;
extern_C_braces[extern_C_braces_length++] extern_C_braces[extern_C_braces_length++]
...@@ -236,29 +221,9 @@ scan_decls (pfile, argc, argv) ...@@ -236,29 +221,9 @@ scan_decls (pfile, argc, argv)
break; break;
} }
/* This may be the name of a variable or function. */ /* This may be the name of a variable or function. */
prev_id_start = start_written; prev_id = token;
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);
break; break;
default:
prev_id_start = 0;
} }
start_written = CPP_WRITTEN (pfile);
token = cpp_get_token (pfile); token = cpp_get_token (pfile);
} }
} }
...@@ -50,6 +50,8 @@ struct fn_decl ...@@ -50,6 +50,8 @@ struct fn_decl
struct partial_proto *partial; struct partial_proto *partial;
}; };
struct cpp_token;
extern int lineno; extern int lineno;
extern void sstring_append _PARAMS((sstring *, sstring *)); extern void sstring_append _PARAMS((sstring *, sstring *));
extern void make_sstring_space _PARAMS((sstring *, int)); extern void make_sstring_space _PARAMS((sstring *, int));
...@@ -58,8 +60,9 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int)); ...@@ -58,8 +60,9 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int));
extern int scan_string _PARAMS((FILE *, sstring *, int)); extern int scan_string _PARAMS((FILE *, sstring *, int));
extern int read_upto _PARAMS((FILE *, sstring *, int)); extern int read_upto _PARAMS((FILE *, sstring *, int));
extern unsigned long hash _PARAMS((const char *)); extern unsigned long hash _PARAMS((const char *));
extern void recognized_function _PARAMS((const char *, int, int, const char *, int, int, const char *, int)); extern void recognized_function _PARAMS((const struct cpp_token *, int, int,
extern void recognized_extern _PARAMS((const char *, int, const char *, int)); const char *));
extern void recognized_extern _PARAMS((const struct cpp_token *));
extern unsigned int hashstr _PARAMS((const char *, unsigned int)); extern unsigned int hashstr _PARAMS((const char *, unsigned int));
struct cpp_reader; 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> 2000-07-03 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/20000703-1.c: New test. * gcc.c-torture/execute/20000703-1.c: New test.
......
/* { dg-do preprocess } */ /* { dg-do preprocess } */
/* { dg-error "include expects" "" { target *-*-* } 4 } */ /* { dg-error "include expects" "" { target *-*-* } 4 } */
/* { dg-warning "no newline" "" { target *-*-* } 5 } */ /* { dg-error "newline at end" "" { target *-*-* } 4 } */
#include /\ #include /\
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
int int
main(void) 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) */ char *y = "0-0"; /* should be the expansion of SP1(0,MZ) */
if(strcmp(x, y)) if(strcmp(x, y))
......
...@@ -11,6 +11,6 @@ main(void) ...@@ -11,6 +11,6 @@ main(void)
{ {
goto socket; goto socket;
ENTRY(socket) ENTRY(socket) /* { dg-warning "valid preprocessing token" "" } */
return 0; return 0;
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define xstr(x) #x #define xstr(x) #x
const char a[] = str(symbol_version(getrlimit, GLIBC_2.0)); 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 b[] = str(getrlimit@GLIBC_2.0);
const char c[] = "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