214 lines
5.7 KiB
C
214 lines
5.7 KiB
C
/* Part of CPP library. (Macro hash table support.)
|
|
Copyright (C) 1986, 87, 89, 92-95, 1996 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 "gansidecl.h"
|
|
#include "cpplib.h"
|
|
#include "cpphash.h"
|
|
|
|
extern char *xmalloc PARAMS ((unsigned));
|
|
|
|
/* Return hash function on name. must be compatible with the one
|
|
computed a step at a time, elsewhere */
|
|
|
|
int
|
|
hashf (name, len, hashsize)
|
|
register const U_CHAR *name;
|
|
register int len;
|
|
int hashsize;
|
|
{
|
|
register int r = 0;
|
|
|
|
while (len--)
|
|
r = HASHSTEP (r, *name++);
|
|
|
|
return MAKE_POS (r) % hashsize;
|
|
}
|
|
|
|
/* Find the most recent hash node for name "name" (ending with first
|
|
non-identifier char) installed by install
|
|
|
|
If LEN is >= 0, it is the length of the name.
|
|
Otherwise, compute the length by scanning the entire name.
|
|
|
|
If HASH is >= 0, it is the precomputed hash code.
|
|
Otherwise, compute the hash code.
|
|
If HASH == -1, it is normal lookups. Else, if HASH is -2, it is
|
|
lookups for undef. */
|
|
|
|
HASHNODE *
|
|
cpp_lookup (pfile, name, len, hash)
|
|
cpp_reader *pfile ATTRIBUTE_UNUSED;
|
|
const U_CHAR *name;
|
|
int len;
|
|
int hash;
|
|
{
|
|
register const U_CHAR *bp;
|
|
register HASHNODE *bucket;
|
|
int islookup = (hash == -1);
|
|
static int warned_unix = 0;
|
|
|
|
if (len < 0)
|
|
{
|
|
for (bp = name; is_idchar[*bp]; bp++) ;
|
|
len = bp - name;
|
|
}
|
|
|
|
if (hash < 0)
|
|
hash = hashf (name, len, HASHSIZE);
|
|
|
|
bucket = hashtab[hash];
|
|
while (bucket) {
|
|
if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
|
|
return bucket;
|
|
bucket = bucket->next;
|
|
}
|
|
/* Lookups pass no hashcode. #define passes one. Look for no hashcode. */
|
|
if (islookup && len == 4 && bcmp(name, "unix", 4) == 0 && !warned_unix) {
|
|
warned_unix++;
|
|
warning("deprecated symbol \"unix\" is no longer predefined");
|
|
}
|
|
return (HASHNODE *) 0;
|
|
}
|
|
|
|
/*
|
|
* Delete a hash node. Some weirdness to free junk from macros.
|
|
* More such weirdness will have to be added if you define more hash
|
|
* types that need it.
|
|
*/
|
|
|
|
/* Note that the DEFINITION of a macro is removed from the hash table
|
|
but its storage is not freed. This would be a storage leak
|
|
except that it is not reasonable to keep undefining and redefining
|
|
large numbers of macros many times.
|
|
In any case, this is necessary, because a macro can be #undef'd
|
|
in the middle of reading the arguments to a call to it.
|
|
If #undef freed the DEFINITION, that would crash. */
|
|
|
|
void
|
|
delete_macro (hp)
|
|
HASHNODE *hp;
|
|
{
|
|
|
|
if (hp->prev != NULL)
|
|
hp->prev->next = hp->next;
|
|
if (hp->next != NULL)
|
|
hp->next->prev = hp->prev;
|
|
|
|
/* make sure that the bucket chain header that
|
|
the deleted guy was on points to the right thing afterwards. */
|
|
if (hp == *hp->bucket_hdr)
|
|
*hp->bucket_hdr = hp->next;
|
|
|
|
if (hp->type == T_MACRO)
|
|
{
|
|
DEFINITION *d = hp->value.defn;
|
|
struct reflist *ap, *nextap;
|
|
|
|
for (ap = d->pattern; ap != NULL; ap = nextap)
|
|
{
|
|
nextap = ap->next;
|
|
free (ap);
|
|
}
|
|
if (d->nargs >= 0)
|
|
free (d->args.argnames);
|
|
free (d);
|
|
}
|
|
|
|
free (hp);
|
|
}
|
|
|
|
/* Install a name in the main hash table, even if it is already there.
|
|
name stops with first non alphanumeric, except leading '#'.
|
|
caller must check against redefinition if that is desired.
|
|
delete_macro () removes things installed by install () in fifo order.
|
|
this is important because of the `defined' special symbol used
|
|
in #if, and also if pushdef/popdef directives are ever implemented.
|
|
|
|
If LEN is >= 0, it is the length of the name.
|
|
Otherwise, compute the length by scanning the entire name.
|
|
|
|
If HASH is >= 0, it is the precomputed hash code.
|
|
Otherwise, compute the hash code. */
|
|
|
|
HASHNODE *
|
|
install (name, len, type, ivalue, value, hash)
|
|
U_CHAR *name;
|
|
int len;
|
|
enum node_type type;
|
|
int ivalue;
|
|
char *value;
|
|
int hash;
|
|
{
|
|
register HASHNODE *hp;
|
|
register int i, bucket;
|
|
register U_CHAR *p, *q;
|
|
|
|
if (len < 0) {
|
|
p = name;
|
|
while (is_idchar[*p])
|
|
p++;
|
|
len = p - name;
|
|
}
|
|
|
|
if (hash < 0)
|
|
hash = hashf (name, len, HASHSIZE);
|
|
|
|
i = sizeof (HASHNODE) + len + 1;
|
|
hp = (HASHNODE *) xmalloc (i);
|
|
bucket = hash;
|
|
hp->bucket_hdr = &hashtab[bucket];
|
|
hp->next = hashtab[bucket];
|
|
hashtab[bucket] = hp;
|
|
hp->prev = NULL;
|
|
if (hp->next != NULL)
|
|
hp->next->prev = hp;
|
|
hp->type = type;
|
|
hp->length = len;
|
|
if (hp->type == T_CONST)
|
|
hp->value.ival = ivalue;
|
|
else
|
|
hp->value.cpval = value;
|
|
hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
|
|
p = hp->name;
|
|
q = name;
|
|
for (i = 0; i < len; i++)
|
|
*p++ = *q++;
|
|
hp->name[len] = 0;
|
|
return hp;
|
|
}
|
|
|
|
void
|
|
cpp_hash_cleanup (pfile)
|
|
cpp_reader *pfile ATTRIBUTE_UNUSED;
|
|
{
|
|
register int i;
|
|
for (i = HASHSIZE; --i >= 0; )
|
|
{
|
|
while (hashtab[i])
|
|
delete_macro (hashtab[i]);
|
|
}
|
|
}
|