diff options
author | Zack Weinberg <zack@gcc.gnu.org> | 2000-07-04 01:58:21 +0000 |
---|---|---|
committer | Zack Weinberg <zack@gcc.gnu.org> | 2000-07-04 01:58:21 +0000 |
commit | 041c31944c94d5ee089bd569c4361fbc3d2acaea (patch) | |
tree | 1c91fa44eb386dd706e44d139ed980ea94f05cae /gcc | |
parent | 4f647814cefff8ee95ac918a8484d5da8c415825 (diff) | |
download | gcc-041c31944c94d5ee089bd569c4361fbc3d2acaea.zip gcc-041c31944c94d5ee089bd569c4361fbc3d2acaea.tar.gz gcc-041c31944c94d5ee089bd569c4361fbc3d2acaea.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 92 | ||||
-rw-r--r-- | gcc/cpperror.c | 31 | ||||
-rw-r--r-- | gcc/cppexp.c | 106 | ||||
-rw-r--r-- | gcc/cppfiles.c | 68 | ||||
-rw-r--r-- | gcc/cpphash.c | 1998 | ||||
-rw-r--r-- | gcc/cpphash.h | 162 | ||||
-rw-r--r-- | gcc/cppinit.c | 151 | ||||
-rw-r--r-- | gcc/cpplex.c | 3771 | ||||
-rw-r--r-- | gcc/cpplib.c | 1561 | ||||
-rw-r--r-- | gcc/cpplib.h | 212 | ||||
-rw-r--r-- | gcc/cppmain.c | 1 | ||||
-rw-r--r-- | gcc/fix-header.c | 68 | ||||
-rw-r--r-- | gcc/scan-decls.c | 159 | ||||
-rw-r--r-- | gcc/scan.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/19951025-1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/19990703-1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/20000625-1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/20000625-2.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/macro1.c | 72 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/paste1.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/paste2.c | 115 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/paste3.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/paste4.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/strify1.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/strify2.c | 45 |
26 files changed, 3758 insertions, 4929 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4aced4a..f9c9b73 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,97 @@ 2000-07-03 Zack Weinberg <zack@wolery.cumb.org> + * fix-header.c (struct partial_proto): Remove unnecessary fields. + (recognized_extern, recognized_function, read_scan_file): + Update for new scheme. + (check_protection): It's still a multiple include guard even + if it doesn't always trigger. + * scan-decls.c (skip_to_closing_brace, scan_decls): Update for + new scheme. + * scan.h: Declare struct cpp_token. Update prototypes. + +2000-07-03 Neil Booth <neilb@earthling.net> + Zack Weinberg <zack@wolery.cumb.org> + + Complete overhaul of the lexer and macro expander. + + * cpphash.c (object_defn, funct_defn, push_macro_expansion, + arg, arglist, argdata, reflist, collect_objlike_expansion, + collect_funlike_expansion, collect_params, + warn_trad_stringify, trad_stringify, duplicate_arg_p, add_pat, + unsafe_chars, macarg, compare_defs, special_symbol, + scan_arguments, stringify, funlike_macroexpand, + _cpp_quote_string, monthnames): Delete. + (cpp_lookup, _cpp_free_definition, dump_funlike_macro, + _cpp_create_definition, _cpp_dump_definition, + dump_hash_helper): Adjust. + (find_param, count_params, parse_define, var_args_str, + check_macro_redefinition, save_expansion): New. + + * cpplex.c (skip_block_comment, skip_line_comment, parse_name, + parse_string, output_line_command, trigraph_replace, + lex_line, cpp_push_buffer, cpp_pop_buffer, cpp_output_tokens, + cpp_scan_buffer_nooutput, cpp_scan_buffer, cpp_free_toklist, + cpp_idcmp, _cpp_get_directive_token, _cpp_init_input_buffer, + _cpp_skip_rest_of_line): Modify. + + (maybe_macroexpand, skip_comment, copy_comment, skip_string, + find_position, null_warning, bump_column, expand_name_space, + pedantic_whitespace, _cpp_output_list, _cpp_slice_toklist, + _cpp_squeeze_toklist, _cpp_scan_until, _cpp_skip_hspace, + _cpp_parse_name, _cpp_lex_token, cpp_get_non_space_token, + _cpp_prescan): Delete. + + (dump_param_spelling, process_directive, lex_next, + is_macro_disabled, stringify_arg, expand_context_stack, + output_token, make_string_token, alloc_number_token, + special_symbol, duplicate_token, maybe_paste_with_next, + can_paste, prevent_macro_expansion, restore_macro_expansion, + get_temp_token, release_temp_tokens, quote_string, + token_names, token_spellings, _cpp_expand_name_space, + _cpp_glue_header_name, _cpp_reserve_name_space, + digraph_spellings, trigraph_ok, skip_whitespace, save_comment, + placemarker_token, eof_token, cpp_context, macro_args, + get_raw_token, parse_arg, parse_args, save_token, + push_arg_context, push_macro_context, pop_context, + do_pop_context, free_macro_args, _cpp_get_line, + _cpp_run_directive): New. + + * cpplib.c (validate_else, parse_include, push_conditional, + pass_thru_directive, read_line_number, parse_ifdef, + detect_if_not_defined, _cpp_check_directive, do_define, + do_undef, do_include, do_import, do_include_next, do_error, + do_warning, do_ident, do_pragma, pragma_dispatch, gcc_pragmas, + top_pragmas, do_pragma_gcc, do_pragma_implementation, + do_pragma_poison, do_pragma_system_header, + do_pragma_dependency, do_sccs, do_ifdef, do_ifndef, do_else, + dl_elif, do_endif, _cpp_unwind_if_stack, do_assert, + do_unassert, cpp_define, cpp_undef, cpp_assert, cpp_unassert, + cpp_defined): Update for new scheme. + (strtoul_for_line, get_define_node, dump_macro_name, + _cpp_check_linemarker, _cpp_parse_assertion): New. + (_cpp_handle_directive, do_pragma_default): Delete. + + * cpphash.h (struct predicate): Now struct answer. + (enum spell_type, struct token_spelling, struct directive, + directive_handler): New. + Update prototypes. Remove unused macros. + * cpplib.h: Update prototypes. Remove unused macros, + structure definitions, and fields. + + * cpperror.c (print_containing_files, v_message): Adjust. + * cppexp.c (parse_assertion, lex, parse_escape, + _cpp_parse_expr): Adjust. + * cppfiles.c (open_include_file, _cpp_execute_include, + _cpp_compare_file_date, cpp_read_file, read_include_file): + Adjust. + * cppinit.c (dump_special_to_buffer): Delete. + (append_include_chain, merge_include_chains, cpp_reader_init, + cpp_cleanup, initialize_builtins, builtin_array, cpp_start_read, + cpp_finish, handle_option, print_help): Adjust. + * cppmain.c (main): Adjust. + +2000-07-03 Zack Weinberg <zack@wolery.cumb.org> + * cppspec.c (lang_specific_driver): Use double quotes in error message. diff --git a/gcc/cpperror.c b/gcc/cpperror.c index 0e8afc4..a2769b6 100644 --- a/gcc/cpperror.c +++ b/gcc/cpperror.c @@ -58,23 +58,27 @@ print_containing_files (pfile, ip) if (first) { first = 0; + /* N.B. The current line in each outer source file is one + greater than the line of the #include, so we must + subtract one to correct for that. */ fprintf (stderr, _("In file included from %s:%u"), - ip->nominal_fname, CPP_BUF_LINE (ip)); + ip->nominal_fname, CPP_BUF_LINE (ip) - 1); } else /* Translators note: this message is used in conjunction with "In file included from %s:%ld" and some other tricks. We want something like this: - In file included from sys/select.h:123, - from sys/types.h:234, - from userfile.c:31: - bits/select.h:45: <error message here> + | In file included from sys/select.h:123, + | from sys/types.h:234, + | from userfile.c:31: + | bits/select.h:45: <error message here> + with all the "from"s lined up. The trailing comma is at the beginning of this message, and the trailing colon is not translated. */ fprintf (stderr, _(",\n from %s:%u"), - ip->nominal_fname, CPP_BUF_LINE (ip)); + ip->nominal_fname, CPP_BUF_LINE (ip) - 1); } if (first == 0) fputs (":\n", stderr); @@ -111,17 +115,14 @@ v_message (pfile, is_error, file, line, col, msg, ap) const char *msg; va_list ap; { - cpp_buffer *ip = cpp_file_buffer (pfile); + cpp_buffer *ip = CPP_BUFFER (pfile); if (ip) { if (file == NULL) file = ip->nominal_fname; if (line == 0) - { - line = CPP_BUF_LINE (ip); - col = CPP_BUF_COL (ip); - } + line = _cpp_get_line (pfile, &col); print_containing_files (pfile, ip); print_file_and_line (file, line, CPP_OPTION (pfile, show_column) ? col : 0); @@ -132,8 +133,12 @@ v_message (pfile, is_error, file, line, col, msg, ap) switch (is_error) { case 0: - fprintf (stderr, _("warning: ")); - break; + if (! CPP_OPTION (pfile, warnings_are_errors)) + { + fprintf (stderr, _("warning: ")); + break; + } + /* else fall through */ case 1: if (pfile->errors < CPP_FATAL_LIMIT) pfile->errors++; diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 58430c3..392132b 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -394,74 +394,22 @@ parse_assertion (pfile) cpp_reader *pfile; { struct operation op; + struct answer *answer; cpp_hashnode *hp; - struct predicate *pred; - cpp_toklist query; - enum cpp_ttype type; - U_CHAR *tok; - size_t len; - unsigned int old_written; - int specific = 0; - - old_written = CPP_WRITTEN (pfile); - CPP_PUTC (pfile, '#'); - pfile->no_macro_expand++; - type = _cpp_get_directive_token (pfile); - if (type == CPP_VSPACE) - SYNTAX_ERROR ("assertion without predicate"); - else if (type != CPP_NAME) - SYNTAX_ERROR ("assertion predicate is not an identifier"); - - tok = pfile->token_buffer + old_written; - len = CPP_WRITTEN (pfile) - old_written; - hp = cpp_lookup (pfile, tok, len); - /* Look ahead for an open paren. */ - _cpp_skip_hspace (pfile); - if (CPP_BUF_PEEK (CPP_BUFFER (pfile)) == '(') + op.op = ERROR; + hp = _cpp_parse_assertion (pfile, &answer); + if (hp) { - if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN) - CPP_ICE ("impossible token, expecting ( in parse_assertion"); - - _cpp_init_toklist (&query, NO_DUMMY_TOKEN); - specific = 1; - if (_cpp_scan_until (pfile, &query, CPP_CLOSE_PAREN) != CPP_CLOSE_PAREN) - SYNTAX_ERROR ("missing close paren on assertion answer"); - - if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) - CPP_ICE ("impossible token, expecting ) in parse_assertion"); - } + /* If we get here, the syntax is valid. */ + op.op = INT; + op.value = (hp->type == T_ASSERTION && + (answer == 0 || *find_answer (hp, &answer->list) != 0)); - /* If we get here, the syntax is valid. */ - op.op = INT; - op.value = 0; - /* Has this predicate been asserted at all? */ - if (hp->type == T_ASSERTION) - { - if (specific) - { - for (pred = hp->value.pred; pred; pred = pred->next) - if (_cpp_equiv_toklists (&query, &pred->answer)) - { - op.value = 1; - break; - } - _cpp_free_toklist (&query); - } - else - op.value = 1; + if (answer) + FREE_ANSWER (answer); } - - out: - pfile->no_macro_expand--; - CPP_SET_WRITTEN (pfile, old_written); return op; - - syntax_error: - if (specific) - _cpp_free_toklist (&query); - op.op = ERROR; - goto out; } struct token @@ -480,8 +428,6 @@ static const struct token tokentab2[] = {"!=", NOTEQUAL}, {"<=", LEQ}, {">=", GEQ}, - {"++", ERROR}, - {"--", ERROR}, {NULL, ERROR} }; @@ -496,16 +442,20 @@ lex (pfile, skip_evaluation) enum cpp_ttype token; struct operation op; U_CHAR *tok_start, *tok_end; - long old_written; + long old_written = CPP_WRITTEN (pfile); - old_written = CPP_WRITTEN (pfile); + retry: token = _cpp_get_directive_token (pfile); - tok_start = pfile->token_buffer + old_written; tok_end = CPP_PWRITTEN (pfile); CPP_SET_WRITTEN (pfile, old_written); + switch (token) { + case CPP_PLACEMARKER: + CPP_SET_WRITTEN (pfile, old_written); + goto retry; + case CPP_EOF: /* Should not happen ... */ case CPP_VSPACE: op.op = 0; @@ -524,6 +474,7 @@ lex (pfile, skip_evaluation) return parse_charconst (pfile, tok_start, tok_end); case CPP_NAME: + /* FIXME: could this not overflow the tok_start buffer? */ if (!ustrncmp (tok_start, U"defined", 7)) return parse_defined (pfile); @@ -539,7 +490,16 @@ lex (pfile, skip_evaluation) case CPP_HASH: return parse_assertion (pfile); - case CPP_OTHER: + case CPP_AND_AND: op.op = ANDAND; return op; + case CPP_OR_OR: op.op = OROR; return op; + case CPP_LSHIFT: op.op = LSH; return op; + case CPP_RSHIFT: op.op = RSH; return op; + case CPP_EQ_EQ: op.op = EQUAL; return op; + case CPP_NOT_EQ: op.op = NOTEQUAL; return op; + case CPP_LESS_EQ: op.op = LEQ; return op; + case CPP_GREATER_EQ:op.op = GEQ; return op; + + default: /* See if it is a special token of length 2. */ if (tok_start + 2 == tok_end) { @@ -553,8 +513,6 @@ lex (pfile, skip_evaluation) op.op = toktab->token; return op; } - /* fall through */ - default: op.op = *tok_start; return op; } @@ -612,7 +570,7 @@ parse_escape (pfile, string_ptr, result_mask) case 'e': case 'E': if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, '\\%c'", c); + cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c); return TARGET_ESC; case 'f': return TARGET_FF; @@ -844,9 +802,7 @@ _cpp_parse_expr (pfile) char buff[5]; /* Save parser state and set it to something sane. */ - int save_only_seen_white = pfile->only_seen_white; int save_skipping = pfile->skipping; - pfile->only_seen_white = 0; pfile->skipping = 0; /* We've finished when we try to reduce this. */ @@ -875,7 +831,8 @@ _cpp_parse_expr (pfile) case ERROR: goto syntax_error; default: - SYNTAX_ERROR ("invalid character in #if"); + SYNTAX_ERROR2 ("invalid character '%s' in #if", + op_to_str (op.op, buff)); push_immediate: case INT: @@ -1168,7 +1125,6 @@ _cpp_parse_expr (pfile) if (stack != init_stack) free (stack); CPP_SET_WRITTEN (pfile, old_written); - pfile->only_seen_white = save_only_seen_white; pfile->skipping = save_skipping; return result; } diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index 4def8ed..66fb7bc 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -180,7 +180,7 @@ open_include_file (pfile, filename) #ifdef EACCES if (errno == EACCES) { - cpp_error (pfile, "included file `%s' exists but is not readable", + cpp_error (pfile, "included file \"%s\" exists but is not readable", filename); } #endif @@ -360,16 +360,16 @@ cpp_make_system_header (pfile, pbuf, flag) #define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth)) void -_cpp_execute_include (pfile, f, len, no_reinclude, search_start) +_cpp_execute_include (pfile, f, len, no_reinclude, search_start, angle_brackets) cpp_reader *pfile; - U_CHAR *f; + const U_CHAR *f; unsigned int len; int no_reinclude; struct file_name_list *search_start; + int angle_brackets; { struct include_file *inc; - char *fname = (char *)f; - int angle_brackets = fname[0] == '<'; + char *fname; if (!search_start) { @@ -387,9 +387,8 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start) return; } - /* Remove quote marks. */ - fname++; - len -= 2; + fname = alloca (len + 1); + memcpy (fname, f, len); fname[len] = '\0'; inc = find_include_file (pfile, fname, search_start); @@ -470,32 +469,27 @@ _cpp_execute_include (pfile, f, len, no_reinclude, search_start) if F cannot be located or dated, 1, if it is newer and 0 if older. */ int -_cpp_compare_file_date (pfile, f, len, search_start) +_cpp_compare_file_date (pfile, f, len, angle_brackets) cpp_reader *pfile; - U_CHAR *f; + const U_CHAR *f; unsigned int len; - struct file_name_list *search_start; + int angle_brackets; { - char *fname = (char *)f; - int angle_brackets = fname[0] == '<'; + char *fname; + struct file_name_list *search_start; struct include_file *inc; - struct include_file *current_include = cpp_file_buffer (pfile)->inc; + struct include_file *current_include = CPP_BUFFER (pfile)->inc; - if (!search_start) - { - if (angle_brackets) - search_start = CPP_OPTION (pfile, bracket_include); - else if (CPP_OPTION (pfile, ignore_srcdir)) - search_start = CPP_OPTION (pfile, quote_include); - else - search_start = CPP_BUFFER (pfile)->actual_dir; - } + if (angle_brackets) + search_start = CPP_OPTION (pfile, bracket_include); + else if (CPP_OPTION (pfile, ignore_srcdir)) + search_start = CPP_OPTION (pfile, quote_include); + else + search_start = CPP_BUFFER (pfile)->actual_dir; - /* Remove quote marks. */ - fname++; - len -= 2; + fname = alloca (len + 1); + memcpy (fname, f, len); fname[len] = '\0'; - inc = find_include_file (pfile, fname, search_start); if (!inc) @@ -534,6 +528,12 @@ cpp_read_file (pfile, fname) f = open_include_file (pfile, fname); + if (f == NULL) + { + cpp_error_from_errno (pfile, fname); + return 0; + } + return read_include_file (pfile, f); } @@ -550,12 +550,17 @@ read_include_file (pfile, inc) cpp_buffer *fp; int fd = inc->fd; + /* Ensures we dump our current line before entering an include file. */ + if (CPP_BUFFER (pfile) && pfile->printer) + cpp_output_tokens (pfile, pfile->printer, + CPP_BUF_LINE (CPP_BUFFER (pfile))); + fp = cpp_push_buffer (pfile, NULL, 0); if (fp == 0) goto push_fail; - if (fstat (fd, &st) < 0) + if (fd < 0 || fstat (fd, &st) < 0) goto perror_fail; inc->date = st.st_mtime; @@ -622,9 +627,6 @@ read_include_file (pfile, inc) if (length == 0) inc->cmacro = NEVER_REREAD; - else - /* Temporary - I hope. */ - length = _cpp_prescan (pfile, fp, length); fp->rlimit = fp->buf + length; fp->cur = fp->buf; @@ -637,13 +639,13 @@ read_include_file (pfile, inc) fp->actual_dir = actual_directory (pfile, inc->name); pfile->input_stack_listing_current = 0; - pfile->only_seen_white = 2; return 1; perror_fail: cpp_error_from_errno (pfile, inc->name); /* Do not try to read this file again. */ - close (fd); + if (fd != -1) + close (fd); inc->fd = -1; inc->cmacro = NEVER_REREAD; fail: diff --git a/gcc/cpphash.c b/gcc/cpphash.c index d82c285..ba812d5 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -31,75 +31,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef abort -/* Structure allocated for every #define. For a simple replacement - such as - #define foo bar - - we allocate an object_defn structure; the expansion field points - to the replacement text. For a function-like macro we allocate a - funct_defn structure; nargs is the number of arguments - it can be zero, - e.g. - #define getchar() getc (stdin) - - When there are args, the expansion is the replacement text with the - args squashed out, and the reflist is a list describing how to - build the output from the input: e.g., "3 chars, then the 1st arg, - then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". - The chars here come from the expansion. Whatever is left of the - expansion after the last arg-occurrence is copied after that arg. - Note that the reflist can be arbitrarily long--- - its length depends on the number of times the arguments appear in - the replacement text, not how many args there are. Example: - #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and - pattern list - { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } - where (x, y) means (nchars, argno). - - Note that EMPTY and IDENTITY macros have object_defn structures too, - but they're just used to hold the file, line, and column. The - expansion field will be NULL. */ - -struct object_defn -{ - const U_CHAR *expansion; - unsigned int length; - - const char *file; /* File, line, column of definition */ - int line; - int col; -}; - -struct reflist -{ - const struct reflist *next; - char stringify; /* nonzero if this arg was preceded by a - # operator. */ - char raw_before; /* Nonzero if a ## operator before arg. */ - char raw_after; /* Nonzero if a ## operator after arg. */ - char rest_args; /* Nonzero if this arg. absorbs the rest */ - int nchars; /* Number of literal chars to copy before - this arg occurrence. */ - int argno; /* Number of arg to substitute (origin-0) */ -}; - -struct funct_defn -{ - int nargs; - int length; /* length of expansion string */ - const U_CHAR *expansion; - char rest_args; /* Nonzero if last arg. absorbs the rest */ - const struct reflist *pattern; - - /* Names of macro args, concatenated in order with \0 between - them. The only use of this is that we warn on redefinition if - this differs between the old and new definitions. */ - U_CHAR *argnames; - - const char *file; /* File, line, column of definition */ - int line; - int col; -}; - /* This is the second argument to eq_HASHNODE. */ struct hashdummy { @@ -107,96 +38,30 @@ struct hashdummy unsigned short length; }; +/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */ +#define HASHSIZE 500 + static unsigned int hash_HASHNODE PARAMS ((const void *)); static int eq_HASHNODE PARAMS ((const void *, const void *)); static void del_HASHNODE PARAMS ((void *)); static cpp_hashnode *make_HASHNODE PARAMS ((const U_CHAR *, size_t, enum node_type, unsigned int)); - -static void dump_funlike_macro PARAMS ((cpp_reader *, - const struct funct_defn *)); static int dump_hash_helper PARAMS ((void **, void *)); -static void push_macro_expansion PARAMS ((cpp_reader *, const U_CHAR *, - int, cpp_hashnode *)); -static int unsafe_chars PARAMS ((cpp_reader *, int, int)); -static enum cpp_ttype macarg PARAMS ((cpp_reader *, int)); -static void special_symbol PARAMS ((cpp_reader *, cpp_hashnode *)); -static int compare_defs PARAMS ((cpp_reader *, - const struct funct_defn *, - const struct funct_defn *)); +static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *)); -/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */ -#define HASHSIZE 500 - -/* The arglist structure is built by collect_params to tell - collect_funlike_expansion where the argument names begin. That is, - for a define like "#define f(x,y,z) foo+x-bar*y", the arglist would - contain pointers to the strings x, y, and z. - collect_funlike_expansion would then build a funct_defn node, with - reflist nodes pointing to the places x, y, and z had appeared. - - The arglist is just convenience data passed between these two - routines. It is not kept around after the current #define has been - processed and entered into the hash table. */ +static const cpp_token *count_params PARAMS ((cpp_reader *, + const cpp_token *, + cpp_toklist *)); +static cpp_toklist *parse_define PARAMS((cpp_reader *)); +static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp, + const cpp_toklist *)); +static int save_expansion PARAMS((cpp_reader *, cpp_toklist *, + const cpp_token *, const cpp_token *)); +static unsigned int find_param PARAMS ((const cpp_token *, + const cpp_token *)); -struct arg -{ - const U_CHAR *name; - unsigned int len; - char rest_arg; -}; - -struct arglist -{ - U_CHAR *namebuf; - const struct arg *argv; - int argc; -}; - -static struct object_defn * -collect_objlike_expansion PARAMS ((cpp_reader *, cpp_toklist *)); -static struct funct_defn * -collect_funlike_expansion PARAMS ((cpp_reader *, cpp_toklist *, - struct arglist *, unsigned int)); -static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *, - struct arglist *)); - -static void warn_trad_stringify PARAMS ((cpp_reader *, const U_CHAR *, size_t, - unsigned int, const struct arg *)); -static unsigned int trad_stringify PARAMS ((cpp_reader *, const U_CHAR *, - size_t, - unsigned int, const struct arg *, - struct reflist **, - struct reflist **, unsigned int)); -static int duplicate_arg_p PARAMS ((U_CHAR *, U_CHAR *)); -static void add_pat PARAMS ((struct reflist **, struct reflist **, - unsigned int, unsigned int, int, int, int, int)); - -/* This structure represents one parsed argument in a macro call. - `raw' points to the argument text as written (`raw_length' is its length). - `expanded' points to the argument's macro-expansion - (its length is `expand_length'). - `stringified_length' is the length the argument would have - if stringified. */ - -/* raw and expanded are relative to ARG_BASE */ -#define ARG_BASE ((pfile)->token_buffer) - -struct argdata -{ - /* Strings relative to pfile->token_buffer */ - long raw, expanded, stringified; - int raw_length, expand_length; - int stringified_length; -}; - -static void scan_arguments PARAMS ((cpp_reader *, - const struct funct_defn *, - struct argdata *, const U_CHAR *)); -static void stringify PARAMS ((cpp_reader *, struct argdata *)); -static void funlike_macroexpand PARAMS ((cpp_reader *, cpp_hashnode *, - struct argdata *)); +static const unsigned char var_args_str[] = "__VA_ARGS__"; /* Calculate hash of a string of length LEN. */ unsigned int @@ -297,7 +162,8 @@ cpp_lookup (pfile, name, len) return *slot; new = make_HASHNODE (name, len, T_VOID, hash); - new->value.cpval = NULL; + new->value.expansion = NULL; + *slot = new; return new; } @@ -317,1521 +183,419 @@ void _cpp_free_definition (h) cpp_hashnode *h; { - if (h->type == T_XCONST) - free ((PTR) h->value.cpval); - else if (h->type == T_MACRO) - { - if (h->value.odefn->expansion) - free ((PTR) h->value.odefn->expansion); - free ((PTR) h->value.odefn); - } - else if (h->type == T_FMACRO) - { - const struct funct_defn *d = h->value.fdefn; - const struct reflist *ap, *nextap; - - for (ap = d->pattern; ap != NULL; ap = nextap) - { - nextap = ap->next; - free ((PTR) ap); - } - if (d->argnames) - free ((PTR) d->argnames); - free ((PTR) d); - } - h->value.cpval = NULL; -} - -/* Create pat nodes. */ - -static void -add_pat (pat, endpat, nchars, argno, raw_before, raw_after, strize, rest) - struct reflist **pat, **endpat; - unsigned int nchars; - unsigned int argno; - int raw_before, raw_after, strize, rest; -{ - struct reflist *tpat; - tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); - tpat->next = NULL; - tpat->raw_before = raw_before; - tpat->raw_after = raw_after; - tpat->stringify = strize; - tpat->rest_args = rest; - tpat->argno = argno; - tpat->nchars = nchars; - - if (*endpat == NULL) - *pat = tpat; - else - (*endpat)->next = tpat; - *endpat = tpat; -} - -/* Issue warnings for macro argument names seen inside strings. */ -static void -warn_trad_stringify (pfile, p, len, argc, argv) - cpp_reader *pfile; - const U_CHAR *p; - size_t len; - unsigned int argc; - const struct arg *argv; -{ - const U_CHAR *limit; - unsigned int i; - - limit = p + len; - for (;;) - { - while (p < limit && !is_idstart (*p)) p++; - if (p >= limit) - break; - - for (i = 0; i < argc; i++) - if (!ustrncmp (p, argv[i].name, argv[i].len) - && ! is_idchar (p[argv[i].len])) - { - cpp_warning (pfile, - "macro argument \"%s\" would be stringified in traditional C", - argv[i].name); - break; - } - p++; - while (p < limit && is_idchar (*p)) p++; - if (p >= limit) - break; - } + if (h->type == T_MACRO) + _cpp_free_toklist (h->value.expansion); + h->value.expansion = NULL; } -/* Generate pat nodes for macro arguments seen inside strings. */ +/* Scans for a given token, returning the parameter number if found, + or 0 if not found. Scans from FIRST to TOKEN - 1 or the first + CPP_CLOSE_PAREN for TOKEN. */ static unsigned int -trad_stringify (pfile, base, len, argc, argv, pat, endpat, last) - cpp_reader *pfile; - const U_CHAR *base; - size_t len; - unsigned int argc; - const struct arg *argv; - struct reflist **pat, **endpat; - unsigned int last; -{ - const U_CHAR *p, *limit; - unsigned int i; - - p = base; - limit = base + len; - for (;;) - { - proceed: - while (p < limit && !is_idstart (*p)) p++; - if (p >= limit) - break; - - for (i = 0; i < argc; i++) - if (!ustrncmp (p, argv[i].name, argv[i].len) - && ! is_idchar (p[argv[i].len])) - { - if (CPP_WTRADITIONAL (pfile)) - cpp_warning (pfile, "macro argument \"%s\" is stringified", - argv[i].name); - /* Write out the string up to this point, and add a pat - node for the argument. Note that the argument is NOT - stringified. */ - CPP_PUTS (pfile, base, p - base); - add_pat (pat, endpat, CPP_WRITTEN (pfile) - last, i /* argno */, - !is_hspace (p[-1]) /* raw_before */, - !is_hspace (p[argv[i].len]) /* raw_after */, - 0 /* strize */, - argv[i].rest_arg); - last = CPP_WRITTEN (pfile); - base = p + argv[i].len; - p = base; - goto proceed; - } - p++; - while (p < limit && is_idchar (*p)) p++; - if (p >= limit) - break; - } - CPP_PUTS (pfile, base, p - base); - return last; -} - -/* Read a replacement list for an object-like macro, and build the - object_defn structure. LIST contains the replacement list, - beginning at 1. */ -static struct object_defn * -collect_objlike_expansion (pfile, list) - cpp_reader *pfile; - cpp_toklist *list; +find_param (first, token) + const cpp_token *first, *token; { - struct object_defn *defn; - unsigned int i; - unsigned int start; - int last_was_paste = 0; - U_CHAR *exp; - size_t len; - - /* We copy the expansion text into the token_buffer, then out to - its proper home. */ - start = CPP_WRITTEN (pfile); - CPP_PUTS (pfile, "\r ", 2); - - for (i = 1; i < list->tokens_used; i++) - { - switch (TOK_TYPE (list, i)) - { - case CPP_PASTE: - /* ## is not special if it appears right after another ##; - nor is it special if -traditional. */ - if (last_was_paste || CPP_TRADITIONAL (pfile)) - break; - if (i == 1) - cpp_error (pfile, "`##' at start of macro definition"); - - last_was_paste = 1; - continue; - - default:; - } - - if (i > 1 && !last_was_paste && TOK_PREV_WHITE (list, i)) - CPP_PUTC (pfile, ' '); - - CPP_PUTS (pfile, TOK_NAME (list, i), TOK_LEN (list, i)); - last_was_paste = 0; - } - - if (last_was_paste) - cpp_error (pfile, "`##' at end of macro definition"); - - CPP_PUTS (pfile, "\r ", 2); - len = CPP_WRITTEN (pfile) - start; - CPP_SET_WRITTEN (pfile, start); + unsigned int param = 0; - if (len <= 4) - cpp_ice (pfile, "empty object-like macro went through full #define"); - - exp = (U_CHAR *) xmalloc (len + 1); - memcpy (exp, pfile->token_buffer + start, len); - exp[len] = '\0'; - - defn = (struct object_defn *) xmalloc (sizeof (struct object_defn)); - defn->length = len; - defn->expansion = exp; + for (; first < token && first->type != CPP_CLOSE_PAREN; first++) + if (first->type == CPP_NAME) + { + param++; + if (first->val.name.len == token->val.name.len + && !memcmp (first->val.name.text, token->val.name.text, + token->val.name.len)) + return param; + } - return defn; + return 0; } -/* Read a replacement list for a function-like macro, and build the - funct_defn structure. LIST contains the replacement list, - beginning at REPLACEMENT. ARGLIST specifies the formal parameters - to look for in the text of the definition. */ - -static struct funct_defn * -collect_funlike_expansion (pfile, list, arglist, replacement) +/* Counts the parameters to a function like macro, and saves their + spellings if necessary. Returns the token that we stopped scanning + at; if it's type isn't CPP_CLOSE_PAREN there was an error, which + has been reported. */ +static const cpp_token * +count_params (pfile, first, list) cpp_reader *pfile; + const cpp_token *first; cpp_toklist *list; - struct arglist *arglist; - unsigned int replacement; { - struct funct_defn *defn; - struct reflist *pat = 0, *endpat = 0; - enum cpp_ttype token; - unsigned int start, last; - unsigned int i; - int j, argc; - size_t len; - const struct arg *argv; - const U_CHAR *tok; - U_CHAR *exp; - enum { START = 0, NORM, ARG, STRIZE, PASTE } last_token = START; - - argv = arglist->argv; - argc = arglist->argc; - - /* We copy the expansion text into the token_buffer, then out to - its proper home. */ - last = start = CPP_WRITTEN (pfile); - CPP_PUTS (pfile, "\r ", 2); - - for (i = replacement; i < list->tokens_used; i++) + unsigned int params_len = 0, prev_ident = 0; + unsigned int line = pfile->token_list.line; + const cpp_token *token, *temp; + + list->paramc = 0; + for (token = first;; token++) { - token = TOK_TYPE (list, i); - tok = TOK_NAME (list, i); - len = TOK_LEN (list, i); - switch (token) + switch (token->type) { - case CPP_HASH: - /* # is special in function-like macros with no args. - (6.10.3.2 para 1.) However, it is not special after - PASTE. (Implied by 6.10.3.3 para 4.) Nor is it special - if -traditional. */ - if (last_token == PASTE || CPP_TRADITIONAL (pfile)) - break; - last_token = STRIZE; - continue; - - case CPP_PASTE: - /* ## is not special if it appears right after another ##; - nor is it special if -traditional. */ - if (last_token == PASTE || CPP_TRADITIONAL (pfile)) - break; - - if (last_token == START) - cpp_error (pfile, "`##' at start of macro definition"); - else if (last_token == ARG) - /* If the last token was an argument, mark it raw_after. */ - endpat->raw_after = 1; - else if (last_token == STRIZE) - /* Oops - that wasn't a stringify operator. */ - CPP_PUTC (pfile, '#'); - - last_token = PASTE; - continue; - - default:; - } + case CPP_EOF: + cpp_error_with_line (pfile, line, token->col, + "missing ')' in macro parameter list"); + goto out; - if (last_token != PASTE && last_token != START - && TOK_PREV_WHITE (list, i)) - CPP_PUTC (pfile, ' '); - if (last_token == ARG && CPP_TRADITIONAL (pfile) - && !TOK_PREV_WHITE (list, i)) - endpat->raw_after = 1; + case CPP_COMMENT: + continue; /* Ignore -C comments. */ - switch (token) - { - case CPP_STRING: - case CPP_CHAR: - if (argc == 0) - goto norm; - if (CPP_TRADITIONAL (pfile)) + case CPP_NAME: + if (prev_ident) { - last = trad_stringify (pfile, tok, len, argc, argv, - &pat, &endpat, last); - break; + cpp_error_with_line (pfile, line, token->col, + "macro parameters must be comma-separated"); + goto out; } - else + + /* Constraint 6.10.3.5 */ + if (token->val.name.len == sizeof (var_args_str) - 1 + && !ustrncmp (token->val.name.text, var_args_str, + sizeof (var_args_str) - 1)) { - if (CPP_WTRADITIONAL (pfile)) - warn_trad_stringify (pfile, tok, len, argc, argv); - goto norm; + cpp_error_with_line (pfile, line, token->col, + "\"%s\" is not a valid parameter name", + var_args_str); + goto out; } - case CPP_NAME: - for (j = 0; j < argc; j++) - if (argv[j].len == len - && !ustrncmp (tok, argv[j].name, argv[j].len)) - goto addref; + params_len += token->val.name.len + 1; + prev_ident = 1; + list->paramc++; - /* fall through */ - default: - norm: - if (last_token == STRIZE) + /* Constraint 6.10.3.6 - duplicate parameter names. */ + if (find_param (first, token)) { - /* This is a mandatory diagnostic (6.10.3.2 para 1), but - in assembly language # may have some other - significance we don't know about, so suppress the - warning. */ - if (! CPP_OPTION (pfile, lang_asm)) - cpp_pedwarn (pfile, - "# is not followed by a macro argument name"); - if (TOK_PREV_WHITE (list, i)) - CPP_ADJUST_WRITTEN (pfile, -1); - if (TOK_PREV_WHITE (list, i-1)) - CPP_PUTC (pfile, ' '); - CPP_PUTC (pfile, '#'); - if (TOK_PREV_WHITE (list, i)) - CPP_PUTC (pfile, ' '); + cpp_error_with_line (pfile, line, token->col, + "duplicate macro parameter \"%.*s\"", + (int) token->val.name.len, + token->val.name.text); + goto out; } - CPP_PUTS (pfile, tok, len); - last_token = NORM; - } - continue; - - addref: - { - int raw_before = (last_token == PASTE - || (CPP_TRADITIONAL (pfile) - && ! TOK_PREV_WHITE (list, j))); - - add_pat (&pat, &endpat, - CPP_WRITTEN (pfile) - last /* nchars */, j /* argno */, - raw_before, 0 /* raw_after */, - (last_token == STRIZE), argv[j].rest_arg); - - last = CPP_WRITTEN (pfile); - } - last_token = ARG; - } + break; - if (last_token == STRIZE) - cpp_error (pfile, "`#' is not followed by a macro argument name"); - else if (last_token == PASTE) - cpp_error (pfile, "`##' at end of macro definition"); - - CPP_PUTS (pfile, "\r ", 2); - len = CPP_WRITTEN (pfile) - start; - CPP_SET_WRITTEN (pfile, start); - - exp = (U_CHAR *) xmalloc (len + 1); - memcpy (exp, pfile->token_buffer + start, len); - exp[len] = '\0'; - - defn = (struct funct_defn *) xmalloc (sizeof (struct funct_defn)); - defn->length = len; - defn->expansion = exp; - defn->pattern = pat; - defn->rest_args = argc && argv[argc - 1].rest_arg; - defn->nargs = argc; - defn->argnames = arglist->namebuf; - if (argv) - free ((PTR) argv); - return defn; -} + default: + cpp_error_with_line (pfile, line, token->col, + "illegal token in macro parameter list"); + goto out; -/* Is argument NEW, which has just been added to the argument list, - a duplicate of a previous argument name? */ -static int -duplicate_arg_p (args, new) - U_CHAR *args, *new; -{ - size_t newlen = ustrlen (new) + 1; - size_t oldlen; + case CPP_CLOSE_PAREN: + if (prev_ident || list->paramc == 0) + goto scanned; - while (args < new) - { - oldlen = ustrlen (args) + 1; - if (!memcmp (args, new, MIN (oldlen, newlen))) - return 1; - args += oldlen; - } - return 0; -} + /* Fall through to pick up the error. */ + case CPP_COMMA: + if (!prev_ident) + { + cpp_error_with_line (pfile, line, token->col, + "missing parameter name"); + goto out; + } + prev_ident = 0; + break; -static unsigned int -collect_params (pfile, list, arglist) - cpp_reader *pfile; - cpp_toklist *list; - struct arglist *arglist; -{ - struct arg *argv = 0; - const U_CHAR *tok; - U_CHAR *namebuf, *p; - unsigned int len, argslen; - unsigned int argc, a, i, j; - - /* The formal parameters list starts at token 1. */ - if (TOK_TYPE (list, 1) != CPP_OPEN_PAREN) - { - cpp_ice (pfile, "first token = %d not %d in collect_formal_parameters", - TOK_TYPE (list, 1), CPP_OPEN_PAREN); - return 0; - } + case CPP_ELLIPSIS: + /* Convert ISO-style var_args to named varargs by changing + the ellipsis into an identifier with name __VA_ARGS__. + This simplifies other handling. We can safely have its + text outside list->namebuf because there is no reason to + extend the size of the list's namebuf (and thus change + the pointer) in do_define. */ + if (!prev_ident) + { + cpp_token *tok = (cpp_token *) token; - /* Scan once and count the number of parameters; also check for - syntax errors here. */ - argc = 0; - argslen = 0; - for (i = 2; i < list->tokens_used; i++) - switch (TOK_TYPE (list, i)) - { - case CPP_NAME: - argslen += TOK_LEN (list, i) + 1; - argc++; - break; - case CPP_COMMA: - break; - case CPP_CLOSE_PAREN: - goto scanned; - case CPP_VSPACE: - case CPP_EOF: - cpp_ice (pfile, "impossible token in macro argument list"); - return 0; - - default: - cpp_error_with_line (pfile, list->line, TOK_COL (list, i), - "illegal token in macro argument list"); - return 0; - - case CPP_ELLIPSIS: - if (TOK_TYPE (list, i-1) != CPP_NAME) - { - argslen += sizeof "__VA_ARGS__"; - argc++; - } - i++; - if (TOK_TYPE (list, i) != CPP_CLOSE_PAREN) - { - cpp_error_with_line (pfile, list->line, TOK_COL (list, i), - "another parameter follows \"...\""); - return 0; - } - goto scanned; - } - cpp_error_with_line (pfile, list->line, TOK_COL (list, i-1), - "missing right paren in macro argument list"); - return 0; + tok->type = CPP_NAME; + tok->val.name.len = sizeof (var_args_str) - 1; + tok->val.name.text = var_args_str; /* Safe. */ + list->paramc++; - scanned: - if (argc == 0) /* function-like macro, no arguments */ - { - arglist->argc = 0; - arglist->argv = 0; - arglist->namebuf = 0; - return i + 1; - } - if (argslen == 0) - { - cpp_ice (pfile, "collect_params: argc=%d argslen=0", argc); - return 0; + if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) + cpp_pedwarn (pfile, + "C89 does not permit anon varargs macros"); + } + else if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, + "ISO C does not permit named varargs parameters"); + + list->flags |= VAR_ARGS; + token++; + if (token->type == CPP_CLOSE_PAREN) + goto scanned; + cpp_error_with_line (pfile, line, token->col, + "')' expected after \"...\""); + goto out; + } } - /* Now allocate space and copy the suckers. */ - argv = (struct arg *) xmalloc (argc * sizeof (struct arg)); - namebuf = (U_CHAR *) xmalloc (argslen); - p = namebuf; - a = 0; - for (j = 2; j < i; j++) - switch (TOK_TYPE (list, j)) - { - case CPP_NAME: - tok = TOK_NAME (list, j); - len = TOK_LEN (list, j); - memcpy (p, tok, len); - p[len] = '\0'; - if (duplicate_arg_p (namebuf, p)) - { - cpp_error (pfile, "duplicate macro argument name \"%s\"", tok); - a++; - break; - } - if (CPP_PEDANTIC (pfile) && CPP_OPTION (pfile, c99) - && len == sizeof "__VA_ARGS__" - 1 - && !ustrcmp (p, U"__VA_ARGS__")) - cpp_pedwarn (pfile, - "C99 does not permit use of __VA_ARGS__ as a macro argument name"); - argv[a].len = len; - argv[a].name = p; - argv[a].rest_arg = 0; - p += len + 1; - a++; - break; - - case CPP_COMMA: - break; - - case CPP_ELLIPSIS: - if (TOK_TYPE (list, j-1) != CPP_NAME) - { - if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) - cpp_pedwarn (pfile, "C89 does not permit varargs macros"); - - argv[a].len = sizeof "__VA_ARGS__" - 1; - argv[a].name = p; - argv[a].rest_arg = 1; - strcpy ((char *)p, "__VA_ARGS__"); - } - else + scanned: + /* Store the null-terminated parameter spellings of a function, to + provide pedantic warnings to satisfy 6.10.3.2, or for use when + dumping macro definitions. */ + if (list->paramc > 0 && pfile->save_parameter_spellings) + { + U_CHAR *buf; + + _cpp_reserve_name_space (list, params_len); + list->params_len = list->name_used = params_len; + buf = list->namebuf; + for (temp = first; temp <= token; temp++) + if (temp->type == CPP_NAME) { - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, - "ISO C does not permit named varargs macros"); - argv[a-1].rest_arg = 1; + memcpy (buf, temp->val.name.text, temp->val.name.len); + buf += temp->val.name.len; + *buf++ = '\0'; } - break; - - default: - cpp_ice (pfile, "collect_params: impossible token type %d", - TOK_TYPE (list, j)); - } + } - arglist->argc = argc; - arglist->argv = argv; - arglist->namebuf = namebuf; - return i + 1; + out: + return token; } -/* Create a definition for a macro. The replacement text (including - formal parameters if present) is in LIST. If FUNLIKE is true, this - is a function-like macro. */ - -int -_cpp_create_definition (pfile, list, hp) +/* Parses a #define directive. Returns null pointer on error. */ +static cpp_toklist * +parse_define (pfile) cpp_reader *pfile; - cpp_toklist *list; - cpp_hashnode *hp; { - struct funct_defn *fdefn = 0; - struct object_defn *odefn = 0; - enum node_type ntype; - int ok; - - /* Special-case a few simple and common idioms: - #define TOKEN // nothing - #define TOKEN TOKEN - - Might also be good to special-case these: - - #define FUNC() // nothing - #define FUNC(a, b, ...) // nothing - #define FUNC(a, b, c) FUNC(a, b, c) */ - - if (list->tokens_used == 1) - ntype = T_EMPTY; /* Empty definition of object-like macro. */ - else if (list->tokens_used == 2 && TOK_TYPE (list, 1) == CPP_NAME - && TOK_LEN (list, 0) == TOK_LEN (list, 1) - && !ustrncmp (TOK_NAME (list, 0), TOK_NAME (list, 1), - TOK_LEN (list, 0))) - ntype = T_IDENTITY; /* Object like macro defined to itself. */ - - /* The macro is function-like only if the next character, - with no intervening whitespace, is '('. */ - else if (TOK_TYPE (list, 1) == CPP_OPEN_PAREN - && ! TOK_PREV_WHITE (list, 1)) - { - struct arglist args; - int replacement; + const cpp_token *token, *first_param; + cpp_toklist *list; + int prev_white = 0; - replacement = collect_params (pfile, list, &args); - if (replacement == 0) - return 0; - fdefn = collect_funlike_expansion (pfile, list, &args, replacement); - if (fdefn == 0) - return 0; + while ((token = cpp_get_token (pfile))->type == CPP_COMMENT) + prev_white = 1; - ntype = T_FMACRO; - } + /* Allocate the expansion's list. It will go in the hash table. */ + list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist)); + _cpp_init_toklist (list, 0); + first_param = token + 1; + list->paramc = -1; /* Object-like macro. */ - /* Otherwise it is an object-like macro, and C99 requires - whitespace after the name (6.10.3 para 3). */ - else + if (!prev_white && !(token->flags & PREV_WHITE)) { - if (! TOK_PREV_WHITE (list, 1)) - cpp_pedwarn (pfile, - "The C standard requires whitespace after #define %s", - hp->name); - - odefn = collect_objlike_expansion (pfile, list); - if (odefn == 0) - return 0; - - ntype = T_MACRO; - } - - if (ntype == T_EMPTY || ntype == T_IDENTITY) - { - odefn = xmalloc (sizeof (struct object_defn)); - odefn->length = 0; - odefn->expansion = 0; - } - - /* Check for a redefinition, and its legality. Redefining a macro - of whatever stripe is ok if the definitions are the same. - Redefining a built-in _constant_ (T_CONST or T_XCONST) is ok only - with -D. Otherwise a redefinition is not ok. */ - - switch (hp->type) - { - case T_VOID: ok = 1; break; - default: ok = 0; break; - - case T_MACRO: - ok = (ntype == hp->type - && odefn->length == hp->value.odefn->length - && !ustrncmp (odefn->expansion, hp->value.odefn->expansion, - odefn->length)); - break; - case T_FMACRO: - ok = (ntype == hp->type - && !compare_defs (pfile, fdefn, hp->value.fdefn)); - break; - case T_IDENTITY: - case T_EMPTY: - ok = (ntype == hp->type); - break; - case T_CONST: - case T_XCONST: - ok = ! pfile->done_initializing; - break; - } - - /* Print the warning or error if it's not ok. */ - if (! ok) - { - cpp_pedwarn (pfile, "\"%s\" redefined", hp->name); - if (pfile->done_initializing) + if (token->type == CPP_OPEN_PAREN) { - const char *file; - unsigned int line, col; - if (hp->type == T_FMACRO) - { - file = hp->value.fdefn->file; - line = hp->value.fdefn->line; - col = hp->value.fdefn->col; - } - else - { - file = hp->value.odefn->file; - line = hp->value.odefn->line; - col = hp->value.odefn->col; - } - cpp_pedwarn_with_file_and_line (pfile, file, line, col, - "this is the location of the previous definition"); + token = count_params (pfile, first_param, list); + if (token->type != CPP_CLOSE_PAREN) + goto error; + token++; } + else if (token->type != CPP_EOF) + cpp_pedwarn (pfile, + "ISO C requires whitespace after the macro name"); } - /* And replace the old definition (if any). */ - - _cpp_free_definition (hp); - - hp->type = ntype; - if (ntype == T_FMACRO) + if (save_expansion (pfile, list, token, first_param)) { - fdefn->file = CPP_BUFFER (pfile)->nominal_fname; - fdefn->line = list->line; - fdefn->col = TOK_COL (list, 0); - hp->value.fdefn = fdefn; - } - else - { - odefn->file = CPP_BUFFER (pfile)->nominal_fname; - odefn->line = list->line; - odefn->col = TOK_COL (list, 0); - hp->value.odefn = odefn; - } - return 1; -} - -/* - * Parse a macro argument and append the info on PFILE's token_buffer. - * REST_ARGS means to absorb the rest of the args. - * Return nonzero to indicate a syntax error. - */ - -static enum cpp_ttype -macarg (pfile, rest_args) - cpp_reader *pfile; - int rest_args; -{ - int paren = 0; - enum cpp_ttype token; - - /* Try to parse as much of the argument as exists at this - input stack level. */ - for (;;) - { - token = cpp_get_token (pfile); - switch (token) - { - case CPP_EOF: - /* We've hit end of file; this is an error. - Caller will report it. */ - return token; - case CPP_OPEN_PAREN: - paren++; - break; - case CPP_CLOSE_PAREN: - if (--paren < 0) - goto found; - break; - case CPP_COMMA: - /* if we've returned to lowest level and - we aren't absorbing all args */ - if (paren == 0 && rest_args == 0) - goto found; - break; - found: - /* Remove ',' or ')' from argument buffer. */ - CPP_ADJUST_WRITTEN (pfile, -1); - return token; - default:; - } + error: + _cpp_free_toklist (list); + list = 0; } -} - - -static const char * const monthnames[] = -{ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", -}; - -/* Place into PFILE a quoted string representing the string SRC. - Caller must reserve enough space in pfile->token_buffer. */ - -void -_cpp_quote_string (pfile, src) - cpp_reader *pfile; - const U_CHAR *src; -{ - U_CHAR c; - - CPP_PUTC_Q (pfile, '\"'); - for (;;) - switch ((c = *src++)) - { - default: - if (ISPRINT (c)) - CPP_PUTC_Q (pfile, c); - else - { - sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c); - CPP_ADJUST_WRITTEN (pfile, 4); - } - break; - case '\"': - case '\\': - CPP_PUTC_Q (pfile, '\\'); - CPP_PUTC_Q (pfile, c); - break; - - case '\0': - CPP_PUTC_Q (pfile, '\"'); - return; - } + return list; } -/* - * expand things like __FILE__. Place the expansion into the output - * buffer *without* rescanning. - */ - -#define DSC(str) (const U_CHAR *)str, sizeof str - 1 -static void -special_symbol (pfile, hp) - cpp_reader *pfile; - cpp_hashnode *hp; -{ - const U_CHAR *buf; - cpp_buffer *ip; - size_t len; - - switch (hp->type) - { - case T_FILE: - case T_BASE_FILE: - ip = cpp_file_buffer (pfile); - if (ip == NULL) - { - CPP_PUTS (pfile, "\"\"", 2); - return; - } - if (hp->type == T_BASE_FILE) - while (CPP_PREV_BUFFER (ip) != NULL) - ip = CPP_PREV_BUFFER (ip); - - buf = (const U_CHAR *) ip->nominal_fname; - len = ustrlen (buf); - CPP_RESERVE (pfile, 3 + 4 * len); - _cpp_quote_string (pfile, buf); - return; - - case T_INCLUDE_LEVEL: - { - int true_indepth = 0; - ip = cpp_file_buffer (pfile); - while (ip) - { - true_indepth++; - ip = CPP_PREV_BUFFER (ip); - } - - CPP_RESERVE (pfile, 10); - sprintf ((char *)CPP_PWRITTEN (pfile), "%d", true_indepth); - len = ustrlen (CPP_PWRITTEN (pfile)); - CPP_ADJUST_WRITTEN (pfile, len); - return; - } - - case T_STDC: -#ifdef STDC_0_IN_SYSTEM_HEADERS - ip = cpp_file_buffer (pfile); - if (ip && ip->inc->sysp - && !cpp_defined (pfile, DSC("__STRICT_ANSI__"))) - { - CPP_PUTC (pfile, '0'); - return; - } -#endif - constant: - buf = hp->value.cpval; - if (!buf || *buf == '\0') - return; - - len = ustrlen (buf); - CPP_PUTS (pfile, buf, len); - return; - - case T_SPECLINE: - ip = cpp_file_buffer (pfile); - if (ip == NULL) - { - CPP_PUTC (pfile, '0'); - return; - } - CPP_RESERVE (pfile, 10); - sprintf ((char *)CPP_PWRITTEN (pfile), "%u", CPP_BUF_LINE (ip)); - len = ustrlen (CPP_PWRITTEN (pfile)); - CPP_ADJUST_WRITTEN (pfile, len); - return; - - case T_DATE: - case T_TIME: - /* Generate both __DATE__ and __TIME__, stuff them into their - respective hash nodes, and mark the nodes T_XCONST so we - don't have to do this again. We don't generate these strings - at init time because time() and localtime() are very slow on - some systems. */ - { - time_t tt = time (NULL); - struct tm *tb = localtime (&tt); - cpp_hashnode *d, *t; - - if (hp->type == T_DATE) - d = hp, t = cpp_lookup (pfile, DSC("__TIME__")); - else - t = hp, d = cpp_lookup (pfile, DSC("__DATE__")); - - d->value.cpval = xmalloc (sizeof "'Oct 11 1347'"); - sprintf ((char *)d->value.cpval, "\"%s %2d %4d\"", - monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900); - d->type = T_XCONST; - - t->value.cpval = xmalloc (sizeof "'12:34:56'"); - sprintf ((char *)t->value.cpval, "\"%02d:%02d:%02d\"", - tb->tm_hour, tb->tm_min, tb->tm_sec); - t->type = T_XCONST; - goto constant; - } - - case T_POISON: - cpp_error (pfile, "attempt to use poisoned `%s'.", hp->name); - CPP_PUTC (pfile, '0'); - break; - - default: - cpp_ice (pfile, "invalid special hash type"); - return; - } -} -#undef DSC - -/* Expand a macro call. - HP points to the symbol that is the macro being called. - Put the result of expansion onto the input stack - so that subsequent input by our caller will use it. - - If macro wants arguments, caller has already verified that - an argument list follows; arguments come from the input stack. */ - -void -_cpp_macroexpand (pfile, hp) +static int +check_macro_redefinition (pfile, hp, list2) cpp_reader *pfile; cpp_hashnode *hp; + const cpp_toklist *list2; { - const struct funct_defn *defn; - struct argdata *args; - unsigned int old_written; - int i; - - /* Object like macro - most common case. */ - if (hp->type == T_MACRO) - { - push_macro_expansion (pfile, hp->value.odefn->expansion, - hp->value.odefn->length, hp); - return; - } - - /* Or might it be a constant string? */ - if (hp->type == T_CONST || hp->type == T_XCONST) - { - const U_CHAR *cpval = hp->value.cpval; - if (cpval && *cpval != '\0') - push_macro_expansion (pfile, cpval, ustrlen (cpval), hp); - return; - } - - /* Or a special symbol? */ - if (hp->type != T_FMACRO) - { - U_CHAR *xbuf; - unsigned int len; - - old_written = CPP_WRITTEN (pfile); - special_symbol (pfile, hp); - len = CPP_WRITTEN (pfile) - old_written; - CPP_SET_WRITTEN (pfile, old_written); - if (len == 0) - return; - - xbuf = (U_CHAR *) xmalloc (len + 1); - memcpy (xbuf, CPP_PWRITTEN (pfile), len); - xbuf[len] = '\0'; - push_macro_expansion (pfile, xbuf, len, hp); - return; - } - - /* Okay, it's a full-on function-like macro... */ - old_written = CPP_WRITTEN (pfile); - defn = hp->value.fdefn; - - args = alloca (MAX (defn->nargs, 1) * sizeof (struct argdata)); - for (i = 0; i < MAX (defn->nargs, 1); i++) - { - args[i].raw = args[i].expanded = 0; - args[i].raw_length = 0; - args[i].expand_length = args[i].stringified_length = -1; - } + const cpp_toklist *list1; - pfile->output_escapes++; - scan_arguments (pfile, defn, args, hp->name); + if (hp->type != T_MACRO) + return ! pfile->done_initializing; - /* If macro wants zero args, we parsed the arglist for checking only. - Read directly from the macro definition. */ - if (defn->nargs == 0 || defn->pattern == 0) - { - /* If the defn is the empty string, don't bother pushing it. */ - if (defn->length > 4) - push_macro_expansion (pfile, defn->expansion, defn->length, hp); - } - else - funlike_macroexpand (pfile, hp, args); + /* Clear the whitespace and BOL flags of the first tokens. They get + altered during macro expansion, but is not significant here. */ + list1 = hp->value.expansion; + list1->tokens[0].flags &= ~(PREV_WHITE|BOL); + list2->tokens[0].flags &= ~(PREV_WHITE|BOL); - CPP_SET_WRITTEN (pfile, old_written); - pfile->output_escapes--; -} + if (!_cpp_equiv_toklists (list1, list2)) + return 0; -static void -scan_arguments (pfile, defn, args, name) - cpp_reader *pfile; - const struct funct_defn *defn; - struct argdata *args; - const U_CHAR *name; -{ - enum cpp_ttype token; - unsigned int start_line, start_column; - unsigned int nargs = defn->nargs; - unsigned int i; - - cpp_buffer *ip = cpp_file_buffer (pfile); - if (ip) - { - start_line = CPP_BUF_LINE (ip); - start_column = CPP_BUF_COL (ip); - } - else - start_line = start_column = 0; - - /* Parse all the macro args that are supplied. I counts them. The - first NARGS args are stored in ARGS. The rest are discarded. If - rest_args is set then we assume macarg absorbed the rest of the - args. */ - i = 0; - - /* Skip over the opening parenthesis. */ - CPP_OPTION (pfile, discard_comments)++; - pfile->no_macro_expand++; - pfile->no_directives++; - - token = cpp_get_non_space_token (pfile); - if (token != CPP_OPEN_PAREN) - cpp_ice (pfile, "macroexpand: unexpected token %d (wanted LPAREN)", - token); - CPP_ADJUST_WRITTEN (pfile, -1); - - token = CPP_EOF; - do - { - if (i < MAX (nargs, 1)) - { - args[i].raw = CPP_WRITTEN (pfile); - token = macarg (pfile, (i == nargs - 1 && defn->rest_args)); - args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw; - } - else - token = macarg (pfile, 0); - if (token == CPP_EOF) - cpp_error_with_line (pfile, start_line, start_column, - "unterminated macro call"); - i++; - } - while (token == CPP_COMMA); - CPP_OPTION (pfile, discard_comments)--; - pfile->no_macro_expand--; - pfile->no_directives--; - if (token != CPP_CLOSE_PAREN) - return; - - /* foo ( ) is equivalent to foo () unless foo takes exactly one - argument, in which case the former is allowed and the latter - is not. XXX C99 is silent on this rule, but it seems - inconsistent to me. */ - if (i == 1 && nargs == 0) - { - register U_CHAR *bp = ARG_BASE + args[0].raw; - register U_CHAR *lim = bp + args[0].raw_length; - while (bp != lim && is_space(*bp)) - bp++; - if (bp == lim) - i = 0; - } + if (CPP_OPTION (pfile, pedantic) + && list1->paramc > 0 + && (list1->params_len != list2->params_len + || memcmp (list1->namebuf, list2->namebuf, list1->params_len))) + return 0; - /* Don't output an error message if we have already output one for - a parse error above. */ - if (nargs == 0 && i > 0) - { - cpp_error (pfile, "arguments given to macro `%s'", name); - } - else if (i < nargs) - { - /* traditional C allows foo() if foo wants one argument. */ - if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) - ; - /* the rest args token is allowed to absorb 0 tokens */ - else if (i == nargs - 1 && defn->rest_args) - ; - else if (i == 0) - cpp_error (pfile, "macro `%s' used without args", name); - else if (i == 1) - cpp_error (pfile, "macro `%s' used with just one arg", name); - else - cpp_error (pfile, "macro `%s' used with only %d args", name, i); - } - else if (i > nargs) - { - cpp_error (pfile, "macro `%s' used with too many (%d) args", name, i); - } + return 1; } -static void -stringify (pfile, arg) +/* Copy the tokens of the expansion. Change the type of macro + arguments from CPP_NAME to CPP_MACRO_ARG. Remove #'s that + represent stringification, flagging the CPP_MACRO_ARG it operates + on STRINGIFY. Remove ##'s, flagging the token on its immediate + left PASTE_LEFT. Returns non-zero on error. */ +static int +save_expansion (pfile, list, first, first_param) cpp_reader *pfile; - struct argdata *arg; + cpp_toklist *list; + const cpp_token *first; + const cpp_token *first_param; { - int arglen = arg->raw_length; - int escaped = 0; - int in_string = 0; - int c; - int i; - /* Initially need_space is -1. Otherwise, 1 means the previous - character was a space, but we suppressed it; 0 means the previous - character was a non-space. */ - int need_space = -1; - i = 0; - arg->stringified = CPP_WRITTEN (pfile); - CPP_PUTC (pfile, '\"'); /* insert beginning quote */ - for (; i < arglen; i++) + const cpp_token *token; + cpp_token *dest; + unsigned int len, ntokens; + unsigned char *buf; + + /* Count tokens in expansion. We drop paste tokens, and stringize + tokens, so don't count them. */ + ntokens = len = 0; + for (token = first; token->type != CPP_EOF; token++) { - c = (ARG_BASE + arg->raw)[i]; + const char *msg; - if (!in_string) + if (token->type == CPP_PASTE) { - /* Delete "\r " and "\r-" escapes. */ - if (c == '\r') - { - i++; - continue; - } - /* Internal sequences of whitespace are replaced by one - space except within a string or char token. */ - else if (is_space(c)) + /* Token-paste ##, but is a normal token if traditional. */ + if (! CPP_TRADITIONAL (pfile)) { - if (need_space == 0) - need_space = 1; + msg = "\"##\" cannot appear at either end of a macro expansion"; + /* Constraint 6.10.3.3.1 */ + if (token == first || token[1].type == CPP_EOF) + goto error; continue; } - else if (need_space > 0) - CPP_PUTC (pfile, ' '); - need_space = 0; } - - if (escaped) - escaped = 0; - else + else if (token->type == CPP_HASH) { - if (c == '\\') - escaped = 1; - if (in_string) + /* Stringifying #, but is a normal character if traditional, + or in object-like macros. Constraint 6.10.3.2.1. */ + if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile)) { - if (c == in_string) - in_string = 0; + if (token[1].type == CPP_NAME + && find_param (first_param, token + 1)) + continue; + if (! CPP_OPTION (pfile, lang_asm)) + { + msg = "'#' is not followed by a macro parameter"; + error: + cpp_error_with_line (pfile, token->line, token->col, msg); + return 1; + } } - else if (c == '\"' || c == '\'') - in_string = c; - } - - /* Escape these chars */ - if (c == '\"' || (in_string && c == '\\')) - CPP_PUTC (pfile, '\\'); - if (ISPRINT (c)) - CPP_PUTC (pfile, c); - else - { - CPP_RESERVE (pfile, 4); - sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o", (unsigned int) c); - CPP_ADJUST_WRITTEN (pfile, 4); } + ntokens++; + if (token_spellings[token->type].type > SPELL_NONE) + len += token->val.name.len; } - CPP_PUTC (pfile, '\"'); /* insert ending quote */ - arg->stringified_length = CPP_WRITTEN (pfile) - arg->stringified; -} -static void -funlike_macroexpand (pfile, hp, args) - cpp_reader *pfile; - cpp_hashnode *hp; - struct argdata *args; -{ - const struct funct_defn *defn = hp->value.fdefn; - register U_CHAR *xbuf; - int xbuf_len; - const U_CHAR *exp = defn->expansion; - int offset; /* offset in expansion, copied a piece at a time */ - int totlen; /* total amount of exp buffer filled so far */ - const struct reflist *ap, *last_ap; - int i; - - /* Compute length in characters of the macro's expansion. - Also count number of times each arg is used. */ - xbuf_len = defn->length; - for (ap = defn->pattern; ap != NULL; ap = ap->next) - { - if (ap->stringify) - { - /* Stringify if it hasn't already been */ - if (args[ap->argno].stringified_length < 0) - stringify (pfile, &args[ap->argno]); - xbuf_len += args[ap->argno].stringified_length; - } - else if (ap->raw_before || ap->raw_after) - /* Add 4 for two \r-space markers to prevent - token concatenation. */ - xbuf_len += args[ap->argno].raw_length + 4; - else - { - /* We have an ordinary (expanded) occurrence of the arg. - So compute its expansion, if we have not already. */ - if (args[ap->argno].expand_length < 0) - { - args[ap->argno].expanded = CPP_WRITTEN (pfile); - _cpp_expand_to_buffer (pfile, ARG_BASE + args[ap->argno].raw, - args[ap->argno].raw_length); + /* Allocate space to hold the tokens. Empty expansions are stored + as a single placemarker token. */ + if (ntokens == 0) + ntokens++; + _cpp_expand_token_space (list, ntokens); + if (len > 0) + _cpp_expand_name_space (list, len); - args[ap->argno].expand_length - = CPP_WRITTEN (pfile) - args[ap->argno].expanded; - } + dest = list->tokens; + buf = list->namebuf + list->name_used; + for (token = first; token->type != CPP_EOF; token++) + { + unsigned int param_no; - /* Add 4 for two \r-space markers to prevent - token concatenation. */ - xbuf_len += args[ap->argno].expand_length + 4; - } - } + switch (token->type) + { + case CPP_NAME: + if (list->paramc == -1) + break; - xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + /* Check if the name is a macro parameter. */ + param_no = find_param (first_param, token); + if (param_no == 0) + break; + dest->val.aux = param_no - 1; - /* Generate in XBUF the complete expansion with arguments - substituted in. TOTLEN is the total size generated so far. - OFFSET is the index in the definition of where we are copying - from. */ - offset = totlen = 0; - for (last_ap = NULL, ap = defn->pattern; ap != NULL; - last_ap = ap, ap = ap->next) - { - register struct argdata *arg = &args[ap->argno]; - int count_before = totlen; - - /* Add chars to XBUF. */ - i = ap->nchars; - memcpy (&xbuf[totlen], &exp[offset], i); - totlen += i; - offset += i; - - /* If followed by an empty rest arg with concatenation, - delete the last run of nonwhite chars. */ - if (arg->raw_length == 0 && totlen > count_before - && ((ap->rest_args && ap->raw_before) - || (last_ap != NULL && last_ap->rest_args - && last_ap->raw_after))) - { - /* Delete final whitespace. */ - while (totlen > count_before && is_space(xbuf[totlen - 1])) - totlen--; + dest->type = CPP_MACRO_ARG; + if (token[-1].type == CPP_HASH && ! CPP_TRADITIONAL (pfile)) + dest->flags = token[-1].flags | STRINGIFY_ARG; + else + dest->flags = token->flags; /* Particularly PREV_WHITE. */ - /* Delete the nonwhites before them. */ - while (totlen > count_before && !is_space(xbuf[totlen - 1])) - totlen--; - } + if ((int) param_no == list->paramc && list->flags & VAR_ARGS + && dest != list->tokens && dest[-1].flags & PASTE_LEFT) + dest[-1].flags |= GNU_VARARGS; + dest++; + continue; - if (ap->stringify != 0) - { - memcpy (xbuf + totlen, ARG_BASE + arg->stringified, - arg->stringified_length); - totlen += arg->stringified_length; - } - else if (ap->raw_before || ap->raw_after) - { - U_CHAR *p1 = ARG_BASE + arg->raw; - U_CHAR *l1 = p1 + arg->raw_length; - if (ap->raw_before) - { - /* Arg is concatenated before: delete leading whitespace, - whitespace markers, and no-reexpansion markers. */ - while (p1 < l1) - { - if (is_space(p1[0])) - p1++; - else if (p1[0] == '\r') - p1 += 2; - else - break; - } - } - if (ap->raw_after) + case CPP_PASTE: + if (! CPP_TRADITIONAL (pfile)) { - /* Arg is concatenated after: delete trailing whitespace, - whitespace markers, and no-reexpansion markers. */ - while (p1 < l1) - { - if (is_space(l1[-1])) - l1--; - else if (l1[-1] == '\r') - l1--; - else if (l1[-1] == '-') - { - if (l1 != p1 + 1 && l1[-2] == '\r') - l1 -= 2; - else - break; - } - else - break; - } + dest[-1].flags |= PASTE_LEFT; + continue; } + break; - /* Delete any no-reexpansion marker that precedes - an identifier at the beginning of the argument. */ - if (p1 + 2 <= l1 && p1[0] == '\r' && p1[1] == '-') - p1 += 2; + case CPP_HASH: + /* Stringifying #. Constraint 6.10.3.2.1 */ + if (list->paramc >= 0 && ! CPP_TRADITIONAL (pfile) + && token[1].type == CPP_NAME + && find_param (first_param, token + 1)) + continue; + break; - memcpy (xbuf + totlen, p1, l1 - p1); - totlen += l1 - p1; + default: + break; } - else - { - U_CHAR *expanded = ARG_BASE + arg->expanded; - if (!ap->raw_before && totlen > 0 && arg->expand_length - && unsafe_chars (pfile, xbuf[totlen - 1], expanded[0])) - { - xbuf[totlen++] = '\r'; - xbuf[totlen++] = ' '; - } - - memcpy (xbuf + totlen, expanded, arg->expand_length); - totlen += arg->expand_length; - if (!ap->raw_after && totlen > 0 && offset < defn->length - && unsafe_chars (pfile, xbuf[totlen - 1], exp[offset])) - { - xbuf[totlen++] = '\r'; - xbuf[totlen++] = ' '; - } + /* Copy the token. */ + *dest = *token; + if (token_spellings[token->type].type > SPELL_NONE) + { + memcpy (buf, token->val.name.text, token->val.name.len); + dest->val.name.text = buf; + buf += dest->val.name.len; } + dest++; } - /* if there is anything left of the definition - after handling the arg list, copy that in too. */ - - for (i = offset; i < defn->length; i++) - xbuf[totlen++] = exp[i]; - xbuf[totlen] = 0; - - if (totlen > xbuf_len) - /* Just die - we've trashed the heap at this point. */ - abort (); - - /* Now put the expansion on the input stack - so our caller will commence reading from it. */ - push_macro_expansion (pfile, xbuf, totlen, hp); - - /* Overload buffer->mapped to indicate that xbuf needs to be freed. */ - CPP_BUFFER (pfile)->mapped = 1; -} - -/* Return 1 iff a token ending in C1 followed directly by a token C2 - could cause mis-tokenization. */ - -static int -unsafe_chars (pfile, c1, c2) - cpp_reader *pfile; - int c1, c2; -{ - /* If c2 is EOF, that's always safe. */ - if (c2 == EOF) - return 0; - - switch (c1) + if (dest == list->tokens) { - case EOF: - /* We don't know what the previous character was. We do know - that it can't have been an idchar (or else it would have been - pasted with the idchars of the macro name), and there are a - number of second characters for which it doesn't matter what - the first was. */ - if (is_idchar (c2) || c2 == '\'' || c2 == '\"' - || c2 == '(' || c2 == '[' || c2 == '{' - || c2 == ')' || c2 == ']' || c2 == '}') - return 0; - return 1; - - case '+': case '-': - if (c2 == c1 || c2 == '=') - return 1; - goto letter; - - case 'e': case 'E': case 'p': case 'P': - if (c2 == '-' || c2 == '+') - return 1; /* could extend a pre-processing number */ - goto letter; - - case '$': - if (CPP_OPTION (pfile, dollars_in_ident)) - goto letter; - return 0; - - case 'L': - if (c2 == '\'' || c2 == '\"') - return 1; /* Could turn into L"xxx" or L'xxx'. */ - goto letter; - - case '.': case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': case '8': case '9': - case '_': case 'a': case 'b': case 'c': case 'd': case 'f': - case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'q': case 'r': case 's': - case 't': case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': case 'A': case 'B': case 'C': case 'D': case 'F': - case 'G': case 'H': case 'I': case 'J': case 'K': case 'M': - case 'N': case 'O': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - letter: - /* We're in the middle of either a name or a pre-processing number. */ - return (is_idchar(c2) || c2 == '.'); - - case '<': case '>': case '!': case '%': case '#': case ':': - case '^': case '&': case '|': case '*': case '/': case '=': - return (c2 == c1 || c2 == '='); + dest->type = CPP_PLACEMARKER; + dest->flags = 0; } + + list->tokens_used = ntokens; + list->line = pfile->token_list.line; + list->file = pfile->token_list.file; + list->name_used = len; + return 0; } -static void -push_macro_expansion (pfile, xbuf, len, hp) +int +_cpp_create_definition (pfile, hp) cpp_reader *pfile; - const U_CHAR *xbuf; - int len; cpp_hashnode *hp; { - cpp_buffer *mbuf; - int advance_cur = 0; - - /* The first chars of the expansion should be a "\r " added by - collect_expansion. This is to prevent accidental token-pasting - between the text preceding the macro invocation, and the macro - expansion text. - - We would like to avoid adding unneeded spaces (for the sake of - tools that use cpp, such as imake). In some common cases we can - tell that it is safe to omit the space. */ - - if (xbuf[0] == '\r' && xbuf[1] == ' ' - && !unsafe_chars (pfile, EOF, xbuf[2])) - advance_cur = 1; - - /* Likewise, avoid the extra space at the end of the macro expansion - if this is safe. We can do a better job here since we can know - what the next char will be. */ - if (len >= 3 && xbuf[len-2] == '\r' && xbuf[len-1] == ' ' - && !unsafe_chars (pfile, xbuf[len-3], CPP_BUF_PEEK (CPP_BUFFER (pfile)))) - len -= 2; - - /* If the total expansion is "\r \r ", we must not trim both escapes. */ - if (len == 2 && advance_cur) - advance_cur = 0; - - mbuf = cpp_push_buffer (pfile, xbuf, len); - if (mbuf == NULL) - return; - if (advance_cur) - mbuf->cur += 2; - mbuf->macro = hp; - mbuf->has_escapes = 1; - - /* In C89, a macro cannot be expanded recursively. Traditional C - permits it, but any use in an object-like macro must lead to - infinite recursion, so always follow C89 in object-like macros. - Likewise, in a function-like macro it must cause infinite - recursion unless we are actually doing something with the - arguments. - - Even that criterion is too weak. The only example known where - macro recursion isn't infinite is: - #define bar(x,y) foo(x(y, 0)) - bar(bar, baz) - which expands to foo(bar(baz, 0)) in C89 and - foo(foo(baz(0, 0)) in K+R. This looks pathological to me. - If someone has a real-world example I would love to see it. */ - if (hp->type != T_FMACRO - || hp->value.fdefn->nargs == 0 - || hp->value.fdefn->pattern == 0 - || !CPP_TRADITIONAL (pfile)) - hp->disabled = 1; -} + cpp_toklist *list; -/* Return zero if two funct_defns are isomorphic. */ + list = parse_define (pfile); + if (!list) + return 0; -static int -compare_defs (pfile, d1, d2) - cpp_reader *pfile; - const struct funct_defn *d1, *d2; -{ - const struct reflist *a1, *a2; - - if (d1->nargs != d2->nargs) - return 1; - if (ustrcmp (d1->expansion, d2->expansion)) - return 1; - if (CPP_PEDANTIC (pfile) - && d1->argnames && d2->argnames) + /* Check for a redefinition. Redefinition of a macro is allowed if + and only if the old and new definitions are the same. + (6.10.3 paragraph 2). */ + + if (hp->type != T_VOID) { - U_CHAR *arg1 = d1->argnames; - U_CHAR *arg2 = d2->argnames; - size_t len; - int i = d1->nargs; - while (i--) + if (!check_macro_redefinition (pfile, hp, list)) { - len = ustrlen (arg1) + 1; - if (ustrcmp (arg1, arg2)) - return 1; - arg1 += len; - arg2 += len; + cpp_pedwarn (pfile, "\"%s\" redefined", hp->name); + if (pfile->done_initializing && hp->type == T_MACRO) + cpp_pedwarn_with_file_and_line (pfile, + hp->value.expansion->file, + hp->value.expansion->line, 1, + "this is the location of the previous definition"); } + _cpp_free_definition (hp); } - for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; - a1 = a1->next, a2 = a2->next) - { - if (a1->nchars != a2->nchars - || a1->argno != a2->argno - || a1->stringify != a2->stringify - || a1->raw_before != a2->raw_before - || a1->raw_after != a2->raw_after) - return 1; - } - if (a1 != a2) - return 1; - return 0; + /* Enter definition in hash table. */ + hp->type = T_MACRO; + hp->value.expansion = list; + + return 1; } /* Dump the definition of macro MACRO on stdout. The format is suitable @@ -1846,97 +610,56 @@ _cpp_dump_definition (pfile, hp) CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1); CPP_PUTS_Q (pfile, hp->name, hp->length); - if (hp->type == T_EMPTY) - /* do nothing */; - else if (hp->type == T_FMACRO) - dump_funlike_macro (pfile, hp->value.fdefn); - else + if (hp->type == T_MACRO) { - CPP_PUTC_Q (pfile, ' '); - - if (hp->type == T_IDENTITY) - CPP_PUTS (pfile, hp->name, hp->length); - else if (hp->type == T_MACRO) + if (hp->value.expansion->paramc >= 0) + dump_funlike_macro (pfile, hp); + else { - /* The first and last two characters of a macro expansion are - always "\r "; this needs to be trimmed out. - So we need length-4 chars of space, plus one for the NUL. */ - CPP_RESERVE (pfile, hp->value.odefn->length - 4 + 1); - CPP_PUTS_Q (pfile, hp->value.odefn->expansion + 2, - hp->value.odefn->length - 4); + const cpp_toklist *list = hp->value.expansion; + list->tokens[0].flags &= ~BOL; + list->tokens[0].flags |= PREV_WHITE; + _cpp_dump_list (pfile, list, list->tokens, 1); } - else - cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type); } + else + cpp_ice (pfile, "invalid hash type %d in dump_definition", hp->type); + if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing) CPP_PUTC (pfile, '\n'); } static void -dump_funlike_macro (pfile, defn) +dump_funlike_macro (pfile, node) cpp_reader *pfile; - const struct funct_defn *defn; + cpp_hashnode *node; { - const struct reflist *r; - const U_CHAR **argv = (const U_CHAR **) alloca (defn->nargs * - sizeof(const U_CHAR *)); - int *argl = (int *) alloca (defn->nargs * sizeof(int)); - const U_CHAR *x; - int i; - - /* First extract the argument list. */ - x = defn->argnames; - for (i = 0; i < defn->nargs; i++) - { - argv[i] = x; - argl[i] = ustrlen (x); - x += argl[i] + 1; - } - - /* Now print out the argument list. */ + int i = 0; + const cpp_toklist * list = node->value.expansion; + const U_CHAR *param; + + param = list->namebuf; CPP_PUTC_Q (pfile, '('); - for (i = 0; i < defn->nargs; i++) + for (i = 0; i++ < list->paramc;) { - CPP_RESERVE (pfile, argl[i] + 2); - if (!(i == defn->nargs-1 && defn->rest_args - && !ustrcmp (argv[i], U"__VA_ARGS__"))) - CPP_PUTS_Q (pfile, argv[i], argl[i]); - if (i < defn->nargs-1) - CPP_PUTS_Q (pfile, ", ", 2); - } - if (defn->rest_args) - CPP_PUTS (pfile, "...", 3); - CPP_PUTS (pfile, ") ", 2); + unsigned int len; - /* Now the definition. */ - x = defn->expansion; - for (r = defn->pattern; r; r = r->next) - { - i = r->nchars; - if (*x == '\r') x += 2, i -= 2; - /* i chars for macro text, plus the length of the macro - argument name, plus one for a stringify marker, plus two for - each concatenation marker. */ - CPP_RESERVE (pfile, - i + argl[r->argno] + r->stringify - + (r->raw_before + r->raw_after) * 2); - - if (i > 0) CPP_PUTS_Q (pfile, x, i); - if (r->raw_before) - CPP_PUTS_Q (pfile, "##", 2); - if (r->stringify) - CPP_PUTC_Q (pfile, '#'); - CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]); - if (r->raw_after && !(r->next && r->next->nchars == 0 - && r->next->raw_before)) - CPP_PUTS_Q (pfile, "##", 2); - - x += i; + len = ustrlen (param); + CPP_PUTS (pfile, param, len); + if (i < list->paramc) + CPP_PUTS(pfile, ", ", 2); + else if (list->flags & VAR_ARGS) + { + if (!ustrcmp (param, var_args_str)) + pfile->limit -= sizeof (var_args_str) - 1; + CPP_PUTS (pfile, "...", 3); + } + param += len + 1; } - - i = defn->length - (x - defn->expansion) - 2; - if (*x == '\r') x += 2, i -= 2; - if (i > 0) CPP_PUTS (pfile, x, i); + CPP_PUTC (pfile, ')'); + list->tokens[0].flags &= ~BOL; + list->tokens[0].flags |= PREV_WHITE; + _cpp_dump_list (pfile, list, list->tokens, 1); } /* Dump out the hash table. */ @@ -1948,8 +671,7 @@ dump_hash_helper (h, p) cpp_hashnode *hp = (cpp_hashnode *)*h; cpp_reader *pfile = (cpp_reader *)p; - if (hp->type == T_MACRO || hp->type == T_FMACRO - || hp->type == T_IDENTITY || hp->type == T_EMPTY) + if (hp->type == T_MACRO) _cpp_dump_definition (pfile, hp); return 1; } diff --git a/gcc/cpphash.h b/gcc/cpphash.h index ec9204a..f7c130b 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -25,11 +25,60 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ typedef unsigned char U_CHAR; #define U (const U_CHAR *) /* Intended use: U"string" */ -/* Structure used for assertion predicates. */ -struct predicate +/* Order here matters. Those beyond SPELL_NONE store their spelling + in the token list, and it's length in the token->val.name.len. */ +enum spell_type { - struct predicate *next; - struct cpp_toklist answer; + SPELL_OPERATOR = 0, + SPELL_CHAR, + SPELL_NONE, + SPELL_IDENT, + SPELL_STRING +}; + +struct token_spelling +{ + ENUM_BITFIELD(spell_type) type : CHAR_BIT; + const U_CHAR *spelling; +}; + +extern const struct token_spelling token_spellings[]; + +/* Chained list of answers to an assertion. */ +struct answer +{ + struct answer *next; + cpp_toklist list; +}; +#define FREE_ANSWER(answer) do {_cpp_free_toklist (&answer->list); \ + free (answer); } while (0) + +/* Values for the origin field of struct directive. KANDR directives + come from traditional (K&R) C. STDC89 directives come from the + 1989 C standard. EXTENSION directives are extensions. */ +#define KANDR 0 +#define STDC89 1 +#define EXTENSION 2 + +/* Values for the flags field of struct directive. COND indicates a + conditional. EXPAND means that macros are to be expanded on the + directive line. INCL means to treat "..." and <...> as + q-char-sequence and h-char-sequence respectively. COMMENTS means + preserve comments in the directive if -C. */ +#define COND (1 << 0) +#define EXPAND (1 << 1) +#define INCL (1 << 2) +#define COMMENTS (1 << 3) + +/* Defines one #-directive, including how to handle it. */ +typedef int (*directive_handler) PARAMS ((cpp_reader *)); +struct directive +{ + directive_handler handler; /* Function to handle directive. */ + const U_CHAR *name; /* Name of directive. */ + unsigned short length; /* Length of name. */ + unsigned char origin; /* Origin of directive. */ + unsigned char flags; /* Flags describing this directive. */ }; /* List of directories to look for include files in. */ @@ -105,12 +154,6 @@ extern unsigned char _cpp_IStable[256]; /* Macros. */ -/* One character lookahead in the input buffer. Note that if this - returns EOF, it does *not* necessarily mean the file's end has been - reached. */ -#define CPP_BUF_PEEK(BUFFER) \ - ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur : EOF) - /* Make sure PFILE->token_buffer has space for at least N more characters. */ #define CPP_RESERVE(PFILE, N) \ (CPP_WRITTEN (PFILE) + (size_t)(N) > (PFILE)->token_buffer_size \ @@ -127,53 +170,15 @@ extern unsigned char _cpp_IStable[256]; /* Append character CH to PFILE's output buffer. Make space if need be. */ #define CPP_PUTC(PFILE, CH) (CPP_RESERVE (PFILE, 1), CPP_PUTC_Q (PFILE, CH)) -/* Advance the current line by one. */ -#define CPP_BUMP_BUFFER_LINE(PBUF) ((PBUF)->lineno++,\ - (PBUF)->line_base = (PBUF)->cur) -#define CPP_BUMP_LINE(PFILE) CPP_BUMP_BUFFER_LINE(CPP_BUFFER(PFILE)) -#define CPP_BUMP_BUFFER_LINE_CUR(PBUF, CUR) ((PBUF)->lineno++,\ - (PBUF)->line_base = CUR) -#define CPP_BUMP_LINE_CUR(PFILE, CUR) \ - CPP_BUMP_BUFFER_LINE_CUR(CPP_BUFFER(PFILE), CUR) #define CPP_PREV_BUFFER(BUFFER) ((BUFFER)->prev) - -/* Are we in column 1 right now? Used mainly for -traditional handling - of directives. */ -#define CPP_IN_COLUMN_1(PFILE) \ -(CPP_BUFFER (PFILE)->cur - CPP_BUFFER (PFILE)->line_base == 1) - #define CPP_PRINT_DEPS(PFILE) CPP_OPTION (PFILE, print_deps) #define CPP_TRADITIONAL(PFILE) CPP_OPTION (PFILE, traditional) -#define CPP_IN_SYSTEM_HEADER(PFILE) (cpp_file_buffer (PFILE)->inc->sysp) +#define CPP_IN_SYSTEM_HEADER(PFILE) (CPP_BUFFER (PFILE)->inc->sysp) #define CPP_PEDANTIC(PF) \ (CPP_OPTION (PF, pedantic) && !CPP_IN_SYSTEM_HEADER (PF)) #define CPP_WTRADITIONAL(PF) \ (CPP_OPTION (PF, warn_traditional) && !CPP_IN_SYSTEM_HEADER (PF)) -/* CPP_IS_MACRO_BUFFER is true if the buffer contains macro expansion. - (Note that it is false while we're expanding macro *arguments*.) */ -#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->macro != NULL) - -/* Remember the current position of PFILE so it may be returned to - after looking ahead a bit. - - Note that when you set a mark, you _must_ return to that mark. You - may not forget about it and continue parsing. You may not pop a - buffer with an active mark. You may not call CPP_BUMP_LINE while a - mark is active. */ -#define CPP_SET_BUF_MARK(IP) ((IP)->mark = (IP)->cur) -#define CPP_GOTO_BUF_MARK(IP) ((IP)->cur = (IP)->mark, (IP)->mark = 0) -#define CPP_SET_MARK(PFILE) CPP_SET_BUF_MARK(CPP_BUFFER(PFILE)) -#define CPP_GOTO_MARK(PFILE) CPP_GOTO_BUF_MARK(CPP_BUFFER(PFILE)) - -/* ACTIVE_MARK_P is true if there's a live mark in the buffer. */ -#define ACTIVE_MARK_P(PFILE) (CPP_BUFFER (PFILE)->mark != 0) - -/* Are mark and point adjacent characters? Used mostly to deal with - the somewhat annoying semantic of #define. */ -#define ADJACENT_TO_MARK(PFILE) \ - (CPP_BUFFER(PFILE)->cur - CPP_BUFFER(PFILE)->mark == 1) - /* Flags for _cpp_init_toklist. */ #define DUMMY_TOKEN 0 #define NO_DUMMY_TOKEN 1 @@ -181,22 +186,19 @@ extern unsigned char _cpp_IStable[256]; /* In cpphash.c */ extern unsigned int _cpp_calc_hash PARAMS ((const U_CHAR *, size_t)); extern void _cpp_free_definition PARAMS ((cpp_hashnode *)); -extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_toklist *, - cpp_hashnode *)); +extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *)); extern void _cpp_dump_definition PARAMS ((cpp_reader *, cpp_hashnode *)); -extern void _cpp_quote_string PARAMS ((cpp_reader *, const U_CHAR *)); -extern void _cpp_macroexpand PARAMS ((cpp_reader *, cpp_hashnode *)); extern void _cpp_init_macro_hash PARAMS ((cpp_reader *)); extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *)); /* In cppfiles.c */ extern void _cpp_simplify_pathname PARAMS ((char *)); -extern void _cpp_execute_include PARAMS ((cpp_reader *, U_CHAR *, +extern void _cpp_execute_include PARAMS ((cpp_reader *, const U_CHAR *, unsigned int, int, - struct file_name_list *)); -extern int _cpp_compare_file_date PARAMS ((cpp_reader *, U_CHAR *, - unsigned int, - struct file_name_list *)); + struct file_name_list *, + int)); +extern int _cpp_compare_file_date PARAMS ((cpp_reader *, const U_CHAR *, + unsigned int, int)); extern void _cpp_init_include_table PARAMS ((cpp_reader *)); extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *)); @@ -204,40 +206,46 @@ extern const char *_cpp_fake_include PARAMS ((cpp_reader *, const char *)); extern int _cpp_parse_expr PARAMS ((cpp_reader *)); /* In cpplex.c */ -extern void _cpp_parse_name PARAMS ((cpp_reader *, int)); extern void _cpp_skip_rest_of_line PARAMS ((cpp_reader *)); -extern void _cpp_skip_hspace PARAMS ((cpp_reader *)); -extern void _cpp_expand_to_buffer PARAMS ((cpp_reader *, - const unsigned char *, int)); -extern int _cpp_parse_assertion PARAMS ((cpp_reader *)); -extern enum cpp_ttype _cpp_lex_token PARAMS ((cpp_reader *)); -extern ssize_t _cpp_prescan PARAMS ((cpp_reader *, cpp_buffer *, - ssize_t)); +extern void _cpp_free_temp_tokens PARAMS ((cpp_reader *)); extern void _cpp_init_input_buffer PARAMS ((cpp_reader *)); extern void _cpp_grow_token_buffer PARAMS ((cpp_reader *, long)); extern enum cpp_ttype _cpp_get_directive_token PARAMS ((cpp_reader *)); -extern enum cpp_ttype _cpp_get_define_token - PARAMS ((cpp_reader *)); -extern enum cpp_ttype _cpp_scan_until PARAMS ((cpp_reader *, cpp_toklist *, - enum cpp_ttype)); extern void _cpp_init_toklist PARAMS ((cpp_toklist *, int)); extern void _cpp_clear_toklist PARAMS ((cpp_toklist *)); -extern void _cpp_free_toklist PARAMS ((cpp_toklist *)); -extern void _cpp_slice_toklist PARAMS ((cpp_toklist *, - const cpp_token *, - const cpp_token *)); -extern void _cpp_squeeze_toklist PARAMS ((cpp_toklist *)); +extern void _cpp_free_toklist PARAMS ((const cpp_toklist *)); extern int _cpp_equiv_tokens PARAMS ((const cpp_token *, const cpp_token *)); extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *, const cpp_toklist *)); extern void _cpp_expand_token_space PARAMS ((cpp_toklist *, unsigned int)); +extern void _cpp_reserve_name_space PARAMS ((cpp_toklist *, unsigned int)); +extern void _cpp_expand_name_space PARAMS ((cpp_toklist *, unsigned int)); +extern void _cpp_dump_list PARAMS ((cpp_reader *, + const cpp_toklist *, + const cpp_token *, int)); +extern int _cpp_equiv_tokens PARAMS ((const cpp_token *, + const cpp_token *)); +extern void _cpp_run_directive PARAMS ((cpp_reader *, + const struct directive *, + const char *, size_t)); +extern unsigned int _cpp_get_line PARAMS ((cpp_reader *, + unsigned int *)); +extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *)); +extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*)); +extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *)); /* In cpplib.c */ -extern int _cpp_handle_directive PARAMS ((cpp_reader *)); +extern const struct directive *_cpp_check_directive + PARAMS ((cpp_reader *, const cpp_token *, int)); +extern const struct directive *_cpp_check_linemarker + PARAMS ((cpp_reader *, const cpp_token *, int)); extern void _cpp_unwind_if_stack PARAMS ((cpp_reader *, cpp_buffer *)); -extern void _cpp_check_directive PARAMS ((cpp_toklist *, cpp_token *)); +extern cpp_hashnode * _cpp_parse_assertion PARAMS ((cpp_reader *, + struct answer **)); +extern struct answer** find_answer PARAMS ((cpp_hashnode *, + const cpp_toklist *)); /* Utility routines and macros. */ #define xnew(T) (T *) xmalloc (sizeof(T)) diff --git a/gcc/cppinit.c b/gcc/cppinit.c index 320dfdb..f50bcc1f 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -215,8 +215,6 @@ static void append_include_chain PARAMS ((cpp_reader *, char *, int, int)); static void merge_include_chains PARAMS ((cpp_reader *)); -static void dump_special_to_buffer PARAMS ((cpp_reader *, const U_CHAR *, - size_t)); static void initialize_dependency_output PARAMS ((cpp_reader *)); static void initialize_standard_includes PARAMS ((cpp_reader *)); static void new_pending_directive PARAMS ((struct cpp_pending *, @@ -345,7 +343,7 @@ append_include_chain (pfile, pend, dir, path, cxx_aware) if (errno != ENOENT) cpp_notice_from_errno (pfile, dir); else if (CPP_OPTION (pfile, verbose)) - fprintf (stderr, _("ignoring nonexistent directory `%s'\n"), dir); + fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir); return; } @@ -442,7 +440,7 @@ merge_include_chains (pfile) && cur->dev == other->dev) { if (CPP_OPTION (pfile, verbose)) - fprintf (stderr, _("ignoring duplicate directory `%s'\n"), + fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name); prev->next = cur->next; @@ -462,7 +460,7 @@ merge_include_chains (pfile) && cur->dev == other->dev) { if (CPP_OPTION (pfile, verbose)) - fprintf (stderr, _("ignoring duplicate directory `%s'\n"), + fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name); prev->next = cur->next; @@ -481,7 +479,7 @@ merge_include_chains (pfile) if (quote == qtail) { if (CPP_OPTION (pfile, verbose)) - fprintf (stderr, _("ignoring duplicate directory `%s'\n"), + fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), quote->name); free (quote->name); @@ -495,7 +493,7 @@ merge_include_chains (pfile) cur = cur->next; cur->next = brack; if (CPP_OPTION (pfile, verbose)) - fprintf (stderr, _("ignoring duplicate directory `%s'\n"), + fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), qtail->name); free (qtail->name); @@ -513,24 +511,6 @@ merge_include_chains (pfile) } -/* Write out a #define command for the special named MACRO_NAME - to PFILE's token_buffer. */ - -static void -dump_special_to_buffer (pfile, macro_name, macro_len) - cpp_reader *pfile; - const U_CHAR *macro_name; - size_t macro_len; -{ - static const char define_directive[] = "#define "; - CPP_RESERVE (pfile, sizeof(define_directive) + macro_len); - CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1); - CPP_PUTS_Q (pfile, macro_name, macro_len); - CPP_PUTC_Q (pfile, ' '); - _cpp_expand_to_buffer (pfile, macro_name, macro_len); - CPP_PUTC (pfile, '\n'); -} - /* Initialize a cpp_reader structure. */ void cpp_reader_init (pfile) @@ -545,6 +525,7 @@ cpp_reader_init (pfile) CPP_OPTION (pfile, dollars_in_ident) = 1; CPP_OPTION (pfile, cplusplus_comments) = 1; CPP_OPTION (pfile, warn_import) = 1; + CPP_OPTION (pfile, warn_paste) = 1; CPP_OPTION (pfile, discard_comments) = 1; CPP_OPTION (pfile, show_column) = 1; CPP_OPTION (pfile, tabstop) = 8; @@ -596,25 +577,19 @@ cpp_cleanup (pfile) pfile->token_buffer = NULL; } - if (pfile->input_buffer) - { - free (pfile->input_buffer); - pfile->input_buffer = NULL; - pfile->input_buffer_len = 0; - } - if (pfile->deps) deps_free (pfile->deps); htab_delete (pfile->hashtab); splay_tree_delete (pfile->all_include_files); + _cpp_free_temp_tokens (pfile); } /* This structure defines one built-in macro. A node of type TYPE will be entered in the macro hash table under the name NAME, with value - VALUE (if any). FLAGS tweaks the behavior a little: - DUMP write debug info for this macro + VALUE (if any). Two values are not compile time constants, so we tag + them in the FLAGS field instead: VERS value is the global version_string, quoted ULP value is the global user_label_prefix */ @@ -622,18 +597,17 @@ cpp_cleanup (pfile) struct builtin { const U_CHAR *name; - const U_CHAR *value; + const char *value; unsigned short type; unsigned short flags; unsigned int len; }; -#define DUMP 0x01 -#define VERS 0x02 -#define ULP 0x04 +#define VERS 0x01 +#define ULP 0x02 -#define B(n, t) { U n, 0, t, 0, sizeof n - 1 } -#define C(n, v) { U n, U v, T_CONST, DUMP, sizeof n - 1 } -#define X(n, v, t, f) { U n, U v, t, DUMP|f, sizeof n - 1 } +#define B(n, t) { U n, 0, t, 0, sizeof n - 1 } +#define C(n, v) { U n, v, T_MACRO, 0, sizeof n - 1 } +#define X(n, f) { U n, 0, T_MACRO, f, sizeof n - 1 } static const struct builtin builtin_array[] = { B("__TIME__", T_TIME), @@ -642,10 +616,10 @@ static const struct builtin builtin_array[] = B("__BASE_FILE__", T_BASE_FILE), B("__LINE__", T_SPECLINE), B("__INCLUDE_LEVEL__", T_INCLUDE_LEVEL), + B("__STDC__", T_STDC), - X("__VERSION__", 0, T_XCONST, VERS), - X("__USER_LABEL_PREFIX__", 0, T_CONST, ULP), - X("__STDC__", "1", T_STDC, 0), + X("__VERSION__", VERS), + X("__USER_LABEL_PREFIX__", ULP), C("__REGISTER_PREFIX__", REGISTER_PREFIX), C("__HAVE_BUILTIN_SETJMP__", "1"), #ifndef NO_BUILTIN_SIZE_TYPE @@ -671,35 +645,47 @@ initialize_builtins (pfile) cpp_reader *pfile; { const struct builtin *b; - const U_CHAR *val; - cpp_hashnode *hp; for(b = builtin_array; b < builtin_array_end; b++) { - if (b->type == T_STDC && CPP_TRADITIONAL (pfile)) - continue; - - if (b->flags & ULP) - val = (const U_CHAR *) user_label_prefix; - else if (b->flags & VERS) + if (b->type == T_MACRO) { - val = (const U_CHAR *) xmalloc (strlen (version_string) + 3); - sprintf ((char *)val, "\"%s\"", version_string); + const char *val; + char *str; + + if (b->flags & VERS) + { + /* Allocate enough space for 'name="value"\0'. */ + str = xmalloc (b->len + strlen (version_string) + 4); + sprintf (str, "%s=\"%s\"", b->name, version_string); + } + else + { + if (b->flags & ULP) + val = user_label_prefix; + else + val = b->value; + + /* Allocate enough space for "name=value\0". */ + str = xmalloc (b->len + strlen (val) + 2); + sprintf(str, "%s=%s", b->name, val); + } + cpp_define (pfile, str); } else - val = b->value; - - hp = cpp_lookup (pfile, b->name, b->len); - hp->value.cpval = val; - hp->type = b->type; + { + cpp_hashnode *hp; + + if (b->type == T_STDC && CPP_TRADITIONAL (pfile)) + continue; - if ((b->flags & DUMP) && CPP_OPTION (pfile, debug_output)) - dump_special_to_buffer (pfile, b->name, b->len); + hp = cpp_lookup (pfile, b->name, b->len); + hp->type = b->type; + } } } -#undef DUMP -#undef STDC #undef VERS #undef ULP +#undef builtin_array_end /* Another subroutine of cpp_start_read. This one sets up to do dependency-file output. */ @@ -889,6 +875,13 @@ cpp_start_read (pfile, print, fname) if (CPP_OPTION (pfile, cplusplus)) CPP_OPTION (pfile, warn_traditional) = 0; + /* Do not warn about illegal token pasting if -traditional, + -lang-fortran, or -lang-asm. */ + if (CPP_OPTION (pfile, traditional) + || CPP_OPTION (pfile, lang_fortran) + || CPP_OPTION (pfile, lang_asm)) + CPP_OPTION (pfile, warn_paste) = 0; + /* Set this if it hasn't been set already. */ if (user_label_prefix == NULL) user_label_prefix = USER_LABEL_PREFIX; @@ -898,6 +891,16 @@ cpp_start_read (pfile, print, fname) if (CPP_OPTION (pfile, preprocessed)) pfile->no_macro_expand++; + /* Figure out if we need to save function macro parameter spellings. + We don't use CPP_PEDANTIC() here because that depends on whether + or not the current file is a system header, and there is no + current file yet. */ + pfile->save_parameter_spellings = + CPP_OPTION (pfile, pedantic) + || CPP_OPTION (pfile, debug_output) + || CPP_OPTION (pfile, dump_macros) == dump_definitions + || CPP_OPTION (pfile, dump_macros) == dump_only; + /* Set up the IStable. This doesn't do anything if we were compiled with a compiler that supports C99 designated initializers. */ init_IStable (); @@ -946,13 +949,12 @@ cpp_start_read (pfile, print, fname) as line 0. */ CPP_BUFFER (pfile)->lineno = 0; - if (print) { - print->lineno = 0; print->last_fname = CPP_BUFFER (pfile)->nominal_fname; print->last_id = pfile->include_depth; print->written = CPP_WRITTEN (pfile); + print->lineno = 0; } /* Install __LINE__, etc. */ @@ -968,10 +970,13 @@ cpp_start_read (pfile, print, fname) p = q; } pfile->done_initializing = 1; - pfile->only_seen_white = 2; + + /* Now flush any output recorded during initialization, and advance + to line 1 of the main input file. */ CPP_BUFFER (pfile)->lineno = 1; + if (print && ! CPP_OPTION (pfile, no_output)) - cpp_output_tokens (pfile, print); + cpp_output_tokens (pfile, print, 1); /* The -imacros files can be scanned now, but the -include files have to be pushed onto the include stack and processed later, @@ -992,7 +997,7 @@ cpp_start_read (pfile, print, fname) { if (cpp_read_file (pfile, p->arg) && print && ! CPP_OPTION (pfile, no_output)) - cpp_output_tokens (pfile, print); + cpp_output_tokens (pfile, print, 1); /* record entry to file */ q = p->next; free (p); p = q; @@ -1073,7 +1078,7 @@ cpp_finish (pfile, print) /* Flush any pending output. */ if (print) { - cpp_output_tokens (pfile, print); + cpp_output_tokens (pfile, print, print->lineno); if (ferror (print->outf) || fclose (print->outf)) cpp_notice_from_errno (pfile, CPP_OPTION (pfile, out_fname)); } @@ -1753,6 +1758,8 @@ handle_option (pfile, argc, argv) CPP_OPTION (pfile, warn_undef) = 1; else if (!strcmp (argv[i], "-Wimport")) CPP_OPTION (pfile, warn_import) = 1; + else if (!strcmp (argv[i], "-Wpaste")) + CPP_OPTION (pfile, warn_paste) = 1; else if (!strcmp (argv[i], "-Werror")) CPP_OPTION (pfile, warnings_are_errors) = 1; else if (!strcmp (argv[i], "-Wno-traditional")) @@ -1767,6 +1774,8 @@ handle_option (pfile, argc, argv) CPP_OPTION (pfile, warn_undef) = 0; else if (!strcmp (argv[i], "-Wno-import")) CPP_OPTION (pfile, warn_import) = 0; + else if (!strcmp (argv[i], "-Wno-paste")) + CPP_OPTION (pfile, warn_paste) = 0; else if (!strcmp (argv[i], "-Wno-error")) CPP_OPTION (pfile, warnings_are_errors) = 0; break; @@ -1836,10 +1845,10 @@ Switches:\n\ (dirs specified with -isystem will still be used)\n\ -nostdinc++ Do not search system include directories for C++\n\ -o <file> Put output into <file>\n\ - -pedantic Issue all warnings demanded by strict ANSI C\n\ + -pedantic Issue all warnings demanded by strict ISO C\n\ -pedantic-errors Issue -pedantic warnings as errors instead\n\ -traditional Follow K&R pre-processor behaviour\n\ - -trigraphs Support ANSI C trigraphs\n\ + -trigraphs Support ISO C trigraphs\n\ -lang-c Assume that the input sources are in C\n\ -lang-c89 Assume that the input sources are in C89\n\ -lang-c++ Assume that the input sources are in C++\n\ diff --git a/gcc/cpplex.c b/gcc/cpplex.c index 109e97e..a45336d 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -20,100 +20,128 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + +Cleanups to do:- + +o Fix ISTABLE to flag the parts we want for IS_HSPACE and IS_NEWLINE. +o Get use of digraphs in sync with the standard reqd on the command line. +o -dM and with _cpp_dump_list: too many \n output. +o Put a printer object in cpp_reader? +o Check line numbers assigned to all errors. +o Replace strncmp with memcmp almost everywhere. +o lex_line's use of cur_token, flags and list->token_used is a bit opaque. +o Get rid of cpp_get_directive_token. +o Convert do_ functions to return void. Kaveh thinks its OK; and said he'll + give it a run when we've got some code. +o _cpp_parse_expr updated to new lexer. +o Distinguish integers, floats, and 'other' pp-numbers. +o Store ints and char constants as binary values. +o New command-line assertion syntax. +o Merge hash table text pointer and token list text pointer for identifiers. +o Have _cpp_parse_expr use all the information the new lexer provides. +o Work towards functions in cpperror.c taking a message level parameter. + If we do this, merge the common code of do_warning and do_error. +o Comment all functions, and describe macro expansion algorithm. +o Move as much out of header files as possible. +o Remove single quote pairs `', and some '', from diagnostics. +o Correct pastability test for CPP_NAME and CPP_NUMBER. + +*/ + #include "config.h" #include "system.h" #include "intl.h" #include "cpplib.h" #include "cpphash.h" +#include "symcat.h" #ifdef HAVE_MMAP_FILE # include <sys/mman.h> #endif -#define PEEKBUF(BUFFER, N) \ - ((BUFFER)->rlimit - (BUFFER)->cur > (N) ? (BUFFER)->cur[N] : EOF) -#define GETBUF(BUFFER) \ - ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF) -#define FORWARDBUF(BUFFER, N) ((BUFFER)->cur += (N)) - -#define PEEKN(N) PEEKBUF (CPP_BUFFER (pfile), N) -#define FORWARD(N) FORWARDBUF (CPP_BUFFER (pfile), (N)) -#define GETC() GETBUF (CPP_BUFFER (pfile)) -#define PEEKC() PEEKBUF (CPP_BUFFER (pfile), 0) - -static void skip_block_comment PARAMS ((cpp_reader *)); -static void skip_line_comment PARAMS ((cpp_reader *)); -static int maybe_macroexpand PARAMS ((cpp_reader *, long)); -static int skip_comment PARAMS ((cpp_reader *, int)); -static int copy_comment PARAMS ((cpp_reader *, int)); -static void skip_string PARAMS ((cpp_reader *, int)); -static void parse_string PARAMS ((cpp_reader *, int)); -static U_CHAR *find_position PARAMS ((U_CHAR *, U_CHAR *, unsigned long *)); -static void null_warning PARAMS ((cpp_reader *, unsigned int)); - +#define auto_expand_name_space(list) \ + _cpp_expand_name_space ((list), 1 + (list)->name_cap / 2) static void safe_fwrite PARAMS ((cpp_reader *, const U_CHAR *, size_t, FILE *)); -static void output_line_command PARAMS ((cpp_reader *, cpp_printer *, - unsigned int)); -static void bump_column PARAMS ((cpp_printer *, unsigned int, +static void dump_param_spelling PARAMS ((cpp_reader *, const cpp_toklist *, unsigned int)); -static void expand_name_space PARAMS ((cpp_toklist *, unsigned int)); -static void pedantic_whitespace PARAMS ((cpp_reader *, U_CHAR *, +static void output_line_command PARAMS ((cpp_reader *, cpp_printer *, unsigned int)); -#define auto_expand_name_space(list) \ - expand_name_space ((list), 1 + (list)->name_cap / 2) - -#ifdef NEW_LEXER - -void init_trigraph_map PARAMS ((void)); -static unsigned char* trigraph_replace PARAMS ((cpp_reader *, unsigned char *, +static void process_directive PARAMS ((cpp_reader *, const cpp_token *)); +static unsigned char *trigraph_replace PARAMS ((cpp_reader *, unsigned char *, unsigned char *)); static const unsigned char *backslash_start PARAMS ((cpp_reader *, const unsigned char *)); -static int skip_block_comment2 PARAMS ((cpp_reader *)); -static int skip_line_comment2 PARAMS ((cpp_reader *)); +static int skip_block_comment PARAMS ((cpp_reader *)); +static int skip_line_comment PARAMS ((cpp_reader *)); static void skip_whitespace PARAMS ((cpp_reader *, int)); static void parse_name PARAMS ((cpp_reader *, cpp_toklist *, cpp_name *)); static void parse_number PARAMS ((cpp_reader *, cpp_toklist *, cpp_name *)); -static void parse_string2 PARAMS ((cpp_reader *, cpp_toklist *, cpp_name *, - unsigned int, int)); +static void parse_string PARAMS ((cpp_reader *, cpp_toklist *, cpp_token *, + unsigned int)); static int trigraph_ok PARAMS ((cpp_reader *, const unsigned char *)); static void save_comment PARAMS ((cpp_toklist *, cpp_token *, const unsigned char *, unsigned int, unsigned int)); -void _cpp_lex_line PARAMS ((cpp_reader *, cpp_toklist *)); - -static void _cpp_output_list PARAMS ((cpp_reader *, cpp_toklist *)); +static void lex_line PARAMS ((cpp_reader *, cpp_toklist *)); +static int lex_next PARAMS ((cpp_reader *, int)); +static int is_macro_disabled PARAMS ((cpp_reader *, const cpp_toklist *, + const cpp_token *)); +static cpp_token *stringify_arg PARAMS ((cpp_reader *, const cpp_token *)); +static void expand_context_stack PARAMS ((cpp_reader *)); static unsigned char * spell_token PARAMS ((cpp_reader *, const cpp_token *, - unsigned char *, int)); - + unsigned char *)); +static void output_token PARAMS ((cpp_reader *, const cpp_token *, + const cpp_token *)); typedef unsigned int (* speller) PARAMS ((unsigned char *, cpp_toklist *, cpp_token *)); +static cpp_token *make_string_token PARAMS ((cpp_token *, const U_CHAR *, + unsigned int)); +static cpp_token *alloc_number_token PARAMS ((cpp_reader *, int number)); +static const cpp_token *special_symbol PARAMS ((cpp_reader *, cpp_hashnode *, + const cpp_token *)); +static cpp_token *duplicate_token PARAMS ((cpp_reader *, const cpp_token *)); +static const cpp_token *maybe_paste_with_next PARAMS ((cpp_reader *, + const cpp_token *)); +static enum cpp_ttype can_paste PARAMS ((cpp_reader *, const cpp_token *, + const cpp_token *, int *)); +static unsigned int prevent_macro_expansion PARAMS ((cpp_reader *)); +static void restore_macro_expansion PARAMS ((cpp_reader *, unsigned int)); +static cpp_token *get_temp_token PARAMS ((cpp_reader *)); +static void release_temp_tokens PARAMS ((cpp_reader *)); +static U_CHAR * quote_string PARAMS ((U_CHAR *, const U_CHAR *, unsigned int)); +static void process_directive PARAMS ((cpp_reader *, const cpp_token *)); -/* Macros on a cpp_name. */ #define INIT_TOKEN_NAME(list, token) \ do {(token)->val.name.len = 0; \ (token)->val.name.text = (list)->namebuf + (list)->name_used; \ - (list)->tokens_used = token - (list)->tokens + 1; \ } while (0) +#define VALID_SIGN(c, prevc) \ + (((c) == '+' || (c) == '-') && \ + ((prevc) == 'e' || (prevc) == 'E' \ + || (((prevc) == 'p' || (prevc) == 'P') && !CPP_OPTION (pfile, c89)))) + /* Maybe put these in the ISTABLE eventually. */ #define IS_HSPACE(c) ((c) == ' ' || (c) == '\t') #define IS_NEWLINE(c) ((c) == '\n' || (c) == '\r') /* Handle LF, CR, CR-LF and LF-CR style newlines. Assumes next character, if any, is in buffer. */ + #define handle_newline(cur, limit, c) \ - do {\ + do { \ if ((cur) < (limit) && *(cur) == '\r' + '\n' - c) \ (cur)++; \ - CPP_BUMP_LINE_CUR (pfile, (cur)); \ + pfile->buffer->lineno++; \ + pfile->buffer->line_base = (cur); \ pfile->col_adjust = 0; \ - } while (0) + } while (0) -#define IMMED_TOKEN() (!(cur_token->flags & PREV_WHITESPACE)) +#define IMMED_TOKEN() (!(cur_token->flags & PREV_WHITE)) #define PREV_TOKEN_TYPE (cur_token[-1].type) #define PUSH_TOKEN(ttype) cur_token++->type = ttype @@ -127,30 +155,29 @@ typedef unsigned int (* speller) PARAMS ((unsigned char *, cpp_toklist *, #define TOKEN_LEN(token) (5 + (token_spellings[(token)->type].type > \ SPELL_NONE ? (token)->val.name.len: 0)) -#endif - -/* Order here matters. Those beyond SPELL_NONE store their spelling - in the token list, and it's length in the token->val.name.len. */ -enum spell_type -{ - SPELL_OPERATOR = 0, - SPELL_NONE, - SPELL_CHAR, /* FIXME: revert order of NONE and CHAR after transition. */ - SPELL_IDENT, - SPELL_STRING -}; - #define T(e, s) {SPELL_OPERATOR, (const U_CHAR *) s}, #define I(e, s) {SPELL_IDENT, s}, #define S(e, s) {SPELL_STRING, s}, #define C(e, s) {SPELL_CHAR, s}, #define N(e, s) {SPELL_NONE, s}, -static const struct token_spelling -{ - ENUM_BITFIELD(spell_type) type : CHAR_BIT; - const U_CHAR *spelling; -} token_spellings [N_TTYPES + 1] = {TTYPE_TABLE {0, 0} }; +const struct token_spelling +token_spellings [N_TTYPES + 1] = {TTYPE_TABLE {0, 0} }; + +#undef T +#undef I +#undef S +#undef C +#undef N + +/* For debugging: the internal names of the tokens. */ +#define T(e, s) STRINGX(e), +#define I(e, s) STRINGX(e), +#define S(e, s) STRINGX(e), +#define C(e, s) STRINGX(e), +#define N(e, s) STRINGX(e), + +const char * const token_names[N_TTYPES] = { TTYPE_TABLE }; #undef T #undef I @@ -158,6 +185,34 @@ static const struct token_spelling #undef C #undef N +/* The following table is used by trigraph_ok/trigraph_replace. If we + have designated initializers, it can be constant data; otherwise, + it is set up at runtime by _cpp_init_input_buffer. */ + +#if (GCC_VERSION >= 2007) +#define init_trigraph_map() /* nothing */ +#define TRIGRAPH_MAP \ +__extension__ static const U_CHAR trigraph_map[UCHAR_MAX + 1] = { +#define END }; +#define s(p, v) [p] = v, +#else +#define TRIGRAPH_MAP static U_CHAR trigraph_map[UCHAR_MAX + 1] = { 0 }; \ + static void init_trigraph_map PARAMS ((void)) { \ + unsigned char *x = trigraph_map; +#define END } +#define s(p, v) x[p] = v; +#endif + +TRIGRAPH_MAP + s('=', '#') s(')', ']') s('!', '|') + s('(', '[') s('\'', '^') s('>', '}') + s('/', '\\') s('<', '{') s('-', '~') +END + +#undef TRIGRAPH_MAP +#undef END +#undef s + /* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */ void @@ -187,7 +242,7 @@ cpp_push_buffer (pfile, buffer, length) cpp_buffer *new; if (++pfile->buffer_stack_depth == CPP_STACK_MAX) { - cpp_fatal (pfile, "macro or `#include' recursion too deep"); + cpp_fatal (pfile, "macro or #include recursion too deep"); return NULL; } @@ -196,7 +251,6 @@ cpp_push_buffer (pfile, buffer, length) new->buf = new->cur = buffer; new->rlimit = buffer + length; new->prev = buf; - new->mark = NULL; new->line_base = NULL; CPP_BUFFER (pfile) = new; @@ -208,14 +262,19 @@ cpp_pop_buffer (pfile) cpp_reader *pfile; { cpp_buffer *buf = CPP_BUFFER (pfile); - if (ACTIVE_MARK_P (pfile)) - cpp_ice (pfile, "mark active in cpp_pop_buffer"); if (buf->inc) { _cpp_unwind_if_stack (pfile, buf); if (buf->buf) - free ((PTR) buf->buf); + { +#ifdef HAVE_MMAP_FILE + if (buf->mapped) + munmap ((caddr_t) buf->buf, buf->rlimit - buf->buf); + else +#endif + free ((PTR) buf->buf); + } if (pfile->system_include_depth) pfile->system_include_depth--; if (pfile->include_depth) @@ -234,17 +293,6 @@ cpp_pop_buffer (pfile) buf->inc->fd = -1; } } - else if (buf->macro) - { - cpp_hashnode *m = buf->macro; - - m->disabled = 0; - if ((m->type == T_FMACRO && buf->mapped) - || m->type == T_SPECLINE || m->type == T_FILE - || m->type == T_BASE_FILE || m->type == T_INCLUDE_LEVEL - || m->type == T_STDC) - free ((PTR) buf->buf); - } CPP_BUFFER (pfile) = CPP_PREV_BUFFER (buf); free (buf); pfile->buffer_stack_depth--; @@ -284,13 +332,26 @@ output_line_command (pfile, print, line) cpp_printer *print; unsigned int line; { - cpp_buffer *ip = cpp_file_buffer (pfile); + cpp_buffer *ip = CPP_BUFFER (pfile); enum { same = 0, enter, leave, rname } change; static const char * const codes[] = { "", " 1", " 2", "" }; + if (line == 0) + return; + + /* End the previous line of text. */ + if (pfile->need_newline) + putc ('\n', print->outf); + pfile->need_newline = 0; + if (CPP_OPTION (pfile, no_line_commands)) return; + /* If ip is null, we've been called from cpp_finish, and they just + needed the final flush and trailing newline. */ + if (!ip) + return; + if (pfile->include_depth == print->last_id) { /* Determine whether the current filename has changed, and if so, @@ -316,7 +377,7 @@ output_line_command (pfile, print, line) We cannot do this if print->lineno is zero, because that means we haven't output any line commands yet. (The very first line command output is a `same_file' command.) */ - if (change == same && print->lineno != 0 + if (change == same && print->lineno > 0 && line >= print->lineno && line < print->lineno + 8) { while (line > print->lineno) @@ -346,129 +407,22 @@ output_line_command (pfile, print, line) keeping track of file transitions. */ void -cpp_output_tokens (pfile, print) +cpp_output_tokens (pfile, print, line) cpp_reader *pfile; cpp_printer *print; + unsigned int line; { - cpp_buffer *ip; - if (CPP_WRITTEN (pfile) - print->written) { - if (CPP_PWRITTEN (pfile)[-1] == '\n' && print->lineno) - print->lineno++; safe_fwrite (pfile, pfile->token_buffer, CPP_WRITTEN (pfile) - print->written, print->outf); - } - - ip = cpp_file_buffer (pfile); - if (ip) - output_line_command (pfile, print, CPP_BUF_LINE (ip)); - - CPP_SET_WRITTEN (pfile, print->written); -} - -/* Helper for cpp_output_list - increases the column number to match - what we expect it to be. */ - -static void -bump_column (print, from, to) - cpp_printer *print; - unsigned int from, to; -{ - unsigned int tabs, spcs; - unsigned int delta = to - from; - - /* Only if FROM is 0, advance by tabs. */ - if (from == 0) - tabs = delta / 8, spcs = delta % 8; - else - tabs = 0, spcs = delta; - - while (tabs--) putc ('\t', print->outf); - while (spcs--) putc (' ', print->outf); -} - -/* Write out the list L onto pfile->token_buffer. This function is - incomplete: - - 1) pfile->token_buffer is not going to continue to exist. - 2) At the moment, tokens don't carry the information described - in cpplib.h; they are all strings. - 3) The list has to be a complete line, and has to be written starting - at the beginning of a line. */ - -void -cpp_output_list (pfile, print, list) - cpp_reader *pfile; - cpp_printer *print; - const cpp_toklist *list; -{ - unsigned int i; - unsigned int curcol = 1; - - /* XXX Probably does not do what is intended. */ - if (print->lineno != list->line) - output_line_command (pfile, print, list->line); - - for (i = 0; i < list->tokens_used; i++) - { - if (TOK_TYPE (list, i) == CPP_VSPACE) - { - output_line_command (pfile, print, list->tokens[i].aux); - continue; - } - - if (curcol < TOK_COL (list, i)) - { - /* Insert space to bring the column to what it should be. */ - bump_column (print, curcol - 1, TOK_COL (list, i)); - curcol = TOK_COL (list, i); - } - /* XXX We may have to insert space to prevent an accidental - token paste. */ - safe_fwrite (pfile, TOK_NAME (list, i), TOK_LEN (list, i), print->outf); - curcol += TOK_LEN (list, i); - } -} - -/* Scan a string (which may have escape marks), perform macro expansion, - and write the result to the token_buffer. */ - -void -_cpp_expand_to_buffer (pfile, buf, length) - cpp_reader *pfile; - const U_CHAR *buf; - int length; -{ - cpp_buffer *stop; - enum cpp_ttype token; - U_CHAR *buf1; - - if (length < 0) - { - cpp_ice (pfile, "length < 0 in cpp_expand_to_buffer"); - return; - } - - /* Copy the buffer, because it might be in an unsafe place - for - example, a sequence on the token_buffer, where the pointers will - be invalidated if we enlarge the token_buffer. */ - buf1 = alloca (length); - memcpy (buf1, buf, length); - - /* Set up the input on the input stack. */ - stop = CPP_BUFFER (pfile); - if (cpp_push_buffer (pfile, buf1, length) == NULL) - return; - CPP_BUFFER (pfile)->has_escapes = 1; + pfile->need_newline = 1; + if (print->lineno) + print->lineno++; - /* Scan the input, create the output. */ - for (;;) - { - token = cpp_get_token (pfile); - if (token == CPP_EOF && CPP_BUFFER (pfile) == stop) - break; + CPP_SET_WRITTEN (pfile, print->written); } + output_line_command (pfile, print, line); } /* Scan until CPP_BUFFER (PFILE) is exhausted, discarding output. */ @@ -477,17 +431,20 @@ void cpp_scan_buffer_nooutput (pfile) cpp_reader *pfile; { - cpp_buffer *stop = CPP_PREV_BUFFER (CPP_BUFFER (pfile)); - enum cpp_ttype token; unsigned int old_written = CPP_WRITTEN (pfile); - /* In no-output mode, we can ignore everything but directives. */ + cpp_buffer *stop = CPP_PREV_BUFFER (CPP_BUFFER (pfile)); + for (;;) { - if (! pfile->only_seen_white) - _cpp_skip_rest_of_line (pfile); - token = cpp_get_token (pfile); - if (token == CPP_EOF && CPP_BUFFER (pfile) == stop) - break; + /* In no-output mode, we can ignore everything but directives. */ + const cpp_token *token = cpp_get_token (pfile); + if (token->type == CPP_EOF) + { + cpp_pop_buffer (pfile); + if (CPP_BUFFER (pfile) == stop) + break; + } + _cpp_skip_rest_of_line (pfile); } CPP_SET_WRITTEN (pfile, old_written); } @@ -500,43 +457,79 @@ cpp_scan_buffer (pfile, print) cpp_printer *print; { cpp_buffer *stop = CPP_PREV_BUFFER (CPP_BUFFER (pfile)); - enum cpp_ttype token; + const cpp_token *token, *prev = 0; for (;;) { token = cpp_get_token (pfile); - if (token == CPP_VSPACE || token == CPP_EOF - /* XXX Temporary kluge - force flush after #include only */ - || (token == CPP_DIRECTIVE - && CPP_BUFFER (pfile)->nominal_fname != print->last_fname)) + if (token->type == CPP_EOF) { - cpp_output_tokens (pfile, print); - if (token == CPP_EOF && CPP_BUFFER (pfile) == stop) + cpp_pop_buffer (pfile); + if (CPP_BUFFER (pfile) == stop) return; + cpp_output_tokens (pfile, print, CPP_BUF_LINE (CPP_BUFFER (pfile))); + prev = 0; + continue; } + + if (token->flags & BOL) + { + cpp_output_tokens (pfile, print, pfile->token_list.line); + prev = 0; + } + + output_token (pfile, token, prev); + prev = token; } } -/* Return the topmost cpp_buffer that corresponds to a file (not a macro). */ - -cpp_buffer * -cpp_file_buffer (pfile) +/* Helper routine used by parse_include, which can't see spell_token. + Reinterpret the current line as an h-char-sequence (< ... >); we are + looking at the first token after the <. */ +const cpp_token * +_cpp_glue_header_name (pfile) cpp_reader *pfile; { - cpp_buffer *ip; + unsigned int written = CPP_WRITTEN (pfile); + const cpp_token *t; + cpp_token *hdr; + U_CHAR *buf; + size_t len; + + for (;;) + { + t = cpp_get_token (pfile); + if (t->type == CPP_GREATER || t->type == CPP_EOF) + break; + + CPP_RESERVE (pfile, TOKEN_LEN (t)); + if (t->flags & PREV_WHITE) + CPP_PUTC_Q (pfile, ' '); + pfile->limit = spell_token (pfile, t, pfile->limit); + } + + if (t->type == CPP_EOF) + cpp_error (pfile, "missing terminating > character"); - for (ip = CPP_BUFFER (pfile); ip; ip = CPP_PREV_BUFFER (ip)) - if (ip->inc != NULL) - return ip; - return NULL; + len = CPP_WRITTEN (pfile) - written; + buf = xmalloc (len); + memcpy (buf, pfile->token_buffer + written, len); + CPP_SET_WRITTEN (pfile, written); + + hdr = get_temp_token (pfile); + hdr->type = CPP_HEADER_NAME; + hdr->flags = 0; + hdr->val.name.text = buf; + hdr->val.name.len = len; + return hdr; } /* Token-buffer helper functions. */ /* Expand a token list's string space. It is *vital* that list->tokens_used is correct, to get pointer fix-up right. */ -static void -expand_name_space (list, len) +void +_cpp_expand_name_space (list, len) cpp_toklist *list; unsigned int len; { @@ -557,6 +550,19 @@ expand_name_space (list, len) } } +/* If there is not enough room for LEN more characters, expand the + list by just enough to have room for LEN characters. */ +void +_cpp_reserve_name_space (list, len) + cpp_toklist *list; + unsigned int len; +{ + unsigned int room = list->name_cap - list->name_used; + + if (room < len) + _cpp_expand_name_space (list, len - room); +} + /* Expand the number of tokens in a list. */ void _cpp_expand_token_space (list, count) @@ -585,13 +591,12 @@ _cpp_init_toklist (list, flags) cpp_toklist *list; int flags; { - /* We malloc zero bytes because we may want to realloc later, and - some old implementations don't like realloc-ing a null pointer. */ if (flags == NO_DUMMY_TOKEN) { list->tokens_cap = 0; - list->tokens = (cpp_token *) malloc (0); + list->tokens = 0; list->name_cap = 0; + list->namebuf = 0; list->flags = 0; } else @@ -606,12 +611,10 @@ _cpp_init_toklist (list, flags) /* Initialize name space. */ list->name_cap = 1024; + list->namebuf = (unsigned char *) xmalloc (list->name_cap); list->flags = LIST_OFFSET; } - /* Allocate name space. */ - list->namebuf = (unsigned char *) xmalloc (list->name_cap); - _cpp_clear_toklist (list); } @@ -622,7 +625,9 @@ _cpp_clear_toklist (list) { list->tokens_used = 0; list->name_used = 0; - list->dirno = -1; + list->directive = 0; + list->paramc = 0; + list->params_len = 0; list->flags &= LIST_OFFSET; /* clear all but that one */ } @@ -630,7 +635,7 @@ _cpp_clear_toklist (list) embedded in a larger structure. */ void _cpp_free_toklist (list) - cpp_toklist *list; + const cpp_toklist *list; { if (list->flags & LIST_OFFSET) free (list->tokens - 1); /* Backup over dummy token. */ @@ -639,104 +644,28 @@ _cpp_free_toklist (list) free (list->namebuf); } -/* Slice a token list: copy the sublist [START, FINISH) into COPY. - COPY is assumed not to be initialized. The comment space is not - copied. */ -void -_cpp_slice_toklist (copy, start, finish) - cpp_toklist *copy; - const cpp_token *start, *finish; -{ - unsigned int i, n; - size_t bytes; - - n = finish - start; - copy->tokens_cap = n; - copy->tokens = (cpp_token *) xmalloc (n * sizeof (cpp_token)); - memcpy (copy->tokens, start, n * sizeof (cpp_token)); - - bytes = 0; - for (i = 0; i < n; i++) - if (token_spellings[start[i].type].type > SPELL_NONE) - bytes += start[i].val.name.len; - - copy->namebuf = xmalloc (bytes); - bytes = 0; - for (i = 0; i < n; i++) - if (token_spellings[start[i].type].type > SPELL_NONE) - { - memcpy (copy->namebuf + bytes, - start[i].val.name.text, start[i].val.name.len); - copy->tokens[i].val.name.text = copy->namebuf + bytes; - bytes += start[i].val.name.len; - } - - copy->tokens_cap = n; - copy->tokens_used = n; - copy->name_used = bytes; - copy->name_cap = bytes; - - copy->flags = 0; - copy->dirno = -1; -} - -/* Shrink a token list down to the minimum size. */ -void -_cpp_squeeze_toklist (list) - cpp_toklist *list; -{ - long delta; - const U_CHAR *old_namebuf; - - if (list->flags & LIST_OFFSET) - { - list->tokens--; - memmove (list->tokens, list->tokens + 1, - list->tokens_used * sizeof (cpp_token)); - list->tokens = xrealloc (list->tokens, - list->tokens_used * sizeof (cpp_token)); - list->flags &= ~LIST_OFFSET; - } - else - list->tokens = xrealloc (list->tokens, - list->tokens_used * sizeof (cpp_token)); - list->tokens_cap = list->tokens_used; - - old_namebuf = list->namebuf; - list->namebuf = xrealloc (list->namebuf, list->name_used); - list->name_cap = list->name_used; - - /* Fix up token text pointers. */ - delta = list->namebuf - old_namebuf; - if (delta) - { - unsigned int i; - - for (i = 0; i < list->tokens_used; i++) - if (token_spellings[list->tokens[i].type].type > SPELL_NONE) - list->tokens[i].val.name.text += delta; - } -} - /* Compare two tokens. */ int _cpp_equiv_tokens (a, b) const cpp_token *a, *b; { - if (a->type != b->type - || a->flags != b->flags - || a->aux != b->aux) - return 0; + if (a->type == b->type && a->flags == b->flags) + switch (token_spellings[a->type].type) + { + default: /* Keep compiler happy. */ + case SPELL_OPERATOR: + return 1; + case SPELL_CHAR: + case SPELL_NONE: + return a->val.aux == b->val.aux; /* arg_no or character. */ + case SPELL_IDENT: + case SPELL_STRING: + return (a->val.name.len == b->val.name.len + && !memcmp (a->val.name.text, b->val.name.text, + a->val.name.len)); + } - if (token_spellings[a->type].type > SPELL_NONE) - { - if (a->val.name.len != b->val.name.len - || ustrncmp(a->val.name.text, - b->val.name.text, - a->val.name.len)) - return 0; - } - return 1; + return 0; } /* Compare two token lists. */ @@ -746,7 +675,9 @@ _cpp_equiv_toklists (a, b) { unsigned int i; - if (a->tokens_used != b->tokens_used) + if (a->tokens_used != b->tokens_used + || a->flags != b->flags + || a->paramc != b->paramc) return 0; for (i = 0; i < a->tokens_used; i++) @@ -755,1425 +686,6 @@ _cpp_equiv_toklists (a, b) return 1; } -/* Scan until we encounter a token of type STOP or a newline, and - create a token list for it. Does not macro-expand or execute - directives. The final token is not included in the list or - consumed from the input. Returns the type of the token stopped at. */ - -enum cpp_ttype -_cpp_scan_until (pfile, list, stop) - cpp_reader *pfile; - cpp_toklist *list; - enum cpp_ttype stop; -{ - int i, col; - long written, len; - enum cpp_ttype type; - int space_before; - - _cpp_clear_toklist (list); - list->line = CPP_BUF_LINE (CPP_BUFFER (pfile)); - - written = CPP_WRITTEN (pfile); - i = 0; - space_before = 0; - for (;;) - { - col = CPP_BUFFER (pfile)->cur - CPP_BUFFER (pfile)->line_base; - type = _cpp_lex_token (pfile); - len = CPP_WRITTEN (pfile) - written; - CPP_SET_WRITTEN (pfile, written); - if (type == CPP_HSPACE) - { - if (CPP_PEDANTIC (pfile)) - pedantic_whitespace (pfile, pfile->token_buffer + written, len); - space_before = 1; - continue; - } - else if (type == CPP_COMMENT) - /* Only happens when processing -traditional macro definitions. - Do not give this a token entry, but do not change space_before - either. */ - continue; - - if (list->tokens_used >= list->tokens_cap) - _cpp_expand_token_space (list, 256); - if (list->name_used + len >= list->name_cap) - expand_name_space (list, list->name_used + len + 1 - list->name_cap); - - if (type == CPP_MACRO) - type = CPP_NAME; - - if (type == CPP_VSPACE || type == stop) - break; - - list->tokens_used++; - TOK_TYPE (list, i) = type; - TOK_COL (list, i) = col; - TOK_AUX (list, i) = 0; - TOK_FLAGS (list, i) = space_before ? PREV_WHITESPACE : 0; - - TOK_LEN (list, i) = len; - if (token_spellings[type].type > SPELL_NONE) - { - memcpy (list->namebuf + list->name_used, CPP_PWRITTEN (pfile), len); - TOK_NAME (list, i) = list->namebuf + list->name_used; - list->name_used += len; - } - else - TOK_NAME (list, i) = token_spellings[type].spelling; - i++; - space_before = 0; - } - - /* XXX Temporary kluge: put back the newline (or whatever). */ - FORWARD(-1); - - /* Don't consider the first token to have white before. */ - TOK_FLAGS (list, 0) &= ~PREV_WHITESPACE; - return type; -} - -/* Skip a C-style block comment. We know it's a comment, and point is - at the second character of the starter. */ -static void -skip_block_comment (pfile) - cpp_reader *pfile; -{ - unsigned int line, col; - const U_CHAR *limit, *cur; - - FORWARD(1); - line = CPP_BUF_LINE (CPP_BUFFER (pfile)); - col = CPP_BUF_COL (CPP_BUFFER (pfile)); - limit = CPP_BUFFER (pfile)->rlimit; - cur = CPP_BUFFER (pfile)->cur; - - while (cur < limit) - { - char c = *cur++; - if (c == '\n' || c == '\r') - { - /* \r cannot be a macro escape marker here. */ - if (!ACTIVE_MARK_P (pfile)) - CPP_BUMP_LINE_CUR (pfile, cur); - } - else if (c == '*') - { - /* Check for teminator. */ - if (cur < limit && *cur == '/') - goto out; - - /* Warn about comment starter embedded in comment. */ - if (cur[-2] == '/' && CPP_OPTION (pfile, warn_comments)) - cpp_warning_with_line (pfile, CPP_BUFFER (pfile)->lineno, - cur - CPP_BUFFER (pfile)->line_base, - "'/*' within comment"); - } - } - - cpp_error_with_line (pfile, line, col, "unterminated comment"); - cur--; - out: - CPP_BUFFER (pfile)->cur = cur + 1; -} - -/* Skip a C++/Chill line comment. We know it's a comment, and point - is at the second character of the initiator. */ -static void -skip_line_comment (pfile) - cpp_reader *pfile; -{ - FORWARD(1); - for (;;) - { - int c = GETC (); - - /* We don't have to worry about EOF in here. */ - if (c == '\n') - { - /* Don't consider final '\n' to be part of comment. */ - FORWARD(-1); - return; - } - else if (c == '\r') - { - /* \r cannot be a macro escape marker here. */ - if (!ACTIVE_MARK_P (pfile)) - CPP_BUMP_LINE (pfile); - if (CPP_OPTION (pfile, warn_comments)) - cpp_warning (pfile, "backslash-newline within line comment"); - } - } -} - -/* Skip a comment - C, C++, or Chill style. M is the first character - of the comment marker. If this really is a comment, skip to its - end and return ' '. If this is not a comment, return M (which will - be '/' or '-'). */ - -static int -skip_comment (pfile, m) - cpp_reader *pfile; - int m; -{ - if (m == '/' && PEEKC() == '*') - { - skip_block_comment (pfile); - return ' '; - } - else if (m == '/' && PEEKC() == '/') - { - if (CPP_IN_SYSTEM_HEADER (pfile)) - { - /* We silently allow C++ comments in system headers, irrespective - of conformance mode, because lots of busted systems do that - and trying to clean it up in fixincludes is a nightmare. */ - skip_line_comment (pfile); - return ' '; - } - else if (CPP_OPTION (pfile, cplusplus_comments)) - { - if (! CPP_BUFFER (pfile)->warned_cplusplus_comments) - { - if (CPP_WTRADITIONAL (pfile)) - cpp_pedwarn (pfile, - "C++ style comments are not allowed in traditional C"); - else if (CPP_OPTION (pfile, c89) && CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, - "C++ style comments are not allowed in ISO C89"); - if (CPP_WTRADITIONAL (pfile) - || (CPP_OPTION (pfile, c89) && CPP_PEDANTIC (pfile))) - cpp_pedwarn (pfile, - "(this will be reported only once per input file)"); - CPP_BUFFER (pfile)->warned_cplusplus_comments = 1; - } - skip_line_comment (pfile); - return ' '; - } - else - return m; - } - else if (m == '-' && PEEKC() == '-' - && CPP_OPTION (pfile, chill)) - { - skip_line_comment (pfile); - return ' '; - } - else - return m; -} - -/* Identical to skip_comment except that it copies the comment into the - token_buffer. This is used if !discard_comments. */ -static int -copy_comment (pfile, m) - cpp_reader *pfile; - int m; -{ - const U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */ - const U_CHAR *limit; - - if (skip_comment (pfile, m) == m) - return m; - - limit = CPP_BUFFER (pfile)->cur; - CPP_RESERVE (pfile, limit - start + 2); - CPP_PUTC_Q (pfile, m); - for (; start <= limit; start++) - if (*start != '\r') - CPP_PUTC_Q (pfile, *start); - - return ' '; -} - -static void -null_warning (pfile, count) - cpp_reader *pfile; - unsigned int count; -{ - if (count == 1) - cpp_warning (pfile, "embedded null character ignored"); - else - cpp_warning (pfile, "embedded null characters ignored"); -} - -/* Skip whitespace \-newline and comments. Does not macro-expand. */ - -void -_cpp_skip_hspace (pfile) - cpp_reader *pfile; -{ - unsigned int null_count = 0; - int c; - - while (1) - { - c = GETC(); - if (c == EOF) - goto out; - else if (is_hspace(c)) - { - if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "%s in preprocessing directive", - c == '\f' ? "formfeed" : "vertical tab"); - else if (c == '\0') - null_count++; - } - else if (c == '\r') - { - /* \r is a backslash-newline marker if !has_escapes, and - a deletable-whitespace or no-reexpansion marker otherwise. */ - if (CPP_BUFFER (pfile)->has_escapes) - { - if (PEEKC() == ' ') - FORWARD(1); - else - break; - } - else - CPP_BUMP_LINE (pfile); - } - else if (c == '/' || c == '-') - { - c = skip_comment (pfile, c); - if (c != ' ') - break; - } - else - break; - } - FORWARD(-1); - out: - if (null_count) - null_warning (pfile, null_count); -} - -/* Read and discard the rest of the current line. */ - -void -_cpp_skip_rest_of_line (pfile) - cpp_reader *pfile; -{ - for (;;) - { - int c = GETC(); - switch (c) - { - case '\n': - FORWARD(-1); - case EOF: - return; - - case '\r': - if (! CPP_BUFFER (pfile)->has_escapes) - CPP_BUMP_LINE (pfile); - break; - - case '\'': - case '\"': - skip_string (pfile, c); - break; - - case '/': - case '-': - skip_comment (pfile, c); - break; - - case '\f': - case '\v': - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "%s in preprocessing directive", - c == '\f' ? "formfeed" : "vertical tab"); - break; - - } - } -} - -/* Parse an identifier starting with C. */ - -void -_cpp_parse_name (pfile, c) - cpp_reader *pfile; - int c; -{ - for (;;) - { - if (! is_idchar(c)) - { - FORWARD (-1); - break; - } - - /* $ is not a legal identifier character in the standard, but is - commonly accepted as an extension. Don't warn about it in - skipped conditional blocks. */ - if (c == '$' && CPP_PEDANTIC (pfile) && ! pfile->skipping) - cpp_pedwarn (pfile, "`$' in identifier"); - - CPP_RESERVE(pfile, 2); /* One more for final NUL. */ - CPP_PUTC_Q (pfile, c); - c = GETC(); - if (c == EOF) - break; - } - return; -} - -/* Parse and skip over a string starting with C. A single quoted - string is treated like a double -- some programs (e.g., troff) are - perverse this way. (However, a single quoted string is not allowed - to extend over multiple lines.) */ -static void -skip_string (pfile, c) - cpp_reader *pfile; - int c; -{ - unsigned int start_line, start_column; - unsigned int null_count = 0; - - start_line = CPP_BUF_LINE (CPP_BUFFER (pfile)); - start_column = CPP_BUF_COL (CPP_BUFFER (pfile)); - while (1) - { - int cc = GETC(); - switch (cc) - { - case EOF: - cpp_error_with_line (pfile, start_line, start_column, - "unterminated string or character constant"); - if (pfile->multiline_string_line != start_line - && pfile->multiline_string_line != 0) - cpp_error_with_line (pfile, - pfile->multiline_string_line, -1, - "possible real start of unterminated constant"); - pfile->multiline_string_line = 0; - goto out; - - case '\0': - null_count++; - break; - - case '\n': - CPP_BUMP_LINE (pfile); - /* In Fortran and assembly language, silently terminate - strings of either variety at end of line. This is a - kludge around not knowing where comments are in these - languages. */ - if (CPP_OPTION (pfile, lang_fortran) - || CPP_OPTION (pfile, lang_asm)) - { - FORWARD(-1); - goto out; - } - /* Character constants may not extend over multiple lines. - In Standard C, neither may strings. We accept multiline - strings as an extension. */ - if (c == '\'') - { - cpp_error_with_line (pfile, start_line, start_column, - "unterminated character constant"); - FORWARD(-1); - goto out; - } - if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0) - cpp_pedwarn_with_line (pfile, start_line, start_column, - "string constant runs past end of line"); - if (pfile->multiline_string_line == 0) - pfile->multiline_string_line = start_line; - break; - - case '\r': - if (CPP_BUFFER (pfile)->has_escapes) - { - cpp_ice (pfile, "\\r escape inside string constant"); - FORWARD(1); - } - else - /* Backslash newline is replaced by nothing at all. */ - CPP_BUMP_LINE (pfile); - break; - - case '\\': - FORWARD(1); - break; - - case '\"': - case '\'': - if (cc == c) - goto out; - break; - } - } - - out: - if (null_count == 1) - cpp_warning (pfile, "null character in string or character constant"); - else if (null_count > 1) - cpp_warning (pfile, "null characters in string or character constant"); -} - -/* Parse a string and copy it to the output. */ - -static void -parse_string (pfile, c) - cpp_reader *pfile; - int c; -{ - const U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */ - const U_CHAR *limit; - - skip_string (pfile, c); - - limit = CPP_BUFFER (pfile)->cur; - CPP_RESERVE (pfile, limit - start + 2); - CPP_PUTC_Q (pfile, c); - for (; start < limit; start++) - if (*start != '\r') - CPP_PUTC_Q (pfile, *start); -} - -/* Get the next token, and add it to the text in pfile->token_buffer. - Return the kind of token we got. */ - -enum cpp_ttype -_cpp_lex_token (pfile) - cpp_reader *pfile; -{ - register int c, c2; - enum cpp_ttype token; - - if (CPP_BUFFER (pfile) == NULL) - return CPP_EOF; - - get_next: - c = GETC(); - switch (c) - { - case EOF: - return CPP_EOF; - - case '/': - if (PEEKC () == '=') - goto op2; - - comment: - if (CPP_OPTION (pfile, discard_comments)) - c = skip_comment (pfile, c); - else - c = copy_comment (pfile, c); - if (c != ' ') - goto randomchar; - - /* Comments are equivalent to spaces. - For -traditional, a comment is equivalent to nothing. */ - if (!CPP_OPTION (pfile, discard_comments)) - return CPP_COMMENT; - else if (CPP_TRADITIONAL (pfile)) - goto get_next; - else - { - CPP_PUTC (pfile, c); - return CPP_HSPACE; - } - - case '#': - CPP_PUTC (pfile, c); - - hash: - c2 = PEEKC (); - if (c2 == '#') - { - FORWARD (1); - CPP_PUTC (pfile, c2); - return CPP_PASTE; - } - else if (c2 == '%' && PEEKN (1) == ':') - { - /* Digraph: "%:" == "#". */ - FORWARD (1); - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c2); - CPP_PUTC_Q (pfile, GETC ()); - return CPP_PASTE; - } - else - return CPP_HASH; - - case '\"': - case '\'': - parse_string (pfile, c); - return c == '\'' ? CPP_CHAR : CPP_STRING; - - case '$': - if (!CPP_OPTION (pfile, dollars_in_ident)) - goto randomchar; - goto letter; - - case ':': - c2 = PEEKC (); - /* Digraph: ":>" == "]". */ - if (c2 == '>' - || (c2 == ':' && CPP_OPTION (pfile, cplusplus))) - goto op2; - goto randomchar; - - case '&': - case '+': - case '|': - c2 = PEEKC (); - if (c2 == c || c2 == '=') - goto op2; - goto randomchar; - - case '%': - /* Digraphs: "%:" == "#", "%>" == "}". */ - c2 = PEEKC (); - if (c2 == ':') - { - FORWARD (1); - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, c2); - goto hash; - } - else if (c2 == '>') - { - FORWARD (1); - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, c2); - return CPP_OPEN_BRACE; - } - /* else fall through */ - - case '*': - case '!': - case '=': - case '^': - if (PEEKC () == '=') - goto op2; - goto randomchar; - - case '-': - c2 = PEEKC (); - if (c2 == '-') - { - if (CPP_OPTION (pfile, chill)) - goto comment; /* Chill style comment */ - else - goto op2; - } - else if (c2 == '=') - goto op2; - else if (c2 == '>') - { - if (CPP_OPTION (pfile, cplusplus) && PEEKN (1) == '*') - { - /* In C++, there's a ->* operator. */ - token = CPP_OTHER; - CPP_RESERVE (pfile, 4); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, GETC ()); - CPP_PUTC_Q (pfile, GETC ()); - return token; - } - goto op2; - } - goto randomchar; - - case '<': - if (pfile->parsing_include_directive) - { - for (;;) - { - CPP_PUTC (pfile, c); - if (c == '>') - break; - c = GETC (); - if (c == '\n' || c == EOF) - { - cpp_error (pfile, - "missing '>' in `#include <FILENAME>'"); - break; - } - else if (c == '\r') - { - if (!CPP_BUFFER (pfile)->has_escapes) - { - /* Backslash newline is replaced by nothing. */ - CPP_ADJUST_WRITTEN (pfile, -1); - CPP_BUMP_LINE (pfile); - } - else - { - /* We might conceivably get \r- or \r<space> in - here. Just delete 'em. */ - int d = GETC(); - if (d != '-' && d != ' ') - cpp_ice (pfile, "unrecognized escape \\r%c", d); - CPP_ADJUST_WRITTEN (pfile, -1); - } - } - } - return CPP_STRING; - } - /* Digraphs: "<%" == "{", "<:" == "[". */ - c2 = PEEKC (); - if (c2 == '%') - { - FORWARD (1); - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, c2); - return CPP_CLOSE_BRACE; - } - else if (c2 == ':') - goto op2; - /* else fall through */ - case '>': - c2 = PEEKC (); - if (c2 == '=') - goto op2; - /* GNU C++ supports MIN and MAX operators <? and >?. */ - if (c2 != c && (!CPP_OPTION (pfile, cplusplus) || c2 != '?')) - goto randomchar; - FORWARD(1); - CPP_RESERVE (pfile, 3); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, c2); - if (PEEKC () == '=') - CPP_PUTC_Q (pfile, GETC ()); - return CPP_OTHER; - - case '.': - c2 = PEEKC (); - if (ISDIGIT (c2)) - { - CPP_PUTC (pfile, c); - c = GETC (); - goto number; - } - - /* In C++ there's a .* operator. */ - if (CPP_OPTION (pfile, cplusplus) && c2 == '*') - goto op2; - - if (c2 == '.' && PEEKN(1) == '.') - { - CPP_RESERVE (pfile, 3); - CPP_PUTC_Q (pfile, '.'); - CPP_PUTC_Q (pfile, '.'); - CPP_PUTC_Q (pfile, '.'); - FORWARD (2); - return CPP_ELLIPSIS; - } - goto randomchar; - - op2: - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, GETC ()); - return CPP_OTHER; - - case 'L': - c2 = PEEKC (); - if ((c2 == '\'' || c2 == '\"') && !CPP_TRADITIONAL (pfile)) - { - CPP_PUTC (pfile, c); - c = GETC (); - parse_string (pfile, c); - return c == '\'' ? CPP_WCHAR : CPP_WSTRING; - } - goto letter; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - number: - c2 = '.'; - for (;;) - { - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - c = PEEKC (); - if (c == EOF) - break; - if (!is_numchar(c) && c != '.' - && ((c2 != 'e' && c2 != 'E' - && ((c2 != 'p' && c2 != 'P') - || CPP_OPTION (pfile, c89))) - || (c != '+' && c != '-'))) - break; - FORWARD(1); - c2= c; - } - return CPP_NUMBER; - case 'b': case 'c': case 'd': case 'h': case 'o': - case 'B': case 'C': case 'D': case 'H': case 'O': - if (CPP_OPTION (pfile, chill) && PEEKC () == '\'') - { - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - CPP_PUTC_Q (pfile, '\''); - FORWARD(1); - for (;;) - { - c = GETC(); - if (c == EOF) - goto chill_number_eof; - if (!is_numchar(c)) - break; - CPP_PUTC (pfile, c); - } - if (c == '\'') - { - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c); - return CPP_STRING; - } - else - { - FORWARD(-1); - chill_number_eof: - return CPP_NUMBER; - } - } - else - goto letter; - case '_': - case 'a': case 'e': case 'f': case 'g': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'p': case 'q': - case 'r': case 's': case 't': case 'u': case 'v': case 'w': - case 'x': case 'y': case 'z': - case 'A': case 'E': case 'F': case 'G': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'P': case 'Q': case 'R': - case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - letter: - _cpp_parse_name (pfile, c); - return CPP_MACRO; - - case ' ': case '\t': case '\v': case '\f': case '\0': - { - int null_count = 0; - - for (;;) - { - if (c == '\0') - null_count++; - else - CPP_PUTC (pfile, c); - c = PEEKC (); - if (c == EOF || !is_hspace(c)) - break; - FORWARD(1); - } - if (null_count) - null_warning (pfile, null_count); - return CPP_HSPACE; - } - - case '\r': - if (CPP_BUFFER (pfile)->has_escapes) - { - c = GETC (); - if (c == '-') - { - if (pfile->output_escapes) - CPP_PUTS (pfile, "\r-", 2); - _cpp_parse_name (pfile, GETC ()); - return CPP_NAME; - } - else if (c == ' ') - { - /* "\r " means a space, but only if necessary to prevent - accidental token concatenation. */ - CPP_RESERVE (pfile, 2); - if (pfile->output_escapes) - CPP_PUTC_Q (pfile, '\r'); - CPP_PUTC_Q (pfile, c); - return CPP_HSPACE; - } - else - { - cpp_ice (pfile, "unrecognized escape \\r%c", c); - goto get_next; - } - } - else - { - /* Backslash newline is ignored. */ - if (!ACTIVE_MARK_P (pfile)) - CPP_BUMP_LINE (pfile); - goto get_next; - } - - case '\n': - CPP_PUTC (pfile, c); - return CPP_VSPACE; - - case '(': token = CPP_OPEN_PAREN; goto char1; - case ')': token = CPP_CLOSE_PAREN; goto char1; - case '{': token = CPP_OPEN_BRACE; goto char1; - case '}': token = CPP_CLOSE_BRACE; goto char1; - case ',': token = CPP_COMMA; goto char1; - case ';': token = CPP_SEMICOLON; goto char1; - - randomchar: - default: - token = CPP_OTHER; - char1: - CPP_PUTC (pfile, c); - return token; - } -} - -/* Check for and expand a macro, which is from WRITTEN to CPP_WRITTEN (pfile). - Caller is expected to have checked no_macro_expand. */ -static int -maybe_macroexpand (pfile, written) - cpp_reader *pfile; - long written; -{ - U_CHAR *macro = pfile->token_buffer + written; - size_t len = CPP_WRITTEN (pfile) - written; - cpp_hashnode *hp = cpp_lookup (pfile, macro, len); - - /* cpp_lookup never returns null. */ - if (hp->type == T_VOID) - return 0; - if (hp->disabled || hp->type == T_IDENTITY) - { - if (pfile->output_escapes) - { - /* Insert a no-reexpand marker before IDENT. */ - CPP_RESERVE (pfile, 2); - CPP_ADJUST_WRITTEN (pfile, 2); - macro = pfile->token_buffer + written; - - memmove (macro + 2, macro, len); - macro[0] = '\r'; - macro[1] = '-'; - } - return 0; - } - if (hp->type == T_EMPTY) - { - /* Special case optimization: macro expands to nothing. */ - CPP_SET_WRITTEN (pfile, written); - CPP_PUTC_Q (pfile, ' '); - return 1; - } - - /* If macro wants an arglist, verify that a '(' follows. */ - if (hp->type == T_FMACRO) - { - int macbuf_whitespace = 0; - int c; - - while (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) - { - const U_CHAR *point = CPP_BUFFER (pfile)->cur; - for (;;) - { - _cpp_skip_hspace (pfile); - c = PEEKC (); - if (c == '\n') - FORWARD(1); - else - break; - } - if (point != CPP_BUFFER (pfile)->cur) - macbuf_whitespace = 1; - if (c == '(') - goto is_macro_call; - else if (c != EOF) - goto not_macro_call; - cpp_pop_buffer (pfile); - } - - CPP_SET_MARK (pfile); - for (;;) - { - _cpp_skip_hspace (pfile); - c = PEEKC (); - if (c == '\n') - FORWARD(1); - else - break; - } - CPP_GOTO_MARK (pfile); - - if (c != '(') - { - not_macro_call: - if (macbuf_whitespace) - CPP_PUTC (pfile, ' '); - - /* K+R treated this as a hard error. */ - if (CPP_WTRADITIONAL (pfile)) - cpp_warning (pfile, - "function macro %s must be used with arguments in traditional C", - hp->name); - return 0; - } - } - - is_macro_call: - /* This is now known to be a macro call. - Expand the macro, reading arguments as needed, - and push the expansion on the input stack. */ - _cpp_macroexpand (pfile, hp); - CPP_SET_WRITTEN (pfile, written); - return 1; -} - -/* Complain about \v or \f in a preprocessing directive (constraint - violation, C99 6.10 para 5). Caller has checked CPP_PEDANTIC. */ -static void -pedantic_whitespace (pfile, p, len) - cpp_reader *pfile; - U_CHAR *p; - unsigned int len; -{ - while (len) - { - if (*p == '\v') - cpp_pedwarn (pfile, "vertical tab in preprocessing directive"); - else if (*p == '\f') - cpp_pedwarn (pfile, "form feed in preprocessing directive"); - p++; - len--; - } -} - - -enum cpp_ttype -cpp_get_token (pfile) - cpp_reader *pfile; -{ - enum cpp_ttype token; - long written = CPP_WRITTEN (pfile); - int macro_buffer; - - get_next: - token = _cpp_lex_token (pfile); - - switch (token) - { - default: - if (pfile->skipping) - break; - pfile->potential_control_macro = 0; - pfile->only_seen_white = 0; - break; - - case CPP_HSPACE: - case CPP_COMMENT: - break; - - case CPP_VSPACE: - if (pfile->only_seen_white == 0) - pfile->only_seen_white = 1; - CPP_BUMP_LINE (pfile); - break; - - case CPP_HASH: - pfile->potential_control_macro = 0; - if (!pfile->only_seen_white) - break; - /* XXX shouldn't have to do this - remove the hash or %: from - the token buffer. */ - if (CPP_PWRITTEN (pfile)[-1] == '#') - CPP_ADJUST_WRITTEN (pfile, -1); - else - CPP_ADJUST_WRITTEN (pfile, -2); - - if (_cpp_handle_directive (pfile)) - { - token = CPP_DIRECTIVE; - break; - } - pfile->only_seen_white = 0; - CPP_PUTC (pfile, '#'); - break; - - case CPP_MACRO: - if (pfile->skipping) - break; - pfile->potential_control_macro = 0; - pfile->only_seen_white = 0; - if (! pfile->no_macro_expand - && maybe_macroexpand (pfile, written)) - goto get_next; - token = CPP_NAME; - break; - - /* Do not run this case through the 'skipping' logic. */ - case CPP_EOF: - if (CPP_BUFFER (pfile) == NULL) - return CPP_EOF; - macro_buffer = CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)); - - cpp_pop_buffer (pfile); - if (macro_buffer) - goto get_next; - return CPP_EOF; - } - - if (pfile->skipping) - { - CPP_SET_WRITTEN (pfile, written); - goto get_next; - } - return token; -} - -/* Like cpp_get_token, but skip spaces and comments. */ - -enum cpp_ttype -cpp_get_non_space_token (pfile) - cpp_reader *pfile; -{ - int old_written = CPP_WRITTEN (pfile); - for (;;) - { - enum cpp_ttype token = cpp_get_token (pfile); - if (token != CPP_COMMENT && token != CPP_HSPACE && token != CPP_VSPACE) - return token; - CPP_SET_WRITTEN (pfile, old_written); - } -} - -/* Like cpp_get_token, except that it does not execute directives, - does not consume vertical space, and discards horizontal space. */ -enum cpp_ttype -_cpp_get_directive_token (pfile) - cpp_reader *pfile; -{ - long old_written; - enum cpp_ttype token; - int at_bol; - - get_next: - at_bol = (CPP_BUFFER (pfile)->cur == CPP_BUFFER (pfile)->line_base); - old_written = CPP_WRITTEN (pfile); - token = _cpp_lex_token (pfile); - switch (token) - { - default: - return token; - - case CPP_VSPACE: - /* Put it back and return VSPACE. */ - FORWARD(-1); - CPP_ADJUST_WRITTEN (pfile, -1); - return CPP_VSPACE; - - case CPP_HSPACE: - /* The purpose of this rather strange check is to prevent pedantic - warnings for ^L in an #ifdefed out block. */ - if (CPP_PEDANTIC (pfile) && ! at_bol) - pedantic_whitespace (pfile, pfile->token_buffer + old_written, - CPP_WRITTEN (pfile) - old_written); - CPP_SET_WRITTEN (pfile, old_written); - goto get_next; - return CPP_HSPACE; - - case CPP_MACRO: - if (! pfile->no_macro_expand - && maybe_macroexpand (pfile, old_written)) - goto get_next; - return CPP_NAME; - - case CPP_EOF: - if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) - { - cpp_pop_buffer (pfile); - goto get_next; - } - else - /* This can happen for files that don't end with a newline, - and for cpp_define and friends. Pretend they do, so - callers don't have to deal. A warning will be issued by - someone else, if necessary. */ - return CPP_VSPACE; - } -} - -/* Determine the current line and column. Used only by read_and_prescan. */ -static U_CHAR * -find_position (start, limit, linep) - U_CHAR *start; - U_CHAR *limit; - unsigned long *linep; -{ - unsigned long line = *linep; - U_CHAR *lbase = start; - while (start < limit) - { - U_CHAR ch = *start++; - if (ch == '\n' || ch == '\r') - { - line++; - lbase = start; - } - } - *linep = line; - return lbase; -} - -/* The following table is used by _cpp_prescan. If we have - designated initializers, it can be constant data; otherwise, it is - set up at runtime by _cpp_init_input_buffer. */ - -#if (GCC_VERSION >= 2007) -#define init_chartab() /* nothing */ -#define CHARTAB __extension__ static const U_CHAR chartab[UCHAR_MAX + 1] = { -#define END }; -#define s(p, v) [p] = v, -#else -#define CHARTAB static U_CHAR chartab[UCHAR_MAX + 1] = { 0 }; \ - static void init_chartab PARAMS ((void)) { \ - unsigned char *x = chartab; -#define END } -#define s(p, v) x[p] = v; -#endif - -/* Table of characters that can't be handled in the inner loop. - Also contains the mapping between trigraph third characters and their - replacements. */ -#define SPECCASE_CR 1 -#define SPECCASE_BACKSLASH 2 -#define SPECCASE_QUESTION 3 - -CHARTAB - s('\r', SPECCASE_CR) - s('\\', SPECCASE_BACKSLASH) - s('?', SPECCASE_QUESTION) - - s('=', '#') s(')', ']') s('!', '|') - s('(', '[') s('\'', '^') s('>', '}') - s('/', '\\') s('<', '{') s('-', '~') -END - -#undef CHARTAB -#undef END -#undef s - -#define NORMAL(c) ((chartab[c]) == 0 || (chartab[c]) > SPECCASE_QUESTION) -#define NONTRI(c) ((c) <= SPECCASE_QUESTION) - -/* Prescan pass over a file already loaded into BUF. This is - translation phases 1 and 2 (C99 5.1.1.2). - - Convert end-of-line markers (\n, \r, \r\n, \n\r) to - canonical form (\n). If enabled, convert and/or warn about - trigraphs. Convert backslash-newline to a one-character escape - (\r) and remove it from "embarrassing" places (i.e. the middle of a - token). If there is no newline at the end of the file, add one and - warn. Returns -1 on failure, or the actual length of the data to - be scanned. - - This function does a lot of work, and can be a serious performance - bottleneck. It has been tuned heavily; make sure you understand it - before hacking. The common case - no trigraphs, Unix style line - breaks, backslash-newline set off by whitespace, newline at EOF - - has been optimized at the expense of the others. The performance - penalty for DOS style line breaks (\r\n) is about 15%. - - Warnings lose particularly heavily since we have to determine the - line number, which involves scanning from the beginning of the file - or from the last warning. The penalty for the absence of a newline - at the end of reload1.c is about 60%. (reload1.c is 329k.) - - If your file has more than one kind of end-of-line marker, you - will get messed-up line numbering. */ - -ssize_t -_cpp_prescan (pfile, fp, len) - cpp_reader *pfile; - cpp_buffer *fp; - ssize_t len; -{ - U_CHAR *buf, *op; - const U_CHAR *ibase, *ip, *ilimit; - U_CHAR *line_base; - unsigned long line; - unsigned int deferred_newlines; - - /* Allocate an extra byte in case we must add a trailing \n. */ - buf = (U_CHAR *) xmalloc (len + 1); - line_base = op = buf; - ip = ibase = fp->buf; - ilimit = ibase + len; - line = 1; - deferred_newlines = 0; - - for (;;) - { - const U_CHAR *iq; - - /* Deal with \-newline, potentially in the middle of a token. */ - if (deferred_newlines) - { - if (op != buf && ! is_space (op[-1]) && op[-1] != '\r') - { - /* Previous was not white space. Skip to white - space, if we can, before outputting the \r's */ - iq = ip; - while (iq < ilimit - && *iq != ' ' - && *iq != '\t' - && *iq != '\n' - && NORMAL(*iq)) - iq++; - memcpy (op, ip, iq - ip); - op += iq - ip; - ip += iq - ip; - if (! NORMAL(*ip)) - goto do_speccase; - } - while (deferred_newlines) - deferred_newlines--, *op++ = '\r'; - } - - /* Copy as much as we can without special treatment. */ - iq = ip; - while (iq < ilimit && NORMAL (*iq)) iq++; - memcpy (op, ip, iq - ip); - op += iq - ip; - ip += iq - ip; - - do_speccase: - if (ip >= ilimit) - break; - - switch (chartab[*ip++]) - { - case SPECCASE_CR: /* \r */ - if (ip[-2] != '\n') - { - if (ip < ilimit && *ip == '\n') - ip++; - *op++ = '\n'; - } - break; - - case SPECCASE_BACKSLASH: /* \ */ - backslash: - if (ip < ilimit) - { - if (*ip == '\n') - { - deferred_newlines++; - ip++; - if (*ip == '\r') ip++; - break; - } - else if (*ip == '\r') - { - deferred_newlines++; - ip++; - if (*ip == '\n') ip++; - break; - } - } - - *op++ = '\\'; - break; - - case SPECCASE_QUESTION: /* ? */ - { - unsigned int d, t; - - *op++ = '?'; /* Normal non-trigraph case */ - if (ip > ilimit - 2 || ip[0] != '?') - break; - - d = ip[1]; - t = chartab[d]; - if (NONTRI (t)) - break; - - if (CPP_OPTION (pfile, warn_trigraphs)) - { - unsigned long col; - line_base = find_position (line_base, op, &line); - col = op - line_base + 1; - if (CPP_OPTION (pfile, trigraphs)) - cpp_warning_with_line (pfile, line, col, - "trigraph ??%c converted to %c", d, t); - else - cpp_warning_with_line (pfile, line, col, - "trigraph ??%c ignored", d); - } - - ip += 2; - if (CPP_OPTION (pfile, trigraphs)) - { - op[-1] = t; /* Overwrite '?' */ - if (t == '\\') - { - op--; - goto backslash; - } - } - else - { - *op++ = '?'; - *op++ = d; - } - } - break; - } - } - -#ifdef HAVE_MMAP_FILE - if (fp->mapped) - munmap ((caddr_t) fp->buf, len); - else -#endif - free ((PTR) fp->buf); - - if (op[-1] != '\n') - { - unsigned long col; - line_base = find_position (line_base, op, &line); - col = op - line_base + 1; - cpp_warning_with_line (pfile, line, col, "no newline at end of file"); - *op++ = '\n'; - } - - fp->buf = buf; - return op - buf; -} - -/* Allocate pfile->input_buffer, and initialize chartab[] - if it hasn't happened already. */ - -void -_cpp_init_input_buffer (pfile) - cpp_reader *pfile; -{ - U_CHAR *tmp; - - init_chartab (); - _cpp_init_toklist (&pfile->directbuf, NO_DUMMY_TOKEN); - - /* Determine the appropriate size for the input buffer. Normal C - source files are smaller than eight K. */ - /* 8Kbytes of buffer proper, 1 to detect running off the end without - address arithmetic all the time, and 3 for pushback during buffer - refill, in case there's a potential trigraph or end-of-line - digraph at the end of a block. */ - - tmp = (U_CHAR *) xmalloc (8192 + 1 + 3); - pfile->input_buffer = tmp; - pfile->input_buffer_len = 8192; -} - /* Utility routine: Compares, in the manner of strcmp(3), the token beginning at TOKEN and extending for LEN characters to the NUL-terminated string @@ -2205,8 +717,6 @@ cpp_idcmp (token, len, string) return 1; } -#ifdef NEW_LEXER - /* Lexing algorithm. The original lexer in cpplib was made up of two passes: a first pass @@ -2249,7 +759,7 @@ cpp_idcmp (token, len, string) knowing whether whitespace precedes a particular token. For example, the '=' handler needs to know whether there was whitespace between it and a "!" token on the top of the stack, to make the token conversion - decision correctly. So each token has a PREV_WHITESPACE flag to + decision correctly. So each token has a PREV_WHITE flag to indicate this - the standard permits consecutive whitespace to be regarded as a single space. The compiler front ends are not interested in whitespace at all; they just require a token stream. @@ -2300,21 +810,6 @@ cpp_idcmp (token, len, string) static const unsigned char *digraph_spellings [] = {U"%:", U"%:%:", U"<:", U":>", U"<%", U"%>"}; -static unsigned char trigraph_map[256]; - -void -init_trigraph_map () -{ - trigraph_map['='] = '#'; - trigraph_map['('] = '['; - trigraph_map[')'] = ']'; - trigraph_map['/'] = '\\'; - trigraph_map['\''] = '^'; - trigraph_map['<'] = '{'; - trigraph_map['>'] = '}'; - trigraph_map['!'] = '|'; - trigraph_map['-'] = '~'; -} /* Call when a trigraph is encountered. It warns if necessary, and returns true if the trigraph should be honoured. END is the third @@ -2347,11 +842,11 @@ trigraph_ok (pfile, end) trigraph sequence. Returns a pointer to the end of the name after replacement. */ -static unsigned char* +static unsigned char * trigraph_replace (pfile, src, limit) cpp_reader *pfile; unsigned char *src; - unsigned char* limit; + unsigned char *limit; { unsigned char *dest; @@ -2418,7 +913,7 @@ backslash_start (pfile, cur) previous asterisk may be separated by one or more escaped newlines. Returns non-zero if comment terminated by EOF, zero otherwise. */ static int -skip_block_comment2 (pfile) +skip_block_comment (pfile) cpp_reader *pfile; { cpp_buffer *buffer = pfile->buffer; @@ -2476,7 +971,7 @@ skip_block_comment2 (pfile) /* Skip a C++ or Chill line comment. Handles escaped newlines. Returns non-zero if a multiline comment. */ static int -skip_line_comment2 (pfile) +skip_line_comment (pfile) cpp_reader *pfile; { cpp_buffer *buffer = pfile->buffer; @@ -2569,7 +1064,10 @@ parse_name (pfile, list, name) goto out; namebuf++; cur++; - if (c == '$' && CPP_PEDANTIC (pfile)) + /* $ is not a legal identifier character in the standard, but is + commonly accepted as an extension. Don't warn about it in + skipped conditional blocks. */ + if (c == '$' && CPP_PEDANTIC (pfile) && ! pfile->skipping) { buffer->cur = cur; cpp_pedwarn (pfile, "'$' character in identifier"); @@ -2591,12 +1089,6 @@ parse_name (pfile, list, name) } /* Parse (append) a number. */ - -#define VALID_SIGN(c, prevc) \ - (((c) == '+' || (c) == '-') && \ - ((prevc) == 'e' || (prevc) == 'E' \ - || (((prevc) == 'p' || (prevc) == 'P') && !CPP_OPTION (pfile, c89)))) - static void parse_number (pfile, list, name) cpp_reader *pfile; @@ -2650,19 +1142,19 @@ parse_number (pfile, list, name) allowed, except for within directives. */ static void -parse_string2 (pfile, list, name, terminator, multiline_ok) +parse_string (pfile, list, token, terminator) cpp_reader *pfile; cpp_toklist *list; - cpp_name *name; + cpp_token *token; unsigned int terminator; - int multiline_ok; { cpp_buffer *buffer = pfile->buffer; + cpp_name *name = &token->val.name; register const unsigned char *cur = buffer->cur; const unsigned char *name_limit; unsigned char *namebuf; unsigned int null_count = 0; - int trigraphed_len = 0; + unsigned int trigraphed = list->name_used; expanded: name_limit = list->namebuf + list->name_cap; @@ -2680,14 +1172,14 @@ parse_string2 (pfile, list, name, terminator, multiline_ok) buffer->cur = cur; /* Scan for trigraphs before checking if backslash-escaped. */ - if (CPP_OPTION (pfile, trigraphs) - || CPP_OPTION (pfile, warn_trigraphs)) + if ((CPP_OPTION (pfile, trigraphs) + || CPP_OPTION (pfile, warn_trigraphs)) + && namebuf - (list->namebuf + trigraphed) >= 3) { - namebuf = trigraph_replace (pfile, name->text + trigraphed_len, - namebuf); - trigraphed_len = namebuf - 2 - (name->text + trigraphed_len); - if (trigraphed_len < 0) - trigraphed_len = 0; + namebuf = trigraph_replace (pfile, list->namebuf + trigraphed, + namebuf); + /* The test above guarantees trigraphed will be positive. */ + trigraphed = namebuf - list->namebuf - 2; } namebuf--; /* Drop the newline / terminator from the name. */ @@ -2714,15 +1206,17 @@ parse_string2 (pfile, list, name, terminator, multiline_ok) /* Character constants, headers and asserts may not extend over multiple lines. In Standard C, neither may strings. We accept multiline strings as an - extension, but not in directives. */ - if (!multiline_ok) + extension. (Even in directives - otherwise, glibc's + longlong.h breaks.) */ + if (terminator != '"') goto unterminated; cur++; /* Move forwards again. */ if (pfile->multiline_string_line == 0) { - pfile->multiline_string_line = list->line; + pfile->multiline_string_line = token->line; + pfile->multiline_string_column = token->col; if (CPP_PEDANTIC (pfile)) cpp_pedwarn (pfile, "multi-line string constant"); } @@ -2767,7 +1261,8 @@ parse_string2 (pfile, list, name, terminator, multiline_ok) if (terminator == '\"' && pfile->multiline_string_line != list->line && pfile->multiline_string_line != 0) { - cpp_error_with_line (pfile, pfile->multiline_string_line, -1, + cpp_error_with_line (pfile, pfile->multiline_string_line, + pfile->multiline_string_column, "possible start of unterminated string literal"); pfile->multiline_string_line = 0; } @@ -2800,7 +1295,7 @@ save_comment (list, token, from, len, type) len += COMMENT_START_LEN; if (list->name_used + len > list->name_cap) - expand_name_space (list, len); + _cpp_expand_name_space (list, len); INIT_TOKEN_NAME (list, token); token->type = CPP_COMMENT; @@ -2838,47 +1333,61 @@ save_comment (list, token, from, len, type) * even when enabled. */ -#define IS_DIRECTIVE() (list->tokens[first_token].type == CPP_HASH) +#define IS_DIRECTIVE() (list->directive != 0) +#define MIGHT_BE_DIRECTIVE() \ +(cur_token == &list->tokens[first_token + 1] && cur_token[-1].type == CPP_HASH) -void -_cpp_lex_line (pfile, list) +static void +lex_line (pfile, list) cpp_reader *pfile; cpp_toklist *list; { - cpp_token *cur_token, *token_limit; + cpp_token *cur_token, *token_limit, *first; cpp_buffer *buffer = pfile->buffer; - register const unsigned char *cur = buffer->cur; + const unsigned char *cur = buffer->cur; unsigned char flags = 0; unsigned int first_token = list->tokens_used; + if (!(list->flags & LIST_OFFSET)) + (abort) (); + + list->file = buffer->nominal_fname; list->line = CPP_BUF_LINE (buffer); pfile->col_adjust = 0; + pfile->in_lex_line = 1; + if (cur == buffer->buf) + list->flags |= BEG_OF_FILE; + expanded: token_limit = list->tokens + list->tokens_cap; cur_token = list->tokens + list->tokens_used; for (; cur < buffer->rlimit && cur_token < token_limit;) { - unsigned char c = *cur++; + unsigned char c; /* Optimize whitespace skipping, as most tokens are probably separated by whitespace. (' ' '\t' '\v' '\f' '\0'). */ - - if (is_hspace ((unsigned int) c)) + c = *cur++; + if (is_hspace (c)) { /* Step back to get the null warning and tab correction. */ buffer->cur = cur - 1; skip_whitespace (pfile, IS_DIRECTIVE ()); cur = buffer->cur; - flags = PREV_WHITESPACE; + flags = PREV_WHITE; if (cur == buffer->rlimit) break; c = *cur++; } - /* Initialize current token. Its type is set in the switch. */ + /* Initialize current token. CPP_EOF will not be fixed up by + expand_name_space. */ + list->tokens_used = cur_token - list->tokens + 1; + cur_token->type = CPP_EOF; cur_token->col = CPP_BUF_COLUMN (buffer, cur); + cur_token->line = CPP_BUF_LINE (buffer); cur_token->flags = flags; flags = 0; @@ -2909,8 +1418,13 @@ _cpp_lex_line (pfile, list) buffer->cur = cur; parse_number (pfile, list, &cur_token->val.name); cur = buffer->cur; - cur_token++; } + /* Check for # 123 form of #line. */ + if (MIGHT_BE_DIRECTIVE ()) + list->directive = _cpp_check_linemarker (pfile, cur_token, + !(cur_token[-1].flags + & PREV_WHITE)); + cur_token++; break; letter: @@ -2934,15 +1448,26 @@ _cpp_lex_line (pfile, list) parse_name (pfile, list, &cur_token->val.name); cur = buffer->cur; - /* Find handler for newly created / extended directive. */ - if (IS_DIRECTIVE () && cur_token == &list->tokens[first_token + 1]) - _cpp_check_directive (list, cur_token); + if (MIGHT_BE_DIRECTIVE ()) + list->directive = _cpp_check_directive (pfile, cur_token, + !(list->tokens[0].flags + & PREV_WHITE)); cur_token++; break; case '\'': + /* Character constants are not recognized when processing Fortran, + or if -traditional. */ + if (CPP_OPTION (pfile, lang_fortran) || CPP_TRADITIONAL (pfile)) + goto other; + /* Fall through. */ case '\"': + /* Traditionally, escaped strings are not strings. */ + if (CPP_TRADITIONAL (pfile) && IMMED_TOKEN () + && PREV_TOKEN_TYPE == CPP_BACKSLASH) + goto other; + cur_token->type = c == '\'' ? CPP_CHAR : CPP_STRING; /* Do we have a wide string? */ if (cur_token[-1].type == CPP_NAME && IMMED_TOKEN () @@ -2959,8 +1484,7 @@ _cpp_lex_line (pfile, list) /* Here c is one of ' " or >. */ INIT_TOKEN_NAME (list, cur_token); buffer->cur = cur; - parse_string2 (pfile, list, &cur_token->val.name, c, - c == '"' && !IS_DIRECTIVE()); + parse_string (pfile, list, cur_token, c); cur = buffer->cur; cur_token++; break; @@ -2991,24 +1515,25 @@ _cpp_lex_line (pfile, list) } do_line_comment: buffer->cur = cur; +#if 0 /* Leave until new lexer in place. */ if (cur[-2] != c) cpp_warning (pfile, "comment start split across lines"); - if (skip_line_comment2 (pfile)) - cpp_error_with_line (pfile, list->line, - cur_token[-1].col, - "multi-line comment"); +#endif + if (skip_line_comment (pfile)) + cpp_warning (pfile, "multi-line comment"); /* Back-up to first '-' or '/'. */ cur_token--; if (!CPP_OPTION (pfile, discard_comments) - && (!IS_DIRECTIVE() || list->dirno == 0)) + && (!IS_DIRECTIVE() + || (list->directive->flags & COMMENTS))) save_comment (list, cur_token++, cur, buffer->cur - cur, c); - cur = buffer->cur; + else if (!CPP_OPTION (pfile, traditional)) + flags = PREV_WHITE; - if (!CPP_OPTION (pfile, traditional)) - flags = PREV_WHITESPACE; + cur = buffer->cur; break; } } @@ -3023,26 +1548,30 @@ _cpp_lex_line (pfile, list) if (PREV_TOKEN_TYPE == CPP_DIV) { buffer->cur = cur; +#if 0 /* Leave until new lexer in place. */ if (cur[-2] != '/') cpp_warning (pfile, "comment start '/*' split across lines"); - if (skip_block_comment2 (pfile)) +#endif + if (skip_block_comment (pfile)) cpp_error_with_line (pfile, list->line, cur_token[-1].col, "unterminated comment"); +#if 0 /* Leave until new lexer in place. */ else if (buffer->cur[-2] != '*') cpp_warning (pfile, "comment end '*/' split across lines"); - +#endif /* Back up to opening '/'. */ cur_token--; if (!CPP_OPTION (pfile, discard_comments) - && (!IS_DIRECTIVE() || list->dirno == 0)) + && (!IS_DIRECTIVE() + || (list->directive->flags & COMMENTS))) save_comment (list, cur_token++, cur, buffer->cur - cur, c); - cur = buffer->cur; + else if (!CPP_OPTION (pfile, traditional)) + flags = PREV_WHITE; - if (!CPP_OPTION (pfile, traditional)) - flags = PREV_WHITESPACE; + cur = buffer->cur; break; } else if (CPP_OPTION (pfile, cplusplus)) @@ -3060,29 +1589,58 @@ _cpp_lex_line (pfile, list) case '\n': case '\r': handle_newline (cur, buffer->rlimit, c); - if (PREV_TOKEN_TYPE == CPP_BACKSLASH && IMMED_TOKEN ()) + if (PREV_TOKEN_TYPE == CPP_BACKSLASH) { - /* Remove the escaped newline. Then continue to process - any interrupted name or number. */ - cur_token--; if (IMMED_TOKEN ()) { + /* Remove the escaped newline. Then continue to process + any interrupted name or number. */ cur_token--; - if (cur_token->type == CPP_NAME) - goto continue_name; - else if (cur_token->type == CPP_NUMBER) - goto continue_number; - cur_token++; + /* Backslash-newline may not be immediately followed by + EOF (C99 5.1.1.2). */ + if (cur >= buffer->rlimit) + { + cpp_pedwarn (pfile, "backslash-newline at end of file"); + break; + } + if (IMMED_TOKEN ()) + { + cur_token--; + if (cur_token->type == CPP_NAME) + goto continue_name; + else if (cur_token->type == CPP_NUMBER) + goto continue_number; + cur_token++; + } + /* Remember whitespace setting. */ + flags = cur_token->flags; + break; + } + else + { + buffer->cur = cur; + cpp_warning (pfile, + "backslash and newline separated by space"); } - /* Remember whitespace setting. */ - flags = cur_token->flags; - break; } - if (PREV_TOKEN_TYPE == CPP_BACKSLASH) + else if (MIGHT_BE_DIRECTIVE ()) { - buffer->cur = cur; - cpp_warning (pfile, "backslash and newline separated by space"); + /* "Null directive." C99 6.10.7: A preprocessing + directive of the form # <new-line> has no effect. + + But it is still a directive, and therefore disappears + from the output. */ + cur_token--; + if (cur_token->flags & PREV_WHITE) + { + if (CPP_WTRADITIONAL (pfile)) + cpp_warning (pfile, + "K+R C ignores #\\n with the # indented"); + if (CPP_TRADITIONAL (pfile)) + cur_token++; + } } + /* Skip vertical space until we have at least one token to return. */ if (cur_token != &list->tokens[first_token]) @@ -3101,10 +1659,10 @@ _cpp_lex_line (pfile, list) PUSH_TOKEN (CPP_MINUS); break; - /* The digraph flag checking ensures that ## and %:%: - are interpreted as CPP_PASTE, but #%: and %:# are not. */ make_hash: case '#': + /* The digraph flag checking ensures that ## and %:%: + are interpreted as CPP_PASTE, but #%: and %:# are not. */ if (PREV_TOKEN_TYPE == CPP_HASH && IMMED_TOKEN () && ((cur_token->flags ^ cur_token[-1].flags) & DIGRAPH) == 0) REVISE_TOKEN (CPP_PASTE); @@ -3187,7 +1745,7 @@ _cpp_lex_line (pfile, list) break; } /* Is this the beginning of a header name? */ - if (list->flags & SYNTAX_INCLUDE) + if (IS_DIRECTIVE () && (list->directive->flags & INCL)) { c = '>'; /* Terminator. */ cur_token->type = CPP_HEADER_NAME; @@ -3243,7 +1801,7 @@ _cpp_lex_line (pfile, list) case '.': if (PREV_TOKEN_TYPE == CPP_DOT && cur_token[-2].type == CPP_DOT && IMMED_TOKEN () - && !(cur_token[-1].flags & PREV_WHITESPACE)) + && !(cur_token[-1].flags & PREV_WHITE)) { cur_token -= 2; PUSH_TOKEN (CPP_ELLIPSIS); @@ -3276,9 +1834,9 @@ _cpp_lex_line (pfile, list) if (CPP_OPTION (pfile, dollars_in_ident)) goto letter; /* Fall through */ + other: default: - cur_token->aux = c; - cur_token->val.name.len = 0; /* FIXME: needed for transition only */ + cur_token->val.aux = c; PUSH_TOKEN (CPP_OTHER); break; } @@ -3293,18 +1851,100 @@ _cpp_lex_line (pfile, list) } cur_token->flags = flags; - if (cur_token == &list->tokens[first_token]) + if (cur_token == &list->tokens[first_token] && pfile->done_initializing) { - /* FIXME: move this warning to callers who care. */ if (cur > buffer->buf && !IS_NEWLINE (cur[-1])) - cpp_warning (pfile, "no newline at end of file"); + cpp_pedwarn_with_line (pfile, CPP_BUF_LINE (buffer), + CPP_BUF_COLUMN (buffer, cur), + "no newline at end of file"); cur_token++->type = CPP_EOF; } out: - list->tokens[first_token].flags |= BOL; + /* All tokens are allocated, so the memory location is fixed. */ + first = &list->tokens[first_token]; + + /* Don't complain about the null directive, nor directives in + assembly source: we don't know where the comments are, and # may + introduce assembler pseudo-ops. Don't complain about invalid + directives in skipped conditional groups (6.10 p4). */ + if (first->type == CPP_HASH && list->directive == 0 && !pfile->skipping + && cur_token > first + 1 && !CPP_OPTION (pfile, lang_asm)) + { + if (first[1].type == CPP_NAME) + cpp_error (pfile, "invalid preprocessing directive #%.*s", + (int) first[1].val.name.len, first[1].val.name.text); + else + cpp_error (pfile, "invalid preprocessing directive"); + } + + /* Put EOF at end of directives. This covers "directives do not + extend beyond the end of the line (description 6.10 part 2)". */ + if (IS_DIRECTIVE () || !pfile->done_initializing) + { + pfile->first_directive_token = first; + cur_token++->type = CPP_EOF; + } + + if (first_token == 0 || IS_DIRECTIVE ()) + /* Set beginning of line flag. */ + first->flags |= BOL; + else + /* 6.10.3.10: Within the sequence of preprocessing tokens making + up the invocation of a function-like macro, new line is + considered a normal white-space character. */ + first->flags |= PREV_WHITE; + buffer->cur = cur; list->tokens_used = cur_token - list->tokens; + pfile->in_lex_line = 0; +} + +/* Write the spelling of a token TOKEN, with any appropriate + whitespace before it, to the token_buffer. PREV is the previous + token, which is used to determine if we need to shove in an extra + space in order to avoid accidental token paste. */ +static void +output_token (pfile, token, prev) + cpp_reader *pfile; + const cpp_token *token, *prev; +{ + int dummy; + + if (token->col && (token->flags & BOL)) + { + /* Supply enough whitespace to put this token in its original + column. Don't bother trying to reconstruct tabs; we can't + get it right in general, and nothing ought to care. (Yes, + some things do care; the fault lies with them.) */ + unsigned char *buffer; + unsigned int spaces = token->col - 1; + + CPP_RESERVE (pfile, token->col); + buffer = pfile->limit; + + while (spaces--) + *buffer++ = ' '; + pfile->limit = buffer; + } + else if (token->flags & PREV_WHITE) + CPP_PUTC (pfile, ' '); + /* Check for and prevent accidental token pasting, in ANSI mode. */ + + else if (!CPP_TRADITIONAL (pfile) && prev) + { + if (can_paste (pfile, prev, token, &dummy) != CPP_EOF) + CPP_PUTC (pfile, ' '); + /* can_paste catches most of the accidental paste cases, but not all. + Consider a + ++b - if there is not a space between the + and ++, it + will be misparsed as a++ + b. */ + else if ((prev->type == CPP_PLUS && token->type == CPP_PLUS_PLUS) + || (prev->type == CPP_MINUS && token->type == CPP_MINUS_MINUS)) + CPP_PUTC (pfile, ' '); + } + + CPP_RESERVE (pfile, TOKEN_LEN (token)); + pfile->limit = spell_token (pfile, token, pfile->limit); } /* Write the spelling of a token TOKEN to BUFFER. The buffer must @@ -3314,18 +1954,11 @@ _cpp_lex_line (pfile, list) to the character after the last character written. */ static unsigned char * -spell_token (pfile, token, buffer, whitespace) +spell_token (pfile, token, buffer) cpp_reader *pfile; /* Would be nice to be rid of this... */ const cpp_token *token; unsigned char *buffer; - int whitespace; { - /* Whitespace will not be wanted by handlers of the # and ## - operators calling this function, but will be wanted by the - function that writes out the preprocessed file. */ - if (whitespace && token->flags & PREV_WHITESPACE) - *buffer++ = ' '; - switch (token_spellings[token->type].type) { case SPELL_OPERATOR: @@ -3365,57 +1998,1439 @@ spell_token (pfile, token, buffer, whitespace) break; case SPELL_CHAR: - *buffer++ = token->aux; + *buffer++ = token->val.aux; break; case SPELL_NONE: - cpp_ice (pfile, "Unspellable token"); + cpp_ice (pfile, "Unspellable token %s", token_names[token->type]); break; } return buffer; } -/* Temporary function for illustrative purposes. */ +/* Macro expansion algorithm. TODO. */ + +static const cpp_token placemarker_token = {0, 0, CPP_PLACEMARKER, 0, {0}}; +static const cpp_token eof_token = {0, 0, CPP_EOF, 0, {0}}; + +#define IS_ARG_CONTEXT(c) ((c)->flags & CONTEXT_ARG) +#define CURRENT_CONTEXT(pfile) ((pfile)->contexts + (pfile)->cur_context) + +/* Flags for cpp_context. */ +#define CONTEXT_PASTEL (1 << 0) /* An argument context on LHS of ##. */ +#define CONTEXT_PASTER (1 << 1) /* An argument context on RHS of ##. */ +#define CONTEXT_RAW (1 << 2) /* If argument tokens already expanded. */ +#define CONTEXT_ARG (1 << 3) /* If an argument context. */ + +#define ASSIGN_FLAGS_AND_POS(d, s) \ + do {(d)->flags = (s)->flags & (PREV_WHITE | BOL | PASTE_LEFT); \ + if ((d)->flags & BOL) {(d)->col = (s)->col; (d)->line = (s)->line;} \ + } while (0) + +/* f is flags, just consisting of PREV_WHITE | BOL. */ +#define MODIFY_FLAGS_AND_POS(d, s, f) \ + do {(d)->flags &= ~(PREV_WHITE | BOL); (d)->flags |= (f); \ + if ((f) & BOL) {(d)->col = (s)->col; (d)->line = (s)->line;} \ + } while (0) + +typedef struct cpp_context cpp_context; +struct cpp_context +{ + union + { + const cpp_toklist *list; /* Used for macro contexts only. */ + const cpp_token **arg; /* Used for arg contexts only. */ + } u; + + /* Pushed token to be returned by next call to cpp_get_token. */ + const cpp_token *pushed_token; + + struct macro_args *args; /* 0 for arguments and object-like macros. */ + unsigned short posn; /* Current posn, index into u. */ + unsigned short count; /* No. of tokens in u. */ + unsigned short level; + unsigned char flags; +}; + +typedef struct macro_args macro_args; +struct macro_args +{ + unsigned int *ends; + const cpp_token **tokens; + unsigned int capacity; + unsigned int used; + unsigned short level; +}; + +static const cpp_token *get_raw_token PARAMS ((cpp_reader *)); +static const cpp_token *parse_arg PARAMS ((cpp_reader *, int, unsigned int, + macro_args *, unsigned int *)); +static int parse_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_args *)); +static void save_token PARAMS ((macro_args *, const cpp_token *)); +static const cpp_token *push_arg_context PARAMS ((cpp_reader *, + const cpp_token *)); +static int do_pop_context PARAMS ((cpp_reader *)); +static const cpp_token *pop_context PARAMS ((cpp_reader *)); +static const cpp_token *push_macro_context PARAMS ((cpp_reader *, + cpp_hashnode *, + const cpp_token *)); +static void free_macro_args PARAMS ((macro_args *)); + +/* Free the storage allocated for macro arguments. */ +static void +free_macro_args (args) + macro_args *args; +{ + if (args->tokens) + free (args->tokens); + free (args->ends); + free (args); +} + +/* Determines if a macro has been already used (and is therefore + disabled). */ +static int +is_macro_disabled (pfile, expansion, token) + cpp_reader *pfile; + const cpp_toklist *expansion; + const cpp_token *token; +{ + cpp_context *context = CURRENT_CONTEXT (pfile); + + /* Arguments on either side of ## are inserted in place without + macro expansion (6.10.3.3.2). Conceptually, any macro expansion + occurs during a later rescan pass. The effect is that we expand + iff we would as part of the macro's expansion list, so we should + drop to the macro's context. */ + if (IS_ARG_CONTEXT (context)) + { + if (token->flags & PASTED) + context--; + else if (!(context->flags & CONTEXT_RAW)) + return 1; + else if (context->flags & (CONTEXT_PASTEL | CONTEXT_PASTER)) + context--; + } + + /* Have we already used this macro? */ + while (context->level > 0) + { + if (!IS_ARG_CONTEXT (context) && context->u.list == expansion) + return 1; + /* Raw argument tokens are judged based on the token list they + came from. */ + if (context->flags & CONTEXT_RAW) + context = pfile->contexts + context->level; + else + context--; + } + + /* Function-like macros may be disabled if the '(' is not in the + current context. We check this without disrupting the context + stack. */ + if (expansion->paramc >= 0) + { + const cpp_token *next; + unsigned int prev_nme; + + context = CURRENT_CONTEXT (pfile); + /* Drop down any contexts we're at the end of: the '(' may + appear in lower macro expansions, or in the rest of the file. */ + while (context->posn == context->count && context > pfile->contexts) + { + context--; + /* If we matched, we are disabled, as we appear in the + expansion of each macro we meet. */ + if (!IS_ARG_CONTEXT (context) && context->u.list == expansion) + return 1; + } + + prev_nme = pfile->no_expand_level; + pfile->no_expand_level = context - pfile->contexts; + next = cpp_get_token (pfile); + restore_macro_expansion (pfile, prev_nme); + if (next->type != CPP_OPEN_PAREN) + { + _cpp_push_token (pfile, next); + if (CPP_OPTION (pfile, warn_traditional)) + cpp_warning (pfile, + "function macro %.*s must be used with arguments in traditional C", + (int) token->val.name.len, token->val.name.text); + return 1; + } + } + + return 0; +} + +/* Add a token to the set of tokens forming the arguments to the macro + being parsed in parse_args. */ +static void +save_token (args, token) + macro_args *args; + const cpp_token *token; +{ + if (args->used == args->capacity) + { + args->capacity += args->capacity + 100; + args->tokens = (const cpp_token **) + xrealloc (args->tokens, args->capacity * sizeof (const cpp_token *)); + } + args->tokens[args->used++] = token; +} + +/* Take and save raw tokens until we finish one argument. Empty + arguments are saved as a single CPP_PLACEMARKER token. */ +static const cpp_token * +parse_arg (pfile, var_args, paren_context, args, pcount) + cpp_reader *pfile; + int var_args; + unsigned int paren_context; + macro_args *args; + unsigned int *pcount; +{ + const cpp_token *token; + unsigned int paren = 0, count = 0; + int raw, was_raw = 1; + + for (count = 0;; count++) + { + token = cpp_get_token (pfile); + + switch (token->type) + { + default: + break; + + case CPP_OPEN_PAREN: + paren++; + break; + + case CPP_CLOSE_PAREN: + if (paren-- != 0) + break; + goto out; + + case CPP_COMMA: + /* Commas are not terminators within parantheses or var_args. */ + if (paren || var_args) + break; + goto out; + + case CPP_EOF: /* Error reported by caller. */ + goto out; + } + + raw = pfile->cur_context <= paren_context; + if (raw != was_raw) + { + was_raw = raw; + save_token (args, 0); + count++; + } + save_token (args, token); + } + + out: + if (count == 0) + { + /* Duplicate the placemarker. Then we can set its flags and + position and safely be using more than one. */ + save_token (args, duplicate_token (pfile, &placemarker_token)); + count++; + } + + *pcount = count; + return token; +} + +/* This macro returns true if the argument starting at offset O of arglist + A is empty - that is, it's either a single PLACEMARKER token, or a null + pointer followed by a PLACEMARKER. */ + +#define empty_argument(A, O) \ + ((A)->tokens[O] ? (A)->tokens[O]->type == CPP_PLACEMARKER \ + : (A)->tokens[(O)+1]->type == CPP_PLACEMARKER) + +/* Parse the arguments making up a macro invocation. Nested arguments + are automatically macro expanded, but immediate macros are not + expanded; this enables e.g. operator # to work correctly. Returns + non-zero on error. */ +static int +parse_args (pfile, hp, args) + cpp_reader *pfile; + cpp_hashnode *hp; + macro_args *args; +{ + const cpp_token *token; + const cpp_toklist *macro; + unsigned int total = 0; + unsigned int paren_context = pfile->cur_context; + int argc = 0; + + macro = hp->value.expansion; + do + { + unsigned int count; + + token = parse_arg (pfile, (argc + 1 == macro->paramc + && (macro->flags & VAR_ARGS)), + paren_context, args, &count); + if (argc < macro->paramc) + { + total += count; + args->ends[argc] = total; + } + argc++; + } + while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF); + + if (token->type == CPP_EOF) + { + cpp_error (pfile, "unterminated invocation of macro \"%.*s\"", + hp->length, hp->name); + return 1; + } + else if (argc < macro->paramc) + { + /* A rest argument is allowed to not appear in the invocation at all. + e.g. #define debug(format, args...) ... + debug("string"); + This is exactly the same as if the rest argument had received no + tokens - debug("string",); */ + + if (argc + 1 == macro->paramc && (macro->flags & VAR_ARGS)) + { + /* Duplicate the placemarker. Then we can set its flags and + position and safely be using more than one. */ + save_token (args, duplicate_token (pfile, &placemarker_token)); + args->ends[argc] = total + 1; + return 0; + } + else + { + cpp_error (pfile, + "insufficient arguments in invocation of macro \"%.*s\"", + hp->length, hp->name); + return 1; + } + } + /* An empty argument to an empty function-like macro is fine. */ + else if (argc > macro->paramc + && !(macro->paramc == 0 && argc == 1 && empty_argument (args, 0))) + { + cpp_error (pfile, + "too many arguments in invocation of macro \"%.*s\"", + hp->length, hp->name); + return 1; + } + + return 0; +} + +/* Adds backslashes before all backslashes and double quotes appearing + in strings. Non-printable characters are converted to octal. */ +static U_CHAR * +quote_string (dest, src, len) + U_CHAR *dest; + const U_CHAR *src; + unsigned int len; +{ + while (len--) + { + U_CHAR c = *src++; + + if (c == '\\' || c == '"') + { + *dest++ = '\\'; + *dest++ = c; + } + else + { + if (ISPRINT (c)) + *dest++ = c; + else + { + sprintf ((char *) dest, "\\%03o", c); + dest += 4; + } + } + } + + return dest; +} + +/* Allocates a buffer to hold a token's TEXT, and converts TOKEN to a + CPP_STRING token containing TEXT in quoted form. */ +static cpp_token * +make_string_token (token, text, len) + cpp_token *token; + const U_CHAR *text; + unsigned int len; +{ + U_CHAR *buf; + + buf = (U_CHAR *) xmalloc (len * 4); + token->type = CPP_STRING; + token->flags = 0; + token->val.name.text = buf; + token->val.name.len = quote_string (buf, text, len) - buf; + return token; +} + +/* Allocates and converts a temporary token to a CPP_NUMBER token, + evaluating to NUMBER. */ +static cpp_token * +alloc_number_token (pfile, number) + cpp_reader *pfile; + int number; +{ + cpp_token *result; + char *buf; + + result = get_temp_token (pfile); + buf = xmalloc (20); + sprintf (buf, "%d", number); + + result->type = CPP_NUMBER; + result->flags = 0; + result->val.name.text = (U_CHAR *) buf; + result->val.name.len = strlen (buf); + return result; +} + +/* Returns a temporary token from the temporary token store of PFILE. */ +static cpp_token * +get_temp_token (pfile) + cpp_reader *pfile; +{ + if (pfile->temp_used == pfile->temp_alloced) + { + if (pfile->temp_used == pfile->temp_cap) + { + pfile->temp_cap += pfile->temp_cap + 20; + pfile->temp_tokens = (cpp_token **) xrealloc + (pfile->temp_tokens, pfile->temp_cap * sizeof (cpp_token *)); + } + pfile->temp_tokens[pfile->temp_alloced++] = (cpp_token *) xmalloc + (sizeof (cpp_token)); + } + + return pfile->temp_tokens[pfile->temp_used++]; +} + +/* Release (not free) for re-use the temporary tokens of PFILE. */ +static void +release_temp_tokens (pfile) + cpp_reader *pfile; +{ + while (pfile->temp_used) + { + cpp_token *token = pfile->temp_tokens[--pfile->temp_used]; + + if (token_spellings[token->type].type > SPELL_NONE) + { + free ((char *) token->val.name.text); + token->val.name.text = 0; + } + } +} + +/* Free all of PFILE's dynamically-allocated temporary tokens. */ void -_cpp_lex_file (pfile) - cpp_reader* pfile; +_cpp_free_temp_tokens (pfile) + cpp_reader *pfile; { - cpp_toklist* list; + if (pfile->temp_tokens) + { + /* It is possible, though unlikely (looking for '(' of a funlike + macro into EOF), that we haven't released the tokens yet. */ + release_temp_tokens (pfile); + while (pfile->temp_alloced) + free (pfile->temp_tokens[--pfile->temp_alloced]); + free (pfile->temp_tokens); + } - init_trigraph_map (); - list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist)); - _cpp_init_toklist (list, DUMMY_TOKEN); + if (pfile->date) + { + free ((char *) pfile->date->val.name.text); + free (pfile->date); + free ((char *) pfile->time->val.name.text); + free (pfile->time); + } +} - for (;;) +/* Copy TOKEN into a temporary token from PFILE's store. */ +static cpp_token * +duplicate_token (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + cpp_token *result = get_temp_token (pfile); + + *result = *token; + if (token_spellings[token->type].type > SPELL_NONE) { - _cpp_lex_line (pfile, list); - if (list->tokens[0].type == CPP_EOF) - break; + U_CHAR *buff = (U_CHAR *) xmalloc (token->val.name.len); + memcpy (buff, token->val.name.text, token->val.name.len); + result->val.name.text = buff; + } + return result; +} + +/* Determine whether two tokens can be pasted together, and if so, + what the resulting token is. Returns CPP_EOF if the tokens cannot + be pasted, or the appropriate type for the merged token if they + can. */ +static enum cpp_ttype +can_paste (pfile, token1, token2, digraph) + cpp_reader * pfile; + const cpp_token *token1, *token2; + int* digraph; +{ + enum cpp_ttype a = token1->type, b = token2->type; + int cxx = CPP_OPTION (pfile, cplusplus); + + if (a <= CPP_LAST_EQ && b == CPP_EQ) + return a + (CPP_EQ_EQ - CPP_EQ); -#if 0 - if (list->dirno) - _cpp_handle_directive (pfile, list); + switch (a) + { + case CPP_GREATER: + if (b == a) return CPP_RSHIFT; + if (b == CPP_QUERY && cxx) return CPP_MAX; + if (b == CPP_GREATER_EQ) return CPP_RSHIFT_EQ; + break; + case CPP_LESS: + if (b == a) return CPP_LSHIFT; + if (b == CPP_QUERY && cxx) return CPP_MIN; + if (b == CPP_LESS_EQ) return CPP_LSHIFT_EQ; + if (b == CPP_COLON) + {*digraph = 1; return CPP_OPEN_SQUARE;} /* <: digraph */ + if (b == CPP_MOD) + {*digraph = 1; return CPP_OPEN_BRACE;} /* <% digraph */ + break; + + case CPP_PLUS: if (b == a) return CPP_PLUS_PLUS; break; + case CPP_AND: if (b == a) return CPP_AND_AND; break; + case CPP_OR: if (b == a) return CPP_OR_OR; break; + + case CPP_MINUS: + if (b == a) return CPP_MINUS_MINUS; + if (b == CPP_GREATER) return CPP_DEREF; + break; + case CPP_COLON: + if (b == a && cxx) return CPP_SCOPE; + if (b == CPP_GREATER) + {*digraph = 1; return CPP_CLOSE_SQUARE;} /* :> digraph */ + break; + + case CPP_MOD: + if (b == CPP_GREATER) + {*digraph = 1; return CPP_CLOSE_BRACE;} /* %> digraph */ + if (b == CPP_COLON) + {*digraph = 1; return CPP_HASH;} /* %: digraph */ + break; + case CPP_DEREF: + if (b == CPP_MULT && cxx) return CPP_DEREF_STAR; + break; + case CPP_DOT: + if (b == CPP_MULT && cxx) return CPP_DOT_STAR; + if (b == CPP_NUMBER) return CPP_NUMBER; + break; + + case CPP_HASH: + if (b == a && (token1->flags & DIGRAPH) == (token2->flags & DIGRAPH)) + /* %:%: digraph */ + {*digraph = (token1->flags & DIGRAPH); return CPP_PASTE;} + break; + + case CPP_NAME: + if (b == CPP_NAME) return CPP_NAME; + if (b == CPP_NUMBER + && is_numstart(token2->val.name.text[0])) return CPP_NAME; + if (b == CPP_CHAR + && token1->val.name.len == 1 + && token1->val.name.text[0] == 'L') return CPP_WCHAR; + if (b == CPP_STRING + && token1->val.name.len == 1 + && token1->val.name.text[0] == 'L') return CPP_WSTRING; + break; + + case CPP_NUMBER: + if (b == CPP_NUMBER) return CPP_NUMBER; + if (b == CPP_NAME) return CPP_NUMBER; + if (b == CPP_DOT) return CPP_NUMBER; + /* Numbers cannot have length zero, so this is safe. */ + if ((b == CPP_PLUS || b == CPP_MINUS) + && VALID_SIGN ('+', token1->val.name.text[token1->val.name.len - 1])) + return CPP_NUMBER; + break; + + default: + break; + } + + return CPP_EOF; +} + +/* Check if TOKEN is to be ##-pasted with the token after it. */ +static const cpp_token * +maybe_paste_with_next (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + cpp_token *pasted; + const cpp_token *second; + cpp_context *context = CURRENT_CONTEXT (pfile); + + /* Is this token on the LHS of ## ? */ + if (!((context->flags & CONTEXT_PASTEL) && context->posn == context->count) + && !(token->flags & PASTE_LEFT)) + return token; + + /* Prevent recursion, and possibly pushing back more than one token. */ + if (pfile->paste_level) + return token; + + /* Suppress macro expansion for next token, but don't conflict with + the other method of suppression. If it is an argument, macro + expansion within the argument will still occur. */ + pfile->paste_level = pfile->cur_context; + second = cpp_get_token (pfile); + pfile->paste_level = 0; + + /* Ignore placemarker argument tokens. */ + if (token->type == CPP_PLACEMARKER) + pasted = duplicate_token (pfile, second); + else if (second->type == CPP_PLACEMARKER) + { + /* GCC has special extended semantics for a ## b where b is a + varargs parameter: a disappears if b consists of no tokens. + This extension is deprecated. */ + if (token->flags & GNU_VARARGS) + { + cpp_warning (pfile, "deprecated GNU ## extension used"); + pasted = duplicate_token (pfile, second); + } else -#endif - _cpp_output_list (pfile, list); - _cpp_clear_toklist (list); + pasted = duplicate_token (pfile, token); + } + else + { + int digraph = 0; + enum cpp_ttype type = can_paste (pfile, token, second, &digraph); + + if (type == CPP_EOF) + { + if (CPP_OPTION (pfile, warn_paste)) + cpp_warning (pfile, + "pasting would not give a valid preprocessing token"); + _cpp_push_token (pfile, second); + return token; + } + + if (type == CPP_NAME || type == CPP_NUMBER) + { + /* Join spellings. */ + U_CHAR *buff, *buff2; + + pasted = get_temp_token (pfile); + buff = (U_CHAR *) xmalloc (TOKEN_LEN (token) + TOKEN_LEN (second)); + buff2 = spell_token (pfile, token, buff); + buff2 = spell_token (pfile, second, buff2); + + pasted->val.name.text = buff; + pasted->val.name.len = buff2 - buff; + } + else if (type == CPP_WCHAR || type == CPP_WSTRING) + pasted = duplicate_token (pfile, second); + else + { + pasted = get_temp_token (pfile); + pasted->val.integer = 0; + } + + pasted->type = type; + pasted->flags = digraph ? DIGRAPH: 0; } + + /* The pasted token gets the whitespace flags and position of the + first token, the PASTE_LEFT flag of the second token, plus the + PASTED flag to indicate it is the result of a paste. However, we + want to preserve the DIGRAPH flag. */ + pasted->flags &= ~(PREV_WHITE | BOL | PASTE_LEFT); + pasted->flags |= ((token->flags & (PREV_WHITE | BOL)) + | (second->flags & PASTE_LEFT) | PASTED); + pasted->col = token->col; + pasted->line = token->line; + + return maybe_paste_with_next (pfile, pasted); } -/* Temporary function for illustrative purposes. */ +/* Convert a token sequence to a single string token according to the + rules of the ISO C #-operator. */ +#define INIT_SIZE 200 +static cpp_token * +stringify_arg (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + cpp_token *result; + unsigned char *main_buf; + unsigned int prev_value, backslash_count = 0; + unsigned int buf_used = 0, whitespace = 0, buf_cap = INIT_SIZE; + + prev_value = prevent_macro_expansion (pfile); + main_buf = (unsigned char *) xmalloc (buf_cap); + + result = get_temp_token (pfile); + ASSIGN_FLAGS_AND_POS (result, token); + + for (; (token = cpp_get_token (pfile))->type != CPP_EOF; ) + { + int escape; + unsigned char *buf; + unsigned int len = TOKEN_LEN (token); + + escape = (token->type == CPP_STRING || token->type == CPP_WSTRING + || token->type == CPP_CHAR || token->type == CPP_WCHAR); + if (escape) + len *= 4 + 1; + + if (buf_used + len > buf_cap) + { + buf_cap = buf_used + len + INIT_SIZE; + main_buf = xrealloc (main_buf, buf_cap); + } + + if (whitespace && (token->flags & PREV_WHITE)) + main_buf[buf_used++] = ' '; + + if (escape) + buf = (unsigned char *) xmalloc (len); + else + buf = main_buf + buf_used; + + len = spell_token (pfile, token, buf) - buf; + if (escape) + { + buf_used = quote_string (&main_buf[buf_used], buf, len) - main_buf; + free (buf); + } + else + buf_used += len; + + whitespace = 1; + if (token->type == CPP_BACKSLASH) + backslash_count++; + else + backslash_count = 0; + } + + /* Ignore the final \ of invalid string literals. */ + if (backslash_count & 1) + { + cpp_warning (pfile, "invalid string literal, ignoring final '\\'"); + buf_used--; + } + + result->type = CPP_STRING; + result->val.name.text = main_buf; + result->val.name.len = buf_used; + restore_macro_expansion (pfile, prev_value); + return result; +} + +/* Allocate more room on the context stack of PFILE. */ static void -_cpp_output_list (pfile, list) +expand_context_stack (pfile) cpp_reader *pfile; - cpp_toklist *list; { - unsigned int i; + pfile->context_cap += pfile->context_cap + 20; + pfile->contexts = (cpp_context *) + xrealloc (pfile->contexts, pfile->context_cap * sizeof (cpp_context)); +} + +/* Push the context of macro NODE onto the context stack. TOKEN is + the CPP_NAME token invoking the macro. */ +static const cpp_token * +push_macro_context (pfile, node, token) + cpp_reader *pfile; + cpp_hashnode *node; + const cpp_token *token; +{ + unsigned char orig_flags; + macro_args *args; + cpp_context *context; - for (i = 0; i < list->tokens_used; i++) + if (pfile->cur_context > CPP_STACK_MAX) { - CPP_RESERVE (pfile, TOKEN_LEN (&list->tokens[i])); - pfile->limit = spell_token (pfile, &list->tokens[i], pfile->limit, 1); + cpp_error (pfile, "infinite macro recursion invoking '%s'", node->name); + return token; + } + + /* Token's flags may change when parsing args containing a nested + invocation of this macro. */ + orig_flags = token->flags & (PREV_WHITE | BOL); + args = 0; + if (node->value.expansion->paramc >= 0) + { + unsigned int error, prev_nme; + + /* Allocate room for the argument contexts, and parse them. */ + args = (macro_args *) xmalloc (sizeof (macro_args)); + args->ends = (unsigned int *) + xmalloc (node->value.expansion->paramc * sizeof (unsigned int)); + args->tokens = 0; + args->capacity = 0; + args->used = 0; + args->level = pfile->cur_context; + + prev_nme = prevent_macro_expansion (pfile); + pfile->args = args; + error = parse_args (pfile, node, args); + pfile->args = 0; + restore_macro_expansion (pfile, prev_nme); + if (error) + { + free_macro_args (args); + return token; + } + } + + /* Now push its context. */ + pfile->cur_context++; + if (pfile->cur_context == pfile->context_cap) + expand_context_stack (pfile); + + context = CURRENT_CONTEXT (pfile); + context->u.list = node->value.expansion; + context->args = args; + context->posn = 0; + context->count = context->u.list->tokens_used; + context->level = pfile->cur_context; + context->flags = 0; + context->pushed_token = 0; + + /* Set the flags of the first token. We know there must + be one, empty macros are a single placemarker token. */ + MODIFY_FLAGS_AND_POS (&context->u.list->tokens[0], token, orig_flags); + + return cpp_get_token (pfile); +} + +/* Push an argument to the current macro onto the context stack. + TOKEN is the MACRO_ARG token representing the argument expansion. */ +static const cpp_token * +push_arg_context (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + cpp_context *context; + macro_args *args; + + pfile->cur_context++; + if (pfile->cur_context == pfile->context_cap) + expand_context_stack (pfile); + + context = CURRENT_CONTEXT (pfile); + args = context[-1].args; + + context->count = token->val.aux ? args->ends[token->val.aux - 1]: 0; + context->u.arg = args->tokens + context->count; + context->count = args->ends[token->val.aux] - context->count; + context->args = 0; + context->posn = 0; + context->level = args->level; + context->flags = CONTEXT_ARG | CONTEXT_RAW; + context->pushed_token = 0; + + /* Set the flags of the first token. There is one. */ + { + const cpp_token *first = context->u.arg[0]; + if (!first) + first = context->u.arg[1]; + + MODIFY_FLAGS_AND_POS ((cpp_token *) first, token, + token->flags & (PREV_WHITE | BOL)); + } + + if (token->flags & STRINGIFY_ARG) + return stringify_arg (pfile, token); + + if (token->flags & PASTE_LEFT) + context->flags |= CONTEXT_PASTEL; + if (pfile->paste_level) + context->flags |= CONTEXT_PASTER; + + return get_raw_token (pfile); +} + +/* "Unget" a token. It is effectively inserted in the token queue and + will be returned by the next call to get_raw_token. */ +void +_cpp_push_token (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + cpp_context *context = CURRENT_CONTEXT (pfile); + if (context->pushed_token) + cpp_ice (pfile, "two tokens pushed in a row"); + if (token->type != CPP_EOF) + context->pushed_token = token; + /* Don't push back a directive's CPP_EOF, step back instead. */ + else if (pfile->cur_context == 0) + pfile->contexts[0].posn--; +} + +/* Handle a preprocessing directive. TOKEN is the CPP_HASH token + introducing the directive. */ +static void +process_directive (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + const struct directive *d = pfile->token_list.directive; + int prev_nme = 0; + + /* Skip over the directive name. */ + if (token[1].type == CPP_NAME) + _cpp_get_raw_token (pfile); + else if (token[1].type != CPP_NUMBER) + cpp_ice (pfile, "directive begins with %s?!", + token_names[token[1].type]); + + /* Flush pending tokens at this point, in case the directive produces + output. XXX Directive output won't be visible to a direct caller of + cpp_get_token. */ + if (pfile->printer && CPP_WRITTEN (pfile) - pfile->printer->written) + cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line); + + if (! (d->flags & EXPAND)) + prev_nme = prevent_macro_expansion (pfile); + (void) (*d->handler) (pfile); + if (! (d->flags & EXPAND)) + restore_macro_expansion (pfile, prev_nme); + _cpp_skip_rest_of_line (pfile); +} + +/* The external interface to return the next token. All macro + expansion and directive processing is handled internally, the + caller only ever sees the output after preprocessing. */ +const cpp_token * +cpp_get_token (pfile) + cpp_reader *pfile; +{ + const cpp_token *token; + cpp_hashnode *node; + + /* Loop till we hit a non-directive, non-skipped, non-placemarker token. */ + for (;;) + { + token = get_raw_token (pfile); + if (token->flags & BOL && token->type == CPP_HASH + && pfile->token_list.directive) + { + process_directive (pfile, token); + continue; + } + + /* Short circuit EOF. */ + if (token->type == CPP_EOF) + return token; + + if (pfile->skipping && ! pfile->token_list.directive) + { + _cpp_skip_rest_of_line (pfile); + continue; + } + break; } + + /* If there's a potential control macro and we get here, then that + #ifndef didn't cover the entire file and its argument shouldn't + be taken as a control macro. */ + pfile->potential_control_macro = 0; + + token = maybe_paste_with_next (pfile, token); + + if (token->type != CPP_NAME) + return token; + + /* Is macro expansion disabled in general? */ + if (pfile->no_expand_level == pfile->cur_context || pfile->paste_level) + return token; + + node = cpp_lookup (pfile, token->val.name.text, token->val.name.len); + if (node->type == T_VOID) + return token; + + if (node->type == T_MACRO) + { + if (is_macro_disabled (pfile, node->value.expansion, token)) + return token; + + return push_macro_context (pfile, node, token); + } + else + return special_symbol (pfile, node, token); } +/* Returns the next raw token, i.e. without performing macro + expansion. Argument contexts are automatically entered. */ +static const cpp_token * +get_raw_token (pfile) + cpp_reader *pfile; +{ + const cpp_token *result; + cpp_context *context = CURRENT_CONTEXT (pfile); + + if (context->pushed_token) + { + result = context->pushed_token; + context->pushed_token = 0; + } + else if (context->posn == context->count) + result = pop_context (pfile); + else + { + if (IS_ARG_CONTEXT (context)) + { + result = context->u.arg[context->posn++]; + if (result == 0) + { + context->flags ^= CONTEXT_RAW; + result = context->u.arg[context->posn++]; + } + return result; /* Cannot be a CPP_MACRO_ARG */ + } + result = &context->u.list->tokens[context->posn++]; + } + + if (result->type == CPP_MACRO_ARG) + result = push_arg_context (pfile, result); + return result; +} + +/* Internal interface to get the token without macro expanding. */ +const cpp_token * +_cpp_get_raw_token (pfile) + cpp_reader *pfile; +{ + int prev_nme = prevent_macro_expansion (pfile); + const cpp_token *result = cpp_get_token (pfile); + restore_macro_expansion (pfile, prev_nme); + return result; +} + +/* A thin wrapper to lex_line. CLEAR is non-zero if the current token + list should be overwritten, or zero if we need to append + (typically, if we are within the arguments to a macro, or looking + for the '(' to start a function-like macro invocation). */ +static int +lex_next (pfile, clear) + cpp_reader *pfile; + int clear; +{ + cpp_toklist *list = &pfile->token_list; + const cpp_token *old_list = list->tokens; + unsigned int old_used = list->tokens_used; + + if (clear) + { + /* Release all temporary tokens. */ + _cpp_clear_toklist (list); + pfile->contexts[0].posn = 0; + if (pfile->temp_used) + release_temp_tokens (pfile); + } + else + { + /* If we are currently processing a directive, do not advance. + (6.10 paragraph 2: A new-line character ends the directive + even if it occurs within what would otherwise be an + invocation of a function-like macro.) */ + if (list->directive) + return 1; + } + + lex_line (pfile, list); + pfile->contexts[0].count = list->tokens_used; + + if (!clear && pfile->args) + { + /* Fix up argument token pointers. */ + if (old_list != list->tokens) + { + unsigned int i; + + for (i = 0; i < pfile->args->used; i++) + { + const cpp_token *token = pfile->args->tokens[i]; + if (token >= old_list && token < old_list + old_used) + pfile->args->tokens[i] = (const cpp_token *) + ((char *) token + ((char *) list->tokens - (char *) old_list)); + } + } + + /* 6.10.3 paragraph 11: If there are sequences of preprocessing + tokens within the list of arguments that would otherwise act as + preprocessing directives, the behavior is undefined. + + This implementation will report a hard error and treat the + 'sequence of preprocessing tokens' as part of the macro argument, + not a directive. + + Note if pfile->args == 0, we're OK since we're only inside a + macro argument after a '('. */ + if (list->directive) + { + cpp_error_with_line (pfile, list->tokens[old_used].line, + list->tokens[old_used].col, + "#%s may not be used inside a macro argument", + list->directive->name); + /* Don't treat as a directive: clear list->directive, + prune the final EOF from the list. */ + list->directive = 0; + list->tokens_used--; + pfile->contexts[0].count--; + } + } + + return 0; +} + +/* Pops a context of the context stack. If we're at the bottom, lexes + the next logical line. Returns 1 if we're at the end of the + argument list to the # operator, or if it is illegal to "overflow" + into the rest of the file (e.g. 6.10.3.1.1). */ +static int +do_pop_context (pfile) + cpp_reader *pfile; +{ + cpp_context *context; + + if (pfile->cur_context == 0) + return lex_next (pfile, pfile->no_expand_level == UINT_MAX); + + /* Argument contexts, when parsing args or handling # operator + return CPP_EOF at the end. */ + context = CURRENT_CONTEXT (pfile); + if (IS_ARG_CONTEXT (context) && pfile->cur_context == pfile->no_expand_level) + return 1; + + /* Free resources when leaving macro contexts. */ + if (context->args) + free_macro_args (context->args); + + if (pfile->cur_context == pfile->no_expand_level) + pfile->no_expand_level--; + pfile->cur_context--; + + return 0; +} + +/* Move down the context stack, and return the next raw token. */ +static const cpp_token * +pop_context (pfile) + cpp_reader *pfile; +{ + if (do_pop_context (pfile)) + return &eof_token; + return get_raw_token (pfile); +} + +/* Turn off macro expansion at the current context level. */ +static unsigned int +prevent_macro_expansion (pfile) + cpp_reader *pfile; +{ + unsigned int prev_value = pfile->no_expand_level; + pfile->no_expand_level = pfile->cur_context; + return prev_value; +} + +/* Restore macro expansion to its previous state. */ +static void +restore_macro_expansion (pfile, prev_value) + cpp_reader *pfile; + unsigned int prev_value; +{ + pfile->no_expand_level = prev_value; +} + +/* Used by cpperror.c to obtain the correct line and column to report + in a diagnostic. */ +unsigned int +_cpp_get_line (pfile, pcol) + cpp_reader *pfile; + unsigned int *pcol; +{ + unsigned int index; + const cpp_token *cur_token; + + if (pfile->in_lex_line) + index = pfile->token_list.tokens_used; + else + index = pfile->contexts[0].posn; + + cur_token = &pfile->token_list.tokens[index - 1]; + if (pcol) + *pcol = cur_token->col; + return cur_token->line; +} + +#define DSC(str) (const U_CHAR *)str, sizeof str - 1 +static const char * const monthnames[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +/* Handle builtin macros like __FILE__. */ +static const cpp_token * +special_symbol (pfile, node, token) + cpp_reader *pfile; + cpp_hashnode *node; + const cpp_token *token; +{ + cpp_token *result; + cpp_buffer *ip; + + switch (node->type) + { + case T_FILE: + case T_BASE_FILE: + { + const char *file; + + ip = CPP_BUFFER (pfile); + if (ip == 0) + file = ""; + else + { + if (node->type == T_BASE_FILE) + while (CPP_PREV_BUFFER (ip) != NULL) + ip = CPP_PREV_BUFFER (ip); + + file = ip->nominal_fname; + } + result = make_string_token (get_temp_token (pfile), (U_CHAR *) file, + strlen (file)); + } + break; + + case T_INCLUDE_LEVEL: + { + int true_indepth = 0; + + /* Do not count the primary source file in the include level. */ + ip = CPP_PREV_BUFFER (CPP_BUFFER (pfile)); + while (ip) + { + true_indepth++; + ip = CPP_PREV_BUFFER (ip); + } + result = alloc_number_token (pfile, true_indepth); + } + break; + + case T_SPECLINE: + /* If __LINE__ is embedded in a macro, it must expand to the + line of the macro's invocation, not its definition. + Otherwise things like assert() will not work properly. */ + result = alloc_number_token (pfile, _cpp_get_line (pfile, NULL)); + break; + + case T_STDC: + { + int stdc = 1; + +#ifdef STDC_0_IN_SYSTEM_HEADERS + if (CPP_IN_SYSTEM_HEADER (pfile) + && !cpp_defined (pfile, DSC("__STRICT_ANSI__"))) + stdc = 0; #endif + result = alloc_number_token (pfile, stdc); + } + break; + + case T_DATE: + case T_TIME: + if (pfile->date == 0) + { + /* Allocate __DATE__ and __TIME__ from permanent storage, + and save them in pfile so we don't have to do this again. + We don't generate these strings at init time because + time() and localtime() are very slow on some systems. */ + time_t tt = time (NULL); + struct tm *tb = localtime (&tt); + + pfile->date = make_string_token + ((cpp_token *) xmalloc (sizeof (cpp_token)), DSC("Oct 11 1347")); + pfile->time = make_string_token + ((cpp_token *) xmalloc (sizeof (cpp_token)), DSC("12:34:56")); + + sprintf ((char *) pfile->date->val.name.text, "%s %2d %4d", + monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900); + sprintf ((char *) pfile->time->val.name.text, "%02d:%02d:%02d", + tb->tm_hour, tb->tm_min, tb->tm_sec); + } + result = node->type == T_DATE ? pfile->date: pfile->time; + break; + + case T_POISON: + cpp_error (pfile, "attempt to use poisoned \"%s\".", node->name); + return token; + + default: + cpp_ice (pfile, "invalid special hash type"); + return token; + } + + ASSIGN_FLAGS_AND_POS (result, token); + return result; +} +#undef DSC + +/* Dump the original user's spelling of argument index ARG_NO to the + macro whose expansion is LIST. */ +static void +dump_param_spelling (pfile, list, arg_no) + cpp_reader *pfile; + const cpp_toklist *list; + unsigned int arg_no; +{ + const U_CHAR *param = list->namebuf; + + while (arg_no--) + param += ustrlen (param) + 1; + CPP_PUTS (pfile, param, ustrlen (param)); +} + +/* Dump a token list to the output. */ +void +_cpp_dump_list (pfile, list, token, flush) + cpp_reader *pfile; + const cpp_toklist *list; + const cpp_token *token; + int flush; +{ + const cpp_token *limit = list->tokens + list->tokens_used; + const cpp_token *prev = 0; + + /* Avoid the CPP_EOF. */ + if (list->directive) + limit--; + + while (token < limit) + { + if (token->type == CPP_MACRO_ARG) + { + if (token->flags & PREV_WHITE) + CPP_PUTC (pfile, ' '); + if (token->flags & STRINGIFY_ARG) + CPP_PUTC (pfile, '#'); + dump_param_spelling (pfile, list, token->val.aux); + } + else + output_token (pfile, token, prev); + if (token->flags & PASTE_LEFT) + CPP_PUTS (pfile, " ##", 3); + prev = token; + token++; + } + + if (flush && pfile->printer) + cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line); +} + +/* Stub function during conversion, mainly for cppexp.c's benefit. */ +enum cpp_ttype +_cpp_get_directive_token (pfile) + cpp_reader *pfile; +{ + const cpp_token *tok; + + if (pfile->no_macro_expand) + tok = _cpp_get_raw_token (pfile); + else + tok = cpp_get_token (pfile); + + if (tok->type == CPP_EOF) + return CPP_VSPACE; /* backward compat; and don't try to spell EOF */ + + CPP_RESERVE (pfile, TOKEN_LEN (tok)); + pfile->limit = spell_token (pfile, tok, pfile->limit); + return tok->type; +} + +/* Allocate pfile->input_buffer, and initialize trigraph_map[] + if it hasn't happened already. */ + +void +_cpp_init_input_buffer (pfile) + cpp_reader *pfile; +{ + init_trigraph_map (); + pfile->context_cap = 20; + pfile->contexts = (cpp_context *) + xmalloc (pfile->context_cap * sizeof (cpp_context)); + pfile->cur_context = 0; + pfile->contexts[0].u.list = &pfile->token_list; + + pfile->contexts[0].posn = 0; + pfile->contexts[0].count = 0; + pfile->no_expand_level = UINT_MAX; + + _cpp_init_toklist (&pfile->token_list, DUMMY_TOKEN); +} + +/* Moves to the end of the directive line, popping contexts as + necessary. */ +void +_cpp_skip_rest_of_line (pfile) + cpp_reader *pfile; +{ + /* Get to base context. Clear parsing args and each contexts flags, + since these can cause pop_context to return without popping. */ + pfile->no_expand_level = UINT_MAX; + while (pfile->cur_context != 0) + { + pfile->contexts[pfile->cur_context].flags = 0; + do_pop_context (pfile); + } + + pfile->contexts[pfile->cur_context].count = 0; + pfile->contexts[pfile->cur_context].posn = 0; + pfile->token_list.directive = 0; +} + +/* Directive handler wrapper used by the command line option + processor. */ +void +_cpp_run_directive (pfile, dir, buf, count) + cpp_reader *pfile; + const struct directive *dir; + const char *buf; + size_t count; +{ + if (cpp_push_buffer (pfile, (const U_CHAR *)buf, count) != NULL) + { + unsigned int prev_lvl = 0; + /* scan the line now, else prevent_macro_expansion won't work */ + do_pop_context (pfile); + if (! (dir->flags & EXPAND)) + prev_lvl = prevent_macro_expansion (pfile); + + (void) (*dir->handler) (pfile); + + if (! (dir->flags & EXPAND)) + restore_macro_expansion (pfile, prev_lvl); + + _cpp_skip_rest_of_line (pfile); + cpp_pop_buffer (pfile); + } +} diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 26396df..9e8c4c7 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -27,23 +27,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "intl.h" #include "symcat.h" -/* `struct directive' defines one #-directive, including how to handle it. */ - -struct directive -{ - directive_handler func; /* Function to handle directive. */ - const U_CHAR *name; /* Name of directive. */ - unsigned short length; /* Length of name. */ - unsigned short flags; /* Flags describing this directive. */ -}; - /* Stack of conditionals currently in progress (including both successful and failing conditionals). */ struct if_stack { struct if_stack *next; - int lineno; /* line number where condition started */ + unsigned int lineno; /* line number where condition started */ + unsigned int colno; /* and column */ int was_skipping; /* value of pfile->skipping before this if */ const cpp_hashnode *cmacro; /* macro name for #ifndef around entire file */ int type; /* type of last directive seen in this group */ @@ -51,30 +42,26 @@ struct if_stack /* Forward declarations. */ -static void validate_else PARAMS ((cpp_reader *, const U_CHAR *)); -static unsigned int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int)); -static void push_conditional PARAMS ((cpp_reader *, int, int, - const cpp_hashnode *)); -static void pass_thru_directive PARAMS ((const U_CHAR *, size_t, - cpp_reader *, int)); -static int read_line_number PARAMS ((cpp_reader *, int *)); -static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *)); -static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *)); - -/* Values for the flags field of the table below. KANDR and COND - directives come from traditional (K&R) C. The difference is, if we - care about it while skipping a failed conditional block, its origin - is COND. STDC89 directives come from the 1989 C standard. - EXTENSION directives are extensions, with origins noted below. */ +static void validate_else PARAMS ((cpp_reader *, const U_CHAR *)); +static int parse_include PARAMS ((cpp_reader *, const U_CHAR *, int, + const U_CHAR **, unsigned int *, + int *)); +static void push_conditional PARAMS ((cpp_reader *, int, int, + const cpp_hashnode *)); +static void pass_thru_directive PARAMS ((cpp_reader *)); +static int read_line_number PARAMS ((cpp_reader *, int *)); +static int strtoul_for_line PARAMS ((const U_CHAR *, unsigned int, + unsigned long *)); -#define KANDR 0 -#define COND 1 -#define STDC89 2 -#define EXTENSION 3 +static const cpp_hashnode *parse_ifdef PARAMS ((cpp_reader *, const U_CHAR *)); +static const cpp_hashnode *detect_if_not_defined + PARAMS ((cpp_reader *)); +static cpp_hashnode *get_define_node PARAMS ((cpp_reader *)); +static void dump_macro_name PARAMS ((cpp_reader *, cpp_hashnode *)); -#define ORIGIN_MASK 3 -#define ORIGIN(f) ((f) & ORIGIN_MASK) -#define TRAD_DIRECT_P(f) (ORIGIN (f) == KANDR || ORIGIN (f) == COND) +/* Utility. */ +#define str_match(sym, len, str) \ +((len) == (sizeof (str) - 1) && !ustrncmp ((sym), U(str), sizeof (str) - 1)) /* This is the table of directive handlers. It is ordered by frequency of occurrence; the numbers at the end are directive @@ -88,31 +75,31 @@ static const cpp_hashnode *detect_if_not_defined PARAMS ((cpp_reader *)); /* #sccs is not always recognized. */ #ifdef SCCS_DIRECTIVE -# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION) /* 0 - SVR2? */ +# define SCCS_ENTRY D(sccs, T_SCCS, EXTENSION, 0) #else # define SCCS_ENTRY /* nothing */ #endif -#define DIRECTIVE_TABLE \ -D(define, T_DEFINE = 0, KANDR) /* 270554 */ \ -D(include, T_INCLUDE, KANDR | SYNTAX_INCLUDE) /* 52262 */ \ -D(endif, T_ENDIF, COND) /* 45855 */ \ -D(ifdef, T_IFDEF, COND) /* 22000 */ \ -D(if, T_IF, COND) /* 18162 */ \ -D(else, T_ELSE, COND) /* 9863 */ \ -D(ifndef, T_IFNDEF, COND) /* 9675 */ \ -D(undef, T_UNDEF, KANDR) /* 4837 */ \ -D(line, T_LINE, KANDR) /* 2465 */ \ -D(elif, T_ELIF, COND) /* 610 */ \ -D(error, T_ERROR, STDC89) /* 475 */ \ -D(pragma, T_PRAGMA, STDC89) /* 195 */ \ -D(warning, T_WARNING, EXTENSION) /* 22 GNU */ \ -D(include_next, T_INCLUDE_NEXT, EXTENSION | SYNTAX_INCLUDE) /* 19 GNU */ \ -D(ident, T_IDENT, EXTENSION) /* 11 SVR4 */ \ -D(import, T_IMPORT, EXTENSION | SYNTAX_INCLUDE) /* 0 ObjC */ \ -D(assert, T_ASSERT, EXTENSION) /* 0 SVR4 */ \ -D(unassert, T_UNASSERT, EXTENSION) /* 0 SVR4 */ \ -SCCS_ENTRY +#define DIRECTIVE_TABLE \ +D(define, T_DEFINE = 0, KANDR, COMMENTS) /* 270554 */ \ +D(include, T_INCLUDE, KANDR, EXPAND | INCL) /* 52262 */ \ +D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \ +D(ifdef, T_IFDEF, KANDR, COND) /* 22000 */ \ +D(if, T_IF, KANDR, COND | EXPAND) /* 18162 */ \ +D(else, T_ELSE, KANDR, COND) /* 9863 */ \ +D(ifndef, T_IFNDEF, KANDR, COND) /* 9675 */ \ +D(undef, T_UNDEF, KANDR, 0) /* 4837 */ \ +D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \ +D(elif, T_ELIF, KANDR, COND | EXPAND) /* 610 */ \ +D(error, T_ERROR, STDC89, 0) /* 475 */ \ +D(pragma, T_PRAGMA, STDC89, 0) /* 195 */ \ +D(warning, T_WARNING, EXTENSION, 0) /* 22 GNU */ \ +D(include_next, T_INCLUDE_NEXT, EXTENSION, EXPAND | INCL) /* 19 GNU */ \ +D(ident, T_IDENT, EXTENSION, 0) /* 11 SVR4 */ \ +D(import, T_IMPORT, EXTENSION, EXPAND | INCL) /* 0 ObjC */ \ +D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \ +D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \ +SCCS_ENTRY /* 0 SVR2? */ /* Use the table to generate a series of prototypes, an enum for the directive names, and an array of directive handlers. */ @@ -122,11 +109,11 @@ SCCS_ENTRY pointers to functions returning void. */ /* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */ -#define D(name, t, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *)); +#define D(name, t, o, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *)); DIRECTIVE_TABLE #undef D -#define D(n, tag, f) tag, +#define D(n, tag, o, f) tag, enum { DIRECTIVE_TABLE @@ -135,9 +122,9 @@ enum #undef D /* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */ -#define D(name, t, flags) \ +#define D(name, t, origin, flags) \ { CONCAT2(do_,name), (const U_CHAR *) STRINGX(name), \ - sizeof STRINGX(name) - 1, flags }, + sizeof STRINGX(name) - 1, origin, flags }, static const struct directive dtable[] = { DIRECTIVE_TABLE @@ -147,292 +134,237 @@ DIRECTIVE_TABLE /* Check if a token's name matches that of a known directive. Put in this file to save exporting dtable and other unneeded information. */ -void -_cpp_check_directive (list, token) - cpp_toklist *list; - cpp_token *token; +const struct directive * +_cpp_check_directive (pfile, token, bol) + cpp_reader *pfile; + const cpp_token *token; + int bol; { const U_CHAR *name = token->val.name.text; size_t len = token->val.name.len; unsigned int i; - list->dirno = -1; - list->flags &= ~SYNTAX_INCLUDE; + /* If we are rescanning preprocessed input, don't obey any directives + other than # nnn. */ + if (CPP_OPTION (pfile, preprocessed)) + return 0; for (i = 0; i < N_DIRECTIVES; i++) - if (dtable[i].length == len && !ustrncmp (dtable[i].name, name, len)) + if (dtable[i].length == len && !memcmp (dtable[i].name, name, len)) { - list->dirno = i; - if (dtable[i].flags & SYNTAX_INCLUDE) - list->flags |= SYNTAX_INCLUDE; - break; + /* If we are skipping a failed conditional group, all non-conditional + directives are ignored. */ + if (pfile->skipping && !(dtable[i].flags & COND)) + return 0; + + /* In -traditional mode, a directive is ignored unless its # + is in column 1. */ + if (!bol && dtable[i].origin == KANDR && CPP_WTRADITIONAL (pfile)) + cpp_warning (pfile, "traditional C ignores #%s with the # indented", + dtable[i].name); + + if (!bol && CPP_TRADITIONAL (pfile)) + return 0; + + /* Issue -pedantic warnings for extended directives. */ + if (CPP_PEDANTIC (pfile) && dtable[i].origin == EXTENSION) + cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name); + + /* -Wtraditional gives warnings about directives with inappropriate + indentation of #. */ + if (bol && dtable[i].origin != KANDR && CPP_WTRADITIONAL (pfile)) + cpp_warning (pfile, + "suggest hiding #%s from traditional C with an indented #", + dtable[i].name); + + return &dtable[i]; } -} -/* Handle a possible # directive. - '#' has already been read. */ + return 0; +} -int -_cpp_handle_directive (pfile) +const struct directive * +_cpp_check_linemarker (pfile, token, bol) cpp_reader *pfile; + const cpp_token *token ATTRIBUTE_UNUSED; + int bol; { - int i; - int hash_at_bol; - unsigned int len; - U_CHAR *ident; - long old_written = CPP_WRITTEN (pfile); - enum cpp_ttype tok; - - if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile))) - { - cpp_ice (pfile, "handle_directive called on macro buffer"); - return 0; - } - - /* -traditional directives are recognized only with the # in column 1. */ - hash_at_bol = CPP_IN_COLUMN_1 (pfile); - - /* Scan the next token, then pretend we didn't. */ - CPP_SET_MARK (pfile); - pfile->no_macro_expand++; - tok = _cpp_get_directive_token (pfile); - pfile->no_macro_expand--; - - ident = pfile->token_buffer + old_written; - len = CPP_PWRITTEN (pfile) - ident; - CPP_SET_WRITTEN (pfile, old_written); - CPP_GOTO_MARK (pfile); - /* # followed by a number is equivalent to #line. Do not recognize this form in assembly language source files or skipped conditional groups. Complain about this form if we're being pedantic, but not if this is regurgitated input (preprocessed or fed back in by the C++ frontend). */ - if (tok == CPP_NUMBER) - { - if (pfile->skipping || CPP_OPTION (pfile, lang_asm)) - return 0; - - if (CPP_PEDANTIC (pfile) - && CPP_BUFFER (pfile)->inc - && ! CPP_OPTION (pfile, preprocessed)) - cpp_pedwarn (pfile, "# followed by integer"); - i = T_LINE; - goto process_directive; - } + if (pfile->skipping || CPP_OPTION (pfile, lang_asm)) + return 0; - /* If we are rescanning preprocessed input, don't obey any directives - other than # nnn. */ - else if (CPP_OPTION (pfile, preprocessed)) + if (CPP_PEDANTIC (pfile) && CPP_BUFFER (pfile)->inc + && ! CPP_OPTION (pfile, preprocessed)) + cpp_pedwarn (pfile, "# followed by integer"); + + /* In -traditional mode, a directive is ignored unless its # + is in column 1. */ + if (!bol && CPP_WTRADITIONAL (pfile)) + cpp_warning (pfile, "traditional C ignores #%s with the # indented", + dtable[T_LINE].name); + + if (!bol && CPP_TRADITIONAL (pfile)) return 0; + + return &dtable[T_LINE]; +} - /* A line of just # becomes blank. */ - else if (tok == CPP_VSPACE) - return 1; +static void +dump_macro_name (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + CPP_PUTS (pfile, "#define ", sizeof "#define " - 1); + CPP_PUTS (pfile, node->name, node->length); +} - /* A NAME token might in fact be a directive! */ - else if (tok == CPP_NAME) - { - for (i = 0; i < N_DIRECTIVES; i++) - { - if (dtable[i].length == len - && !ustrncmp (dtable[i].name, ident, len)) - goto real_directive; - } - /* Don't complain about invalid directives in assembly source, - we don't know where the comments are, and # may introduce - assembler pseudo-ops. Don't complain about invalid directives - in skipped conditional groups (6.10 p4). */ - if (!pfile->skipping && !CPP_OPTION (pfile, lang_asm)) - cpp_error (pfile, "invalid preprocessing directive #%.*s", - (int) len, ident); - return 0; - } - /* And anything else means the # wasn't a directive marker. */ - else - return 0; +/* Pass the current directive through to the output file. */ +static void +pass_thru_directive (pfile) + cpp_reader *pfile; +{ + /* XXX This output may be genuinely needed even when there is no + printer. */ + if (! pfile->printer) + return; + /* Flush first (temporary). */ + cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line); + _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 1); +} - real_directive: +static cpp_hashnode * +get_define_node (pfile) + cpp_reader *pfile; +{ + cpp_hashnode *node; + const cpp_token *token; + const U_CHAR *sym; + unsigned int len; - /* If we are skipping a failed conditional group, all non-conditional - directives are ignored. */ - if (pfile->skipping && ORIGIN (dtable[i].flags) != COND) - return 0; + /* Skip any -C comments. */ + while ((token = cpp_get_token (pfile))->type == CPP_COMMENT) + ; - /* In -traditional mode, a directive is ignored unless its # is in - column 1. */ - if (CPP_TRADITIONAL (pfile) && !hash_at_bol) + if (token->type != CPP_NAME) { - if (CPP_WTRADITIONAL (pfile)) - cpp_warning (pfile, "ignoring #%s because of its indented #", - dtable[i].name); + cpp_error_with_line (pfile, pfile->token_list.line, token->col, + "macro names must be identifiers"); return 0; } - /* no_directives is set when we are parsing macro arguments. Directives - in macro arguments are undefined behavior (C99 6.10.3.11); this - implementation chooses to make them hard errors. */ - if (pfile->no_directives) + /* That identifier is not allowed to be "defined". See predefined + macro names (6.10.8.4). */ + len = token->val.name.len; + sym = token->val.name.text; + if (str_match (sym, len, "defined")) { - cpp_error (pfile, "#%s may not be used inside a macro argument", - dtable[i].name); - _cpp_skip_rest_of_line (pfile); - return 1; + cpp_error_with_line (pfile, pfile->token_list.line, token->col, + "\"defined\" is not a legal macro name"); + return 0; } - /* Issue -pedantic warnings for extended directives. */ - if (CPP_PEDANTIC (pfile) && ORIGIN (dtable[i].flags) == EXTENSION) - cpp_pedwarn (pfile, "ISO C does not allow #%s", dtable[i].name); - - /* -Wtraditional gives warnings about directives with inappropriate - indentation of #. */ - if (CPP_WTRADITIONAL (pfile)) + node = cpp_lookup (pfile, sym, len); + /* Check for poisoned identifiers now. */ + if (node->type == T_POISON) { - if (!hash_at_bol && TRAD_DIRECT_P (dtable[i].flags)) - cpp_warning (pfile, "traditional C ignores #%s with the # indented", - dtable[i].name); - else if (hash_at_bol && ! TRAD_DIRECT_P (dtable[i].flags)) - cpp_warning (pfile, - "suggest hiding #%s from traditional C with an indented #", - dtable[i].name); + cpp_error (pfile, "attempt to use poisoned \"%.*s\"", (int) len, sym); + return 0; } - /* Unfortunately, it's necessary to scan the directive name again, - now we know we're going to consume it. FIXME. */ - - pfile->no_macro_expand++; - _cpp_get_directive_token (pfile); - pfile->no_macro_expand--; - CPP_SET_WRITTEN (pfile, old_written); - - process_directive: - (void) (*dtable[i].func) (pfile); - return 1; -} - -/* Pass a directive through to the output file. - BUF points to the contents of the directive, as a contiguous string. - LEN is the length of the string pointed to by BUF. - KEYWORD is the keyword-table entry for the directive. */ - -static void -pass_thru_directive (buf, len, pfile, keyword) - const U_CHAR *buf; - size_t len; - cpp_reader *pfile; - int keyword; -{ - const struct directive *kt = &dtable[keyword]; - register unsigned klen = kt->length; - - CPP_RESERVE (pfile, 1 + klen + len); - CPP_PUTC_Q (pfile, '#'); - CPP_PUTS_Q (pfile, kt->name, klen); - if (len != 0 && buf[0] != ' ') - CPP_PUTC_Q (pfile, ' '); - CPP_PUTS_Q (pfile, buf, len); + return node; } /* Process a #define command. */ - static int do_define (pfile) cpp_reader *pfile; { cpp_hashnode *node; - int len; - const U_CHAR *sym; - cpp_toklist *list = &pfile->directbuf; - pfile->no_macro_expand++; - CPP_OPTION (pfile, discard_comments)++; + if ((node = get_define_node (pfile))) + if (_cpp_create_definition (pfile, node)) + { + if (CPP_OPTION (pfile, debug_output) + || CPP_OPTION (pfile, dump_macros) == dump_definitions) + _cpp_dump_definition (pfile, node); + else if (CPP_OPTION (pfile, dump_macros) == dump_names) + dump_macro_name (pfile, node); + } + return 0; +} + +/* Remove the definition of a symbol from the symbol table. */ +static int +do_undef (pfile) + cpp_reader *pfile; +{ + cpp_hashnode *node = get_define_node (pfile); - _cpp_scan_until (pfile, list, CPP_VSPACE); + if (cpp_get_token (pfile)->type != CPP_EOF) + cpp_pedwarn (pfile, "junk on line after #undef"); - /* First token on the line must be a NAME. There may not be any - tokens in the list (if we had #define all by itself on a line). */ - if (list->tokens_used == 0 - || TOK_TYPE (list, 0) != CPP_NAME) + /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier + is not currently defined as a macro name. */ + if (node && node->type != T_VOID) { - cpp_error_with_line (pfile, list->line, TOK_COL (list, 0), - "#define must be followed by an identifier"); - goto out; - } + /* If we are generating additional info for debugging (with -g) we + need to pass through all effective #undef commands. */ + if (CPP_OPTION (pfile, debug_output) + || CPP_OPTION (pfile, dump_macros) == dump_definitions + || CPP_OPTION (pfile, dump_macros) == dump_names) + pass_thru_directive (pfile); - sym = TOK_NAME (list, 0); - len = TOK_LEN (list, 0); + if (node->type != T_MACRO) + cpp_warning (pfile, "undefining \"%s\"", node->name); - /* That NAME is not allowed to be "defined". (Not clear if the - standard requires this.) */ - if (len == 7 && !ustrncmp (sym, U"defined", 7)) - { - cpp_error_with_line (pfile, list->line, TOK_COL (list, 0), - "\"defined\" is not a legal macro name"); - goto out; + _cpp_free_definition (node); + node->type = T_VOID; } - node = cpp_lookup (pfile, sym, len); - /* Check for poisoned identifiers now. All other checks - are done in cpphash.c. */ - if (node->type == T_POISON) - { - cpp_error (pfile, "redefining poisoned `%.*s'", len, sym); - goto out; - } - - if (_cpp_create_definition (pfile, list, node) == 0) - goto out; - - if (CPP_OPTION (pfile, debug_output) - || CPP_OPTION (pfile, dump_macros) == dump_definitions) - _cpp_dump_definition (pfile, node); - else if (CPP_OPTION (pfile, dump_macros) == dump_names) - pass_thru_directive (sym, len, pfile, T_DEFINE); - - out: - pfile->no_macro_expand--; - CPP_OPTION (pfile, discard_comments)--; return 0; } + /* Handle #include and #import. */ -static unsigned int -parse_include (pfile, name, trail) +static int +parse_include (pfile, dir, trail, strp, lenp, abp) cpp_reader *pfile; - const U_CHAR *name; + const U_CHAR *dir; int trail; + const U_CHAR **strp; + unsigned int *lenp; + int *abp; { - long old_written = CPP_WRITTEN (pfile); - enum cpp_ttype token; - int len; - - pfile->parsing_include_directive++; - token = _cpp_get_directive_token (pfile); - pfile->parsing_include_directive--; + const cpp_token *name = cpp_get_token (pfile); - len = CPP_WRITTEN (pfile) - old_written; - - if (token != CPP_STRING) + if (name->type != CPP_STRING && name->type != CPP_HEADER_NAME) { - cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", name); - CPP_SET_WRITTEN (pfile, old_written); - _cpp_skip_rest_of_line (pfile); - return 0; + if (name->type == CPP_LESS) + name = _cpp_glue_header_name (pfile); + else + { + cpp_error (pfile, "#%s expects \"FILENAME\" or <FILENAME>", dir); + return 1; + } } - - if (!trail && _cpp_get_directive_token (pfile) != CPP_VSPACE) + if (name->val.name.len == 0) { - cpp_error (pfile, "junk at end of #%s", name); - _cpp_skip_rest_of_line (pfile); + cpp_error (pfile, "empty file name in #%s", dir); + return 1; } - CPP_SET_WRITTEN (pfile, old_written); - - if (len == 0) - cpp_error (pfile, "empty file name in #%s", name); + if (!trail && cpp_get_token (pfile)->type != CPP_EOF) + cpp_error (pfile, "junk at end of #%s", dir); - return len; + *lenp = name->val.name.len; + *strp = name->val.name.text; + *abp = (name->type == CPP_HEADER_NAME); + return 0; } static int @@ -440,19 +372,15 @@ do_include (pfile) cpp_reader *pfile; { unsigned int len; - U_CHAR *token; + const U_CHAR *str; + int ab; - len = parse_include (pfile, dtable[T_INCLUDE].name, 0); - if (len == 0) + if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab)) return 0; - token = (U_CHAR *) alloca (len + 1); - memcpy (token, CPP_PWRITTEN (pfile), len); - token[len] = '\0'; - - if (CPP_OPTION (pfile, dump_includes)) - pass_thru_directive (token, len, pfile, T_INCLUDE); - _cpp_execute_include (pfile, token, len, 0, 0); + _cpp_execute_include (pfile, str, len, 0, 0, ab); + if (CPP_OPTION (pfile, dump_includes)) + pass_thru_directive (pfile); return 0; } @@ -461,7 +389,8 @@ do_import (pfile) cpp_reader *pfile; { unsigned int len; - U_CHAR *token; + const U_CHAR *str; + int ab; if (CPP_OPTION (pfile, warn_import) && !CPP_IN_SYSTEM_HEADER (pfile) && !pfile->import_warning) @@ -471,17 +400,12 @@ do_import (pfile) "#import is obsolete, use an #ifndef wrapper in the header file"); } - len = parse_include (pfile, dtable[T_IMPORT].name, 0); - if (len == 0) + if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab)) return 0; - token = (U_CHAR *) alloca (len + 1); - memcpy (token, CPP_PWRITTEN (pfile), len); - token[len] = '\0'; - - if (CPP_OPTION (pfile, dump_includes)) - pass_thru_directive (token, len, pfile, T_IMPORT); - _cpp_execute_include (pfile, token, len, 1, 0); + _cpp_execute_include (pfile, str, len, 1, 0, ab); + if (CPP_OPTION (pfile, dump_includes)) + pass_thru_directive (pfile); return 0; } @@ -490,32 +414,35 @@ do_include_next (pfile) cpp_reader *pfile; { unsigned int len; - U_CHAR *token; + const U_CHAR *str; struct file_name_list *search_start = 0; + int ab; - len = parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0); - if (len == 0) + if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab)) return 0; - token = (U_CHAR *) alloca (len + 1); - memcpy (token, CPP_PWRITTEN (pfile), len); - token[len] = '\0'; - - if (CPP_OPTION (pfile, dump_includes)) - pass_thru_directive (token, len, pfile, T_INCLUDE_NEXT); - /* For #include_next, skip in the search path past the dir in which the - containing file was found. Treat files specified using an absolute path - as if there are no more directories to search. Treat the primary source - file like any other included source, but generate a warning. */ + /* For #include_next, skip in the search path past the dir in which + the current file was found. If this is the last directory in the + search path, don't include anything. If the current file was + specified with an absolute path, use the normal search logic. If + this is the primary source file, use the normal search logic and + generate a warning. */ if (CPP_PREV_BUFFER (CPP_BUFFER (pfile))) { if (CPP_BUFFER (pfile)->inc->foundhere) - search_start = CPP_BUFFER (pfile)->inc->foundhere->next; + { + search_start = CPP_BUFFER (pfile)->inc->foundhere->next; + if (!search_start) + return 0; + } } else cpp_warning (pfile, "#include_next in primary source file"); - _cpp_execute_include (pfile, token, len, 0, search_start); + _cpp_execute_include (pfile, str, len, 0, search_start, ab); + if (CPP_OPTION (pfile, dump_includes)) + pass_thru_directive (pfile); + return 0; } @@ -529,27 +456,47 @@ read_line_number (pfile, num) cpp_reader *pfile; int *num; { - long save_written = CPP_WRITTEN (pfile); - U_CHAR *p; - enum cpp_ttype token = _cpp_get_directive_token (pfile); - p = pfile->token_buffer + save_written; + const cpp_token *tok = cpp_get_token (pfile); + enum cpp_ttype type = tok->type; + const U_CHAR *p = tok->val.name.text; + unsigned int len = tok->val.name.len; - if (token == CPP_NUMBER && p + 1 == CPP_PWRITTEN (pfile) - && p[0] >= '1' && p[0] <= '4') + if (type == CPP_NUMBER && len == 1 && p[0] >= '1' && p[0] <= '4') { *num = p[0] - '0'; - CPP_SET_WRITTEN (pfile, save_written); return 1; } else { - if (token != CPP_VSPACE && token != CPP_EOF) + if (type != CPP_VSPACE && type != CPP_EOF) cpp_error (pfile, "invalid format #line"); - CPP_SET_WRITTEN (pfile, save_written); return 0; } } +/* Another subroutine of do_line. Convert a number in STR, of length + LEN, to binary; store it in NUMP, and return 0 if the number was + legal, 1 if not. Temporary, hopefully. */ +static int +strtoul_for_line (str, len, nump) + const U_CHAR *str; + unsigned int len; + unsigned long *nump; +{ + unsigned long reg = 0; + U_CHAR c; + while (len--) + { + c = *str++; + if (!ISDIGIT (c)) + return 1; + reg *= 10; + reg += c - '0'; + } + *nump = reg; + return 0; +} + /* Interpret #line command. Note that the filename string (if any) is treated as if it were an include filename. That means no escape handling. */ @@ -559,156 +506,92 @@ do_line (pfile) cpp_reader *pfile; { cpp_buffer *ip = CPP_BUFFER (pfile); - unsigned int new_lineno; - long old_written = CPP_WRITTEN (pfile); - enum cpp_ttype token; - char *x; - - token = _cpp_get_directive_token (pfile); + unsigned long new_lineno, old_lineno; + /* C99 raised the minimum limit on #line numbers. */ + unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767; + int action_number = 0; + enum cpp_ttype type; + const U_CHAR *str; + char *fname; + unsigned int len; + const cpp_token *tok; - if (token != CPP_NUMBER) - { - cpp_error (pfile, "token after #line is not an integer"); - goto bad_line_directive; - } + tok = cpp_get_token (pfile); + type = tok->type; + str = tok->val.name.text; + len = tok->val.name.len; - CPP_PUTC (pfile, '\0'); /* not terminated for us */ - new_lineno = strtoul ((const char *) (pfile->token_buffer + old_written), - &x, 10); - if (x[0] != '\0') + if (type != CPP_NUMBER || strtoul_for_line (str, len, &new_lineno)) { - cpp_error (pfile, "token after #line is not an integer"); - goto bad_line_directive; + cpp_error (pfile, "token after #line is not a positive integer"); + goto done; } - CPP_SET_WRITTEN (pfile, old_written); - - if (CPP_PEDANTIC (pfile) && (new_lineno <= 0 || new_lineno > 32767)) - cpp_pedwarn (pfile, "line number out of range in #line"); - token = _cpp_get_directive_token (pfile); + if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap)) + cpp_pedwarn (pfile, "line number out of range"); - if (token == CPP_STRING) - { - U_CHAR *fname = pfile->token_buffer + old_written + 1; - U_CHAR *end_name = CPP_PWRITTEN (pfile) - 1; - int action_number = 0; - - if (read_line_number (pfile, &action_number)) - { - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "garbage at end of #line"); + old_lineno = ip->lineno; + ip->lineno = new_lineno; + tok = cpp_get_token (pfile); + type = tok->type; + str = tok->val.name.text; + len = tok->val.name.len; - /* This is somewhat questionable: change the buffer stack - depth so that output_line_command thinks we've stacked - another buffer. */ - if (action_number == 1) - { - pfile->buffer_stack_depth++; - cpp_make_system_header (pfile, ip, 0); - read_line_number (pfile, &action_number); - } - else if (action_number == 2) - { - pfile->buffer_stack_depth--; - cpp_make_system_header (pfile, ip, 0); - read_line_number (pfile, &action_number); - } - if (action_number == 3) - { - cpp_make_system_header (pfile, ip, 1); - read_line_number (pfile, &action_number); - } - if (action_number == 4) - { - cpp_make_system_header (pfile, ip, 2); - read_line_number (pfile, &action_number); - } - } - - *end_name = '\0'; - - if (strcmp ((const char *)fname, ip->nominal_fname)) - { - if (!strcmp ((const char *)fname, ip->inc->name)) - ip->nominal_fname = ip->inc->name; - else - ip->nominal_fname = _cpp_fake_include (pfile, (const char *)fname); - } - } - else if (token != CPP_VSPACE && token != CPP_EOF) + if (type == CPP_VSPACE || type == CPP_EOF) + goto done; + else if (type != CPP_STRING) { cpp_error (pfile, "second token after #line is not a string"); - goto bad_line_directive; + ip->lineno = old_lineno; /* malformed #line should have no effect */ + goto done; } - /* The Newline at the end of this line remains to be processed. - To put the next line at the specified line number, - we must store a line number now that is one less. */ - ip->lineno = new_lineno - 1; - CPP_SET_WRITTEN (pfile, old_written); - return 0; - - bad_line_directive: - _cpp_skip_rest_of_line (pfile); - CPP_SET_WRITTEN (pfile, old_written); - return 0; -} + fname = alloca (len + 1); + memcpy (fname, str, len); + fname[len] = '\0'; + + if (strcmp (fname, ip->nominal_fname)) + { + if (!strcmp (fname, ip->inc->name)) + ip->nominal_fname = ip->inc->name; + else + ip->nominal_fname = _cpp_fake_include (pfile, fname); + } -/* Remove the definition of a symbol from the symbol table. - According to the C standard, it is not an error to undef - something that has no definitions. */ -static int -do_undef (pfile) - cpp_reader *pfile; -{ - int len; - cpp_hashnode *hp; - U_CHAR *name; - long here = CPP_WRITTEN (pfile); - enum cpp_ttype token; + if (read_line_number (pfile, &action_number) == 0) + return 0; - pfile->no_macro_expand++; - token = _cpp_get_directive_token (pfile); - pfile->no_macro_expand--; + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, "garbage at end of #line"); - if (token != CPP_NAME) + /* This is somewhat questionable: change the buffer stack + depth so that output_line_command thinks we've stacked + another buffer. */ + if (action_number == 1) { - cpp_error (pfile, "token after #undef is not an identifier"); - _cpp_skip_rest_of_line (pfile); - return 0; + pfile->buffer_stack_depth++; + cpp_make_system_header (pfile, ip, 0); + read_line_number (pfile, &action_number); } - len = CPP_WRITTEN (pfile) - here; - - token = _cpp_get_directive_token (pfile); - if (token != CPP_VSPACE) - { - cpp_pedwarn (pfile, "junk on line after #undef"); - _cpp_skip_rest_of_line (pfile); - } - - name = pfile->token_buffer + here; - CPP_SET_WRITTEN (pfile, here); - - hp = cpp_lookup (pfile, name, len); - if (hp->type == T_VOID) - ; /* Not defined in the first place - do nothing. */ - else if (hp->type == T_POISON) - cpp_error (pfile, "cannot undefine poisoned \"%s\"", hp->name); - else + else if (action_number == 2) { - /* If we are generating additional info for debugging (with -g) we - need to pass through all effective #undef commands. */ - if (CPP_OPTION (pfile, debug_output)) - pass_thru_directive (hp->name, len, pfile, T_UNDEF); - - if (hp->type != T_MACRO && hp->type != T_FMACRO - && hp->type != T_EMPTY && hp->type != T_IDENTITY) - cpp_warning (pfile, "undefining `%s'", hp->name); - - _cpp_free_definition (hp); - hp->type = T_VOID; + pfile->buffer_stack_depth--; + cpp_make_system_header (pfile, ip, 0); + read_line_number (pfile, &action_number); } + if (action_number == 3) + { + cpp_make_system_header (pfile, ip, 1); + read_line_number (pfile, &action_number); + } + if (action_number == 4) + { + cpp_make_system_header (pfile, ip, 2); + read_line_number (pfile, &action_number); + } + return 0; + done: return 0; } @@ -722,14 +605,14 @@ static int do_error (pfile) cpp_reader *pfile; { - const U_CHAR *text, *limit; + U_CHAR *text, *limit; - _cpp_skip_hspace (pfile); - text = CPP_BUFFER (pfile)->cur; - _cpp_skip_rest_of_line (pfile); - limit = CPP_BUFFER (pfile)->cur; + text = pfile->limit; + _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0); + limit = pfile->limit; + pfile->limit = text; + cpp_error (pfile, "%.*s", (int)(limit - text), text); - cpp_error (pfile, "#error %.*s", (int)(limit - text), text); return 0; } @@ -742,14 +625,13 @@ static int do_warning (pfile) cpp_reader *pfile; { - const U_CHAR *text, *limit; + U_CHAR *text, *limit; - _cpp_skip_hspace (pfile); - text = CPP_BUFFER (pfile)->cur; - _cpp_skip_rest_of_line (pfile); - limit = CPP_BUFFER (pfile)->cur; - - cpp_warning (pfile, "#warning %.*s", (int)(limit - text), text); + text = pfile->limit; + _cpp_dump_list (pfile, &pfile->token_list, pfile->first_directive_token, 0); + limit = pfile->limit; + pfile->limit = text; + cpp_warning (pfile, "%.*s", (int)(limit - text), text); return 0; } @@ -759,21 +641,17 @@ static int do_ident (pfile) cpp_reader *pfile; { - long old_written = CPP_WRITTEN (pfile); - - CPP_PUTS (pfile, "#ident ", 7); - /* Next token should be a string constant. */ - if (_cpp_get_directive_token (pfile) == CPP_STRING) + if (cpp_get_token (pfile)->type == CPP_STRING) /* And then a newline. */ - if (_cpp_get_directive_token (pfile) == CPP_VSPACE) - /* Good - ship it. */ - return 0; + if (cpp_get_token (pfile)->type == CPP_VSPACE) + { + /* Good - ship it. */ + pass_thru_directive (pfile); + return 0; + } cpp_error (pfile, "invalid #ident"); - _cpp_skip_rest_of_line (pfile); - CPP_SET_WRITTEN (pfile, old_written); /* discard directive */ - return 0; } @@ -792,17 +670,17 @@ do_ident (pfile) They return 1 if the token buffer is to be popped, 0 if not. */ struct pragma_entry { - char const *name; + const char *name; int (*handler) PARAMS ((cpp_reader *)); }; static int pragma_dispatch - PARAMS ((cpp_reader *, const struct pragma_entry *, U_CHAR *, size_t)); + PARAMS ((cpp_reader *, const struct pragma_entry *, + const U_CHAR *, size_t)); static int do_pragma_once PARAMS ((cpp_reader *)); static int do_pragma_implementation PARAMS ((cpp_reader *)); static int do_pragma_poison PARAMS ((cpp_reader *)); static int do_pragma_system_header PARAMS ((cpp_reader *)); -static int do_pragma_default PARAMS ((cpp_reader *)); static int do_pragma_gcc PARAMS ((cpp_reader *)); static int do_pragma_dependency PARAMS ((cpp_reader *)); @@ -811,9 +689,8 @@ static const struct pragma_entry top_pragmas[] = {"once", do_pragma_once}, {"implementation", do_pragma_implementation}, {"poison", do_pragma_poison}, - {"system_header", do_pragma_system_header}, {"GCC", do_pragma_gcc}, - {NULL, do_pragma_default} + {NULL, NULL} }; static const struct pragma_entry gcc_pragmas[] = @@ -822,74 +699,41 @@ static const struct pragma_entry gcc_pragmas[] = {"poison", do_pragma_poison}, {"system_header", do_pragma_system_header}, {"dependency", do_pragma_dependency}, - {NULL, do_pragma_default} + {NULL, NULL} }; static int pragma_dispatch (pfile, table, p, len) cpp_reader *pfile; const struct pragma_entry *table; - U_CHAR *p; + const U_CHAR *p; size_t len; { for (; table->name; table++) if (strlen (table->name) == len && !memcmp (p, table->name, len)) return (*table->handler) (pfile); - return (*table->handler) (pfile); + return 0; } static int do_pragma (pfile) cpp_reader *pfile; { - long here, key; - U_CHAR *buf; + const cpp_token *tok; int pop; - enum cpp_ttype token; - size_t len; - - here = CPP_WRITTEN (pfile); - CPP_PUTS (pfile, "#pragma ", 8); - key = CPP_WRITTEN (pfile); - pfile->no_macro_expand++; - token = _cpp_get_directive_token (pfile); - if (token != CPP_NAME) + tok = cpp_get_token (pfile); + if (tok->type == CPP_EOF) + return 0; + else if (tok->type != CPP_NAME) { - if (token == CPP_VSPACE) - goto empty; - else - goto skip; + cpp_error (pfile, "malformed #pragma directive"); + return 0; } - buf = pfile->token_buffer + key; - len = CPP_WRITTEN (pfile) - key; - CPP_PUTC (pfile, ' '); - - pop = pragma_dispatch (pfile, top_pragmas, buf, len); - - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) - goto skip; - - if (pop) - CPP_SET_WRITTEN (pfile, here); - pfile->no_macro_expand--; - return 0; - - skip: - cpp_error (pfile, "malformed #pragma directive"); - _cpp_skip_rest_of_line (pfile); - empty: - CPP_SET_WRITTEN (pfile, here); - pfile->no_macro_expand--; - return 0; -} - -static int -do_pragma_default (pfile) - cpp_reader *pfile; -{ - while (_cpp_get_directive_token (pfile) != CPP_VSPACE) - CPP_PUTC (pfile, ' '); + pop = pragma_dispatch (pfile, top_pragmas, + tok->val.name.text, tok->val.name.len); + if (!pop) + pass_thru_directive (pfile); return 0; } @@ -897,21 +741,16 @@ static int do_pragma_gcc (pfile) cpp_reader *pfile; { - long key; - enum cpp_ttype token; - U_CHAR *buf; - size_t len; - - key = CPP_WRITTEN (pfile); - token = _cpp_get_directive_token (pfile); - if (token != CPP_NAME) - return token == CPP_VSPACE; - - buf = pfile->token_buffer + key; - len = CPP_WRITTEN (pfile) - key; - CPP_PUTC (pfile, ' '); + const cpp_token *tok; + + tok = cpp_get_token (pfile); + if (tok->type == CPP_EOF) + return 1; + else if (tok->type != CPP_NAME) + return 0; - return pragma_dispatch (pfile, gcc_pragmas, buf, len); + return pragma_dispatch (pfile, gcc_pragmas, + tok->val.name.text, tok->val.name.len); } static int @@ -939,27 +778,22 @@ do_pragma_implementation (pfile) { /* Be quiet about `#pragma implementation' for a file only if it hasn't been included yet. */ - enum cpp_ttype token; - long written = CPP_WRITTEN (pfile); - U_CHAR *name; + const cpp_token *tok = cpp_get_token (pfile); char *copy; - size_t len; - token = _cpp_get_directive_token (pfile); - if (token == CPP_VSPACE) + if (tok->type == CPP_EOF) return 0; - else if (token != CPP_STRING) + else if (tok->type != CPP_STRING + || cpp_get_token (pfile)->type != CPP_EOF) { cpp_error (pfile, "malformed #pragma implementation"); return 1; } - /* Trim the leading and trailing quote marks from the string. */ - name = pfile->token_buffer + written + 1; - len = CPP_PWRITTEN (pfile) - name; - copy = alloca (len); - memcpy (copy, name, len - 1); - copy[len - 1] = '\0'; + /* Make a NUL-terminated copy of the string. */ + copy = alloca (tok->val.name.len + 1); + memcpy (copy, tok->val.name.text, tok->val.name.len); + copy[tok->val.name.len] = '\0'; if (cpp_included (pfile, copy)) cpp_warning (pfile, @@ -974,11 +808,8 @@ do_pragma_poison (pfile) { /* Poison these symbols so that all subsequent usage produces an error message. */ - U_CHAR *p; + const cpp_token *tok; cpp_hashnode *hp; - long written; - size_t len; - enum cpp_ttype token; int writeit; /* As a rule, don't include #pragma poison commands in output, @@ -989,31 +820,25 @@ do_pragma_poison (pfile) for (;;) { - written = CPP_WRITTEN (pfile); - token = _cpp_get_directive_token (pfile); - if (token == CPP_VSPACE) + tok = cpp_get_token (pfile); + if (tok->type == CPP_EOF) break; - if (token != CPP_NAME) + if (tok->type != CPP_NAME) { cpp_error (pfile, "invalid #pragma poison directive"); - _cpp_skip_rest_of_line (pfile); return 1; } - p = pfile->token_buffer + written; - len = CPP_PWRITTEN (pfile) - p; - hp = cpp_lookup (pfile, p, len); + hp = cpp_lookup (pfile, tok->val.name.text, tok->val.name.len); if (hp->type == T_POISON) ; /* It is allowed to poison the same identifier twice. */ else { if (hp->type != T_VOID) - cpp_warning (pfile, "poisoning existing macro `%s'", hp->name); + cpp_warning (pfile, "poisoning existing macro \"%s\"", hp->name); _cpp_free_definition (hp); hp->type = T_POISON; } - if (writeit) - CPP_PUTC (pfile, ' '); } return !writeit; } @@ -1028,7 +853,7 @@ static int do_pragma_system_header (pfile) cpp_reader *pfile; { - cpp_buffer *ip = cpp_file_buffer (pfile); + cpp_buffer *ip = CPP_BUFFER (pfile); if (CPP_PREV_BUFFER (ip) == NULL) cpp_warning (pfile, "#pragma system_header outside include file"); else @@ -1044,33 +869,37 @@ static int do_pragma_dependency (pfile) cpp_reader *pfile; { - U_CHAR *original_name, *name; - unsigned len; - int ordering; - - len = parse_include (pfile, (const U_CHAR *)"pragma dependency", 1); - original_name = (U_CHAR *) alloca (len + 1); - name = (U_CHAR *) alloca (len + 1); - memcpy (original_name, CPP_PWRITTEN (pfile), len); - memcpy (name, CPP_PWRITTEN (pfile), len); - original_name[len] = name[len] = 0; - - ordering = _cpp_compare_file_date (pfile, name, len, 0); + const U_CHAR *name; + unsigned int len; + int ordering, ab; + char left, right; + + if (parse_include (pfile, U"pragma dependency", 1, &name, &len, &ab)) + return 1; + + left = ab ? '<' : '"'; + right = ab ? '>' : '"'; + + ordering = _cpp_compare_file_date (pfile, name, len, ab); if (ordering < 0) - cpp_warning (pfile, "cannot find source %s", original_name); + cpp_warning (pfile, "cannot find source %c%s%c", left, name, right); else if (ordering > 0) { - const U_CHAR *text, *limit; - _cpp_skip_hspace (pfile); - text = CPP_BUFFER (pfile)->cur; - _cpp_skip_rest_of_line (pfile); - limit = CPP_BUFFER (pfile)->cur; + const cpp_token *msg = cpp_get_token (pfile); - cpp_warning (pfile, "current file is older than %s", original_name); - if (limit != text) - cpp_warning (pfile, "%.*s", (int)(limit - text), text); + cpp_warning (pfile, "current file is older than %c%s%c", + left, name, right); + if (msg->type != CPP_EOF) + { + U_CHAR *text, *limit; + + text = pfile->limit; + _cpp_dump_list (pfile, &pfile->token_list, msg, 0); + limit = pfile->limit; + pfile->limit = text; + cpp_warning (pfile, "%.*s", (int)(limit - text), text); + } } - _cpp_skip_rest_of_line (pfile); return 1; } @@ -1078,9 +907,8 @@ do_pragma_dependency (pfile) #ifdef SCCS_DIRECTIVE static int do_sccs (pfile) - cpp_reader *pfile; + cpp_reader *pfile ATTRIBUTE_UNUSED; { - _cpp_skip_rest_of_line (pfile); return 0; } #endif @@ -1096,117 +924,76 @@ static const cpp_hashnode * detect_if_not_defined (pfile) cpp_reader *pfile; { - const cpp_hashnode *cmacro = 0; - enum cpp_ttype token; - unsigned int base_offset; - unsigned int token_offset; - unsigned int need_rparen = 0; - unsigned int token_len; - - if (pfile->skipping || pfile->only_seen_white != 2) - return NULL; - - /* Save state required for restore. */ - pfile->no_macro_expand++; - CPP_SET_MARK (pfile); - base_offset = CPP_WRITTEN (pfile); - - /* Look for `!', */ - if (_cpp_get_directive_token (pfile) != CPP_OTHER - || CPP_WRITTEN (pfile) != (size_t) base_offset + 1 - || CPP_PWRITTEN (pfile)[-1] != '!') - goto restore; - - /* ...then `defined', */ - token_offset = CPP_WRITTEN (pfile); - token = _cpp_get_directive_token (pfile); - if (token != CPP_NAME) - goto restore; - if (ustrncmp (pfile->token_buffer + token_offset, U"defined", 7)) - goto restore; - - /* ...then an optional '(' and the name, */ - token_offset = CPP_WRITTEN (pfile); - token = _cpp_get_directive_token (pfile); - if (token == CPP_OPEN_PAREN) - { - token_offset = CPP_WRITTEN (pfile); - need_rparen = 1; - token = _cpp_get_directive_token (pfile); - } - if (token != CPP_NAME) - goto restore; + const cpp_token *token; + cpp_hashnode *cmacro = 0; + + /* We are guaranteed that tokens are consecutive and end in CPP_EOF. */ + token = pfile->first_directive_token + 2; + + if (token->type != CPP_NOT) + return 0; - token_len = CPP_WRITTEN (pfile) - token_offset; + token++; + if (token->type != CPP_NAME + || !str_match (token->val.name.text, token->val.name.len, "defined")) + return 0; + + token++; + if (token->type == CPP_OPEN_PAREN) + token++; - /* ...then the ')', if necessary, */ - if (need_rparen && _cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) - goto restore; + if (token->type != CPP_NAME) + return 0; - /* ...and make sure there's nothing else on the line. */ - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) - goto restore; + cmacro = cpp_lookup (pfile, token->val.name.text, token->val.name.len); - /* We have a legitimate controlling macro for this header. */ - cmacro = cpp_lookup (pfile, pfile->token_buffer + token_offset, token_len); + if (token[-1].type == CPP_OPEN_PAREN) + { + token++; + if (token->type != CPP_CLOSE_PAREN) + return 0; + } - restore: - CPP_SET_WRITTEN (pfile, base_offset); - pfile->no_macro_expand--; - CPP_GOTO_MARK (pfile); + token++; + if (token->type != CPP_EOF) + return 0; return cmacro; } -/* Parse an #ifdef or #ifndef directive. Returns 1 for defined, 0 for - not defined; the macro tested is left in the token buffer (but - popped). */ +/* Parse an #ifdef or #ifndef directive. Returns the hash node of the + macro being tested, and issues various error messages. */ static const cpp_hashnode * parse_ifdef (pfile, name) cpp_reader *pfile; const U_CHAR *name; { - U_CHAR *ident; + const U_CHAR *ident; unsigned int len; - enum cpp_ttype token; - long old_written = CPP_WRITTEN (pfile); + enum cpp_ttype type; const cpp_hashnode *node = 0; - pfile->no_macro_expand++; - token = _cpp_get_directive_token (pfile); - pfile->no_macro_expand--; - - ident = pfile->token_buffer + old_written; - len = CPP_WRITTEN (pfile) - old_written; + const cpp_token *token = cpp_get_token (pfile); + type = token->type; + ident = token->val.name.text; + len = token->val.name.len; - if (token == CPP_VSPACE) + if (!CPP_TRADITIONAL (pfile)) { - if (! CPP_TRADITIONAL (pfile)) + if (type == CPP_EOF) cpp_pedwarn (pfile, "#%s with no argument", name); - goto done; - } - else if (token == CPP_NAME) - { - node = cpp_lookup (pfile, ident, len); - } - else - { - if (! CPP_TRADITIONAL (pfile)) - cpp_error (pfile, "#%s with invalid argument", name); + else if (type != CPP_NAME) + cpp_pedwarn (pfile, "#%s with invalid argument", name); + else if (cpp_get_token (pfile)->type != CPP_EOF) + cpp_pedwarn (pfile, "garbage at end of #%s", name); } - if (!CPP_TRADITIONAL (pfile)) - { - if (_cpp_get_directive_token (pfile) == CPP_VSPACE) - goto done; - - cpp_pedwarn (pfile, "garbage at end of #%s", name); - } - _cpp_skip_rest_of_line (pfile); - - done: - CPP_SET_WRITTEN (pfile, old_written); /* Pop */ + if (type == CPP_NAME) + node = cpp_lookup (pfile, ident, len); + if (node && node->type == T_POISON) + cpp_error (pfile, "attempt to use poisoned identifier \"%s\"", node->name); + return node; } @@ -1217,14 +1004,15 @@ do_ifdef (pfile) cpp_reader *pfile; { int def = 0; - const cpp_hashnode *node = parse_ifdef (pfile, dtable[T_IFDEF].name); - if (node) + const cpp_hashnode *node = 0; + + if (! pfile->skipping) { - if (node->type == T_POISON) - cpp_error (pfile, "attempt to use poisoned `%s'", node->name); - else - def = (node->type != T_VOID); + node = parse_ifdef (pfile, dtable[T_IFDEF].name); + if (node) + def = (node->type != T_VOID && node->type != T_POISON); } + push_conditional (pfile, !def, T_IFDEF, 0); return 0; } @@ -1236,21 +1024,19 @@ static int do_ifndef (pfile) cpp_reader *pfile; { - int start_of_file; + int start_of_file = 0; int def = 0; - const cpp_hashnode *cmacro; + const cpp_hashnode *cmacro = 0; - start_of_file = pfile->only_seen_white == 2; - cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name); - if (cmacro) + if (! pfile->skipping) { - if (cmacro->type == T_POISON) - cpp_error (pfile, "attempt to use poisoned `%s'", cmacro->name); - else - def = (cmacro->type != T_VOID); + start_of_file = (pfile->token_list.flags & BEG_OF_FILE); + cmacro = parse_ifdef (pfile, dtable[T_IFNDEF].name); + if (cmacro) + def = cmacro->type != T_VOID; } - push_conditional (pfile, def, T_IFNDEF, - start_of_file ? cmacro : 0); + + push_conditional (pfile, def, T_IFNDEF, start_of_file ? cmacro : 0); return 0; } @@ -1282,7 +1068,6 @@ do_else (pfile) cpp_reader *pfile; { struct if_stack *ifs = CPP_BUFFER (pfile)->if_stack; - validate_else (pfile, dtable[T_ELSE].name); if (ifs == NULL) @@ -1293,13 +1078,13 @@ do_else (pfile) if (ifs->type == T_ELSE) { cpp_error (pfile, "#else after #else"); - cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here"); + cpp_error_with_line (pfile, ifs->lineno, ifs->colno, + "the conditional began here"); } /* #ifndef can't have its special treatment for containing the whole file if it has a #else clause. */ ifs->cmacro = 0; - ifs->type = T_ELSE; if (! ifs->was_skipping) { @@ -1330,24 +1115,24 @@ do_elif (pfile) if (ifs->type == T_ELSE) { cpp_error (pfile, "#elif after #else"); - cpp_error_with_line (pfile, ifs->lineno, 1, "the conditional began here"); + cpp_error_with_line (pfile, ifs->lineno, ifs->colno, + "the conditional began here"); } ifs->type = T_ELIF; if (ifs->was_skipping) - _cpp_skip_rest_of_line (pfile); - else if (pfile->skipping != 1) + return 0; /* Don't evaluate a nested #if */ + + if (pfile->skipping != 1) { - _cpp_skip_rest_of_line (pfile); pfile->skipping = 2; /* one block succeeded, so don't do any others */ + return 0; } - else - pfile->skipping = ! _cpp_parse_expr (pfile); + pfile->skipping = ! _cpp_parse_expr (pfile); return 0; } - /* #endif pops the if stack and resets pfile->skipping. */ static int @@ -1370,6 +1155,7 @@ do_endif (pfile) return 0; } + /* Push an if_stack entry and set pfile->skipping accordingly. If this is a #ifndef starting at the beginning of a file, CMACRO is the macro name tested by the #ifndef. */ @@ -1384,7 +1170,7 @@ push_conditional (pfile, skip, type, cmacro) struct if_stack *ifs; ifs = (struct if_stack *) xmalloc (sizeof (struct if_stack)); - ifs->lineno = CPP_BUFFER (pfile)->lineno; + ifs->lineno = _cpp_get_line (pfile, &ifs->colno); ifs->next = CPP_BUFFER (pfile)->if_stack; ifs->cmacro = cmacro; ifs->was_skipping = pfile->skipping; @@ -1404,19 +1190,11 @@ validate_else (pfile, directive) cpp_reader *pfile; const U_CHAR *directive; { - if (CPP_PEDANTIC (pfile)) - { - long old_written = CPP_WRITTEN (pfile); - pfile->no_macro_expand++; - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) - cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive); - CPP_SET_WRITTEN (pfile, old_written); - pfile->no_macro_expand--; - } - _cpp_skip_rest_of_line (pfile); + if (CPP_PEDANTIC (pfile) && cpp_get_token (pfile)->type != CPP_EOF) + cpp_pedwarn (pfile, "ISO C forbids text after #%s", directive); } -/* Called when we reach the end of a macro buffer. Walk back up the +/* Called when we reach the end of a file. Walk back up the conditional stack till we reach its level at entry to this file, issuing error messages. Then force skipping off. */ void @@ -1428,7 +1206,7 @@ _cpp_unwind_if_stack (pfile, pbuf) for (ifs = pbuf->if_stack; ifs; ifs = nifs) { - cpp_error_with_line (pfile, ifs->lineno, 1, "unterminated #%s", + cpp_error_with_line (pfile, ifs->lineno, ifs->colno, "unterminated #%s", dtable[ifs->type].name); nifs = ifs->next; free (ifs); @@ -1436,173 +1214,210 @@ _cpp_unwind_if_stack (pfile, pbuf) pfile->skipping = 0; } -#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0) -#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0) -#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0) -static int -do_assert (pfile) +/* Parses an assertion, returning a pointer to the hash node of the + predicate, or 0 on error. If an answer was supplied, it is + allocated and placed in ANSWERP, otherwise it is set to 0. We use + _cpp_get_raw_token, since we cannot assume tokens are consecutive + in a #if statement (we may be in a macro), and we don't want to + macro expand. */ +cpp_hashnode * +_cpp_parse_assertion (pfile, answerp) cpp_reader *pfile; + struct answer **answerp; { - long old_written; + struct answer *answer = 0; + cpp_toklist *list; U_CHAR *sym; - size_t len; - cpp_hashnode *hp; - struct predicate *pred = 0; - enum cpp_ttype type; + const cpp_token *token, *predicate; + const struct directive *d = pfile->token_list.directive; + unsigned int len = 0; - old_written = CPP_WRITTEN (pfile); - pfile->no_macro_expand++; + predicate = _cpp_get_raw_token (pfile); + if (predicate->type == CPP_EOF) + { + cpp_error (pfile, "assertion without predicate"); + return 0; + } + else if (predicate->type != CPP_NAME) + { + cpp_error (pfile, "predicate must be an identifier"); + return 0; + } - CPP_PUTC (pfile, '#'); /* force token out of macro namespace */ - type = _cpp_get_directive_token (pfile); - if (type == CPP_VSPACE) - ERROR ("#assert without predicate"); - else if (type != CPP_NAME) - ERROR ("assertion predicate is not an identifier"); + token = _cpp_get_raw_token (pfile); + if (token->type != CPP_OPEN_PAREN) + { + /* #unassert and #if are OK without predicate. */ + if (d == &dtable[T_UNASSERT]) + { + if (token->type == CPP_EOF) + goto lookup_node; + } + else if (d != &dtable[T_ASSERT]) + { + _cpp_push_token (pfile, token); + goto lookup_node; + } + cpp_error (pfile, "missing '(' after predicate"); + return 0; + } - sym = pfile->token_buffer + old_written; - len = CPP_WRITTEN (pfile) - old_written; - hp = cpp_lookup (pfile, sym, len); + /* Allocate a struct answer, and copy the answer to it. */ + answer = (struct answer *) xmalloc (sizeof (struct answer)); + list = &answer->list; + _cpp_init_toklist (list, NO_DUMMY_TOKEN); - if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN) - ERROR ("missing token-sequence in #assert"); + for (;;) + { + cpp_token *dest; - pred = (struct predicate *) xmalloc (sizeof (struct predicate)); - _cpp_init_toklist (&pred->answer, NO_DUMMY_TOKEN); + token = _cpp_get_raw_token (pfile); - if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN) - != CPP_CLOSE_PAREN) - ERROR ("missing close paren in #assert"); + if (token->type == CPP_EOF) + { + cpp_error (pfile, "missing ')' to complete answer"); + goto error; + } + if (token->type == CPP_CLOSE_PAREN) + break; - if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) - ICE ("impossible token, expecting ) in do_assert"); + /* Copy the token. */ + _cpp_expand_token_space (list, 1); + dest = &list->tokens[list->tokens_used++]; + *dest = *token; - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) - ERROR ("junk at end of #assert"); + if (token_spellings[token->type].type > SPELL_NONE) + { + _cpp_expand_name_space (list, token->val.name.len); + dest->val.name.text = list->namebuf + list->name_used; + memcpy (list->namebuf + list->name_used, + token->val.name.text, token->val.name.len); + list->name_used += token->val.name.len; + } + } - if (hp->type == T_ASSERTION) + if (list->tokens_used == 0) { - /* Check for reassertion. */ - const struct predicate *old; - - for (old = hp->value.pred; old; old = old->next) - if (_cpp_equiv_toklists (&pred->answer, &old->answer)) - /* We used to warn about this, but SVR4 cc doesn't, so let's - match that (also consistent with #define). goto error will - clean up. */ - goto error; - pred->next = hp->value.pred; + cpp_error (pfile, "predicate's answer is empty"); + goto error; } - else + + /* Drop whitespace at start. */ + list->tokens[0].flags &= ~PREV_WHITE; + + if ((d == &dtable[T_ASSERT] || d == &dtable[T_UNASSERT]) + && token[1].type != CPP_EOF) { - hp->type = T_ASSERTION; - pred->next = 0; + cpp_error (pfile, "junk at end of assertion"); + goto error; } - - _cpp_squeeze_toklist (&pred->answer); - hp->value.pred = pred; - pfile->no_macro_expand--; - CPP_SET_WRITTEN (pfile, old_written); - return 0; + + lookup_node: + *answerp = answer; + len = predicate->val.name.len + 1; + sym = alloca (len); + + /* Prefix '#' to get it out of macro namespace. */ + sym[0] = '#'; + memcpy (sym + 1, predicate->val.name.text, len); + return cpp_lookup (pfile, sym, len); error: - _cpp_skip_rest_of_line (pfile); - pfile->no_macro_expand--; - CPP_SET_WRITTEN (pfile, old_written); - if (pred) - { - _cpp_free_toklist (&pred->answer); - free (pred); - } + FREE_ANSWER (answer); return 0; } -static int -do_unassert (pfile) - cpp_reader *pfile; +/* Returns a pointer to the pointer to the answer in the answer chain, + or a pointer to NULL if the answer is not in the chain. */ +struct answer ** +find_answer (node, candidate) + cpp_hashnode *node; + const cpp_toklist *candidate; { - long old_written; - U_CHAR *sym; - size_t len; - cpp_hashnode *hp; - cpp_toklist ans; - enum cpp_ttype type; - int specific = 0; + struct answer **result; - old_written = CPP_WRITTEN (pfile); - pfile->no_macro_expand++; + for (result = &node->value.answers; *result; result = &(*result)->next) + if (_cpp_equiv_toklists (&(*result)->list, candidate)) + break; - CPP_PUTC (pfile, '#'); /* force token out of macro namespace */ - if (_cpp_get_directive_token (pfile) != CPP_NAME) - ERROR ("#unassert must be followed by an identifier"); - - sym = pfile->token_buffer + old_written; - len = CPP_WRITTEN (pfile) - old_written; - hp = cpp_lookup (pfile, sym, len); + return result; +} - type = _cpp_get_directive_token (pfile); - if (type == CPP_OPEN_PAREN) +#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0) +#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0) +#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0) +static int +do_assert (pfile) + cpp_reader *pfile; +{ + struct answer *new_answer; + cpp_hashnode *node; + + node = _cpp_parse_assertion (pfile, &new_answer); + if (node) { - specific = 1; - _cpp_init_toklist (&ans, NO_DUMMY_TOKEN); - - if (_cpp_scan_until (pfile, &ans, CPP_CLOSE_PAREN) - != CPP_CLOSE_PAREN) - ERROR ("missing close paren in #unassert"); - - if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) - ICE ("impossible token, expecting ) in do_unassert"); + new_answer->next = 0; + new_answer->list.line = pfile->token_list.line; + new_answer->list.file = pfile->token_list.file; - type = _cpp_get_directive_token (pfile); + if (node->type == T_ASSERTION) + { + if (*find_answer (node, &new_answer->list)) + goto err; + new_answer->next = node->value.answers; + } + node->type = T_ASSERTION; + node->value.answers = new_answer; } + return 0; - if (type != CPP_VSPACE) - ERROR ("junk at end of #unassert"); - - if (hp->type != T_ASSERTION) - /* Not an error to #unassert something that isn't asserted. - goto error to clean up. */ - goto error; + err: + cpp_warning (pfile, "\"%.*s\" re-asserted", + node->length - 1, node->name + 1); + FREE_ANSWER (new_answer); + return 0; +} - if (specific) - { - /* Find this specific answer and remove it. */ - struct predicate *o, *p; - - for (p = NULL, o = hp->value.pred; o; p = o, o = o->next) - if (_cpp_equiv_toklists (&ans, &o->answer)) - { - if (p) - p->next = o->next; - else - hp->value.pred = o->next; - - _cpp_free_toklist (&o->answer); - free (o); - break; - } - } - else +static int +do_unassert (pfile) + cpp_reader *pfile; +{ + cpp_hashnode *node; + struct answer *answer, *temp, *next; + + node = _cpp_parse_assertion (pfile, &answer); + if (node) { - struct predicate *o, *p; - for (o = hp->value.pred; o; o = p) + /* It isn't an error to #unassert something that isn't asserted. */ + if (node->type == T_ASSERTION) { - p = o->next; - _cpp_free_toklist ((cpp_toklist *) &o->answer); - free (o); + if (answer) + { + struct answer **p = find_answer (node, &answer->list); + + temp = *p; + if (temp) + { + *p = temp->next; + FREE_ANSWER (temp); + } + if (node->value.answers == 0) + node->type = T_VOID; + } + else + { + for (temp = node->value.answers; temp; temp = next) + { + next = temp->next; + FREE_ANSWER (temp); + } + node->type = T_VOID; + } } - hp->value.pred = NULL; - } - if (hp->value.pred == NULL) - hp->type = T_VOID; /* Last answer for this predicate deleted. */ - - error: - _cpp_skip_rest_of_line (pfile); - pfile->no_macro_expand--; - CPP_SET_WRITTEN (pfile, old_written); - if (specific) - _cpp_free_toklist (&ans); + if (answer) + FREE_ANSWER (answer); + } return 0; } @@ -1643,11 +1458,7 @@ cpp_define (pfile, str) strcpy (&buf[count-4], " 1\n"); } - if (cpp_push_buffer (pfile, (U_CHAR *)buf, count - 1) != NULL) - { - do_define (pfile); - cpp_pop_buffer (pfile); - } + _cpp_run_directive (pfile, &dtable[T_DEFINE], buf, count - 1); } /* Process MACRO as if it appeared as the body of an #undef. */ @@ -1656,17 +1467,7 @@ cpp_undef (pfile, macro) cpp_reader *pfile; const char *macro; { - /* Copy the string so we can append a newline. */ - size_t len = strlen (macro); - char *buf = (char *) alloca (len + 2); - memcpy (buf, macro, len); - buf[len] = '\n'; - buf[len + 1] = '\0'; - if (cpp_push_buffer (pfile, (U_CHAR *)buf, len + 1) != NULL) - { - do_undef (pfile); - cpp_pop_buffer (pfile); - } + _cpp_run_directive (pfile, &dtable[T_UNDEF], macro, strlen (macro)); } /* Process the string STR as if it appeared as the body of a #assert. */ @@ -1675,11 +1476,7 @@ cpp_assert (pfile, str) cpp_reader *pfile; const char *str; { - if (cpp_push_buffer (pfile, (const U_CHAR *)str, strlen (str)) != NULL) - { - do_assert (pfile); - cpp_pop_buffer (pfile); - } + _cpp_run_directive (pfile, &dtable[T_ASSERT], str, strlen (str)); } /* Process STR as if it appeared as the body of an #unassert. */ @@ -1688,11 +1485,7 @@ cpp_unassert (pfile, str) cpp_reader *pfile; const char *str; { - if (cpp_push_buffer (pfile, (const U_CHAR *)str, strlen (str)) != NULL) - { - do_unassert (pfile); - cpp_pop_buffer (pfile); - } + _cpp_run_directive (pfile, &dtable[T_UNASSERT], str, strlen (str)); } /* Determine whether the identifier ID, of length LEN, is a defined macro. */ @@ -1705,7 +1498,7 @@ cpp_defined (pfile, id, len) cpp_hashnode *hp = cpp_lookup (pfile, id, len); if (hp->type == T_POISON) { - cpp_error (pfile, "attempt to use poisoned `%s'", hp->name); + cpp_error (pfile, "attempt to use poisoned \"%s\"", hp->name); return 0; } return (hp->type != T_VOID); diff --git a/gcc/cpplib.h b/gcc/cpplib.h index b14bb78..2040f30 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -108,7 +108,8 @@ typedef struct cpp_hashnode cpp_hashnode; T(CPP_DOT_STAR, ".*") \ T(CPP_MIN, "<?") /* extension */ \ T(CPP_MAX, ">?") \ - C(CPP_OTHER, 0) /* stray punctuation */ \ + T(CPP_PLACEMARKER, "") /* Placemarker token. */ \ + C(CPP_OTHER, 0) /* stray punctuation */ \ \ I(CPP_NAME, 0) /* word */ \ I(CPP_INT, 0) /* 23 */ \ @@ -121,15 +122,11 @@ typedef struct cpp_hashnode cpp_hashnode; \ I(CPP_COMMENT, 0) /* Only if output comments. */ \ N(CPP_MACRO_ARG, 0) /* Macro argument. */ \ - N(CPP_SUBLIST, 0) /* Sublist. */ \ N(CPP_EOF, 0) /* End of file. */ \ - N(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \ + I(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \ \ /* Obsolete - will be removed when no code uses them still. */ \ - T(CPP_VSPACE, "\n") /* End of line. */ \ - N(CPP_HSPACE, 0) /* Horizontal white space. */ \ - N(CPP_DIRECTIVE, 0) /* #define and the like */ \ - N(CPP_MACRO, 0) /* Like a NAME, but expanded. */ + T(CPP_VSPACE, "\n") /* End of line. */ #define T(e, s) e, #define I(e, s) e, @@ -154,49 +151,42 @@ struct cpp_name const unsigned char *text; }; -/* Accessor macros for token lists - all expect you have a - list and an index. */ - -#define TOK_TYPE(l_, i_) ((l_)->tokens[i_].type) -#define TOK_FLAGS(l_, i_) ((l_)->tokens[i_].flags) -#define TOK_AUX(l_, i_) ((l_)->tokens[i_].aux) -#define TOK_COL(l_, i_) ((l_)->tokens[i_].col) -#define TOK_INT(l_, i_) ((l_)->tokens[i_].val.integer) -#define TOK_NAME(l_, i_) ((l_)->tokens[i_].val.name.text) -#define TOK_LEN(l_, i_) ((l_)->tokens[i_].val.name.len) - -#define TOK_PREV_WHITE(l_, i_) (TOK_FLAGS(l_, i_) & PREV_WHITESPACE) - /* Flags for the cpp_token structure. */ -#define PREV_WHITESPACE 1 /* If whitespace before this token. */ -#define BOL 2 /* Beginning of line. */ -#define DIGRAPH 4 /* If it was a digraph. */ -#define UNSIGNED_INT 8 /* If int preprocessing token unsigned. */ +#define PREV_WHITE (1 << 0) /* If whitespace before this token. */ +#define BOL (1 << 1) /* Beginning of logical line. */ +#define DIGRAPH (1 << 2) /* If it was a digraph. */ +#define STRINGIFY_ARG (1 << 3) /* If macro argument to be stringified. */ +#define PASTE_LEFT (1 << 4) /* If on LHS of a ## operator. */ +#define PASTED (1 << 5) /* The result of a ## operator. */ +#define GNU_VARARGS (1 << 6) /* GNU ## kludge. */ /* A preprocessing token. This has been carefully packed and should - occupy 16 bytes on both 32- and 64-bit hosts. */ + occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */ struct cpp_token { - unsigned short col; /* starting column of this token */ - ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* node type */ - unsigned char flags; /* flags - see above */ - unsigned int aux; /* CPP_OTHER character. Hash of a - NAME, or something - see uses - in the code */ + unsigned int line; /* starting line number of this token */ + unsigned short col; /* starting column of this token */ + ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */ + unsigned char flags; /* flags - see above */ + union { - struct cpp_name name; /* a string */ - HOST_WIDEST_INT integer; /* an integer */ + HOST_WIDEST_INT integer; /* an integer */ + struct cpp_name name; /* a string */ + unsigned int aux; /* argument no. for a CPP_MACRO_ARG, or + character represented by CPP_OTHER. */ } val; }; -/* General flags. */ -#define LIST_OFFSET (1 << 0) - -/* Directive flags. */ -#define SYNTAX_INCLUDE (1 << 8) +/* cpp_toklist flags. */ +#define LIST_OFFSET (1 << 0) +#define VAR_ARGS (1 << 1) +#define BEG_OF_FILE (1 << 2) -typedef int (*directive_handler) PARAMS ((cpp_reader *)); +struct directive; /* These are deliberately incomplete. */ +struct answer; +struct macro_args; +struct cpp_context; struct cpp_toklist { @@ -208,11 +198,15 @@ struct cpp_toklist unsigned int name_used; /* _bytes_ used */ unsigned int name_cap; /* _bytes_ allocated */ + /* If the list represents a directive, this points to it. */ + const struct directive *directive; + + const char *file; /* in file name */ unsigned int line; /* starting line number */ - /* The handler to call after lexing the rest of this line. - -1 for none */ - short dirno; + unsigned short params_len; /* length of macro parameter names. */ + + short int paramc; /* no. of macro params (-1 = obj-like). */ /* Per-list flags, see above */ unsigned short flags; @@ -224,12 +218,12 @@ struct cpp_buffer const unsigned char *rlimit; /* end of valid data */ const unsigned char *buf; /* entire buffer */ const unsigned char *line_base; /* start of current line */ - const unsigned char *mark; /* Saved position for lengthy backtrack. */ struct cpp_buffer *prev; /* Filename specified with #line command. */ const char *nominal_fname; + /* Actual directory of this file, used only for "" includes */ struct file_name_list *actual_dir; @@ -237,10 +231,6 @@ struct cpp_buffer to record control macros. */ struct include_file *inc; - /* If the buffer is the expansion of a macro, this points to the - macro's hash table entry. */ - struct cpp_hashnode *macro; - /* Value of if_stack at start of this file. Used to prohibit unmatched #endif (etc) in an include file. */ struct if_stack *if_stack; @@ -248,29 +238,13 @@ struct cpp_buffer /* Line number at line_base (above). */ unsigned int lineno; - /* True if buffer contains escape sequences. - Currently there are two kinds: - "\r-" means following identifier should not be macro-expanded. - "\r " means a token-separator. This turns into " " in final output - if not stringizing and needed to separate tokens; otherwise nothing. - Any other two-character sequence beginning with \r is an error. - - If this is NOT set, then \r is a one-character escape meaning backslash - newline. This is guaranteed not to occur in the middle of a token. - The two interpretations of \r do not conflict, because the two-character - escapes are used only in macro buffers, and backslash-newline is removed - from macro expansion text in collect_expansion and/or macarg. */ - char has_escapes; - /* True if we have already warned about C++ comments in this file. The warning happens only for C89 extended mode with -pedantic on, or for -Wtraditional, and only once per file (otherwise it would be far too noisy). */ char warned_cplusplus_comments; - /* In a file buffer, true if this buffer's data is mmapped - (currently never the case). In a macro buffer, true if this - buffer's data must be freed. */ + /* True if this buffer's data is mmapped. */ char mapped; }; @@ -354,7 +328,7 @@ struct cpp_options /* Nonzero means don't copy comments into the output file. */ unsigned char discard_comments; - /* Nonzero means process the ANSI trigraph sequences. */ + /* Nonzero means process the ISO trigraph sequences. */ unsigned char trigraphs; /* Nonzero means print the names of included files rather than the @@ -396,6 +370,10 @@ struct cpp_options with the # indented from the beginning of the line. */ unsigned char warn_traditional; + /* Nonzero means warn if ## is applied to two tokens that cannot be + pasted together. */ + unsigned char warn_paste; + /* Nonzero means turn warnings into errors. */ unsigned char warnings_are_errors; @@ -417,7 +395,7 @@ struct cpp_options /* Zero means dollar signs are punctuation. */ unsigned char dollars_in_ident; - /* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */ + /* Nonzero means try to imitate old fashioned non-ISO preprocessor. */ unsigned char traditional; /* Nonzero means warn if undefined identifiers are evaluated in an #if. */ @@ -460,19 +438,18 @@ struct cpp_options unsigned char show_column; }; - /* A cpp_reader encapsulates the "state" of a pre-processor run. Applying cpp_get_token repeatedly yields a stream of pre-processor tokens. Usually, there is only one cpp_reader object active. */ struct cpp_reader { + /* HACK FIXME. Maybe make into cpp_printer printer later. */ + cpp_printer *printer; + /* Top of buffer stack. */ cpp_buffer *buffer; - /* Token list used by get_directive_token. */ - cpp_toklist directbuf; - /* A buffer used for both for cpp_get_token's output, and also internally. */ unsigned char *token_buffer; /* Allocated size of token_buffer. CPP_RESERVE allocates space. */ @@ -483,8 +460,9 @@ struct cpp_reader /* Error counter for exit code */ unsigned int errors; - /* Line where a newline was first seen in a string constant. */ + /* Line and column where a newline was first seen in a string constant. */ unsigned int multiline_string_line; + unsigned int multiline_string_column; /* Current depth in #include directives that use <...>. */ unsigned int system_include_depth; @@ -509,19 +487,46 @@ struct cpp_reader for include files. (Altered as we get more of them.) */ unsigned int max_include_len; + /* Potential controlling macro for the current buffer. This is only + live between the #endif and the end of file, and there can only + be one at a time, so it is per-reader not per-buffer. */ const cpp_hashnode *potential_control_macro; /* Token column position adjustment owing to tabs in whitespace. */ unsigned int col_adjust; + /* Token list used to store logical lines with new lexer. */ + cpp_toklist token_list; + + /* Temporary token store. */ + cpp_token **temp_tokens; + unsigned int temp_cap; + unsigned int temp_alloced; + unsigned int temp_used; + + /* Date and time tokens. Calculated together if either is requested. */ + cpp_token *date; + cpp_token *time; + + /* The # of a the current directive. It may not be first in line if + we append, and finding it is tedious. */ + const cpp_token *first_directive_token; + + /* Context stack. Used for macro expansion and for determining + which macros are disabled. */ + unsigned int context_cap; + unsigned int cur_context; + unsigned int no_expand_level; + unsigned int paste_level; + struct cpp_context *contexts; + + /* Current arguments when scanning arguments. Used for pointer + fix-up. */ + struct macro_args *args; + /* Buffer of -M output. */ struct deps *deps; - /* A buffer used only by read_and_prescan (in cppfiles.c), which is - allocated once per cpp_reader object to keep it off the stack. */ - unsigned char *input_buffer; - size_t input_buffer_len; - /* User visible options. */ struct cpp_options opts; @@ -532,31 +537,24 @@ struct cpp_reader /* If non-zero, macros are not expanded. */ unsigned char no_macro_expand; - /* If non-zero, directives cause a hard error. Used when parsing - macro arguments. */ - unsigned char no_directives; - /* We're printed a warning recommending against using #import. */ unsigned char import_warning; - /* If true, characters between '<' and '>' are a single (string) token. */ - unsigned char parsing_include_directive; - - /* True if escape sequences (as described for has_escapes in - parse_buffer) should be emitted. */ - unsigned char output_escapes; - - /* 0: Have seen non-white-space on this line. - 1: Only seen white space so far on this line. - 2: Only seen white space so far in this file. */ - unsigned char only_seen_white; - /* True after cpp_start_read completes. Used to inhibit some warnings while parsing the command line. */ unsigned char done_initializing; /* True if we are skipping a failed conditional group. */ unsigned char skipping; + + /* Do we need to save paramter spellings. */ + unsigned char save_parameter_spellings; + + /* If we're in lex_line. */ + unsigned char in_lex_line; + + /* True if output_line_command needs to output a newline. */ + unsigned char need_newline; }; /* struct cpp_printer encapsulates state used to convert the stream of @@ -611,13 +609,8 @@ enum node_type T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ T_TIME, /* `__TIME__' */ T_STDC, /* `__STDC__' */ - T_CONST, /* Constant string, used by `__SIZE_TYPE__' etc */ - T_XCONST, /* Ditto, but the string is malloced memory */ T_POISON, /* poisoned identifier */ - T_MACRO, /* object-like macro */ - T_FMACRO, /* function-like macro */ - T_IDENTITY, /* macro defined to itself */ - T_EMPTY, /* macro defined to nothing */ + T_MACRO, /* a macro, either object-like or function-like */ T_ASSERTION /* predicate for #assert */ }; @@ -634,11 +627,10 @@ struct cpp_hashnode ENUM_BITFIELD(node_type) type : 8; /* node type */ char disabled; /* macro turned off for rescan? */ - union { - const unsigned char *cpval; /* some predefined macros */ - const struct object_defn *odefn; /* #define foo bar */ - const struct funct_defn *fdefn; /* #define foo(x) bar(x) */ - struct predicate *pred; /* #assert */ + union + { + const cpp_toklist *expansion; /* a macro's replacement list. */ + struct answer *answers; /* answers to an assertion. */ } value; union tree_node *fe_value; /* front end value */ @@ -646,23 +638,17 @@ struct cpp_hashnode const unsigned char name[1]; /* name[length] */ }; - - -extern void _cpp_lex_file PARAMS((cpp_reader *)); extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **)); -extern enum cpp_ttype cpp_get_token PARAMS ((cpp_reader *)); -extern enum cpp_ttype cpp_get_non_space_token PARAMS ((cpp_reader *)); - extern void cpp_reader_init PARAMS ((cpp_reader *)); extern cpp_printer *cpp_printer_init PARAMS ((cpp_reader *, cpp_printer *)); extern int cpp_start_read PARAMS ((cpp_reader *, cpp_printer *, const char *)); -extern void cpp_output_tokens PARAMS ((cpp_reader *, cpp_printer *)); -extern void cpp_output_list PARAMS ((cpp_reader *, cpp_printer *, - const cpp_toklist *)); +extern void cpp_output_tokens PARAMS ((cpp_reader *, cpp_printer *, + unsigned int)); extern void cpp_finish PARAMS ((cpp_reader *, cpp_printer *)); extern void cpp_cleanup PARAMS ((cpp_reader *)); -extern cpp_buffer *cpp_file_buffer PARAMS((cpp_reader *)); +extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *)); + extern void cpp_define PARAMS ((cpp_reader *, const char *)); extern void cpp_assert PARAMS ((cpp_reader *, const char *)); extern void cpp_undef PARAMS ((cpp_reader *, const char *)); diff --git a/gcc/cppmain.c b/gcc/cppmain.c index 0eeafe4..5239f8d 100644 --- a/gcc/cppmain.c +++ b/gcc/cppmain.c @@ -68,6 +68,7 @@ main (argc, argv) print = cpp_printer_init (pfile, &parse_out); if (! print) return (FATAL_EXIT_CODE); + pfile->printer = print; if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname))) return (FATAL_EXIT_CODE); diff --git a/gcc/fix-header.c b/gcc/fix-header.c index 473ef7a..6ff458a 100644 --- a/gcc/fix-header.c +++ b/gcc/fix-header.c @@ -432,8 +432,6 @@ write_lbrac () struct partial_proto { struct partial_proto *next; - char *fname; /* name of function */ - char *rtype; /* return type */ struct fn_decl *fn; int line_seen; }; @@ -497,15 +495,13 @@ recognized_macro (fname) } void -recognized_extern (name, name_length, type, type_length) - const char *name; - const char *type ATTRIBUTE_UNUSED; - int name_length, type_length ATTRIBUTE_UNUSED; +recognized_extern (name) + const cpp_token *name; { switch (special_file_handling) { case errno_h: - if (name_length == 5 && strncmp (name, "errno", 5) == 0 && !seen_errno) + if (!cpp_idcmp (name->val.name.text, name->val.name.len, "errno")) seen_errno = 1, required_other--; break; @@ -515,25 +511,17 @@ recognized_extern (name, name_length, type, type_length) } /* Called by scan_decls if it saw a function definition for a function - named FNAME, with return type RTYPE, and argument list ARGS, - in source file FILE_SEEN on line LINE_SEEN. - KIND is 'I' for an inline function; - 'F' if a normal function declaration preceded by 'extern "C"' - (or nested inside 'extern "C"' braces); or + named FNAME, in source file FILE_SEEN on line LINE_SEEN. KIND is + 'I' for an inline function; 'F' if a normal function declaration + preceded by 'extern "C"' (or nested inside 'extern "C"' braces); or 'f' for other function declarations. */ void -recognized_function (fname, fname_length, - kind, rtype, rtype_length, - have_arg_list, file_seen, line_seen) - const char *fname; - int fname_length; +recognized_function (fname, kind, have_arg_list, file_seen) + const cpp_token *fname; int kind; /* One of 'f' 'F' or 'I' */ - const char *rtype; - int rtype_length; int have_arg_list; const char *file_seen; - int line_seen; { struct partial_proto *partial; int i; @@ -543,7 +531,8 @@ recognized_function (fname, fname_length, missing_extern_C_count++; #endif - fn = lookup_std_proto (fname, fname_length); + fn = lookup_std_proto ((const char *)fname->val.name.text, + fname->val.name.len); /* Remove the function from the list of required function. */ if (fn) @@ -577,12 +566,7 @@ recognized_function (fname, fname_length, partial_count++; partial = (struct partial_proto *) obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto)); - partial->fname = obstack_alloc (&scan_file_obstack, fname_length + 1); - bcopy (fname, partial->fname, fname_length); - partial->fname[fname_length] = 0; - partial->rtype = obstack_alloc (&scan_file_obstack, rtype_length + 1); - sprintf (partial->rtype, "%.*s", rtype_length, rtype); - partial->line_seen = line_seen; + partial->line_seen = fname->line; partial->fn = fn; fn->partial = partial; partial->next = partial_proto_list; @@ -590,7 +574,7 @@ recognized_function (fname, fname_length, if (verbose) { fprintf (stderr, "(%s: %s non-prototype function declaration.)\n", - inc_filename, partial->fname); + inc_filename, fn->fname); } } @@ -646,19 +630,12 @@ read_scan_file (in_fname, argc, argv) for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++) check_macro_names (&scan_in, cur_symbols->names); - if (verbose && (scan_in.errors + warnings) > 0) - fprintf (stderr, "(%s: %d errors and %d warnings from cpp)\n", - inc_filename, scan_in.errors, warnings); - if (scan_in.errors) - exit (SUCCESS_EXIT_CODE); - /* Traditionally, getc and putc are defined in terms of _filbuf and _flsbuf. If so, those functions are also required. */ if (special_file_handling == stdio_h && (fn = lookup_std_proto ("_filbuf", 7)) != NULL) { static const unsigned char getchar_call[] = "getchar();"; - int old_written = CPP_WRITTEN (&scan_in); int seen_filbuf = 0; cpp_buffer *buf = CPP_BUFFER (&scan_in); if (cpp_push_buffer (&scan_in, getchar_call, @@ -668,14 +645,17 @@ read_scan_file (in_fname, argc, argv) /* Scan the macro expansion of "getchar();". */ for (;;) { - enum cpp_ttype token = cpp_get_token (&scan_in); - int length = CPP_WRITTEN (&scan_in) - old_written; - unsigned char *id = scan_in.token_buffer + old_written; - - CPP_SET_WRITTEN (&scan_in, old_written); - if (token == CPP_EOF && CPP_BUFFER (&scan_in) == buf) - break; - if (token == CPP_NAME && cpp_idcmp (id, length, "_filbuf") == 0) + const cpp_token *t = cpp_get_token (&scan_in); + + if (t->type == CPP_EOF) + { + cpp_pop_buffer (&scan_in); + if (CPP_BUFFER (&scan_in) == buf) + break; + } + else if (t->type == CPP_NAME && cpp_idcmp (t->val.name.text, + t->val.name.len, + "_filbuf") == 0) seen_filbuf++; } if (seen_filbuf) @@ -1030,8 +1010,6 @@ check_protection (ifndef_line, endif_line) } else if (!strcmp (buf.base, "define")) { - if (if_nesting != 1) - goto skip_to_eol; c = inf_skip_spaces (c); c = inf_scan_ident (&buf, c); if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0) diff --git a/gcc/scan-decls.c b/gcc/scan-decls.c index e65d832..969b208 100644 --- a/gcc/scan-decls.c +++ b/gcc/scan-decls.c @@ -45,7 +45,7 @@ skip_to_closing_brace (pfile) int nesting = 1; for (;;) { - enum cpp_ttype token = cpp_get_token (pfile); + enum cpp_ttype token = cpp_get_token (pfile)->type; if (token == CPP_EOF) break; if (token == CPP_OPEN_BRACE) @@ -84,24 +84,17 @@ scan_decls (pfile, argc, argv) char **argv ATTRIBUTE_UNUSED; { int saw_extern, saw_inline; - int start_written; - /* If declarator_start is non-zero, it marks the start of the current - declarator. If it is zero, we are either still parsing the - decl-specs, or prev_id_start marks the start of the declarator. */ - int declarator_start; - int prev_id_start, prev_id_end = 0; - enum cpp_ttype token; + const cpp_token *prev_id; + const cpp_token *token; new_statement: - CPP_SET_WRITTEN (pfile, 0); - start_written = 0; token = cpp_get_token (pfile); handle_statement: current_extern_C = 0; saw_extern = 0; saw_inline = 0; - if (token == CPP_OPEN_BRACE) + if (token->type == CPP_OPEN_BRACE) { /* Pop an 'extern "C"' nesting level, if appropriate. */ if (extern_C_braces_length @@ -110,120 +103,112 @@ scan_decls (pfile, argc, argv) brace_nesting--; goto new_statement; } - if (token == CPP_OPEN_BRACE) + if (token->type == CPP_OPEN_BRACE) { brace_nesting++; goto new_statement; } - if (token == CPP_EOF) + if (token->type == CPP_EOF) { + cpp_pop_buffer (pfile); if (CPP_BUFFER (pfile) == NULL) return 0; - else - goto new_statement; + + goto new_statement; } - if (token == CPP_SEMICOLON) + if (token->type == CPP_SEMICOLON) goto new_statement; - if (token != CPP_NAME) + if (token->type != CPP_NAME) goto new_statement; - prev_id_start = 0; - declarator_start = 0; + prev_id = 0; for (;;) { - switch (token) + switch (token->type) { + default: + goto handle_statement; + case CPP_MULT: + case CPP_AND: + case CPP_PLACEMARKER: + /* skip */ + break; + + case CPP_COMMA: + case CPP_SEMICOLON: + if (prev_id && saw_extern) + { + recognized_extern (prev_id); + } + if (token->type == CPP_COMMA) + break; + /* ... fall through ... */ + case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE: + goto new_statement; + + case CPP_EOF: + cpp_pop_buffer (pfile); + if (CPP_BUFFER (pfile) == NULL) + return 0; + break; + case CPP_OPEN_PAREN: /* Looks like this is the start of a formal parameter list. */ - if (prev_id_start) + if (prev_id) { int nesting = 1; int have_arg_list = 0; - cpp_buffer *fbuf = cpp_file_buffer (pfile); - unsigned int func_lineno = CPP_BUF_LINE (fbuf); for (;;) { token = cpp_get_token (pfile); - if (token == CPP_OPEN_PAREN) + if (token->type == CPP_OPEN_PAREN) nesting++; - else if (token == CPP_CLOSE_PAREN) + else if (token->type == CPP_CLOSE_PAREN) { nesting--; if (nesting == 0) break; } - else if (token == CPP_EOF) + else if (token->type == CPP_EOF) break; - else if (token == CPP_NAME || token == CPP_ELLIPSIS) + else if (token->type == CPP_NAME + || token->type == CPP_ELLIPSIS) have_arg_list = 1; } - recognized_function (pfile->token_buffer + prev_id_start, - prev_id_end - prev_id_start, + recognized_function (prev_id, (saw_inline ? 'I' : in_extern_C_brace || current_extern_C - ? 'F' : 'f'), - pfile->token_buffer, prev_id_start, - have_arg_list, - fbuf->nominal_fname, func_lineno); - token = cpp_get_non_space_token (pfile); - if (token == CPP_OPEN_BRACE) + ? 'F' : 'f'), have_arg_list, + CPP_BUFFER (pfile)->nominal_fname); + token = cpp_get_token (pfile); + if (token->type == CPP_OPEN_BRACE) { /* skip body of (normally) inline function */ skip_to_closing_brace (pfile); goto new_statement; } - goto maybe_handle_comma; + if (token->type == CPP_SEMICOLON) + goto new_statement; } break; - case CPP_OTHER: - if (CPP_WRITTEN (pfile) == (size_t) start_written + 1 - && (CPP_PWRITTEN (pfile)[-1] == '*' - || CPP_PWRITTEN (pfile)[-1] == '&')) - declarator_start = start_written; - else - goto handle_statement; - break; - case CPP_COMMA: - case CPP_SEMICOLON: - if (prev_id_start && saw_extern) - { - recognized_extern (pfile->token_buffer + prev_id_start, - prev_id_end - prev_id_start, - pfile->token_buffer, - prev_id_start); - } - /* ... fall through ... */ - maybe_handle_comma: - if (token != CPP_COMMA) - goto new_statement; - - /* Handle multiple declarators in a single declaration, - as in: extern char *strcpy (), *strcat (), ... ; */ - if (declarator_start == 0) - declarator_start = prev_id_start; - CPP_SET_WRITTEN (pfile, declarator_start); - break; case CPP_NAME: /* "inline" and "extern" are recognized but skipped */ - if (!cpp_idcmp (pfile->token_buffer, - CPP_WRITTEN (pfile), "inline")) + if (!cpp_idcmp (token->val.name.text, token->val.name.len, "inline")) { saw_inline = 1; - CPP_SET_WRITTEN (pfile, start_written); } - else if (!cpp_idcmp (pfile->token_buffer, - CPP_WRITTEN (pfile), "extern")) + else if (!cpp_idcmp (token->val.name.text, + token->val.name.len, "extern")) { saw_extern = 1; - CPP_SET_WRITTEN (pfile, start_written); - token = cpp_get_non_space_token (pfile); - if (token == CPP_STRING - && strcmp (pfile->token_buffer, "\"C\"") == 0) + token = cpp_get_token (pfile); + if (token->type == CPP_STRING + && !cpp_idcmp (token->val.name.text, + token->val.name.len, "C")) { - CPP_SET_WRITTEN (pfile, start_written); current_extern_C = 1; - token = cpp_get_non_space_token (pfile); - if (token == CPP_OPEN_BRACE) + token = cpp_get_token (pfile); + if (token->type == CPP_OPEN_BRACE) { brace_nesting++; extern_C_braces[extern_C_braces_length++] @@ -236,29 +221,9 @@ scan_decls (pfile, argc, argv) break; } /* This may be the name of a variable or function. */ - prev_id_start = start_written; - prev_id_end = CPP_WRITTEN (pfile); - break; - - case CPP_OPEN_BRACE: case CPP_CLOSE_BRACE: case CPP_DIRECTIVE: - goto new_statement; /* handle_statement? */ - - case CPP_EOF: - if (CPP_BUFFER (pfile) == NULL) - return 0; - /* else fall through */ - - case CPP_HSPACE: case CPP_VSPACE: case CPP_COMMENT: - /* Skip initial white space. */ - if (start_written == 0) - CPP_SET_WRITTEN (pfile, 0); + prev_id = token; break; - - default: - prev_id_start = 0; } - - start_written = CPP_WRITTEN (pfile); token = cpp_get_token (pfile); } } @@ -50,6 +50,8 @@ struct fn_decl struct partial_proto *partial; }; +struct cpp_token; + extern int lineno; extern void sstring_append _PARAMS((sstring *, sstring *)); extern void make_sstring_space _PARAMS((sstring *, int)); @@ -58,8 +60,9 @@ extern int scan_ident _PARAMS((FILE *, sstring *, int)); extern int scan_string _PARAMS((FILE *, sstring *, int)); extern int read_upto _PARAMS((FILE *, sstring *, int)); extern unsigned long hash _PARAMS((const char *)); -extern void recognized_function _PARAMS((const char *, int, int, const char *, int, int, const char *, int)); -extern void recognized_extern _PARAMS((const char *, int, const char *, int)); +extern void recognized_function _PARAMS((const struct cpp_token *, int, int, + const char *)); +extern void recognized_extern _PARAMS((const struct cpp_token *)); extern unsigned int hashstr _PARAMS((const char *, unsigned int)); struct cpp_reader; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 283c2b5..1231dab 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2000-07-03 Zack Weinberg <zack@wolery.cumb.org> + + * testsuite/gcc.dg/cpp/19951025-1.c: Adjust regexps. + * testsuite/gcc.dg/cpp/19990703-1.c: Likewise. + * testsuite/gcc.dg/cpp/20000625-1.c: Likewise. + * testsuite/gcc.dg/cpp/20000625-2.c: Likewise. + + * testsuite/gcc.dg/cpp/macro1.c, + testsuite/gcc.dg/cpp/paste1.c, testsuite/gcc.dg/cpp/paste2.c, + testsuite/gcc.dg/cpp/paste3.c, testsuite/gcc.dg/cpp/paste4.c, + testsuite/gcc.dg/cpp/strify1.c, + testsuite/gcc.dg/cpp/strify2.c: New tests. + 2000-07-03 Jakub Jelinek <jakub@redhat.com> * gcc.c-torture/execute/20000703-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/cpp/19951025-1.c b/gcc/testsuite/gcc.dg/cpp/19951025-1.c index c243df0..283b5f5 100644 --- a/gcc/testsuite/gcc.dg/cpp/19951025-1.c +++ b/gcc/testsuite/gcc.dg/cpp/19951025-1.c @@ -1,4 +1,4 @@ /* { dg-do preprocess } */ /* { dg-error "include expects" "" { target *-*-* } 4 } */ -/* { dg-warning "no newline" "" { target *-*-* } 5 } */ +/* { dg-error "newline at end" "" { target *-*-* } 4 } */ #include /\ diff --git a/gcc/testsuite/gcc.dg/cpp/19990703-1.c b/gcc/testsuite/gcc.dg/cpp/19990703-1.c index 88dc9e6..c3ac233 100644 --- a/gcc/testsuite/gcc.dg/cpp/19990703-1.c +++ b/gcc/testsuite/gcc.dg/cpp/19990703-1.c @@ -14,7 +14,7 @@ int main(void) { - char *x = SP1(0,MZ); + char *x = SP1(0,MZ); /* { dg-warning "valid preprocessing token" "" } */ char *y = "0-0"; /* should be the expansion of SP1(0,MZ) */ if(strcmp(x, y)) diff --git a/gcc/testsuite/gcc.dg/cpp/20000625-1.c b/gcc/testsuite/gcc.dg/cpp/20000625-1.c index 9193e39..ddfdb99 100644 --- a/gcc/testsuite/gcc.dg/cpp/20000625-1.c +++ b/gcc/testsuite/gcc.dg/cpp/20000625-1.c @@ -11,6 +11,6 @@ main(void) { goto socket; - ENTRY(socket) + ENTRY(socket) /* { dg-warning "valid preprocessing token" "" } */ return 0; } diff --git a/gcc/testsuite/gcc.dg/cpp/20000625-2.c b/gcc/testsuite/gcc.dg/cpp/20000625-2.c index e983450..e0dd35c 100644 --- a/gcc/testsuite/gcc.dg/cpp/20000625-2.c +++ b/gcc/testsuite/gcc.dg/cpp/20000625-2.c @@ -7,6 +7,7 @@ #define xstr(x) #x const char a[] = str(symbol_version(getrlimit, GLIBC_2.0)); +/* { dg-warning "valid preprocessing token" "" { target *-*-* } 9 } */ const char b[] = str(getrlimit@GLIBC_2.0); const char c[] = "getrlimit@GLIBC_2.0"; diff --git a/gcc/testsuite/gcc.dg/cpp/macro1.c b/gcc/testsuite/gcc.dg/cpp/macro1.c new file mode 100644 index 0000000..60347ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/macro1.c @@ -0,0 +1,72 @@ +/* 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; +} diff --git a/gcc/testsuite/gcc.dg/cpp/paste1.c b/gcc/testsuite/gcc.dg/cpp/paste1.c new file mode 100644 index 0000000..7b07f74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/paste1.c @@ -0,0 +1,10 @@ +/* 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" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/paste2.c b/gcc/testsuite/gcc.dg/cpp/paste2.c new file mode 100644 index 0000000..1ce13a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/paste2.c @@ -0,0 +1,115 @@ +/* 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; +} diff --git a/gcc/testsuite/gcc.dg/cpp/paste3.c b/gcc/testsuite/gcc.dg/cpp/paste3.c new file mode 100644 index 0000000..0c9c52d --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/paste3.c @@ -0,0 +1,14 @@ +/* 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; +} diff --git a/gcc/testsuite/gcc.dg/cpp/paste4.c b/gcc/testsuite/gcc.dg/cpp/paste4.c new file mode 100644 index 0000000..fac1d43 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/paste4.c @@ -0,0 +1,14 @@ +/* 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; +} diff --git a/gcc/testsuite/gcc.dg/cpp/strify1.c b/gcc/testsuite/gcc.dg/cpp/strify1.c new file mode 100644 index 0000000..3535540 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/strify1.c @@ -0,0 +1,10 @@ +/* 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" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/strify2.c b/gcc/testsuite/gcc.dg/cpp/strify2.c new file mode 100644 index 0000000..ddde976 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/strify2.c @@ -0,0 +1,45 @@ +/* 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; +} |