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
|
|
|
|
2009-02-20 21:35:52 -05:00
|
|
|
/* initialise the shared string system */
|
2012-09-22 01:11:44 -04:00
|
|
|
void TableInit(Picoc *pc)
|
2009-02-20 21:35:52 -05:00
|
|
|
{
|
2012-09-22 01:11:44 -04:00
|
|
|
TableInitTable(&pc->StringTable, &pc->StringHashTable[0], STRING_TABLE_SIZE, TRUE);
|
|
|
|
pc->StrEmpty = TableStrRegister(pc, "");
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
|
|
|
|
2009-02-03 17:05:11 -05:00
|
|
|
/* hash function for strings */
|
|
|
|
static 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
|
|
|
}
|
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
/* initialise a table */
|
2009-02-20 21:35:52 -05: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;
|
2009-04-03 23:11:12 -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 */
|
2009-02-28 17:13:55 -05:00
|
|
|
static struct TableEntry *TableSearch(struct Table *Tbl, const char *Key, int *AddAt)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
2009-01-29 17:26:04 -05:00
|
|
|
struct TableEntry *Entry;
|
2009-02-03 19:17:30 -05:00
|
|
|
int HashValue = ((unsigned long)Key) % Tbl->Size; /* shared strings have unique addresses so we don't need to hash them */
|
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() */
|
2012-09-22 01:11:44 -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 */
|
2012-09-22 01:11:44 -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;
|
|
|
|
return TRUE;
|
2008-10-12 20:53:28 -04:00
|
|
|
}
|
2009-01-26 03:57:32 -05: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() */
|
2011-02-16 18:38:41 -05: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)
|
2008-12-18 19:22:52 -05: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
|
|
|
|
2008-12-18 19:22:52 -05: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
|
|
|
{
|
|
|
|
struct TableEntry **EntryPtr;
|
|
|
|
int HashValue = ((unsigned long)Key) % Tbl->Size; /* shared strings have unique addresses so we don't need to hash them */
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (EntryPtr = &Tbl->HashTable[HashValue]; *EntryPtr != NULL; EntryPtr = &(*EntryPtr)->Next) {
|
|
|
|
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 */
|
2009-02-28 17:13:55 -05:00
|
|
|
static struct TableEntry *TableSearchIdentifier(struct Table *Tbl, const char *Key, int Len, int *AddAt)
|
2009-02-01 22:25:15 -05:00
|
|
|
{
|
|
|
|
struct TableEntry *Entry;
|
|
|
|
int HashValue = TableHash(Key, Len) % Tbl->Size;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Entry = Tbl->HashTable[HashValue]; Entry != NULL; Entry = Entry->Next) {
|
2009-04-03 23:11:12 -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 */
|
2012-09-22 01:11:44 -04:00
|
|
|
char *TableSetIdentifier(Picoc *pc, struct Table *Tbl, const char *Ident, int IdentLen)
|
2009-02-01 06:31:18 -05:00
|
|
|
{
|
|
|
|
int AddAt;
|
2009-02-28 17:13:55 -05: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-07 00:40:08 -04:00
|
|
|
else { /* add it to the table - we economise by not allocating the whole structure here */
|
2012-09-22 01:11:44 -04:00
|
|
|
struct TableEntry *NewEntry = HeapAllocMem(pc, sizeof(struct TableEntry) - sizeof(union TableEntryPayload) + IdentLen + 1);
|
2009-02-20 21:35:52 -05:00
|
|
|
if (NewEntry == NULL)
|
2012-09-22 01:11:44 -04:00
|
|
|
ProgramFailNoParser(pc, "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
|
|
|
{
|
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry;
|
|
|
|
int Count;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Count = 0; Count < pc->StringTable.Size; Count++) {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|