215 lines
5.4 KiB
C
215 lines
5.4 KiB
C
|
/* Part of CPP library. (Macro hash table support.)
|
||
|
Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
|
||
|
Written by Per Bothner, 1994.
|
||
|
Based on CCCP program by 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 "cpplib.h"
|
||
|
#include "cpphash.h"
|
||
|
|
||
|
extern char *xmalloc PARAMS ((unsigned));
|
||
|
|
||
|
/* Define a generic NULL if one hasn't already been defined. */
|
||
|
|
||
|
#ifndef NULL
|
||
|
#define NULL 0
|
||
|
#endif
|
||
|
|
||
|
#ifndef __STDC__
|
||
|
#define const
|
||
|
#define volatile
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* 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.
|
||
|
*/
|
||
|
HASHNODE *
|
||
|
cpp_lookup (pfile, name, len, hash)
|
||
|
struct parse_file *pfile;
|
||
|
const U_CHAR *name;
|
||
|
int len;
|
||
|
int hash;
|
||
|
{
|
||
|
register const U_CHAR *bp;
|
||
|
register HASHNODE *bucket;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
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;
|
||
|
{
|
||
|
register int i;
|
||
|
for (i = HASHSIZE; --i >= 0; )
|
||
|
{
|
||
|
while (hashtab[i])
|
||
|
delete_macro (hashtab[i]);
|
||
|
}
|
||
|
}
|