diff options
author | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-18 00:59:49 +0000 |
---|---|---|
committer | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-18 00:59:49 +0000 |
commit | 69461e0d90d5ee950b9e0b8ba60d4bbf3299f472 (patch) | |
tree | a8929adb35764d62c4016b482a4cb4b619be00cb | |
parent | c25f946dfdb078a45f04f77f6d2ba17241d27716 (diff) | |
download | gcc-69461e0d90d5ee950b9e0b8ba60d4bbf3299f472.tar.gz |
2000-02-17 Zack Weinberg <zack@wolery.cumb.org>
* cpphash.c: Don't include hashtab.h. Most macro-handling code
moved to cppmacro.c.
(hash_HASHNODE, eq_HASHNODE, _cpp_dump_macro_hash,
dump_hash_helper): Delete.
(expand_hash, higher_prime_number, _cpp_lookup_with_hash,
cpp_forall_identifiers): New. Implement specialized version of
Vlad's expandable hash table.
(cpp_lookup): Use new functions.
(_cpp_init_macros, _cpp_cleanup_macros): Adjust for new
implementation.
* cppmacro.c: New file.
* cppinit.c (dump_macros_helper): New.
(cpp_finish): Iterate over the identifier table directly.
* cpplex.c (parse_name): Calculate the hash of the identifier
while we scan it. Use _cpp_lookup_with_hash when we can.
* cpphash.h: Update prototypes.
(xcnewvec, HASHSTEP): New helper macros.
* cpplib.h: Update prototypes.
* Makefile.in (LIBCPP_OBJS): Add cppmacro.o.
(cppmacro.o): New rule.
(cpphash.o): Update deps.
* cppmain.c: Do not set pfile->printer if no_output is on.
2000-02-15 Neil Booth <neilb@earthling.net>
* cpplib.c: Change all directive-handler functions to return
void, not int.
* cpphash.h: Update typedefs.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@35113 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 33 | ||||
-rw-r--r-- | gcc/Makefile.in | 9 | ||||
-rw-r--r-- | gcc/cpphash.c | 814 | ||||
-rw-r--r-- | gcc/cpphash.h | 15 | ||||
-rw-r--r-- | gcc/cppinit.c | 15 | ||||
-rw-r--r-- | gcc/cpplex.c | 19 | ||||
-rw-r--r-- | gcc/cpplib.c | 90 | ||||
-rw-r--r-- | gcc/cpplib.h | 24 | ||||
-rw-r--r-- | gcc/cppmacro.c | 603 | ||||
-rw-r--r-- | gcc/cppmain.c | 3 |
10 files changed, 902 insertions, 723 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 32bd5a6dbc3..16065e22b89 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,36 @@ +2000-02-17 Zack Weinberg <zack@wolery.cumb.org> + + * cpphash.c: Don't include hashtab.h. Most macro-handling code + moved to cppmacro.c. + (hash_HASHNODE, eq_HASHNODE, _cpp_dump_macro_hash, + dump_hash_helper): Delete. + (expand_hash, higher_prime_number, _cpp_lookup_with_hash, + cpp_forall_identifiers): New. Implement specialized version of + Vlad's expandable hash table. + (cpp_lookup): Use new functions. + (_cpp_init_macros, _cpp_cleanup_macros): Adjust for new + implementation. + * cppmacro.c: New file. + * cppinit.c (dump_macros_helper): New. + (cpp_finish): Iterate over the identifier table directly. + * cpplex.c (parse_name): Calculate the hash of the identifier + while we scan it. Use _cpp_lookup_with_hash when we can. + + * cpphash.h: Update prototypes. + (xcnewvec, HASHSTEP): New helper macros. + * cpplib.h: Update prototypes. + * Makefile.in (LIBCPP_OBJS): Add cppmacro.o. + (cppmacro.o): New rule. + (cpphash.o): Update deps. + + * cppmain.c: Do not set pfile->printer if no_output is on. + +2000-02-15 Neil Booth <neilb@earthling.net> + + * cpplib.c: Change all directive-handler functions to return + void, not int. + * cpphash.h: Update typedefs. + 2000-07-17 Geoffrey Keating <geoffk@cygnus.com> * configure: Regenerate. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 17e2eb2bd29..6566b090f7d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1782,9 +1782,9 @@ PREPROCESSOR_DEFINES = \ -DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \ -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" -LIBCPP_OBJS = cpplib.o cpphash.o cpperror.o cppexp.o cppfiles.o \ - cppinit.o cppulp.o cpplex.o cppdefault.o mkdeps.o \ - prefix.o version.o mbchar.o @extra_cpp_objs@ +LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \ + cpphash.o cpperror.o cppinit.o cppulp.o cppdefault.o \ + mkdeps.o prefix.o version.o mbchar.o @extra_cpp_objs@ LIBCPP_DEPS = cpplib.h cpphash.h intl.h system.h @@ -1806,8 +1806,9 @@ cppulp.o: cppulp.c $(CONFIG_H) system.h output.h cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS) cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS) cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS) +cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS) cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H) -cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H) $(HASHTAB_H) +cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H) cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h cppinit.o: cppinit.c $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \ mkdeps.h prefix.h output.h version.h diff --git a/gcc/cpphash.c b/gcc/cpphash.c index b7f3944c4e5..c26f7b54c4c 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -1,4 +1,4 @@ -/* Part of CPP library. (Macro handling.) +/* Part of CPP library. (Identifier and string tables.) Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000 Free Software Foundation, Inc. Written by Per Bothner, 1994. @@ -27,720 +27,252 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "system.h" #include "cpplib.h" #include "cpphash.h" -#include "hashtab.h" #include "obstack.h" #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free -/* This is the second argument to eq_HASHNODE. */ -struct hashdummy -{ - const U_CHAR *name; - unsigned int hash; - unsigned short length; -}; +/* Initial hash table size. (It can grow if necessary.) This is the + largest prime number smaller than 2**12. */ +#define HASHSIZE 4093 -/* Stores basic information about a macro, before it is allocated. */ -struct macro_info +/* This is the structure used for the hash table. */ +struct htab { - const cpp_token *first_param; /* First parameter token. */ - const cpp_token *first; /* First expansion token. */ - unsigned int paramlen; /* Length of parameter names. */ - unsigned int len; /* Length of token strings. */ - unsigned int ntokens; /* Number of tokens in expansion. */ - short paramc; /* Number of parameters. */ - unsigned char flags; + struct cpp_hashnode **entries; + size_t size; + size_t nelts; }; -/* Initial hash table size. (It can grow if necessary - see hashtab.c.) */ -#define HASHSIZE 4096 - -static unsigned int hash_HASHNODE PARAMS ((const void *)); -static int eq_HASHNODE PARAMS ((const void *, const void *)); -static int dump_hash_helper PARAMS ((void **, void *)); -static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *)); -static void count_params PARAMS ((cpp_reader *, struct macro_info *)); -static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *)); - -static int parse_define PARAMS((cpp_reader *, struct macro_info *)); -static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp, - const cpp_toklist *)); -static const cpp_toklist * save_expansion PARAMS((cpp_reader *, - struct macro_info *)); -static unsigned int find_param PARAMS ((const cpp_token *, - const cpp_token *)); -static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *)); - -/* Calculate hash of a string of length LEN. */ -unsigned int -_cpp_calc_hash (str, len) - const U_CHAR *str; - size_t len; -{ - size_t n = len; - unsigned int r = 0; - - do - r = r * 67 + (*str++ - 113); - while (--n); - return r + len; -} - -/* Calculate hash of a cpp_hashnode structure. */ -static unsigned int -hash_HASHNODE (x) - const void *x; -{ - const cpp_hashnode *h = (const cpp_hashnode *)x; - return h->hash; -} - -/* Compare a cpp_hashnode structure (already in the table) with a - hashdummy structure (not yet in the table). This relies on the - rule that the existing entry is the first argument, the potential - entry the second. It also relies on the comparison function never - being called except as a direct consequence of a call to - the htab_find routines. */ -static int -eq_HASHNODE (x, y) - const void *x; - const void *y; -{ - const cpp_hashnode *a = (const cpp_hashnode *)x; - const struct hashdummy *b = (const struct hashdummy *)y; - - return (a->hash == b->hash - && a->length == b->length - && !memcmp (a->name, b->name, a->length)); -} - -/* Find the hash node for name "name", of length LEN. */ - -cpp_hashnode * -cpp_lookup (pfile, name, len) - cpp_reader *pfile; - const U_CHAR *name; - int len; -{ - struct hashdummy dummy; - cpp_hashnode *new, **slot; - unsigned int hash; - U_CHAR *p; - - dummy.name = name; - dummy.length = len; - dummy.hash = hash = _cpp_calc_hash (name, len); - - slot = (cpp_hashnode **) - htab_find_slot_with_hash (pfile->hashtab, (void *)&dummy, hash, INSERT); - if (*slot) - return *slot; - - /* Create a new hash node. */ - p = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode) + len); - new = (cpp_hashnode *)p; - p += offsetof (cpp_hashnode, name); - - new->type = T_VOID; - new->length = len; - new->hash = hash; - new->fe_value = 0; - new->value.expansion = NULL; - - memcpy (p, name, len); - p[len] = 0; - - *slot = new; - return new; -} +static void expand_hash PARAMS ((struct htab *)); +static unsigned long higher_prime_number PARAMS ((unsigned long)); /* Set up and tear down internal structures for macro expansion. */ void _cpp_init_macros (pfile) cpp_reader *pfile; { - pfile->hashtab = htab_create (HASHSIZE, hash_HASHNODE, - eq_HASHNODE, (htab_del) _cpp_free_definition); pfile->hash_ob = xnew (struct obstack); obstack_init (pfile->hash_ob); -} - -void -_cpp_cleanup_macros (pfile) - cpp_reader *pfile; -{ - htab_delete (pfile->hashtab); - obstack_free (pfile->hash_ob, 0); - free (pfile->hash_ob); -} - -/* Free the definition of macro H. */ - -void -_cpp_free_definition (h) - cpp_hashnode *h; -{ - if (h->type == T_MACRO) - free ((PTR) h->value.expansion); - h->value.expansion = NULL; -} -/* 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 -find_param (first, token) - const cpp_token *first, *token; -{ - unsigned int param = 0; - - for (; first < token && first->type != CPP_CLOSE_PAREN; first++) - if (first->type == CPP_NAME) - { - param++; - if (first->val.node == token->val.node) - return param; - } + pfile->hashtab = xobnew (pfile->hash_ob, struct htab); - return 0; + pfile->hashtab->nelts = 0; + pfile->hashtab->size = HASHSIZE; + pfile->hashtab->entries = xcnewvec (cpp_hashnode *, HASHSIZE); } -/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the - replacement list of a variable-arguments macro. TOKEN is assumed - to be of type CPP_NAME. */ -static int -is__va_args__ (pfile, token) - cpp_reader *pfile; - const cpp_token *token; -{ - if (!CPP_PEDANTIC (pfile) - || token->val.node != pfile->spec_nodes->n__VA_ARGS__) - return 0; - - cpp_pedwarn_with_line (pfile, token->line, token->col, - "\"%s\" is only valid in the replacement list of a function-like macro", - token->val.node->name); - return 1; -} - -/* Counts the parameters to a function-like macro, the length of their - null-terminated names, and whether the macro is a variable-argument - one. FIRST is the token immediately after the open parenthesis, - INFO stores the data. - - On success, info->first is updated to the token after the closing - parenthesis, i.e. the first token of the expansion. Otherwise - there was an error, which has been reported. */ -static void -count_params (pfile, info) +void +_cpp_cleanup_macros (pfile) cpp_reader *pfile; - struct macro_info *info; { - unsigned int prev_ident = 0; - const cpp_token *token; + cpp_hashnode **p, **limit; - info->paramc = 0; - info->paramlen = 0; - info->flags = 0; - info->first = info->first_param; /* Not a ')' indicating success. */ - - for (token = info->first_param;; token++) + p = pfile->hashtab->entries; + limit = p + pfile->hashtab->size; + do { - switch (token->type) + if (*p) { - default: - cpp_error_with_line (pfile, token->line, token->col, - "illegal token in macro parameter list"); - return; - - case CPP_EOF: - missing_paren: - cpp_error_with_line (pfile, token->line, token->col, - "missing ')' in macro parameter list"); - return; - - case CPP_COMMENT: - continue; /* Ignore -C comments. */ - - case CPP_NAME: - if (prev_ident) - { - cpp_error_with_line (pfile, token->line, token->col, - "macro parameters must be comma-separated"); - return; - } - - /* Constraint 6.10.3.5 */ - if (is__va_args__ (pfile, token)) - return; - - /* Constraint 6.10.3.6 - duplicate parameter names. */ - if (find_param (info->first, token)) - { - cpp_error_with_line (pfile, token->line, token->col, - "duplicate macro parameter \"%s\"", - token->val.node->name); - return; - } - - prev_ident = 1; - info->paramc++; - info->paramlen += token->val.node->length + 1; - continue; - - case CPP_CLOSE_PAREN: - if (prev_ident || info->paramc == 0) - break; - - /* Fall through to pick up the error. */ - case CPP_COMMA: - if (!prev_ident) - { - cpp_error_with_line (pfile, token->line, token->col, - "parameter name expected"); - return; - } - prev_ident = 0; - continue; - - 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. */ - if (!prev_ident) - { - cpp_token *tok = (cpp_token *) token; - - tok->type = CPP_NAME; - tok->val.node = pfile->spec_nodes->n__VA_ARGS__; - - info->paramc++; - info->paramlen += tok->val.node->length + 1; - - if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) - cpp_pedwarn (pfile, - "C89 does not permit anon varargs macros"); - } - else - { - info->flags |= GNU_REST_ARGS; - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, - "ISO C does not permit named varargs parameters"); - } - - info->flags |= VAR_ARGS; - token++; - if (token->type == CPP_CLOSE_PAREN) - break; - goto missing_paren; + _cpp_free_definition (*p); + (*p)->fe_value = 0; /* expose the node to GC */ } - - /* Success. */ - info->first = token + 1; - if (!pfile->save_parameter_spellings) - info->paramlen = 0; - return; } + while (++p < limit); + + free (pfile->hashtab->entries); + obstack_free (pfile->hash_ob, 0); + free (pfile->hash_ob); } -/* Parses a #define directive. On success, returns zero, and INFO is - filled in appropriately. */ -static int -parse_define (pfile, info) +/* The code below is a specialization of Vladimir Makarov's expandable + hash tables (see libiberty/hashtab.c). The abstraction penalty was + too high to continue using the generic form. This code knows + intrinsically how to calculate a hash value, and how to compare an + existing entry with a potential new one. Also, the ability to + delete members from the table has been removed. */ + +cpp_hashnode * +cpp_lookup (pfile, name, len) cpp_reader *pfile; - struct macro_info *info; + const U_CHAR *name; + size_t len; { - const cpp_token *token; - int prev_white = 0; - - /* The first token after the macro's name. */ - token = _cpp_get_token (pfile); - - /* Constraint 6.10.3.5 */ - if (is__va_args__ (pfile, token - 1)) - return 1; - - while (token->type == CPP_COMMENT) - token++, prev_white = 1; - prev_white |= token->flags & PREV_WHITE; + size_t n = len; + unsigned int r = 0; + const U_CHAR *str = name; - if (token->type == CPP_OPEN_PAREN && !prev_white) - { - /* A function-like macro. */ - info->first_param = token + 1; - count_params (pfile, info); - if (info->first[-1].type != CPP_CLOSE_PAREN) - return 1; - } - else + do { - /* An object-like macro. */ - info->paramc = -1; - info->paramlen = 0; - info->flags = 0; - info->first = token; - if (!prev_white && token->type != CPP_EOF) - cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name"); + r = HASHSTEP (r, str); + str++; } + while (--n); - /* Count tokens in expansion. We drop paste tokens, and stringize - tokens, so don't count them. */ - info->ntokens = info->len = 0; - for (token = info->first; token->type != CPP_EOF; token++) - { - if (token->type == CPP_PASTE) - { - /* Token-paste ##, can appear in both object-like and - function-like macros, but not at the ends. Constraint - 6.10.3.3.1 */ - if (token == info->first || token[1].type == CPP_EOF) - { - cpp_error_with_line (pfile, token->line, token->col, - "'##' cannot appear at either end of a macro expansion"); - return 1; - } - continue; - } - else if (token->type == CPP_HASH) - { - /* Stringifying #, but a normal character in object-like - macros. Must come before a parameter name. Constraint - 6.10.3.2.1. */ - if (info->paramc >= 0) - { - if (token[1].type == CPP_NAME - && find_param (info->first_param, token + 1)) - continue; - if (! CPP_OPTION (pfile, lang_asm)) - { - cpp_error_with_line (pfile, token->line, token->col, - "'#' is not followed by a macro parameter"); - return 1; - } - } - } - else if (token->type == CPP_NAME) - { - /* Constraint 6.10.3.5 */ - if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token)) - return 1; - /* It might be worth doing a check here that we aren't a - macro argument, since we don't store the text of macro - arguments. This would reduce "len" and save space. */ - } - info->ntokens++; - if (TOKEN_SPELL (token) == SPELL_STRING) - info->len += token->val.str.len; - } - - return 0; + return _cpp_lookup_with_hash (pfile, name, len, r); } -/* Returns non-zero if a macro redefinition is trivial. */ -static int -check_macro_redefinition (pfile, hp, list2) +cpp_hashnode * +_cpp_lookup_with_hash (pfile, name, len, hash) cpp_reader *pfile; - cpp_hashnode *hp; - const cpp_toklist *list2; + const U_CHAR *name; + size_t len; + unsigned int hash; { - const cpp_toklist *list1; + unsigned int index; + unsigned int hash2; + size_t size; + cpp_hashnode *entry; + cpp_hashnode **entries; - if (hp->type != T_MACRO) - return ! pfile->done_initializing; + entries = pfile->hashtab->entries; + size = pfile->hashtab->size; - /* 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); + hash += len; + index = hash % size; - if (!_cpp_equiv_toklists (list1, list2)) - return 0; + entry = entries[index]; + if (entry == NULL) + goto insert; + if (entry->hash == hash && entry->length == len + && !memcmp (entry->name, name, len)) + return entry; - if (CPP_OPTION (pfile, pedantic) - && list1->paramc > 0 - && (list1->params_len != list2->params_len - || memcmp (list1->namebuf, list2->namebuf, list1->params_len))) - return 0; + hash2 = 1 + hash % (size - 2); - return 1; -} - -/* This is a dummy structure whose only purpose is getting alignment - correct. */ -struct toklist_dummy -{ - cpp_toklist list; - cpp_token first_token; -}; - - -/* Allocate space to hold the token list, its tokens, their text, and - the parameter names if needed. Empty expansions are stored as a - single placemarker token. - - These are all allocated in a block together for performance - reasons. Therefore, this token list cannot be expanded like a - normal token list. Try to do so, and you lose. */ -static cpp_toklist * -alloc_macro (pfile, info) - cpp_reader *pfile; - struct macro_info *info; -{ - unsigned int size; - struct toklist_dummy *dummy; - cpp_toklist *list; - - /* Empty macros become a single placemarker token. */ - if (info->ntokens == 0) - info->ntokens = 1; - - size = sizeof (struct toklist_dummy); - size += (info->ntokens - 1) * sizeof(cpp_token); - size += info->len + info->paramlen; - - dummy = (struct toklist_dummy *) xmalloc (size); - list = (cpp_toklist *) dummy; - - /* Initialize the monster. */ - list->tokens = &dummy->first_token; - list->tokens_used = list->tokens_cap = info->ntokens; - - list->namebuf = (unsigned char *) &list->tokens[info->ntokens]; - list->name_used = list->name_cap = info->len + info->paramlen; - - list->directive = 0; - list->line = pfile->token_list.line; - list->file = pfile->token_list.file; - list->params_len = info->paramlen; - list->paramc = info->paramc; - list->flags = info->flags; - - return list; -} - -/* Copy the tokens of the expansion, beginning with info->first until - CPP_EOF. INFO contains information about the macro. - - Change the type of macro arguments in the expansion 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 the - token list for the macro expansion. */ -static const cpp_toklist * -save_expansion (pfile, info) - cpp_reader *pfile; - struct macro_info *info; -{ - const cpp_token *token; - cpp_toklist *list; - cpp_token *dest; - unsigned char *buf; - - list = alloc_macro (pfile, info); - buf = list->namebuf; - - /* Store the null-terminated parameter spellings of a macro, to - provide pedantic warnings to satisfy 6.10.3.2, or for use when - dumping macro definitions. They must go first. */ - if (list->params_len) - for (token = info->first_param; token < info->first; token++) - if (token->type == CPP_NAME) - { - /* Copy null too. */ - memcpy (buf, token->val.node->name, token->val.node->length + 1); - buf += token->val.node->length + 1; - } - - dest = list->tokens; - for (token = info->first; token->type != CPP_EOF; token++) + for (;;) { - unsigned int param_no; - - switch (token->type) - { - case CPP_NAME: - if (list->paramc == -1) - break; - - /* Check if the name is a macro parameter. */ - param_no = find_param (info->first_param, token); - if (param_no == 0) - break; - dest->val.aux = param_no - 1; - - dest->type = CPP_MACRO_ARG; - if (token[-1].type == CPP_HASH) - dest->flags = token[-1].flags | STRINGIFY_ARG; - else - dest->flags = token->flags; /* Particularly PREV_WHITE. */ - /* Turn off PREV_WHITE if we immediately follow a paste. - That way, even if the paste turns out to be illegal, there - will be no space between the two tokens in the output. */ - if (token[-1].type == CPP_PASTE) - dest->flags &= ~PREV_WHITE; - dest++; - continue; - - case CPP_PASTE: - dest[-1].flags |= PASTE_LEFT; - continue; - - case CPP_HASH: - /* Stringifying #. Constraint 6.10.3.2.1 */ - if (list->paramc >= 0 && token[1].type == CPP_NAME - && find_param (info->first_param, token + 1)) - continue; - break; - - default: - break; - } - - /* Copy the token. */ - *dest = *token; - if (TOKEN_SPELL (token) == SPELL_STRING) - { - memcpy (buf, token->val.str.text, token->val.str.len); - dest->val.str.text = buf; - buf += dest->val.str.len; - } - if (token[-1].type == CPP_PASTE) - dest->flags &= ~PREV_WHITE; - dest++; + index += hash2; + if (index >= size) + index -= size; + entry = entries[index]; + + if (entry == NULL) + goto insert; + if (entry->hash == hash && entry->length == len + && !memcmp (entry->name, name, len)) + return entry; } - /* Empty macros become a single placemarker token. */ - if (dest == list->tokens) - { - dest->type = CPP_PLACEMARKER; - dest->flags = 0; - } + insert: + pfile->hashtab->nelts++; - return list; + /* Create a new hash node. */ + { + U_CHAR *p = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode) + len); + entry = (cpp_hashnode *)p; + p += offsetof (cpp_hashnode, name); + + entry->type = T_VOID; + entry->fe_value = 0; + entry->length = len; + entry->hash = hash; + entry->value.expansion = NULL; + memcpy (p, name, len); + p[len] = 0; + + entries[index] = entry; + } + + if (size * 3 <= pfile->hashtab->nelts * 4) + expand_hash (pfile->hashtab); + + return entry; } -/* Parse a macro and save its expansion. Returns non-zero on success. */ -int -_cpp_create_definition (pfile, hp) - cpp_reader *pfile; - cpp_hashnode *hp; +static void +expand_hash (htab) + struct htab *htab; { - struct macro_info info; - const cpp_toklist *list; + cpp_hashnode **oentries; + cpp_hashnode **olimit; + cpp_hashnode **p; + size_t size; - if (parse_define (pfile, &info)) - return 0; - list = save_expansion (pfile, &info); + oentries = htab->entries; + olimit = oentries + htab->size; - /* 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). */ + htab->size = size = higher_prime_number (htab->size * 2); + htab->entries = xcnewvec (cpp_hashnode *, size); - if (hp->type != T_VOID) + for (p = oentries; p < olimit; p++) { - if (!check_macro_redefinition (pfile, hp, list)) + if (*p != NULL) { - 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); - } - - /* Enter definition in hash table. */ - hp->type = T_MACRO; - hp->value.expansion = list; + unsigned int index; + unsigned int hash, hash2; + cpp_hashnode *entry = *p; - return 1; -} + hash = entry->hash; + index = hash % size; -/* Dump the definition of macro MACRO on stdout. The format is suitable - to be read back in again. */ + if (htab->entries[index] == NULL) + { + insert: + htab->entries[index] = entry; + continue; + } -void -_cpp_dump_definition (pfile, hp) - cpp_reader *pfile; - cpp_hashnode *hp; -{ - CPP_RESERVE (pfile, hp->length + sizeof "#define "); - CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1); - CPP_PUTS_Q (pfile, hp->name, hp->length); + hash2 = 1 + hash % (size - 2); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; - if (hp->type == T_MACRO) - { - if (hp->value.expansion->paramc >= 0) - dump_funlike_macro (pfile, hp); - else - { - 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); + if (htab->entries[index] == NULL) + goto insert; + } } } - 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'); + free (oentries); } -static void -dump_funlike_macro (pfile, node) - cpp_reader *pfile; - cpp_hashnode *node; +/* The following function returns the nearest prime number which is + greater than a given source number, N. */ + +static unsigned long +higher_prime_number (n) + unsigned long n; { - int i = 0; - const cpp_toklist * list = node->value.expansion; - const U_CHAR *param; + unsigned long i; - param = list->namebuf; - CPP_PUTC_Q (pfile, '('); - for (i = 0; i++ < list->paramc;) - { - unsigned int len; + /* Ensure we have a larger number and then force to odd. */ + n++; + n |= 0x01; - 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, U"__VA_ARGS__")) - pfile->limit -= sizeof (U"__VA_ARGS__") - 1; - CPP_PUTS_Q (pfile, "...", 3); - } - param += len + 1; - } - CPP_PUTC (pfile, ')'); - list->tokens[0].flags &= ~BOL; - list->tokens[0].flags |= PREV_WHITE; - _cpp_dump_list (pfile, list, list->tokens, 1); -} + /* All odd numbers < 9 are prime. */ + if (n < 9) + return n; -/* Dump out the hash table. */ -static int -dump_hash_helper (h, p) - void **h; - void *p; -{ - cpp_hashnode *hp = (cpp_hashnode *)*h; - cpp_reader *pfile = (cpp_reader *)p; + /* Otherwise find the next prime using a sieve. */ + + next: + for (i = 3; i * i <= n; i += 2) + if (n % i == 0) + { + n += 2; + goto next; + } - if (hp->type == T_MACRO) - _cpp_dump_definition (pfile, hp); - return 1; + return n; } void -_cpp_dump_macro_hash (pfile) +cpp_forall_identifiers (pfile, cb) cpp_reader *pfile; + int (*cb) PARAMS ((cpp_reader *, cpp_hashnode *)); { - htab_traverse (pfile->hashtab, dump_hash_helper, pfile); + cpp_hashnode **p, **limit; + + p = pfile->hashtab->entries; + limit = p + pfile->hashtab->size; + do + { + if (*p) + if ((*cb) (pfile, *p) == 0) + break; + } + while (++p < limit); } diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 5f4f86bedb6..98fcbb67ecf 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -72,7 +72,7 @@ struct answer #define COMMENTS (1 << 3) /* Defines one #-directive, including how to handle it. */ -typedef int (*directive_handler) PARAMS ((cpp_reader *)); +typedef void (*directive_handler) PARAMS ((cpp_reader *)); struct directive { directive_handler handler; /* Function to handle directive. */ @@ -202,18 +202,24 @@ extern unsigned char _cpp_IStable[256]; #define CPP_WTRADITIONAL(PF) \ (CPP_OPTION (PF, warn_traditional) && !CPP_IN_SYSTEM_HEADER (PF)) +/* Hash step. The hash calculation is duplicated in cpp_lookup and + parse_name. */ +#define HASHSTEP(r, str) ((r) * 67 + (*str - 113)); + /* Flags for _cpp_init_toklist. */ #define DUMMY_TOKEN 0 #define NO_DUMMY_TOKEN 1 -/* In cpphash.c */ -extern unsigned int _cpp_calc_hash PARAMS ((const U_CHAR *, size_t)); +/* In cppmacro.c */ extern void _cpp_free_definition PARAMS ((cpp_hashnode *)); extern int _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *)); extern void _cpp_dump_definition PARAMS ((cpp_reader *, cpp_hashnode *)); + +/* In cpphash.c */ extern void _cpp_init_macros PARAMS ((cpp_reader *)); extern void _cpp_cleanup_macros PARAMS ((cpp_reader *)); -extern void _cpp_dump_macro_hash PARAMS ((cpp_reader *)); +extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, const U_CHAR *, + size_t, unsigned int)); /* In cppfiles.c */ extern void _cpp_simplify_pathname PARAMS ((char *)); @@ -278,6 +284,7 @@ extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *)); /* Utility routines and macros. */ #define xnew(T) (T *) xmalloc (sizeof(T)) #define xnewvec(T, N) (T *) xmalloc (sizeof(T) * (N)) +#define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T)) #define xobnew(O, T) (T *) obstack_alloc (O, sizeof(T)) /* These are inline functions instead of macros so we can get type diff --git a/gcc/cppinit.c b/gcc/cppinit.c index c31b2fda366..a58f459b8ba 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -114,6 +114,7 @@ static int opt_comp PARAMS ((const void *, const void *)); static void sort_options PARAMS ((void)); #endif static int parse_option PARAMS ((const char *)); +static int dump_macros_helper PARAMS ((cpp_reader *, cpp_hashnode *)); /* Fourth argument to append_include_chain: chain to use */ enum { QUOTE = 0, BRACKET, SYSTEM, AFTER }; @@ -891,6 +892,18 @@ cpp_start_read (pfile, print, fname) return 1; } + +/* Dump out the hash table. */ +static int +dump_macros_helper (pfile, hp) + cpp_reader *pfile; + cpp_hashnode *hp; +{ + if (hp->type == T_MACRO) + _cpp_dump_definition (pfile, hp); + return 1; +} + /* This is called at the end of preprocessing. It pops the last buffer and writes dependency output. It should also clear macro definitions, such that you could call cpp_start_read @@ -934,7 +947,7 @@ cpp_finish (pfile, print) } if (CPP_OPTION (pfile, dump_macros) == dump_only) - _cpp_dump_macro_hash (pfile); + cpp_forall_identifiers (pfile, dump_macros_helper); /* Flush any pending output. */ if (print) diff --git a/gcc/cpplex.c b/gcc/cpplex.c index fe337c0a852..a41e4eea6ed 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -1070,16 +1070,21 @@ skip_whitespace (pfile, in_directive) } } -/* Parse (append) an identifier. */ +/* Parse (append) an identifier. Calculates the hash value of the + token while parsing, for performance. The algorithm *must* match + cpp_lookup(). */ static const U_CHAR * parse_name (pfile, tok, cur, rlimit) cpp_reader *pfile; cpp_token *tok; const U_CHAR *cur, *rlimit; { - const U_CHAR *name = cur; + const U_CHAR *name; unsigned int len; + unsigned int r; + name = cur; + r = 0; while (cur < rlimit) { if (! is_idchar (*cur)) @@ -1092,21 +1097,23 @@ parse_name (pfile, tok, cur, rlimit) CPP_BUFFER (pfile)->cur = cur; cpp_pedwarn (pfile, "'$' character in identifier"); } + + r = HASHSTEP (r, cur); cur++; } len = cur - name; - if (tok->val.node) + if (tok->val.node == 0) + tok->val.node = _cpp_lookup_with_hash (pfile, name, len, r); + else { unsigned int oldlen = tok->val.node->length; U_CHAR *newname = alloca (oldlen + len); memcpy (newname, tok->val.node->name, oldlen); memcpy (newname + oldlen, name, len); - len += oldlen; - name = newname; + tok->val.node = cpp_lookup (pfile, newname, len + oldlen); } - tok->val.node = cpp_lookup (pfile, name, len); return cur; } diff --git a/gcc/cpplib.c b/gcc/cpplib.c index aaf55a0d3c5..adbd8d1e8ae 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -113,7 +113,7 @@ SCCS_ENTRY /* 0 SVR2? */ pointers to functions returning void. */ /* Don't invoke CONCAT2 with any whitespace or K&R cc will fail. */ -#define D(name, t, o, f) static int CONCAT2(do_,name) PARAMS ((cpp_reader *)); +#define D(name, t, o, f) static void CONCAT2(do_,name) PARAMS ((cpp_reader *)); DIRECTIVE_TABLE #undef D @@ -272,7 +272,7 @@ get_define_node (pfile) } /* Process a #define command. */ -static int +static void do_define (pfile) cpp_reader *pfile; { @@ -287,11 +287,10 @@ do_define (pfile) 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 +static void do_undef (pfile) cpp_reader *pfile; { @@ -317,8 +316,6 @@ do_undef (pfile) _cpp_free_definition (node); node->type = T_VOID; } - - return 0; } @@ -360,7 +357,7 @@ parse_include (pfile, dir, trail, strp, lenp, abp) return 0; } -static int +static void do_include (pfile) cpp_reader *pfile; { @@ -369,15 +366,14 @@ do_include (pfile) int ab; if (parse_include (pfile, dtable[T_INCLUDE].name, 0, &str, &len, &ab)) - return 0; + return; _cpp_execute_include (pfile, str, len, 0, 0, ab); if (CPP_OPTION (pfile, dump_includes)) pass_thru_directive (pfile); - return 0; } -static int +static void do_import (pfile) cpp_reader *pfile; { @@ -394,15 +390,14 @@ do_import (pfile) } if (parse_include (pfile, dtable[T_IMPORT].name, 0, &str, &len, &ab)) - return 0; + return; _cpp_execute_include (pfile, str, len, 1, 0, ab); if (CPP_OPTION (pfile, dump_includes)) pass_thru_directive (pfile); - return 0; } -static int +static void do_include_next (pfile) cpp_reader *pfile; { @@ -412,7 +407,7 @@ do_include_next (pfile) int ab; if (parse_include (pfile, dtable[T_INCLUDE_NEXT].name, 0, &str, &len, &ab)) - return 0; + return; /* 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 @@ -426,7 +421,7 @@ do_include_next (pfile) { search_start = CPP_BUFFER (pfile)->inc->foundhere->next; if (!search_start) - return 0; + return; } } else @@ -435,8 +430,6 @@ do_include_next (pfile) _cpp_execute_include (pfile, str, len, 0, search_start, ab); if (CPP_OPTION (pfile, dump_includes)) pass_thru_directive (pfile); - - return 0; } /* Subroutine of do_line. Read next token from PFILE without adding it to @@ -494,7 +487,7 @@ strtoul_for_line (str, len, nump) Note that the filename string (if any) is treated as if it were an include filename. That means no escape handling. */ -static int +static void do_line (pfile) cpp_reader *pfile; { @@ -552,7 +545,7 @@ do_line (pfile) } if (read_line_number (pfile, &action_number) == 0) - return 0; + return; if (CPP_PEDANTIC (pfile)) cpp_pedwarn (pfile, "garbage at end of #line"); @@ -582,10 +575,9 @@ do_line (pfile) cpp_make_system_header (pfile, ip, 2); read_line_number (pfile, &action_number); } - return 0; done: - return 0; + return; } /* @@ -594,7 +586,7 @@ do_line (pfile) * (We use error because it prints the filename & line#.) */ -static int +static void do_error (pfile) cpp_reader *pfile; { @@ -605,8 +597,6 @@ do_error (pfile) limit = pfile->limit; pfile->limit = text; cpp_error (pfile, "%.*s", (int)(limit - text), text); - - return 0; } /* @@ -614,7 +604,7 @@ do_error (pfile) * Use the text of the line in the warning message, then continue. */ -static int +static void do_warning (pfile) cpp_reader *pfile; { @@ -625,12 +615,11 @@ do_warning (pfile) limit = pfile->limit; pfile->limit = text; cpp_warning (pfile, "%.*s", (int)(limit - text), text); - return 0; } /* Report program identification. */ -static int +static void do_ident (pfile) cpp_reader *pfile; { @@ -641,11 +630,10 @@ do_ident (pfile) { /* Good - ship it. */ pass_thru_directive (pfile); - return 0; + return; } cpp_error (pfile, "invalid #ident"); - return 0; } /* Pragmata handling. We handle some of these, and pass the rest on @@ -708,7 +696,7 @@ static int pragma_dispatch (pfile, table, node) return 0; } -static int +static void do_pragma (pfile) cpp_reader *pfile; { @@ -717,17 +705,16 @@ do_pragma (pfile) tok = _cpp_get_token (pfile); if (tok->type == CPP_EOF) - return 0; + return; else if (tok->type != CPP_NAME) { cpp_error (pfile, "malformed #pragma directive"); - return 0; + return; } pop = pragma_dispatch (pfile, top_pragmas, tok->val.node); if (!pop) pass_thru_directive (pfile); - return 0; } static int @@ -900,11 +887,10 @@ do_pragma_dependency (pfile) /* Just ignore #sccs, on systems where we define it at all. */ #ifdef SCCS_DIRECTIVE -static int +static void do_sccs (pfile) cpp_reader *pfile ATTRIBUTE_UNUSED; { - return 0; } #endif @@ -991,7 +977,7 @@ parse_ifdef (pfile, name) /* #ifdef is dead simple. */ -static int +static void do_ifdef (pfile) cpp_reader *pfile; { @@ -1001,13 +987,12 @@ do_ifdef (pfile) node = parse_ifdef (pfile, dtable[T_IFDEF].name); push_conditional (pfile, !(node && node->type != T_VOID), T_IFDEF, 0); - return 0; } /* #ifndef is a tad more complex, because we need to check for a no-reinclusion wrapper. */ -static int +static void do_ifndef (pfile) cpp_reader *pfile; { @@ -1022,13 +1007,12 @@ do_ifndef (pfile) push_conditional (pfile, node && node->type != T_VOID, T_IFNDEF, start_of_file ? node : 0); - return 0; } /* #if is straightforward; just call _cpp_parse_expr, then conditional_skip. Also, check for a reinclude preventer of the form #if !defined (MACRO). */ -static int +static void do_if (pfile) cpp_reader *pfile; { @@ -1042,14 +1026,13 @@ do_if (pfile) value = _cpp_parse_expr (pfile); } push_conditional (pfile, value == 0, T_IF, cmacro); - return 0; } /* #else flips pfile->skipping and continues without changing if_stack; this is so that the error message for missing #endif's etc. will point to the original #if. */ -static int +static void do_else (pfile) cpp_reader *pfile; { @@ -1059,7 +1042,7 @@ do_else (pfile) if (ifs == NULL) { cpp_error (pfile, "#else without #if"); - return 0; + return; } if (ifs->type == T_ELSE) { @@ -1079,7 +1062,6 @@ do_else (pfile) if (pfile->skipping < 2) pfile->skipping = ! pfile->skipping; } - return 0; } /* @@ -1087,7 +1069,7 @@ do_else (pfile) * see the comment above do_else. */ -static int +static void do_elif (pfile) cpp_reader *pfile; { @@ -1096,7 +1078,7 @@ do_elif (pfile) if (ifs == NULL) { cpp_error (pfile, "#elif without #if"); - return 0; + return; } if (ifs->type == T_ELSE) { @@ -1107,21 +1089,20 @@ do_elif (pfile) ifs->type = T_ELIF; if (ifs->was_skipping) - return 0; /* Don't evaluate a nested #if */ + return; /* Don't evaluate a nested #if */ if (pfile->skipping != 1) { pfile->skipping = 2; /* one block succeeded, so don't do any others */ - return 0; + return; } pfile->skipping = ! _cpp_parse_expr (pfile); - return 0; } /* #endif pops the if stack and resets pfile->skipping. */ -static int +static void do_endif (pfile) cpp_reader *pfile; { @@ -1138,7 +1119,6 @@ do_endif (pfile) pfile->potential_control_macro = ifs->cmacro; obstack_free (pfile->buffer_ob, ifs); } - return 0; } @@ -1332,7 +1312,7 @@ _cpp_find_answer (node, candidate) #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 +static void do_assert (pfile) cpp_reader *pfile; { @@ -1355,16 +1335,15 @@ do_assert (pfile) node->type = T_ASSERTION; node->value.answers = new_answer; } - return 0; + return; err: cpp_warning (pfile, "\"%.*s\" re-asserted", node->length - 1, node->name + 1); FREE_ANSWER (new_answer); - return 0; } -static int +static void do_unassert (pfile) cpp_reader *pfile; { @@ -1404,7 +1383,6 @@ do_unassert (pfile) if (answer) FREE_ANSWER (answer); } - return 0; } /* These are for -D, -U, -A. */ diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 500b5e25a0e..80671cf5ce1 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -653,6 +653,10 @@ extern void cpp_undef PARAMS ((cpp_reader *, const char *)); extern void cpp_unassert PARAMS ((cpp_reader *, const char *)); extern void cpp_free_token_list PARAMS ((cpp_toklist *)); +extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *, + const unsigned char *, long)); +extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *)); +extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int)); /* N.B. The error-message-printer prototypes have not been nicely formatted because exgettext needs to see 'msgid' on the same line @@ -680,8 +684,8 @@ extern void cpp_pedwarn_with_line PARAMS ((cpp_reader *, int, int, const char *m ATTRIBUTE_PRINTF_4; extern void cpp_pedwarn_with_file_and_line PARAMS ((cpp_reader *, const char *, int, int, const char *msgid, ...)) ATTRIBUTE_PRINTF_5; -extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *)); -extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *)); +extern void cpp_error_from_errno PARAMS ((cpp_reader *, const char *)); +extern void cpp_notice_from_errno PARAMS ((cpp_reader *, const char *)); /* In cpplex.c */ extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *, @@ -694,16 +698,16 @@ extern int cpp_ideq PARAMS ((const cpp_token *, const char *)); /* In cpphash.c */ -extern int cpp_defined PARAMS ((cpp_reader *, - const unsigned char *, int)); -extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *, - const unsigned char *, int)); +extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *, + const unsigned char *, size_t)); +extern void cpp_forall_identifiers PARAMS ((cpp_reader *, + int (*) PARAMS ((cpp_reader *, + cpp_hashnode *)))); /* In cppfiles.c */ -extern int cpp_included PARAMS ((cpp_reader *, const char *)); -extern int cpp_read_file PARAMS ((cpp_reader *, const char *)); -extern void cpp_make_system_header PARAMS ((cpp_reader *, - cpp_buffer *, int)); +extern int cpp_included PARAMS ((cpp_reader *, const char *)); +extern int cpp_read_file PARAMS ((cpp_reader *, const char *)); +extern void cpp_make_system_header PARAMS ((cpp_reader *, cpp_buffer *, int)); #ifdef __cplusplus } diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c new file mode 100644 index 00000000000..710dbdedaa1 --- /dev/null +++ b/gcc/cppmacro.c @@ -0,0 +1,603 @@ +/* Part of CPP library. (Macro handling.) + Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998, + 1999, 2000 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +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. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#include "config.h" +#include "system.h" +#include "cpplib.h" +#include "cpphash.h" + +/* Stores basic information about a macro, before it is allocated. */ +struct macro_info +{ + const cpp_token *first_param; /* First parameter token. */ + const cpp_token *first; /* First expansion token. */ + unsigned int paramlen; /* Length of parameter names. */ + unsigned int len; /* Length of token strings. */ + unsigned int ntokens; /* Number of tokens in expansion. */ + short paramc; /* Number of parameters. */ + unsigned char flags; +}; + +static void dump_funlike_macro PARAMS ((cpp_reader *, cpp_hashnode *)); +static void count_params PARAMS ((cpp_reader *, struct macro_info *)); +static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *)); + +static int parse_define PARAMS((cpp_reader *, struct macro_info *)); +static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp, + const cpp_toklist *)); +static const cpp_toklist * save_expansion PARAMS((cpp_reader *, + struct macro_info *)); +static unsigned int find_param PARAMS ((const cpp_token *, + const cpp_token *)); +static cpp_toklist * alloc_macro PARAMS ((cpp_reader *, struct macro_info *)); + + +/* 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 +find_param (first, token) + const cpp_token *first, *token; +{ + unsigned int param = 0; + + for (; first < token && first->type != CPP_CLOSE_PAREN; first++) + if (first->type == CPP_NAME) + { + param++; + if (first->val.node == token->val.node) + return param; + } + + return 0; +} + +/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the + replacement list of a variable-arguments macro. TOKEN is assumed + to be of type CPP_NAME. */ +static int +is__va_args__ (pfile, token) + cpp_reader *pfile; + const cpp_token *token; +{ + if (!CPP_PEDANTIC (pfile) + || token->val.node != pfile->spec_nodes->n__VA_ARGS__) + return 0; + + cpp_pedwarn_with_line (pfile, token->line, token->col, + "\"%s\" is only valid in the replacement list of a function-like macro", + token->val.node->name); + return 1; +} + +/* Counts the parameters to a function-like macro, the length of their + null-terminated names, and whether the macro is a variable-argument + one. FIRST is the token immediately after the open parenthesis, + INFO stores the data. + + On success, info->first is updated to the token after the closing + parenthesis, i.e. the first token of the expansion. Otherwise + there was an error, which has been reported. */ +static void +count_params (pfile, info) + cpp_reader *pfile; + struct macro_info *info; +{ + unsigned int prev_ident = 0; + const cpp_token *token; + + info->paramc = 0; + info->paramlen = 0; + info->flags = 0; + info->first = info->first_param; /* Not a ')' indicating success. */ + + for (token = info->first_param;; token++) + { + switch (token->type) + { + default: + cpp_error_with_line (pfile, token->line, token->col, + "illegal token in macro parameter list"); + return; + + case CPP_EOF: + missing_paren: + cpp_error_with_line (pfile, token->line, token->col, + "missing ')' in macro parameter list"); + return; + + case CPP_COMMENT: + continue; /* Ignore -C comments. */ + + case CPP_NAME: + if (prev_ident) + { + cpp_error_with_line (pfile, token->line, token->col, + "macro parameters must be comma-separated"); + return; + } + + /* Constraint 6.10.3.5 */ + if (is__va_args__ (pfile, token)) + return; + + /* Constraint 6.10.3.6 - duplicate parameter names. */ + if (find_param (info->first, token)) + { + cpp_error_with_line (pfile, token->line, token->col, + "duplicate macro parameter \"%s\"", + token->val.node->name); + return; + } + + prev_ident = 1; + info->paramc++; + info->paramlen += token->val.node->length + 1; + continue; + + case CPP_CLOSE_PAREN: + if (prev_ident || info->paramc == 0) + break; + + /* Fall through to pick up the error. */ + case CPP_COMMA: + if (!prev_ident) + { + cpp_error_with_line (pfile, token->line, token->col, + "parameter name expected"); + return; + } + prev_ident = 0; + continue; + + 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. */ + if (!prev_ident) + { + cpp_token *tok = (cpp_token *) token; + + tok->type = CPP_NAME; + tok->val.node = pfile->spec_nodes->n__VA_ARGS__; + + info->paramc++; + info->paramlen += tok->val.node->length + 1; + + if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)) + cpp_pedwarn (pfile, + "C89 does not permit anon varargs macros"); + } + else + { + info->flags |= GNU_REST_ARGS; + if (CPP_PEDANTIC (pfile)) + cpp_pedwarn (pfile, + "ISO C does not permit named varargs parameters"); + } + + info->flags |= VAR_ARGS; + token++; + if (token->type == CPP_CLOSE_PAREN) + break; + goto missing_paren; + } + + /* Success. */ + info->first = token + 1; + if (!pfile->save_parameter_spellings) + info->paramlen = 0; + return; + } +} + +/* Parses a #define directive. On success, returns zero, and INFO is + filled in appropriately. */ +static int +parse_define (pfile, info) + cpp_reader *pfile; + struct macro_info *info; +{ + const cpp_token *token; + int prev_white = 0; + + /* The first token after the macro's name. */ + token = _cpp_get_token (pfile); + + /* Constraint 6.10.3.5 */ + if (is__va_args__ (pfile, token - 1)) + return 1; + + while (token->type == CPP_COMMENT) + token++, prev_white = 1; + prev_white |= token->flags & PREV_WHITE; + + if (token->type == CPP_OPEN_PAREN && !prev_white) + { + /* A function-like macro. */ + info->first_param = token + 1; + count_params (pfile, info); + if (info->first[-1].type != CPP_CLOSE_PAREN) + return 1; + } + else + { + /* An object-like macro. */ + info->paramc = -1; + info->paramlen = 0; + info->flags = 0; + info->first = token; + if (!prev_white && token->type != CPP_EOF) + cpp_pedwarn (pfile, "ISO C requires whitespace after the macro name"); + } + + /* Count tokens in expansion. We drop paste tokens, and stringize + tokens, so don't count them. */ + info->ntokens = info->len = 0; + for (token = info->first; token->type != CPP_EOF; token++) + { + if (token->type == CPP_PASTE) + { + /* Token-paste ##, can appear in both object-like and + function-like macros, but not at the ends. Constraint + 6.10.3.3.1 */ + if (token == info->first || token[1].type == CPP_EOF) + { + cpp_error_with_line (pfile, token->line, token->col, + "'##' cannot appear at either end of a macro expansion"); + return 1; + } + continue; + } + else if (token->type == CPP_HASH) + { + /* Stringifying #, but a normal character in object-like + macros. Must come before a parameter name. Constraint + 6.10.3.2.1. */ + if (info->paramc >= 0) + { + if (token[1].type == CPP_NAME + && find_param (info->first_param, token + 1)) + continue; + if (! CPP_OPTION (pfile, lang_asm)) + { + cpp_error_with_line (pfile, token->line, token->col, + "'#' is not followed by a macro parameter"); + return 1; + } + } + } + else if (token->type == CPP_NAME) + { + /* Constraint 6.10.3.5 */ + if (!(info->flags & VAR_ARGS) && is__va_args__ (pfile, token)) + return 1; + /* It might be worth doing a check here that we aren't a + macro argument, since we don't store the text of macro + arguments. This would reduce "len" and save space. */ + } + info->ntokens++; + if (TOKEN_SPELL (token) == SPELL_STRING) + info->len += token->val.str.len; + } + + return 0; +} + +/* Returns non-zero if a macro redefinition is trivial. */ +static int +check_macro_redefinition (pfile, hp, list2) + cpp_reader *pfile; + cpp_hashnode *hp; + const cpp_toklist *list2; +{ + const cpp_toklist *list1; + + if (hp->type != T_MACRO) + return ! pfile->done_initializing; + + /* 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); + + if (!_cpp_equiv_toklists (list1, list2)) + return 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; + + return 1; +} + +/* This is a dummy structure whose only purpose is getting alignment + correct. */ +struct toklist_dummy +{ + cpp_toklist list; + cpp_token first_token; +}; + +/* Allocate space to hold the token list, its tokens, their text, and + the parameter names if needed. Empty expansions are stored as a + single placemarker token. + + These are all allocated in a block together for performance + reasons. Therefore, this token list cannot be expanded like a + normal token list. Try to do so, and you lose. */ +static cpp_toklist * +alloc_macro (pfile, info) + cpp_reader *pfile; + struct macro_info *info; +{ + unsigned int size; + struct toklist_dummy *dummy; + cpp_toklist *list; + + /* Empty macros become a single placemarker token. */ + if (info->ntokens == 0) + info->ntokens = 1; + + size = sizeof (struct toklist_dummy); + size += (info->ntokens - 1) * sizeof(cpp_token); + size += info->len + info->paramlen; + + dummy = (struct toklist_dummy *) xmalloc (size); + list = (cpp_toklist *) dummy; + + /* Initialize the monster. */ + list->tokens = &dummy->first_token; + list->tokens_used = list->tokens_cap = info->ntokens; + + list->namebuf = (unsigned char *) &list->tokens[info->ntokens]; + list->name_used = list->name_cap = info->len + info->paramlen; + + list->directive = 0; + list->line = pfile->token_list.line; + list->file = pfile->token_list.file; + list->params_len = info->paramlen; + list->paramc = info->paramc; + list->flags = info->flags; + + return list; +} + +/* Free the definition of macro H. */ + +void +_cpp_free_definition (h) + cpp_hashnode *h; +{ + if (h->type == T_MACRO) + free ((PTR) h->value.expansion); + h->value.expansion = NULL; +} + +/* Copy the tokens of the expansion, beginning with info->first until + CPP_EOF. INFO contains information about the macro. + + Change the type of macro arguments in the expansion 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 the + token list for the macro expansion. */ +static const cpp_toklist * +save_expansion (pfile, info) + cpp_reader *pfile; + struct macro_info *info; +{ + const cpp_token *token; + cpp_toklist *list; + cpp_token *dest; + unsigned char *buf; + + list = alloc_macro (pfile, info); + buf = list->namebuf; + + /* Store the null-terminated parameter spellings of a macro, to + provide pedantic warnings to satisfy 6.10.3.2, or for use when + dumping macro definitions. They must go first. */ + if (list->params_len) + for (token = info->first_param; token < info->first; token++) + if (token->type == CPP_NAME) + { + /* Copy null too. */ + memcpy (buf, token->val.node->name, token->val.node->length + 1); + buf += token->val.node->length + 1; + } + + dest = list->tokens; + for (token = info->first; token->type != CPP_EOF; token++) + { + unsigned int param_no; + + switch (token->type) + { + case CPP_NAME: + if (list->paramc == -1) + break; + + /* Check if the name is a macro parameter. */ + param_no = find_param (info->first_param, token); + if (param_no == 0) + break; + dest->val.aux = param_no - 1; + + dest->type = CPP_MACRO_ARG; + if (token[-1].type == CPP_HASH) + dest->flags = token[-1].flags | STRINGIFY_ARG; + else + dest->flags = token->flags; /* Particularly PREV_WHITE. */ + /* Turn off PREV_WHITE if we immediately follow a paste. + That way, even if the paste turns out to be illegal, there + will be no space between the two tokens in the output. */ + if (token[-1].type == CPP_PASTE) + dest->flags &= ~PREV_WHITE; + dest++; + continue; + + case CPP_PASTE: + dest[-1].flags |= PASTE_LEFT; + continue; + + case CPP_HASH: + /* Stringifying #. Constraint 6.10.3.2.1 */ + if (list->paramc >= 0 && token[1].type == CPP_NAME + && find_param (info->first_param, token + 1)) + continue; + break; + + default: + break; + } + + /* Copy the token. */ + *dest = *token; + if (TOKEN_SPELL (token) == SPELL_STRING) + { + memcpy (buf, token->val.str.text, token->val.str.len); + dest->val.str.text = buf; + buf += dest->val.str.len; + } + if (token[-1].type == CPP_PASTE) + dest->flags &= ~PREV_WHITE; + dest++; + } + + /* Empty macros become a single placemarker token. */ + if (dest == list->tokens) + { + dest->type = CPP_PLACEMARKER; + dest->flags = 0; + } + + return list; +} + +/* Parse a macro and save its expansion. Returns non-zero on success. */ +int +_cpp_create_definition (pfile, hp) + cpp_reader *pfile; + cpp_hashnode *hp; +{ + struct macro_info info; + const cpp_toklist *list; + + if (parse_define (pfile, &info)) + return 0; + list = save_expansion (pfile, &info); + + /* 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) + { + if (!check_macro_redefinition (pfile, hp, list)) + { + 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); + } + + /* 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 + to be read back in again. */ + +void +_cpp_dump_definition (pfile, hp) + cpp_reader *pfile; + cpp_hashnode *hp; +{ + CPP_RESERVE (pfile, hp->length + sizeof "#define "); + CPP_PUTS_Q (pfile, "#define ", sizeof "#define " - 1); + CPP_PUTS_Q (pfile, hp->name, hp->length); + + if (hp->type == T_MACRO) + { + if (hp->value.expansion->paramc >= 0) + dump_funlike_macro (pfile, hp); + else + { + 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); + + if (CPP_BUFFER (pfile) == 0 || ! pfile->done_initializing) + CPP_PUTC (pfile, '\n'); +} + +static void +dump_funlike_macro (pfile, node) + cpp_reader *pfile; + cpp_hashnode *node; +{ + 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++ < list->paramc;) + { + unsigned int len; + + 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, U"__VA_ARGS__")) + pfile->limit -= sizeof (U"__VA_ARGS__") - 1; + CPP_PUTS_Q (pfile, "...", 3); + } + param += len + 1; + } + CPP_PUTC (pfile, ')'); + list->tokens[0].flags &= ~BOL; + list->tokens[0].flags |= PREV_WHITE; + _cpp_dump_list (pfile, list, list->tokens, 1); +} diff --git a/gcc/cppmain.c b/gcc/cppmain.c index 5239f8d74d5..8be2a1df63e 100644 --- a/gcc/cppmain.c +++ b/gcc/cppmain.c @@ -68,7 +68,8 @@ main (argc, argv) print = cpp_printer_init (pfile, &parse_out); if (! print) return (FATAL_EXIT_CODE); - pfile->printer = print; + if (! CPP_OPTION (pfile, no_output)) + pfile->printer = print; if (! cpp_start_read (pfile, print, CPP_OPTION (pfile, in_fname))) return (FATAL_EXIT_CODE); |