2011-05-01 02:50:00 -04:00
|
|
|
/* picoc hash table module. This hash table code is used for both symbol tables
|
|
|
|
* and the shared string table. */
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2011-02-17 02:11:20 -05:00
|
|
|
#include "interpreter.h"
|
2009-01-23 06:34:12 -05:00
|
|
|
|
2015-06-17 05:30:27 -04:00
|
|
|
|
|
|
|
static unsigned int TableHash(const char *Key, int Len);
|
|
|
|
static struct TableEntry *TableSearch(struct Table *Tbl, const char *Key,
|
|
|
|
int *AddAt);
|
|
|
|
static struct TableEntry *TableSearchIdentifier(struct Table *Tbl,
|
|
|
|
const char *Key, int Len, int *AddAt);
|
|
|
|
|
2015-06-18 23:49:47 -04:00
|
|
|
/* initialize the shared string system */
|
2012-09-22 01:11:44 -04:00
|
|
|
void TableInit(Picoc *pc)
|
2009-02-20 21:35:52 -05:00
|
|
|
{
|
2015-06-10 19:49:09 -04:00
|
|
|
TableInitTable(&pc->StringTable, &pc->StringHashTable[0],
|
|
|
|
STRING_TABLE_SIZE, true);
|
2012-09-22 01:11:44 -04:00
|
|
|
pc->StrEmpty = TableStrRegister(pc, "");
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
|
|
|
|
2009-02-03 17:05:11 -05:00
|
|
|
/* hash function for strings */
|
2015-06-17 05:30:27 -04:00
|
|
|
unsigned int TableHash(const char *Key, int Len)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
2009-02-03 17:05:11 -05:00
|
|
|
unsigned int Hash = Len;
|
|
|
|
int Offset;
|
|
|
|
int Count;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Count = 0, Offset = 8; Count < Len; Count++, Offset+=7) {
|
2009-02-03 17:05:11 -05:00
|
|
|
if (Offset > sizeof(unsigned int) * 8 - 7)
|
|
|
|
Offset -= sizeof(unsigned int) * 8 - 6;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-03 17:05:11 -05:00
|
|
|
Hash ^= *Key++ << Offset;
|
|
|
|
}
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-03 17:05:11 -05:00
|
|
|
return Hash;
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
|
|
|
|
2015-06-18 23:49:47 -04:00
|
|
|
/* initialize a table */
|
2015-06-10 19:49:09 -04:00
|
|
|
void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size,
|
|
|
|
int OnHeap)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
|
|
|
Tbl->Size = Size;
|
2009-01-29 17:26:04 -05:00
|
|
|
Tbl->OnHeap = OnHeap;
|
2008-10-12 20:53:28 -04:00
|
|
|
Tbl->HashTable = HashTable;
|
2015-06-09 03:45:00 -04:00
|
|
|
memset((void*)HashTable, '\0', sizeof(struct TableEntry*) * Size);
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
|
|
|
|
2009-01-29 17:26:04 -05:00
|
|
|
/* check a hash table entry for a key */
|
2015-06-17 05:30:27 -04:00
|
|
|
struct TableEntry *TableSearch(struct Table *Tbl, const char *Key,
|
2015-06-10 20:27:30 -04:00
|
|
|
int *AddAt)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
2015-06-13 20:06:23 -04:00
|
|
|
/* shared strings have unique addresses so we don't need to hash them */
|
|
|
|
int HashValue = ((unsigned long)Key) % Tbl->Size;
|
2015-06-10 14:07:58 -04:00
|
|
|
struct TableEntry *Entry;
|
|
|
|
|
2015-06-07 00:40:08 -04:00
|
|
|
for (Entry = Tbl->HashTable[HashValue]; Entry != NULL; Entry = Entry->Next) {
|
2009-02-01 22:25:15 -05:00
|
|
|
if (Entry->p.v.Key == Key)
|
2009-02-28 17:13:55 -05:00
|
|
|
return Entry; /* found */
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-29 17:26:04 -05:00
|
|
|
*AddAt = HashValue; /* didn't find it in the chain */
|
2009-02-28 17:13:55 -05:00
|
|
|
return NULL;
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
|
|
|
|
2015-06-07 00:40:08 -04:00
|
|
|
/* set an identifier to a value. returns FALSE if it already exists.
|
2009-02-20 21:35:52 -05:00
|
|
|
* Key must be a shared string from TableStrRegister() */
|
2015-06-10 19:49:09 -04:00
|
|
|
int TableSet(Picoc *pc, struct Table *Tbl, char *Key, struct Value *Val,
|
|
|
|
const char *DeclFileName, int DeclLine, int DeclColumn)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
|
|
|
int AddAt;
|
2009-02-28 17:13:55 -05:00
|
|
|
struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
if (FoundEntry == NULL) { /* add it to the table */
|
2015-06-10 20:27:30 -04:00
|
|
|
struct TableEntry *NewEntry = VariableAlloc(pc, NULL,
|
|
|
|
sizeof(struct TableEntry), Tbl->OnHeap);
|
2011-02-16 18:38:41 -05:00
|
|
|
NewEntry->DeclFileName = DeclFileName;
|
2010-07-24 12:07:56 -04:00
|
|
|
NewEntry->DeclLine = DeclLine;
|
|
|
|
NewEntry->DeclColumn = DeclColumn;
|
2009-02-01 22:25:15 -05:00
|
|
|
NewEntry->p.v.Key = Key;
|
|
|
|
NewEntry->p.v.Val = Val;
|
2009-01-29 17:26:04 -05:00
|
|
|
NewEntry->Next = Tbl->HashTable[AddAt];
|
|
|
|
Tbl->HashTable[AddAt] = NewEntry;
|
2015-06-10 15:24:53 -04:00
|
|
|
return true;
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
2009-01-26 03:57:32 -05:00
|
|
|
|
2015-06-10 15:24:53 -04:00
|
|
|
return false;
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
|
|
|
|
2015-06-07 00:40:08 -04:00
|
|
|
/* find a value in a table. returns FALSE if not found.
|
2009-02-20 21:35:52 -05:00
|
|
|
* Key must be a shared string from TableStrRegister() */
|
2015-06-10 19:49:09 -04:00
|
|
|
int TableGet(struct Table *Tbl, const char *Key, struct Value **Val,
|
|
|
|
const char **DeclFileName, int *DeclLine, int *DeclColumn)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
|
|
|
int AddAt;
|
2009-02-28 17:13:55 -05:00
|
|
|
struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt);
|
|
|
|
if (FoundEntry == NULL)
|
2015-06-10 15:24:53 -04:00
|
|
|
return false;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-28 17:13:55 -05:00
|
|
|
*Val = FoundEntry->p.v.Val;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
if (DeclFileName != NULL) {
|
2011-02-16 18:38:41 -05:00
|
|
|
*DeclFileName = FoundEntry->DeclFileName;
|
2010-07-24 12:07:56 -04:00
|
|
|
*DeclLine = FoundEntry->DeclLine;
|
|
|
|
*DeclColumn = FoundEntry->DeclColumn;
|
|
|
|
}
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 15:24:53 -04:00
|
|
|
return true;
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
2009-02-01 06:31:18 -05:00
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* remove an entry from the table */
|
2012-09-22 01:11:44 -04:00
|
|
|
struct Value *TableDelete(Picoc *pc, struct Table *Tbl, const char *Key)
|
2009-03-15 06:44:56 -04:00
|
|
|
{
|
2015-06-13 20:06:23 -04:00
|
|
|
/* shared strings have unique addresses so we don't need to hash them */
|
|
|
|
int HashValue = ((unsigned long)Key) % Tbl->Size;
|
2015-06-10 14:07:58 -04:00
|
|
|
struct TableEntry **EntryPtr;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
for (EntryPtr = &Tbl->HashTable[HashValue];
|
|
|
|
*EntryPtr != NULL; EntryPtr = &(*EntryPtr)->Next) {
|
2015-06-07 00:40:08 -04:00
|
|
|
if ((*EntryPtr)->p.v.Key == Key) {
|
2011-02-14 20:21:27 -05:00
|
|
|
struct TableEntry *DeleteEntry = *EntryPtr;
|
|
|
|
struct Value *Val = DeleteEntry->p.v.Val;
|
|
|
|
*EntryPtr = DeleteEntry->Next;
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(pc, DeleteEntry);
|
2011-02-14 20:21:27 -05:00
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
return Val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-01 22:25:15 -05:00
|
|
|
/* check a hash table entry for an identifier */
|
2015-06-17 05:30:27 -04:00
|
|
|
struct TableEntry *TableSearchIdentifier(struct Table *Tbl,
|
2015-06-10 19:49:09 -04:00
|
|
|
const char *Key, int Len, int *AddAt)
|
2009-02-01 22:25:15 -05:00
|
|
|
{
|
|
|
|
int HashValue = TableHash(Key, Len) % Tbl->Size;
|
2015-06-10 14:07:58 -04:00
|
|
|
struct TableEntry *Entry;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Entry = Tbl->HashTable[HashValue]; Entry != NULL; Entry = Entry->Next) {
|
2015-06-14 05:46:15 -04:00
|
|
|
if (strncmp(&Entry->p.Key[0], (char *)Key, Len) == 0 &&
|
|
|
|
Entry->p.Key[Len] == '\0')
|
2009-02-28 17:13:55 -05:00
|
|
|
return Entry; /* found */
|
2009-02-01 22:25:15 -05:00
|
|
|
}
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-01 22:25:15 -05:00
|
|
|
*AddAt = HashValue; /* didn't find it in the chain */
|
2009-02-28 17:13:55 -05:00
|
|
|
return NULL;
|
2009-02-01 22:25:15 -05:00
|
|
|
}
|
|
|
|
|
2009-02-01 06:31:18 -05:00
|
|
|
/* set an identifier and return the identifier. share if possible */
|
2015-06-14 05:46:15 -04:00
|
|
|
char *TableSetIdentifier(Picoc *pc, struct Table *Tbl, const char *Ident,
|
|
|
|
int IdentLen)
|
2009-02-01 06:31:18 -05:00
|
|
|
{
|
|
|
|
int AddAt;
|
2015-06-14 05:46:15 -04:00
|
|
|
struct TableEntry *FoundEntry = TableSearchIdentifier(Tbl, Ident, IdentLen,
|
|
|
|
&AddAt);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-28 17:13:55 -05:00
|
|
|
if (FoundEntry != NULL)
|
|
|
|
return &FoundEntry->p.Key[0];
|
2015-06-13 20:06:23 -04:00
|
|
|
else {
|
|
|
|
/* add it to the table - we economise by not allocating
|
|
|
|
the whole structure here */
|
2015-06-10 20:27:30 -04:00
|
|
|
struct TableEntry *NewEntry = HeapAllocMem(pc,
|
2015-06-13 20:06:23 -04:00
|
|
|
sizeof(struct TableEntry) -
|
|
|
|
sizeof(union TableEntryPayload) + IdentLen + 1);
|
2009-02-20 21:35:52 -05:00
|
|
|
if (NewEntry == NULL)
|
2015-06-09 03:45:00 -04:00
|
|
|
ProgramFailNoParser(pc, "(TableSetIdentifier) out of memory");
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-04-03 23:11:12 -04:00
|
|
|
strncpy((char *)&NewEntry->p.Key[0], (char *)Ident, IdentLen);
|
2009-03-10 17:59:18 -04:00
|
|
|
NewEntry->p.Key[IdentLen] = '\0';
|
2009-02-01 06:31:18 -05:00
|
|
|
NewEntry->Next = Tbl->HashTable[AddAt];
|
|
|
|
Tbl->HashTable[AddAt] = NewEntry;
|
2009-02-02 17:33:51 -05:00
|
|
|
return &NewEntry->p.Key[0];
|
2009-02-01 06:31:18 -05:00
|
|
|
}
|
|
|
|
}
|
2009-02-20 21:35:52 -05:00
|
|
|
|
|
|
|
/* register a string in the shared string store */
|
2012-09-22 01:11:44 -04:00
|
|
|
char *TableStrRegister2(Picoc *pc, const char *Str, int Len)
|
2009-02-20 21:35:52 -05:00
|
|
|
{
|
2012-09-22 01:11:44 -04:00
|
|
|
return TableSetIdentifier(pc, &pc->StringTable, Str, Len);
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
|
|
|
|
2012-09-22 01:11:44 -04:00
|
|
|
char *TableStrRegister(Picoc *pc, const char *Str)
|
2009-02-20 21:35:52 -05:00
|
|
|
{
|
2012-09-22 01:11:44 -04:00
|
|
|
return TableStrRegister2(pc, Str, strlen((char *)Str));
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
2009-03-10 22:19:18 -04:00
|
|
|
|
|
|
|
/* free all the strings */
|
2012-09-22 01:11:44 -04:00
|
|
|
void TableStrFree(Picoc *pc)
|
2009-03-10 22:19:18 -04:00
|
|
|
{
|
2015-06-10 14:07:58 -04:00
|
|
|
int Count;
|
2009-03-10 22:19:18 -04:00
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Count = 0; Count < pc->StringTable.Size; Count++) {
|
2015-06-10 20:27:30 -04:00
|
|
|
for (Entry = pc->StringTable.HashTable[Count];
|
|
|
|
Entry != NULL; Entry = NextEntry) {
|
2009-03-10 22:19:18 -04:00
|
|
|
NextEntry = Entry->Next;
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(pc, Entry);
|
2009-03-10 22:19:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|