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:
......
...@@ -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))
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -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