aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorZack Weinberg <zack@gcc.gnu.org>2000-07-18 00:59:49 +0000
committerZack Weinberg <zack@gcc.gnu.org>2000-07-18 00:59:49 +0000
commit711b88243b220e3cd737696da51de70f32bb7d5c (patch)
treea8929adb35764d62c4016b482a4cb4b619be00cb /gcc
parent5d8fcdcb2ddbd52a35621a7880cf268c50a54027 (diff)
downloadgcc-711b88243b220e3cd737696da51de70f32bb7d5c.zip
gcc-711b88243b220e3cd737696da51de70f32bb7d5c.tar.gz
gcc-711b88243b220e3cd737696da51de70f32bb7d5c.tar.bz2
[multiple changes]
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. From-SVN: r35113
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog33
-rw-r--r--gcc/Makefile.in9
-rw-r--r--gcc/cpphash.c814
-rw-r--r--gcc/cpphash.h15
-rw-r--r--gcc/cppinit.c15
-rw-r--r--gcc/cpplex.c19
-rw-r--r--gcc/cpplib.c90
-rw-r--r--gcc/cpplib.h24
-rw-r--r--gcc/cppmacro.c603
-rw-r--r--gcc/cppmain.c3
10 files changed, 902 insertions, 723 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 32bd5a6..16065e2 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 17e2eb2..6566b09 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 b7f3944..c26f7b5 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 5f4f86b..98fcbb6 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 c31b2fd..a58f459 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 fe337c0..a41e4ee 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 aaf55a0..adbd8d1 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 500b5e2..80671cf 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 0000000..710dbde
--- /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 5239f8d..8be2a1d 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);