2008-10-12 20:53:28 -04:00
|
|
|
#include "picoc.h"
|
2009-01-23 06:34:12 -05:00
|
|
|
|
2009-02-20 21:35:52 -05:00
|
|
|
struct Table StringTable;
|
|
|
|
struct TableEntry *StringHashTable[STRING_TABLE_SIZE];
|
|
|
|
char *StrEmpty = NULL;
|
|
|
|
|
|
|
|
/* initialise the shared string system */
|
|
|
|
void TableInit()
|
|
|
|
{
|
2009-02-21 07:02:15 -05:00
|
|
|
TableInitTable(&StringTable, &StringHashTable[0], STRING_TABLE_SIZE, TRUE);
|
2009-02-20 21:35:52 -05:00
|
|
|
StrEmpty = TableStrRegister("");
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (Count = 0, Offset = 8; Count < Len; Count++, Offset+=7)
|
|
|
|
{
|
|
|
|
if (Offset > sizeof(unsigned int) * 8 - 7)
|
|
|
|
Offset -= sizeof(unsigned int) * 8 - 6;
|
|
|
|
|
|
|
|
Hash ^= *Key++ << Offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
2008-10-12 20:53:28 -04:00
|
|
|
|
2009-01-29 17:26:04 -05:00
|
|
|
for (Entry = Tbl->HashTable[HashValue]; Entry != NULL; Entry = Entry->Next)
|
2008-10-12 20:53:28 -04:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-02-01 22:25:15 -05: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() */
|
2010-07-24 12:07:56 -04:00
|
|
|
int TableSet(struct Table *Tbl, char *Key, struct Value *Val, 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);
|
2008-10-12 20:53:28 -04:00
|
|
|
|
2009-02-28 17:13:55 -05:00
|
|
|
if (FoundEntry == NULL)
|
2009-01-29 17:26:04 -05:00
|
|
|
{ /* add it to the table */
|
|
|
|
struct TableEntry *NewEntry = VariableAlloc(NULL, sizeof(struct TableEntry), Tbl->OnHeap);
|
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
|
|
|
}
|
|
|
|
|
2009-02-01 22:25:15 -05: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() */
|
2010-07-24 12:07:56 -04:00
|
|
|
int TableGet(struct Table *Tbl, const char *Key, struct Value **Val, 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;
|
|
|
|
|
2009-02-28 17:13:55 -05:00
|
|
|
*Val = FoundEntry->p.v.Val;
|
2010-07-24 12:07:56 -04:00
|
|
|
|
|
|
|
if (DeclLine != NULL)
|
|
|
|
{
|
|
|
|
*DeclLine = FoundEntry->DeclLine;
|
|
|
|
*DeclColumn = FoundEntry->DeclColumn;
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
struct Value *TableDelete(struct Table *Tbl, const char *Key)
|
|
|
|
{
|
|
|
|
struct TableEntry **EntryPtr;
|
|
|
|
int HashValue = ((unsigned long)Key) % Tbl->Size; /* shared strings have unique addresses so we don't need to hash them */
|
|
|
|
|
|
|
|
for (EntryPtr = &Tbl->HashTable[HashValue]; *EntryPtr != NULL; EntryPtr = &(*EntryPtr)->Next)
|
|
|
|
{
|
|
|
|
if ((*EntryPtr)->p.v.Key == Key)
|
|
|
|
{
|
|
|
|
struct Value *Val = (*EntryPtr)->p.v.Val;
|
|
|
|
*EntryPtr = (*EntryPtr)->Next;
|
|
|
|
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;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
*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 */
|
2009-02-20 21:35:52 -05:00
|
|
|
char *TableSetIdentifier(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);
|
2009-02-01 06:31:18 -05:00
|
|
|
|
2009-02-28 17:13:55 -05:00
|
|
|
if (FoundEntry != NULL)
|
|
|
|
return &FoundEntry->p.Key[0];
|
2009-02-01 06:31:18 -05:00
|
|
|
else
|
2009-02-01 22:25:15 -05:00
|
|
|
{ /* add it to the table - we economise by not allocating the whole structure here */
|
2010-07-24 12:07:56 -04:00
|
|
|
struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry) - sizeof(union TableEntryPayload) + IdentLen + 1);
|
2009-02-20 21:35:52 -05:00
|
|
|
if (NewEntry == NULL)
|
|
|
|
ProgramFail(NULL, "out of memory");
|
|
|
|
|
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 */
|
|
|
|
char *TableStrRegister2(const char *Str, int Len)
|
|
|
|
{
|
|
|
|
return TableSetIdentifier(&StringTable, Str, Len);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *TableStrRegister(const char *Str)
|
|
|
|
{
|
2009-04-03 23:11:12 -04:00
|
|
|
return TableStrRegister2(Str, strlen((char *)Str));
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
2009-03-10 22:19:18 -04:00
|
|
|
|
|
|
|
/* free all the strings */
|
|
|
|
void TableStrFree()
|
|
|
|
{
|
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry;
|
|
|
|
int Count;
|
|
|
|
|
|
|
|
for (Count = 0; Count < StringTable.Size; Count++)
|
|
|
|
{
|
|
|
|
for (Entry = StringTable.HashTable[Count]; Entry != NULL; Entry = NextEntry)
|
|
|
|
{
|
|
|
|
NextEntry = Entry->Next;
|
2009-06-02 04:00:02 -04:00
|
|
|
HeapFreeMem(Entry);
|
2009-03-10 22:19:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|