Port sp_symhash to C++.

This commit is contained in:
David Anderson 2014-08-21 23:36:26 -07:00
parent f5efdbf6f5
commit 5a4c50ce55
7 changed files with 198 additions and 276 deletions

View File

@ -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')

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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);
}

View 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

View File

@ -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);