Port sp_symhash to C++.
This commit is contained in:
parent
f5efdbf6f5
commit
5a4c50ce55
@ -42,6 +42,7 @@ binary = SM.Program(builder, 'spcomp')
|
||||
compiler = binary.compiler
|
||||
compiler.includes += [
|
||||
os.path.join(builder.sourcePath, 'public'),
|
||||
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
|
||||
os.path.join(builder.sourcePath, 'sourcepawn', 'compiler'),
|
||||
os.path.join(builder.buildPath, 'includes'),
|
||||
@ -50,7 +51,8 @@ compiler.includes += [
|
||||
compiler.sourcedeps += packed_includes
|
||||
|
||||
if compiler.cc.behavior == 'gcc':
|
||||
compiler.cflags += ['-std=c99', '-Wno-format']
|
||||
compiler.cflags += ['-Wno-format']
|
||||
compiler.c_only_flags += ['-std=c99']
|
||||
if builder.target_platform == 'linux':
|
||||
compiler.postlink += ['-lgcc', '-lm']
|
||||
elif compiler.cc.behavior == 'msvc':
|
||||
@ -107,7 +109,7 @@ binary.sources += [
|
||||
'zlib/trees.c',
|
||||
'zlib/uncompr.c',
|
||||
'zlib/zutil.c',
|
||||
'sp_symhash.c'
|
||||
'sp_symhash.cpp'
|
||||
]
|
||||
if builder.target_platform != 'windows':
|
||||
binary.sources.append('binreloc.c')
|
||||
|
@ -599,7 +599,11 @@ long pc_lengthbin(void *handle); /* return the length of the file */
|
||||
* files are "external"
|
||||
*/
|
||||
#if !defined SC_FUNC
|
||||
#define SC_FUNC
|
||||
# if defined(__cplusplus)
|
||||
# define SC_FUNC extern "C"
|
||||
# else
|
||||
# define SC_FUNC
|
||||
# endif
|
||||
#endif
|
||||
#if !defined SC_VDECL
|
||||
#define SC_VDECL extern
|
||||
@ -616,7 +620,7 @@ SC_FUNC void set_extension(char *filename,char *extension,int force);
|
||||
SC_FUNC symbol *fetchfunc(char *name);
|
||||
SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag);
|
||||
SC_FUNC char *funcdisplayname(char *dest,char *funcname);
|
||||
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr);
|
||||
SC_FUNC int exprconst(cell *val,int *tag,symbol **symptr);
|
||||
SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
|
||||
SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index);
|
||||
SC_FUNC void delete_consttable(constvalue *table);
|
||||
|
@ -2794,7 +2794,7 @@ static cell init(int ident,int *tag,int *errorfound)
|
||||
litidx=1; /* reset literal queue */
|
||||
} /* if */
|
||||
*tag=pc_tag_string;
|
||||
} else if (constexpr(&i,tag,NULL)){
|
||||
} else if (exprconst(&i,tag,NULL)){
|
||||
litadd(i); /* store expression result in literal table */
|
||||
} else {
|
||||
if (errorfound!=NULL)
|
||||
@ -2819,7 +2819,7 @@ static cell needsub(int *tag,constvalue **enumroot)
|
||||
if (matchtoken(']')) /* we have already seen "[" */
|
||||
return 0; /* zero size (like "char msg[]") */
|
||||
|
||||
constexpr(&val,tag,&sym); /* get value (must be constant expression) */
|
||||
exprconst(&val,tag,&sym); /* get value (must be constant expression) */
|
||||
if (val<0) {
|
||||
error(9); /* negative array size is invalid; assumed zero */
|
||||
val=0;
|
||||
@ -2891,7 +2891,7 @@ static void decl_const(int vclass)
|
||||
|
||||
symbolline=fline; /* save line where symbol was found */
|
||||
needtoken('=');
|
||||
constexpr(&val,&exprtag,NULL); /* get value */
|
||||
exprconst(&val,&exprtag,NULL); /* get value */
|
||||
|
||||
/* add_constant() checks for duplicate definitions */
|
||||
/* temporarily reset the line number to where the symbol was defined */
|
||||
@ -4523,11 +4523,11 @@ static void decl_enum(int vclass)
|
||||
multiplier=1;
|
||||
if (matchtoken('(')) {
|
||||
if (matchtoken(taADD)) {
|
||||
constexpr(&increment,NULL,NULL);
|
||||
exprconst(&increment,NULL,NULL);
|
||||
} else if (matchtoken(taMULT)) {
|
||||
constexpr(&multiplier,NULL,NULL);
|
||||
exprconst(&multiplier,NULL,NULL);
|
||||
} else if (matchtoken(taSHL)) {
|
||||
constexpr(&val,NULL,NULL);
|
||||
exprconst(&val,NULL,NULL);
|
||||
while (val-->0)
|
||||
multiplier*=2;
|
||||
} /* if */
|
||||
@ -4568,12 +4568,12 @@ static void decl_enum(int vclass)
|
||||
size=increment; /* default increment of 'val' */
|
||||
fieldtag=0; /* default field tag */
|
||||
if (matchtoken('[')) {
|
||||
constexpr(&size,&fieldtag,NULL); /* get size */
|
||||
exprconst(&size,&fieldtag,NULL); /* get size */
|
||||
needtoken(']');
|
||||
} /* if */
|
||||
/* :TODO: do we need a size modifier here for pc_tag_string? */
|
||||
if (matchtoken('='))
|
||||
constexpr(&value,NULL,NULL); /* get value */
|
||||
exprconst(&value,NULL,NULL); /* get value */
|
||||
/* add_constant() checks whether a variable (global or local) or
|
||||
* a constant with the same name already exists
|
||||
*/
|
||||
@ -5125,7 +5125,7 @@ static symbol *funcstub(int tokid, declinfo_t *decl, const int *thistag)
|
||||
tokeninfo(&val,&str);
|
||||
insert_alias(sym->name,str);
|
||||
} else {
|
||||
constexpr(&val,NULL,NULL);
|
||||
exprconst(&val,NULL,NULL);
|
||||
sym->addr=val;
|
||||
/* At the moment, I have assumed that this syntax is only valid if
|
||||
* val < 0. To properly mix "normal" native functions and indexed
|
||||
@ -5728,7 +5728,7 @@ static void doarg(declinfo_t *decl, int offset, int fpublic, int chkshadow, argi
|
||||
while (paranthese--)
|
||||
needtoken(')');
|
||||
} else {
|
||||
constexpr(&arg->defvalue.val,&arg->defvalue_tag,NULL);
|
||||
exprconst(&arg->defvalue.val,&arg->defvalue_tag,NULL);
|
||||
assert(type->numtags > 0);
|
||||
matchtag(type->tags[0], arg->defvalue_tag, TRUE);
|
||||
} /* if */
|
||||
@ -6901,9 +6901,9 @@ static int doexpr2(int comma,int chkeffect,int allowarray,int mark_endexpr,
|
||||
return ident;
|
||||
}
|
||||
|
||||
/* constexpr
|
||||
/* exprconst
|
||||
*/
|
||||
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr)
|
||||
SC_FUNC int exprconst(cell *val,int *tag,symbol **symptr)
|
||||
{
|
||||
int ident,index;
|
||||
cell cidx;
|
||||
@ -7294,7 +7294,7 @@ static void doswitch(void)
|
||||
* parse all expressions until that special token.
|
||||
*/
|
||||
|
||||
constexpr(&val,NULL,NULL);
|
||||
exprconst(&val,NULL,NULL);
|
||||
/* Search the insertion point (the table is kept in sorted order, so
|
||||
* that advanced abstract machines can sift the case table with a
|
||||
* binary search). Check for duplicate case values at the same time.
|
||||
|
@ -796,7 +796,7 @@ static int preproc_expr(cell *val,int *tag)
|
||||
term=strchr((char*)pline,'\0');
|
||||
assert(term!=NULL);
|
||||
chrcat((char*)pline,PREPROC_TERM); /* the "DEL" code (see SC.H) */
|
||||
result=constexpr(val,tag,NULL); /* get value (or 0 on error) */
|
||||
result=exprconst(val,tag,NULL); /* get value (or 0 on error) */
|
||||
*term='\0'; /* erase the token (if still present) */
|
||||
lexclr(FALSE); /* clear any "pushed" tokens */
|
||||
return result;
|
||||
|
@ -1,230 +0,0 @@
|
||||
/* vim: set ts=4 sw=4 tw=99 et: */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "sp_file_headers.h"
|
||||
#include "sc.h"
|
||||
#include "sp_symhash.h"
|
||||
|
||||
SC_FUNC uint32_t
|
||||
NameHash(const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
const uint8_t *data = (uint8_t *)str;
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
|
||||
#undef get16bits
|
||||
}
|
||||
|
||||
SC_FUNC HashTable *NewHashTable()
|
||||
{
|
||||
HashTable *ht = (HashTable*)malloc(sizeof(HashTable));
|
||||
if (!ht)
|
||||
return ht;
|
||||
ht->buckets = (HashEntry **)calloc(32, sizeof(HashEntry *));
|
||||
if (!ht->buckets) {
|
||||
free(ht);
|
||||
return NULL;
|
||||
}
|
||||
ht->nbuckets = 32;
|
||||
ht->nused = 0;
|
||||
ht->bucketmask = 32 - 1;
|
||||
return ht;
|
||||
}
|
||||
|
||||
SC_FUNC void
|
||||
DestroyHashTable(HashTable *ht)
|
||||
{
|
||||
uint32_t i;
|
||||
if (!ht)
|
||||
return;
|
||||
for (i = 0; i < ht->nbuckets; i++) {
|
||||
HashEntry *he = ht->buckets[i];
|
||||
while (he != NULL) {
|
||||
HashEntry *next = he->next;
|
||||
free(he);
|
||||
he = next;
|
||||
}
|
||||
}
|
||||
free(ht->buckets);
|
||||
free(ht);
|
||||
}
|
||||
|
||||
SC_FUNC symbol *
|
||||
FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber,
|
||||
int *cmptag)
|
||||
{
|
||||
int count=0;
|
||||
symbol *firstmatch=NULL;
|
||||
uint32_t hash = NameHash(name);
|
||||
uint32_t bucket = hash & ht->bucketmask;
|
||||
HashEntry *he = ht->buckets[bucket];
|
||||
|
||||
assert(cmptag!=NULL);
|
||||
|
||||
while (he != NULL) {
|
||||
symbol *sym = he->sym;
|
||||
if ((sym->parent==NULL || sym->ident==iCONSTEXPR) &&
|
||||
(sym->fnumber<0 || sym->fnumber==fnumber) &&
|
||||
(strcmp(sym->name, name) == 0))
|
||||
{
|
||||
/* return closest match or first match; count number of matches */
|
||||
if (firstmatch==NULL)
|
||||
firstmatch=sym;
|
||||
if (*cmptag==0)
|
||||
count++;
|
||||
if (*cmptag==sym->tag) {
|
||||
*cmptag=1; /* good match found, set number of matches to 1 */
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
he = he->next;
|
||||
}
|
||||
|
||||
if (firstmatch!=NULL)
|
||||
*cmptag=count;
|
||||
return firstmatch;
|
||||
}
|
||||
|
||||
SC_FUNC symbol *
|
||||
FindInHashTable(HashTable *ht, const char *name, int fnumber)
|
||||
{
|
||||
uint32_t hash = NameHash(name);
|
||||
uint32_t bucket = hash & ht->bucketmask;
|
||||
HashEntry *he = ht->buckets[bucket];
|
||||
|
||||
while (he != NULL) {
|
||||
symbol *sym = he->sym;
|
||||
if ((sym->parent==NULL || sym->ident==iCONSTEXPR) &&
|
||||
(sym->fnumber<0 || sym->fnumber==fnumber) &&
|
||||
(strcmp(sym->name, name) == 0))
|
||||
{
|
||||
return sym;
|
||||
}
|
||||
he = he->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ResizeHashTable(HashTable *ht)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t xnbuckets = ht->nbuckets * 2;
|
||||
uint32_t xbucketmask = xnbuckets - 1;
|
||||
HashEntry **xbuckets = (HashEntry **)calloc(xnbuckets, sizeof(HashEntry*));
|
||||
if (!xbuckets)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ht->nbuckets; i++) {
|
||||
HashEntry *he = ht->buckets[i];
|
||||
while (he != NULL) {
|
||||
HashEntry *next = he->next;
|
||||
uint32_t bucket = he->sym->hash & xbucketmask;
|
||||
he->next = xbuckets[bucket];
|
||||
xbuckets[bucket] = he;
|
||||
he = next;
|
||||
}
|
||||
}
|
||||
free(ht->buckets);
|
||||
ht->buckets = xbuckets;
|
||||
ht->nbuckets = xnbuckets;
|
||||
ht->bucketmask = xbucketmask;
|
||||
}
|
||||
|
||||
SC_FUNC void
|
||||
AddToHashTable(HashTable *ht, symbol *sym)
|
||||
{
|
||||
uint32_t bucket = sym->hash & ht->bucketmask;
|
||||
HashEntry **hep, *he;
|
||||
|
||||
hep = &ht->buckets[bucket];
|
||||
while (*hep) {
|
||||
assert((*hep)->sym != sym);
|
||||
hep = &(*hep)->next;
|
||||
}
|
||||
|
||||
he = (HashEntry *)malloc(sizeof(HashEntry));
|
||||
if (!he)
|
||||
error(163);
|
||||
he->sym = sym;
|
||||
he->next = NULL;
|
||||
*hep = he;
|
||||
ht->nused++;
|
||||
|
||||
if (ht->nused > ht->nbuckets && ht->nbuckets <= INT_MAX / 2)
|
||||
ResizeHashTable(ht);
|
||||
}
|
||||
|
||||
SC_FUNC void
|
||||
RemoveFromHashTable(HashTable *ht, symbol *sym)
|
||||
{
|
||||
uint32_t bucket = sym->hash & ht->bucketmask;
|
||||
HashEntry **hep = &ht->buckets[bucket];
|
||||
HashEntry *he = *hep;
|
||||
|
||||
while (he != NULL) {
|
||||
if (he->sym == sym) {
|
||||
*hep = he->next;
|
||||
free(he);
|
||||
ht->nused--;
|
||||
return;
|
||||
}
|
||||
hep = &he->next;
|
||||
he = *hep;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
156
sourcepawn/compiler/sp_symhash.cpp
Normal file
156
sourcepawn/compiler/sp_symhash.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "sp_file_headers.h"
|
||||
#include "sc.h"
|
||||
#include "sp_symhash.h"
|
||||
#include <am-hashtable.h>
|
||||
|
||||
struct NameAndScope
|
||||
{
|
||||
const char *name;
|
||||
int fnumber;
|
||||
int *cmptag;
|
||||
mutable symbol *matched;
|
||||
mutable int count;
|
||||
|
||||
NameAndScope(const char *name, int fnumber, int *cmptag)
|
||||
: name(name),
|
||||
fnumber(fnumber),
|
||||
cmptag(cmptag),
|
||||
matched(nullptr),
|
||||
count(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct SymbolHashPolicy
|
||||
{
|
||||
typedef symbol *Payload;
|
||||
|
||||
// Everything with the same name has the same hash, because the compiler
|
||||
// wants to know two names that have the same tag for some reason. Even
|
||||
// so, we can't be that accurate, since we might match the right symbol
|
||||
// very early.
|
||||
static uint32_t hash(const NameAndScope &key) {
|
||||
return ke::HashCharSequence(key.name, strlen(key.name));
|
||||
}
|
||||
static uint32_t hash(const symbol *s) {
|
||||
return ke::HashCharSequence(s->name, strlen(s->name));
|
||||
}
|
||||
|
||||
static bool matches(const NameAndScope &key, symbol *sym) {
|
||||
if (sym->parent && sym->ident != iCONSTEXPR)
|
||||
return false;
|
||||
if (sym->fnumber >= 0 && sym->fnumber != key.fnumber)
|
||||
return false;
|
||||
if (strcmp(key.name, sym->name) != 0)
|
||||
return false;
|
||||
if (key.cmptag) {
|
||||
key.count++;
|
||||
key.matched = sym;
|
||||
if (*key.cmptag != sym->tag)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool matches(const symbol *key, symbol *sym) {
|
||||
return key == sym;
|
||||
}
|
||||
};
|
||||
|
||||
struct HashTable : public ke::HashTable<SymbolHashPolicy>
|
||||
{
|
||||
};
|
||||
|
||||
SC_FUNC uint32_t
|
||||
NameHash(const char *str)
|
||||
{
|
||||
return ke::HashCharSequence(str, strlen(str));
|
||||
}
|
||||
|
||||
SC_FUNC HashTable *NewHashTable()
|
||||
{
|
||||
HashTable *ht = new HashTable();
|
||||
if (!ht->init()) {
|
||||
delete ht;
|
||||
return nullptr;
|
||||
}
|
||||
return ht;
|
||||
}
|
||||
|
||||
SC_FUNC void
|
||||
DestroyHashTable(HashTable *ht)
|
||||
{
|
||||
delete ht;
|
||||
}
|
||||
|
||||
SC_FUNC symbol *
|
||||
FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber, int *cmptag)
|
||||
{
|
||||
NameAndScope nas(name, fnumber, cmptag);
|
||||
HashTable::Result r = ht->find(nas);
|
||||
if (!r.found()) {
|
||||
if (nas.matched) {
|
||||
*cmptag = nas.count;
|
||||
return nas.matched;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*cmptag = 1;
|
||||
return *r;
|
||||
}
|
||||
|
||||
SC_FUNC symbol *
|
||||
FindInHashTable(HashTable *ht, const char *name, int fnumber)
|
||||
{
|
||||
NameAndScope nas(name, fnumber, nullptr);
|
||||
HashTable::Result r = ht->find(nas);
|
||||
if (!r.found())
|
||||
return nullptr;
|
||||
return *r;
|
||||
}
|
||||
|
||||
SC_FUNC void
|
||||
AddToHashTable(HashTable *ht, symbol *sym)
|
||||
{
|
||||
HashTable::Insert i = ht->findForAdd(sym);
|
||||
assert(!i.found());
|
||||
ht->add(i, sym);
|
||||
}
|
||||
|
||||
SC_FUNC void
|
||||
RemoveFromHashTable(HashTable *ht, symbol *sym)
|
||||
{
|
||||
HashTable::Result r = ht->find(sym);
|
||||
assert(r.found());
|
||||
ht->remove(r);
|
||||
}
|
||||
|
||||
#if defined __linux__ || defined __APPLE__
|
||||
extern "C" void __cxa_pure_virtual(void)
|
||||
{
|
||||
}
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
@ -4,17 +4,7 @@
|
||||
|
||||
SC_FUNC uint32_t NameHash(const char *str);
|
||||
|
||||
typedef struct HashEntry {
|
||||
symbol *sym;
|
||||
struct HashEntry *next;
|
||||
} HashEntry;
|
||||
|
||||
struct HashTable {
|
||||
uint32_t nbuckets;
|
||||
uint32_t nused;
|
||||
uint32_t bucketmask;
|
||||
HashEntry **buckets;
|
||||
};
|
||||
struct HashTable;
|
||||
|
||||
SC_FUNC HashTable *NewHashTable();
|
||||
SC_FUNC void DestroyHashTable(HashTable *ht);
|
||||
|
Loading…
Reference in New Issue
Block a user