diff options
author | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-04 01:58:21 +0000 |
---|---|---|
committer | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-04 01:58:21 +0000 |
commit | f80e83a9f911d6ad59031508c14d19b65bae1738 (patch) | |
tree | 1c91fa44eb386dd706e44d139ed980ea94f05cae /gcc/cpphash.c | |
parent | 89675bc17a113f0dc6d81a3f086c42613ecd7b57 (diff) | |
download | gcc-f80e83a9f911d6ad59031508c14d19b65bae1738.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@34859 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cpphash.c')
-rw-r--r-- | gcc/cpphash.c | 1998 |
1 files changed, 360 insertions, 1638 deletions
diff --git a/gcc/cpphash.c b/gcc/cpphash.c index d82c2850809..ba812d5e2de 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; } |