diff --git a/sourcepawn/compiler/AMBuilder b/sourcepawn/compiler/AMBuilder index 2752a06c..5ce55047 100644 --- a/sourcepawn/compiler/AMBuilder +++ b/sourcepawn/compiler/AMBuilder @@ -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') diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 9741b46e..4b309769 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -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); diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 94f6e2d0..2b0e0245 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -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. diff --git a/sourcepawn/compiler/sc2.c b/sourcepawn/compiler/sc2.c index f1b6505d..87690e74 100644 --- a/sourcepawn/compiler/sc2.c +++ b/sourcepawn/compiler/sc2.c @@ -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; diff --git a/sourcepawn/compiler/sp_symhash.c b/sourcepawn/compiler/sp_symhash.c deleted file mode 100644 index bb35a5ac..00000000 --- a/sourcepawn/compiler/sp_symhash.c +++ /dev/null @@ -1,230 +0,0 @@ -/* vim: set ts=4 sw=4 tw=99 et: */ -#include -#include -#include -#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); -} - diff --git a/sourcepawn/compiler/sp_symhash.cpp b/sourcepawn/compiler/sp_symhash.cpp new file mode 100644 index 00000000..9664d553 --- /dev/null +++ b/sourcepawn/compiler/sp_symhash.cpp @@ -0,0 +1,156 @@ +// vim: set ts=8 sts=2 sw=2 tw=99 et: +#include +#include +#include +#include "sp_file_headers.h" +#include "sc.h" +#include "sp_symhash.h" +#include + +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 +{ +}; + +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 diff --git a/sourcepawn/compiler/sp_symhash.h b/sourcepawn/compiler/sp_symhash.h index beb0f1e5..688c69d2 100644 --- a/sourcepawn/compiler/sp_symhash.h +++ b/sourcepawn/compiler/sp_symhash.h @@ -1,28 +1,18 @@ -/* vim: set ts=4 sw=4 tw=99 et: */ -#ifndef _INCLUDE_SPCOMP_SYMHASH_H_ -#define _INCLUDE_SPCOMP_SYMHASH_H_ - -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; -}; - -SC_FUNC HashTable *NewHashTable(); -SC_FUNC void DestroyHashTable(HashTable *ht); -SC_FUNC void AddToHashTable(HashTable *ht, symbol *sym); -SC_FUNC void RemoveFromHashTable(HashTable *ht, symbol *sym); -SC_FUNC symbol *FindInHashTable(HashTable *ht, const char *name, int fnumber); -SC_FUNC symbol *FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber, - int *cmptag); - -#endif /* _INCLUDE_SPCOMP_SYMHASH_H_ */ - +/* vim: set ts=4 sw=4 tw=99 et: */ +#ifndef _INCLUDE_SPCOMP_SYMHASH_H_ +#define _INCLUDE_SPCOMP_SYMHASH_H_ + +SC_FUNC uint32_t NameHash(const char *str); + +struct HashTable; + +SC_FUNC HashTable *NewHashTable(); +SC_FUNC void DestroyHashTable(HashTable *ht); +SC_FUNC void AddToHashTable(HashTable *ht, symbol *sym); +SC_FUNC void RemoveFromHashTable(HashTable *ht, symbol *sym); +SC_FUNC symbol *FindInHashTable(HashTable *ht, const char *name, int fnumber); +SC_FUNC symbol *FindTaggedInHashTable(HashTable *ht, const char *name, int fnumber, + int *cmptag); + +#endif /* _INCLUDE_SPCOMP_SYMHASH_H_ */ +