*** empty log message ***
This commit is contained in:
697
lang/cem/cemcom/idf.c
Normal file
697
lang/cem/cemcom/idf.c
Normal file
@@ -0,0 +1,697 @@
|
||||
/* $Header$ */
|
||||
/* IDENTIFIER FIDDLING & SYMBOL TABLE HANDLING */
|
||||
|
||||
#include "debug.h"
|
||||
#include "idfsize.h"
|
||||
#include "botch_free.h"
|
||||
#include "nopp.h"
|
||||
#include "alloc.h"
|
||||
#include "arith.h"
|
||||
#include "align.h"
|
||||
#include "LLlex.h"
|
||||
#include "level.h"
|
||||
#include "stack.h"
|
||||
#include "idf.h"
|
||||
#include "label.h"
|
||||
#include "def.h"
|
||||
#include "type.h"
|
||||
#include "struct.h"
|
||||
#include "declarator.h"
|
||||
#include "decspecs.h"
|
||||
#include "sizes.h"
|
||||
#include "Lpars.h"
|
||||
#include "assert.h"
|
||||
#include "specials.h" /* registration of special identifiers */
|
||||
#include "storage.h"
|
||||
|
||||
int idfsize = IDFSIZE;
|
||||
extern char options[];
|
||||
|
||||
char sp_occurred[SP_TOTAL]; /* indicate occurrence of special id */
|
||||
|
||||
struct idf *idf_hashtable[HASHSIZE];
|
||||
/* All identifiers can in principle be reached through
|
||||
idf_hashtable; idf_hashtable[hc] is the start of a chain of
|
||||
idf's whose tags all hash to hc. Each idf is the start of
|
||||
a chain of def's for that idf, sorted according to level,
|
||||
with the most recent one on top.
|
||||
Any identifier occurring on a level is entered into this
|
||||
list, regardless of the nature of its declaration
|
||||
(variable, selector, structure tag, etc.).
|
||||
*/
|
||||
|
||||
struct idf *
|
||||
idf_hashed(tg, size, hc)
|
||||
char *tg;
|
||||
int size; /* includes the '\0' character */
|
||||
int hc;
|
||||
{
|
||||
/* The tag tg with length size and known hash value hc is
|
||||
looked up in the identifier table; if not found, it is
|
||||
entered. A pointer to it is returned.
|
||||
The identifier has already been truncated to idfsize
|
||||
characters.
|
||||
*/
|
||||
register struct idf **hook = &idf_hashtable[hc], *notch;
|
||||
|
||||
while ((notch = *hook)) {
|
||||
register cmp = strcmp(tg, notch->id_text);
|
||||
|
||||
if (cmp < 0)
|
||||
break;
|
||||
else
|
||||
if (cmp == 0) {
|
||||
/* suppose that special identifiers, as
|
||||
"setjmp", are already inserted
|
||||
*/
|
||||
sp_occurred[notch->id_special] = 1;
|
||||
return notch;
|
||||
}
|
||||
else
|
||||
hook = ¬ch->next;
|
||||
}
|
||||
/* a new struct idf must be inserted at the hook */
|
||||
notch = new_idf();
|
||||
clear((char *)notch, sizeof(struct idf));
|
||||
notch->next = *hook;
|
||||
*hook = notch; /* hooked in */
|
||||
notch->id_text = Salloc(tg, size);
|
||||
#ifndef NOPP
|
||||
notch->id_resmac = 0;
|
||||
#endif NOPP
|
||||
return notch;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
hash_stat()
|
||||
{
|
||||
if (options['h']) {
|
||||
int i;
|
||||
|
||||
printf("Hash table tally:\n");
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
struct idf *notch = idf_hashtable[i];
|
||||
int cnt = 0;
|
||||
|
||||
while (notch) {
|
||||
cnt++;
|
||||
notch = notch->next;
|
||||
}
|
||||
printf("%d %d\n", i, cnt);
|
||||
}
|
||||
printf("End hash table tally\n");
|
||||
}
|
||||
}
|
||||
#endif DEBUG
|
||||
|
||||
struct idf *
|
||||
str2idf(tg)
|
||||
char tg[];
|
||||
{
|
||||
/* str2idf() returns an entry in the symbol table for the
|
||||
identifier tg. If necessary, an entry is created.
|
||||
It is used where the text of the identifier is available
|
||||
but its hash value is not; otherwise idf_hashed() is to
|
||||
be used.
|
||||
*/
|
||||
register char *cp = tg;
|
||||
register int hash;
|
||||
register int pos = -1;
|
||||
register int ch;
|
||||
char ntg[IDFSIZE + 1];
|
||||
register char *ncp = ntg;
|
||||
|
||||
hash = STARTHASH();
|
||||
while (++pos < idfsize && (ch = *cp++)) {
|
||||
*ncp++ = ch;
|
||||
hash = ENHASH(hash, ch, pos);
|
||||
}
|
||||
hash = STOPHASH(hash);
|
||||
*ncp++ = '\0';
|
||||
return idf_hashed(ntg, ncp - ntg, hash);
|
||||
}
|
||||
|
||||
struct idf *
|
||||
gen_idf()
|
||||
{
|
||||
/* A new idf is created out of nowhere, to serve as an
|
||||
anonymous name.
|
||||
*/
|
||||
static int name_cnt;
|
||||
char buff[100];
|
||||
char *sprintf();
|
||||
|
||||
sprintf(buff, "#%d in %s, line %u",
|
||||
++name_cnt, dot.tk_file, dot.tk_line);
|
||||
return str2idf(buff);
|
||||
}
|
||||
|
||||
int
|
||||
is_anon_idf(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
return idf->id_text[0] == '#';
|
||||
}
|
||||
|
||||
declare_idf(ds, dc, lvl)
|
||||
struct decspecs *ds;
|
||||
struct declarator *dc;
|
||||
{
|
||||
/* The identifier inside dc is declared on the level lvl, with
|
||||
properties deduced from the decspecs ds and the declarator
|
||||
dc.
|
||||
The level is given explicitly to be able to insert, e.g.,
|
||||
labels on the outermost level inside the function.
|
||||
This routine implements the rich semantics of C
|
||||
declarations.
|
||||
*/
|
||||
register struct idf *idf = dc->dc_idf;
|
||||
register int sc = ds->ds_sc;
|
||||
/* This local copy is essential:
|
||||
char b(), c;
|
||||
makes b GLOBAL and c AUTO.
|
||||
*/
|
||||
register struct def *def = idf->id_def; /* may be NULL */
|
||||
register struct type *type;
|
||||
struct stack_level *stl = stack_level_of(lvl);
|
||||
char formal_array = 0;
|
||||
|
||||
/* determine the present type */
|
||||
if (ds->ds_type == 0) {
|
||||
/* at the L_FORMAL1 level there is no type specified yet
|
||||
*/
|
||||
ASSERT(lvl == L_FORMAL1);
|
||||
type = 0;
|
||||
}
|
||||
else {
|
||||
/* combine the decspecs and the declarator into one type */
|
||||
type = declare_type(ds->ds_type, dc);
|
||||
if (type->tp_size == (arith)-1) {
|
||||
/* the type is not yet known */
|
||||
if (actual_declaration(sc, type)) {
|
||||
/* but it has to be: */
|
||||
extern char *symbol2str();
|
||||
error("unknown %s-type",
|
||||
symbol2str(type->tp_fund));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* some additional work for formal definitions */
|
||||
if (lvl == L_FORMAL2) {
|
||||
switch (type->tp_fund) {
|
||||
|
||||
case FUNCTION:
|
||||
warning("%s is a function; cannot be formal",
|
||||
idf->id_text);
|
||||
type = construct_type(POINTER, type, (arith)0);
|
||||
break;
|
||||
case ARRAY: /* RM 10.1 */
|
||||
type = construct_type(POINTER, type->tp_up, (arith)0);
|
||||
formal_array = 1;
|
||||
break;
|
||||
case FLOAT: /* RM 10.1 */
|
||||
type = double_type;
|
||||
break;
|
||||
case CHAR:
|
||||
case SHORT:
|
||||
/* The RM is not clear about this: we must
|
||||
convert the parameter from int (they have
|
||||
been pushed as ints) to the specified type.
|
||||
The conversion to type int or uint is not
|
||||
allowed.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The tests on types, postponed from do_decspecs(), can now
|
||||
be performed.
|
||||
*/
|
||||
/* update the storage class */
|
||||
if (type && type->tp_fund == FUNCTION) {
|
||||
if (sc == 0 || (ds->ds_sc_given && sc == AUTO)) /* RM 8.1 */
|
||||
sc = GLOBAL;
|
||||
else
|
||||
if (sc == REGISTER) {
|
||||
error("function has illegal storage class");
|
||||
ds->ds_sc = sc = GLOBAL;
|
||||
}
|
||||
}
|
||||
else { /* non-FUNCTION */
|
||||
if (sc == 0)
|
||||
sc =
|
||||
lvl == L_GLOBAL ?
|
||||
GLOBAL :
|
||||
lvl == L_FORMAL1 || lvl == L_FORMAL2 ?
|
||||
FORMAL :
|
||||
AUTO;
|
||||
}
|
||||
|
||||
if (options['R']) {
|
||||
/* some special K & R tests */
|
||||
|
||||
/* is it also an enum? */
|
||||
if (idf->id_enum && idf->id_enum->tg_level == level)
|
||||
warning("%s is also an enum tag", idf->id_text);
|
||||
|
||||
/* is it a universal typedef? */
|
||||
if (def && def->df_level == L_UNIVERSAL)
|
||||
warning("redeclaring reserved word %s", idf->id_text);
|
||||
}
|
||||
if (def && def->df_level >= lvl) {
|
||||
/* There is already a declaration for idf on this
|
||||
level, or even more inside.
|
||||
The rules differ for different levels.
|
||||
*/
|
||||
switch (lvl) {
|
||||
case L_GLOBAL:
|
||||
global_redecl(idf, sc, type);
|
||||
break;
|
||||
case L_FORMAL1: /* formal declaration */
|
||||
error("formal %s redeclared", idf->id_text);
|
||||
break;
|
||||
case L_FORMAL2: /* formal definition */
|
||||
default: /* local */
|
||||
error("%s redeclared", idf->id_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* the idf is unknown on this level */
|
||||
if (lvl == L_FORMAL2 && sc != ENUM && good_formal(def, idf)) {
|
||||
/* formal declaration, update only */
|
||||
def->df_type = type;
|
||||
def->df_formal_array = formal_array;
|
||||
def->df_sc = sc;
|
||||
if (def->df_sc != FORMAL)
|
||||
crash("non-formal formal");
|
||||
def->df_register = (sc == REGISTER) ? REG_BONUS : REG_DEFAULT;
|
||||
}
|
||||
else
|
||||
if ( lvl >= L_LOCAL &&
|
||||
(type->tp_fund == FUNCTION || sc == EXTERN)
|
||||
) {
|
||||
/* extern declaration inside function is treated the
|
||||
same way as global extern declaration
|
||||
*/
|
||||
if ( options['R'] &&
|
||||
(sc == STATIC && type->tp_fund == FUNCTION)
|
||||
) {
|
||||
if (!is_anon_idf(idf))
|
||||
warning("non-global static function %s",
|
||||
idf->id_text);
|
||||
}
|
||||
declare_idf(ds, dc, L_GLOBAL);
|
||||
}
|
||||
else {
|
||||
/* fill in the def block */
|
||||
register struct def *newdef = new_def();
|
||||
|
||||
clear((char *)newdef, sizeof(struct def));
|
||||
newdef->next = def;
|
||||
newdef->df_level = lvl;
|
||||
newdef->df_type = type;
|
||||
newdef->df_sc = sc;
|
||||
|
||||
/* link it into the name list in the proper place */
|
||||
idf->id_def = newdef;
|
||||
update_ahead(idf);
|
||||
stack_idf(idf, stl);
|
||||
|
||||
/* We now calculate the address.
|
||||
Globals have names and don't get addresses, they
|
||||
get numbers instead (through data_label()).
|
||||
Formals are handled by declare_formals().
|
||||
So here we hand out local addresses only.
|
||||
*/
|
||||
|
||||
if (lvl >= L_LOCAL) {
|
||||
switch (sc) {
|
||||
case 0:
|
||||
crash("local sc == 0");
|
||||
break;
|
||||
case REGISTER:
|
||||
case AUTO:
|
||||
if (type->tp_size == (arith)-1) {
|
||||
error("size of local \"%s\" unknown",
|
||||
idf->id_text);
|
||||
type = idf->id_def->df_type = int_type;
|
||||
}
|
||||
idf->id_def->df_register =
|
||||
(sc == REGISTER)
|
||||
? REG_BONUS : REG_DEFAULT;
|
||||
idf->id_def->df_address =
|
||||
stl->sl_max_block =
|
||||
stl->sl_local_offset =
|
||||
-align(-stl->sl_local_offset +
|
||||
type->tp_size, type->tp_align);
|
||||
break;
|
||||
case STATIC:
|
||||
idf->id_def->df_address = (arith) data_label();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual_declaration(sc, tp)
|
||||
struct type *tp;
|
||||
{
|
||||
/* An actual_declaration needs space, right here and now.
|
||||
*/
|
||||
register int fund = tp->tp_fund;
|
||||
|
||||
/* virtual declarations */
|
||||
if (sc == ENUM || sc == TYPEDEF)
|
||||
return 0;
|
||||
/* allocation solved in other ways */
|
||||
if (fund == FUNCTION || fund == ARRAY)
|
||||
return 0;
|
||||
/* to be allocated */
|
||||
return 1;
|
||||
}
|
||||
|
||||
global_redecl(idf, new_sc, tp)
|
||||
struct idf *idf;
|
||||
struct type *tp;
|
||||
{
|
||||
/* A global identifier may be declared several times,
|
||||
provided the declarations do not conflict; they might
|
||||
conflict in type (or supplement each other in the case of
|
||||
an array) or they might conflict or supplement each other
|
||||
in storage class.
|
||||
*/
|
||||
register struct def *def = idf->id_def;
|
||||
|
||||
if (tp != def->df_type) {
|
||||
struct type *otp = def->df_type;
|
||||
|
||||
if ( tp->tp_fund != ARRAY || otp->tp_fund != ARRAY ||
|
||||
tp->tp_up != otp->tp_up
|
||||
) {
|
||||
error("redeclaration of %s with different type",
|
||||
idf->id_text);
|
||||
return;
|
||||
}
|
||||
/* Multiple array declaration; this may be interesting */
|
||||
if (tp->tp_size < 0) { /* new decl has [] */
|
||||
/* nothing new */
|
||||
}
|
||||
else
|
||||
if (otp->tp_size < 0) { /* old decl has [] */
|
||||
def->df_type = tp;
|
||||
}
|
||||
else
|
||||
if (tp->tp_size != otp->tp_size)
|
||||
error("inconsistent size in redeclaration of array %s",
|
||||
idf->id_text);
|
||||
}
|
||||
|
||||
/* Now we may be able to update the storage class. */
|
||||
/* Clean out this mess as soon as we know all the possibilities
|
||||
for new_sc.
|
||||
For now we have:
|
||||
EXTERN: we have seen the word "extern"
|
||||
GLOBAL: the item was declared on the outer
|
||||
level, without either "extern" or
|
||||
"static".
|
||||
STATIC: we have seen the word "static"
|
||||
IMPLICIT: function declaration inferred from
|
||||
call
|
||||
*/
|
||||
if (new_sc == IMPLICIT)
|
||||
return; /* no new information */
|
||||
|
||||
switch (def->df_sc) { /* the old storage class */
|
||||
|
||||
case EXTERN:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
|
||||
case EXTERN:
|
||||
case GLOBAL:
|
||||
break;
|
||||
case STATIC:
|
||||
if (def->df_initialized) {
|
||||
error("cannot redeclare %s to static",
|
||||
idf->id_text);
|
||||
}
|
||||
else {
|
||||
warning("%s redeclared to static",
|
||||
idf->id_text);
|
||||
def->df_sc = STATIC;
|
||||
}
|
||||
def->df_sc = new_sc;
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GLOBAL:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
|
||||
case EXTERN:
|
||||
def->df_sc = EXTERN;
|
||||
break;
|
||||
case GLOBAL:
|
||||
break;
|
||||
case STATIC:
|
||||
if (def->df_initialized) {
|
||||
error("cannot redeclare %s to static",
|
||||
idf->id_text);
|
||||
}
|
||||
else {
|
||||
if (options['R'])
|
||||
warning("%s redeclared to static",
|
||||
idf->id_text);
|
||||
def->df_sc = STATIC;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATIC:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
|
||||
case EXTERN:
|
||||
if (def->df_initialized) {
|
||||
error("cannot redeclare %s to extern",
|
||||
idf->id_text);
|
||||
}
|
||||
else {
|
||||
warning("%s redeclared to extern",
|
||||
idf->id_text);
|
||||
def->df_sc = EXTERN;
|
||||
}
|
||||
break;
|
||||
case GLOBAL:
|
||||
case STATIC:
|
||||
if (def->df_type->tp_fund != FUNCTION)
|
||||
warning("%s was already static",
|
||||
idf->id_text);
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IMPLICIT:
|
||||
switch (new_sc) { /* the new storage class */
|
||||
|
||||
case EXTERN:
|
||||
case GLOBAL:
|
||||
def->df_sc = new_sc;
|
||||
break;
|
||||
case STATIC:
|
||||
if (options['R'])
|
||||
warning("%s was implicitly declared as extern",
|
||||
idf->id_text);
|
||||
def->df_sc = new_sc;
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
case TYPEDEF:
|
||||
error("illegal redeclaration of %s", idf->id_text);
|
||||
break;
|
||||
default:
|
||||
crash("bad storage class");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
good_formal(def, idf)
|
||||
register struct def *def;
|
||||
struct idf *idf;
|
||||
{
|
||||
/* Succeeds if def is a proper L_FORMAL1 definition and
|
||||
gives an error message otherwise.
|
||||
*/
|
||||
if (!def || def->df_level != L_FORMAL1) {
|
||||
/* not in parameter list */
|
||||
if (!is_anon_idf(idf))
|
||||
error("%s not in parameter list",
|
||||
idf->id_text);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
declare_params(dc)
|
||||
struct declarator *dc;
|
||||
{
|
||||
/* Declares the formal parameters if they exist.
|
||||
*/
|
||||
register struct idstack_item *is = dc->dc_fparams;
|
||||
|
||||
while (is) {
|
||||
declare_parameter(is->is_idf);
|
||||
is = is->next;
|
||||
}
|
||||
del_idfstack(dc->dc_fparams);
|
||||
dc->dc_fparams = 0;
|
||||
}
|
||||
|
||||
init_idf(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
/* The topmost definition of idf is set to initialized.
|
||||
*/
|
||||
register struct def *def = idf->id_def; /* the topmost */
|
||||
|
||||
if (def->df_initialized)
|
||||
error("multiple initialization of %s", idf->id_text);
|
||||
if (def->df_sc == TYPEDEF) {
|
||||
warning("typedef cannot be initialized");
|
||||
def->df_sc == EXTERN; /* ??? *//* What else ? */
|
||||
}
|
||||
def->df_initialized = 1;
|
||||
}
|
||||
|
||||
declare_parameter(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
/* idf is declared as a formal.
|
||||
*/
|
||||
add_def(idf, FORMAL, (struct type *)0, level);
|
||||
}
|
||||
|
||||
declare_enum(tp, idf, l)
|
||||
struct type *tp;
|
||||
struct idf *idf;
|
||||
arith l;
|
||||
{
|
||||
/* idf is declared as an enum constant with value l.
|
||||
*/
|
||||
add_def(idf, ENUM, tp, level);
|
||||
idf->id_def->df_address = l;
|
||||
}
|
||||
|
||||
declare_formals(fp)
|
||||
arith *fp;
|
||||
{
|
||||
/* Declares those formals as int that haven't been declared
|
||||
by the user.
|
||||
An address is assigned to each formal parameter.
|
||||
The total size of the formals is returned in *fp;
|
||||
*/
|
||||
struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
|
||||
arith f_offset = (arith)0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (options['t'])
|
||||
dumpidftab("start declare_formals", 0);
|
||||
#endif DEBUG
|
||||
while (se) {
|
||||
struct idf *idf = se->se_idf;
|
||||
struct def *def = idf->id_def;
|
||||
|
||||
if (def->df_type == 0)
|
||||
def->df_type = int_type; /* default type */
|
||||
def->df_address = f_offset;
|
||||
|
||||
/* the alignment convention for parameters is: align on
|
||||
word boundaries, i.e. take care that the following
|
||||
parameter starts on a new word boundary.
|
||||
*/
|
||||
f_offset = align(f_offset + def->df_type->tp_size,
|
||||
word_align);
|
||||
|
||||
/* the following is absurd: any char or short formal
|
||||
must be converted from integer to that type
|
||||
*/
|
||||
formal_cvt(def);
|
||||
se = se->next;
|
||||
}
|
||||
*fp = f_offset;
|
||||
}
|
||||
|
||||
add_def(idf, sc, tp, lvl)
|
||||
struct idf *idf;
|
||||
struct type *tp;
|
||||
int lvl;
|
||||
int sc;
|
||||
{
|
||||
/* The identifier idf is declared on level lvl with storage
|
||||
class sc and type tp, through a faked C declaration.
|
||||
This is probably the wrong way to structure the problem,
|
||||
but it will have to do for the time being.
|
||||
*/
|
||||
struct decspecs Ds; struct declarator Dc;
|
||||
|
||||
Ds = null_decspecs;
|
||||
Ds.ds_type = tp;
|
||||
Ds.ds_sc = sc;
|
||||
Dc = null_declarator;
|
||||
Dc.dc_idf = idf;
|
||||
declare_idf(&Ds, &Dc, lvl);
|
||||
}
|
||||
|
||||
update_ahead(idf)
|
||||
register struct idf *idf;
|
||||
{
|
||||
/* The tk_symb of the token ahead is updated in the light of new
|
||||
information about the identifier idf.
|
||||
*/
|
||||
register int tk_symb = AHEAD;
|
||||
|
||||
if ( (tk_symb == IDENTIFIER || tk_symb == TYPE_IDENTIFIER) &&
|
||||
ahead.tk_idf == idf
|
||||
)
|
||||
AHEAD = idf->id_def && idf->id_def->df_sc == TYPEDEF ?
|
||||
TYPE_IDENTIFIER : IDENTIFIER;
|
||||
}
|
||||
|
||||
del_idfstack(is)
|
||||
struct idstack_item *is;
|
||||
{
|
||||
while (is) {
|
||||
register struct idstack_item *tmp = is->next;
|
||||
free_idstack_item(is);
|
||||
is = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
char hmask[IDFSIZE];
|
||||
|
||||
init_hmask() {
|
||||
/* A simple congruence random number generator, as
|
||||
described in Knuth, vol 2.
|
||||
*/
|
||||
int h, rnd = HASH_X;
|
||||
|
||||
for (h = 0; h < IDFSIZE; h++) {
|
||||
hmask[h] = rnd;
|
||||
rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user