2011-05-01 02:50:00 -04:00
|
|
|
/* picoc variable storage. This provides ways of defining and accessing
|
|
|
|
* variables */
|
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
|
|
|
|
2010-07-04 15:52:52 -04:00
|
|
|
/* maximum size of a value to temporarily copy while we create a variable */
|
2015-06-07 23:05:17 -04:00
|
|
|
#define MAX_TMP_COPY_BUF (256)
|
2010-07-04 15:52:52 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
|
2015-06-18 23:49:47 -04:00
|
|
|
/* initialize the variable system */
|
2012-09-22 01:11:44 -04:00
|
|
|
void VariableInit(Picoc *pc)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2015-06-10 19:49:09 -04:00
|
|
|
TableInitTable(&(pc->GlobalTable), &(pc->GlobalHashTable)[0],
|
2015-06-14 05:46:15 -04:00
|
|
|
GLOBAL_TABLE_SIZE, true);
|
2015-06-10 19:49:09 -04:00
|
|
|
TableInitTable(&pc->StringLiteralTable, &pc->StringLiteralHashTable[0],
|
2015-06-14 05:46:15 -04:00
|
|
|
STRING_LITERAL_TABLE_SIZE, true);
|
2012-09-22 01:11:44 -04:00
|
|
|
pc->TopStackFrame = NULL;
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* deallocate the contents of a variable */
|
2012-09-22 01:11:44 -04:00
|
|
|
void VariableFree(Picoc *pc, struct Value *Val)
|
2009-03-15 06:44:56 -04:00
|
|
|
{
|
2015-06-07 00:40:08 -04:00
|
|
|
if (Val->ValOnHeap || Val->AnyValOnHeap) {
|
2009-03-15 06:44:56 -04:00
|
|
|
/* free function bodies */
|
2015-06-10 20:27:30 -04:00
|
|
|
if (Val->Typ == &pc->FunctionType &&
|
|
|
|
Val->Val->FuncDef.Intrinsic == NULL &&
|
|
|
|
Val->Val->FuncDef.Body.Pos != NULL)
|
2015-06-22 15:16:49 -04:00
|
|
|
HeapFreeMem(pc, (void*)Val->Val->FuncDef.Body.Pos);
|
2009-03-15 06:44:56 -04:00
|
|
|
|
|
|
|
/* free macro bodies */
|
2012-09-22 01:11:44 -04:00
|
|
|
if (Val->Typ == &pc->MacroType)
|
2015-06-22 15:16:49 -04:00
|
|
|
HeapFreeMem(pc, (void*)Val->Val->MacroDef.Body.Pos);
|
2009-03-15 06:44:56 -04:00
|
|
|
|
2012-09-03 06:14:06 -04:00
|
|
|
/* free the AnyValue */
|
|
|
|
if (Val->AnyValOnHeap)
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(pc, Val->Val);
|
2009-03-15 06:44:56 -04:00
|
|
|
}
|
2012-09-03 06:14:06 -04:00
|
|
|
|
|
|
|
/* free the value */
|
|
|
|
if (Val->ValOnHeap)
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(pc, Val);
|
2009-03-15 06:44:56 -04:00
|
|
|
}
|
|
|
|
|
2009-03-11 18:28:42 -04:00
|
|
|
/* deallocate the global table and the string literal table */
|
2012-09-22 01:11:44 -04:00
|
|
|
void VariableTableCleanup(Picoc *pc, struct Table *HashTable)
|
2009-03-11 06:01:32 -04:00
|
|
|
{
|
2015-06-10 14:07:58 -04:00
|
|
|
int Count;
|
2009-03-11 06:01:32 -04:00
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Count = 0; Count < HashTable->Size; Count++) {
|
2015-06-10 20:27:30 -04:00
|
|
|
for (Entry = HashTable->HashTable[Count];
|
|
|
|
Entry != NULL;
|
|
|
|
Entry = NextEntry) {
|
2009-03-11 06:01:32 -04:00
|
|
|
NextEntry = Entry->Next;
|
2012-09-22 01:11:44 -04:00
|
|
|
VariableFree(pc, Entry->p.v.Val);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-03-11 19:49:10 -04:00
|
|
|
/* free the hash table entry */
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(pc, Entry);
|
2009-03-11 06:01:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-22 01:11:44 -04:00
|
|
|
void VariableCleanup(Picoc *pc)
|
2009-03-11 18:28:42 -04:00
|
|
|
{
|
2012-09-22 01:11:44 -04:00
|
|
|
VariableTableCleanup(pc, &pc->GlobalTable);
|
|
|
|
VariableTableCleanup(pc, &pc->StringLiteralTable);
|
2009-03-11 18:28:42 -04:00
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* allocate some memory, either on the heap or the stack
|
|
|
|
and check if we've run out */
|
2012-09-22 01:11:44 -04:00
|
|
|
void *VariableAlloc(Picoc *pc, struct ParseState *Parser, int Size, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
|
|
|
void *NewValue;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-26 03:57:32 -05:00
|
|
|
if (OnHeap)
|
2012-09-22 01:11:44 -04:00
|
|
|
NewValue = HeapAllocMem(pc, Size);
|
2009-01-23 06:34:12 -05:00
|
|
|
else
|
2012-09-22 01:11:44 -04:00
|
|
|
NewValue = HeapAllocStack(pc, Size);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
if (NewValue == NULL)
|
2015-06-09 03:45:00 -04:00
|
|
|
ProgramFail(Parser, "(VariableAlloc) out of memory");
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-03 19:17:30 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
|
|
|
if (!OnHeap)
|
|
|
|
printf("pushing %d at 0x%lx\n", Size, (unsigned long)NewValue);
|
|
|
|
#endif
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* allocate a value either on the heap or the stack using space
|
|
|
|
dependent on what type we want */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableAllocValueAndData(Picoc *pc, struct ParseState *Parser,
|
|
|
|
int DataSize, int IsLValue, struct Value *LValueFrom, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *NewValue = VariableAlloc(pc, Parser,
|
2015-06-14 05:46:15 -04:00
|
|
|
MEM_ALIGN(sizeof(struct Value)) + DataSize, OnHeap);
|
2015-06-10 19:49:09 -04:00
|
|
|
NewValue->Val = (union AnyValue*)((char*)NewValue +
|
2015-06-14 05:46:15 -04:00
|
|
|
MEM_ALIGN(sizeof(struct Value)));
|
2009-01-26 03:57:32 -05:00
|
|
|
NewValue->ValOnHeap = OnHeap;
|
2015-06-10 15:24:53 -04:00
|
|
|
NewValue->AnyValOnHeap = false;
|
2009-01-26 03:57:32 -05:00
|
|
|
NewValue->ValOnStack = !OnHeap;
|
2009-02-15 00:52:03 -05:00
|
|
|
NewValue->IsLValue = IsLValue;
|
2009-02-26 04:56:22 -05:00
|
|
|
NewValue->LValueFrom = LValueFrom;
|
2015-06-07 00:40:08 -04:00
|
|
|
if (Parser)
|
2013-03-16 03:39:34 -04:00
|
|
|
NewValue->ScopeID = Parser->ScopeID;
|
|
|
|
|
2015-06-10 15:24:53 -04:00
|
|
|
NewValue->OutOfScope = false;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate a value given its type */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableAllocValueFromType(Picoc *pc, struct ParseState *Parser,
|
|
|
|
struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2015-06-10 15:24:53 -04:00
|
|
|
int Size = TypeSize(Typ, Typ->ArraySize, false);
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Value *NewValue = VariableAllocValueAndData(pc, Parser, Size,
|
|
|
|
IsLValue, LValueFrom, OnHeap);
|
2012-09-22 01:11:44 -04:00
|
|
|
assert(Size >= 0 || Typ == &pc->VoidType);
|
2009-01-23 06:34:12 -05:00
|
|
|
NewValue->Typ = Typ;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* allocate a value either on the heap or the stack and copy
|
|
|
|
its value. handles overlapping data */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableAllocValueAndCopy(Picoc *pc, struct ParseState *Parser,
|
|
|
|
struct Value *FromValue, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2015-06-10 15:24:53 -04:00
|
|
|
int CopySize = TypeSizeValue(FromValue, true);
|
2015-06-10 14:07:58 -04:00
|
|
|
char TmpBuf[MAX_TMP_COPY_BUF];
|
2010-07-04 15:52:52 -04:00
|
|
|
struct ValueType *DType = FromValue->Typ;
|
|
|
|
struct Value *NewValue;
|
|
|
|
|
|
|
|
assert(CopySize <= MAX_TMP_COPY_BUF);
|
2015-06-07 02:28:10 -04:00
|
|
|
memcpy((void*)&TmpBuf[0], (void*)FromValue->Val, CopySize);
|
2015-06-10 19:49:09 -04:00
|
|
|
NewValue = VariableAllocValueAndData(pc, Parser, CopySize,
|
2015-06-14 05:46:15 -04:00
|
|
|
FromValue->IsLValue, FromValue->LValueFrom, OnHeap);
|
2010-07-04 15:52:52 -04:00
|
|
|
NewValue->Typ = DType;
|
2015-06-07 02:28:10 -04:00
|
|
|
memcpy((void*)NewValue->Val, (void*)&TmpBuf[0], CopySize);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* allocate a value either on the heap or the stack from an
|
|
|
|
existing AnyValue and type */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser,
|
2015-06-21 21:54:56 -04:00
|
|
|
struct ValueType *Typ, union AnyValue *FromValue, int IsLValue,
|
|
|
|
struct Value *LValueFrom)
|
2009-02-09 06:40:56 -05:00
|
|
|
{
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Value *NewValue = VariableAlloc(Parser->pc, Parser,
|
|
|
|
sizeof(struct Value), false);
|
2009-02-09 06:40:56 -05:00
|
|
|
NewValue->Typ = Typ;
|
|
|
|
NewValue->Val = FromValue;
|
2015-06-10 15:24:53 -04:00
|
|
|
NewValue->ValOnHeap = false;
|
|
|
|
NewValue->AnyValOnHeap = false;
|
|
|
|
NewValue->ValOnStack = false;
|
2009-02-15 00:52:03 -05:00
|
|
|
NewValue->IsLValue = IsLValue;
|
2009-02-26 04:56:22 -05:00
|
|
|
NewValue->LValueFrom = LValueFrom;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-09 06:40:56 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* allocate a value either on the heap or the stack from an
|
|
|
|
existing Value, sharing the value */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableAllocValueShared(struct ParseState *Parser,
|
2015-06-21 21:54:56 -04:00
|
|
|
struct Value *FromValue)
|
2009-02-11 01:47:36 -05:00
|
|
|
{
|
2015-06-10 19:49:09 -04:00
|
|
|
return VariableAllocValueFromExistingData(Parser, FromValue->Typ,
|
2015-06-14 05:46:15 -04:00
|
|
|
FromValue->Val, FromValue->IsLValue,
|
|
|
|
FromValue->IsLValue ? FromValue : NULL);
|
2009-02-11 01:47:36 -05:00
|
|
|
}
|
|
|
|
|
2012-09-03 06:14:06 -04:00
|
|
|
/* reallocate a variable so its data has a new size */
|
2015-06-14 05:46:15 -04:00
|
|
|
void VariableRealloc(struct ParseState *Parser, struct Value *FromValue,
|
|
|
|
int NewSize)
|
2012-09-03 06:14:06 -04:00
|
|
|
{
|
|
|
|
if (FromValue->AnyValOnHeap)
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(Parser->pc, FromValue->Val);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 15:24:53 -04:00
|
|
|
FromValue->Val = VariableAlloc(Parser->pc, Parser, NewSize, true);
|
|
|
|
FromValue->AnyValOnHeap = true;
|
2012-09-03 06:14:06 -04:00
|
|
|
}
|
|
|
|
|
2015-06-09 03:45:00 -04:00
|
|
|
int VariableScopeBegin(struct ParseState *Parser, int* OldScopeID)
|
2013-03-16 03:39:34 -04:00
|
|
|
{
|
2015-06-09 03:45:00 -04:00
|
|
|
int Count;
|
2013-03-16 03:39:34 -04:00
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry;
|
2015-06-10 14:55:52 -04:00
|
|
|
#ifdef DEBUG_VAR_SCOPE
|
2013-03-16 03:39:34 -04:00
|
|
|
int FirstPrint = 0;
|
2015-06-07 00:40:08 -04:00
|
|
|
#endif
|
|
|
|
|
2015-06-09 03:45:00 -04:00
|
|
|
if (Parser->ScopeID == -1)
|
|
|
|
return -1;
|
2013-03-16 03:39:34 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Table *HashTable = (Parser->pc->TopStackFrame == NULL) ?
|
|
|
|
&(Parser->pc->GlobalTable) : &(Parser->pc->TopStackFrame)->LocalTable;
|
2015-06-10 13:33:16 -04:00
|
|
|
|
2013-03-16 03:39:34 -04:00
|
|
|
/* XXX dumb hash, let's hope for no collisions... */
|
|
|
|
*OldScopeID = Parser->ScopeID;
|
2015-06-10 20:27:30 -04:00
|
|
|
Parser->ScopeID = (int)(intptr_t)(Parser->SourceText) *
|
|
|
|
((int)(intptr_t)(Parser->Pos) / sizeof(char*));
|
2013-03-16 03:39:34 -04:00
|
|
|
/* or maybe a more human-readable hash for debugging? */
|
|
|
|
/* Parser->ScopeID = Parser->Line * 0x10000 + Parser->CharacterPos; */
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
for (Count = 0; Count < HashTable->Size; Count++) {
|
2015-06-10 20:27:30 -04:00
|
|
|
for (Entry = HashTable->HashTable[Count];
|
|
|
|
Entry != NULL; Entry = NextEntry) {
|
2013-03-16 03:39:34 -04:00
|
|
|
NextEntry = Entry->Next;
|
2015-06-10 20:27:30 -04:00
|
|
|
if (Entry->p.v.Val->ScopeID == Parser->ScopeID &&
|
|
|
|
Entry->p.v.Val->OutOfScope == true) {
|
2015-06-10 15:24:53 -04:00
|
|
|
Entry->p.v.Val->OutOfScope = false;
|
2013-03-16 03:39:34 -04:00
|
|
|
Entry->p.v.Key = (char*)((intptr_t)Entry->p.v.Key & ~1);
|
2015-06-10 14:55:52 -04:00
|
|
|
#ifdef DEBUG_VAR_SCOPE
|
2015-06-10 13:33:16 -04:00
|
|
|
if (!FirstPrint) PRINT_SOURCE_POS();
|
2013-03-16 03:39:34 -04:00
|
|
|
FirstPrint = 1;
|
2015-06-10 19:49:09 -04:00
|
|
|
printf(">>> back into scope: %s %x %d\n", Entry->p.v.Key,
|
|
|
|
Entry->p.v.Val->ScopeID, Entry->p.v.Val->Val->Integer);
|
2015-06-07 00:40:08 -04:00
|
|
|
#endif
|
2013-03-16 03:39:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Parser->ScopeID;
|
|
|
|
}
|
|
|
|
|
2015-06-09 03:45:00 -04:00
|
|
|
void VariableScopeEnd(struct ParseState *Parser, int ScopeID, int PrevScopeID)
|
2013-03-16 03:39:34 -04:00
|
|
|
{
|
|
|
|
int Count;
|
2015-06-09 03:45:00 -04:00
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry = NULL;
|
2015-06-10 14:55:52 -04:00
|
|
|
#ifdef DEBUG_VAR_SCOPE
|
2013-03-16 03:39:34 -04:00
|
|
|
int FirstPrint = 0;
|
2015-06-07 00:40:08 -04:00
|
|
|
#endif
|
2013-03-16 03:39:34 -04:00
|
|
|
|
2015-06-09 03:45:00 -04:00
|
|
|
if (ScopeID == -1)
|
|
|
|
return;
|
2013-03-16 03:39:34 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Table *HashTable = (Parser->pc->TopStackFrame == NULL) ?
|
|
|
|
&(Parser->pc->GlobalTable) : &(Parser->pc->TopStackFrame)->LocalTable;
|
2015-06-10 13:33:16 -04:00
|
|
|
|
2015-06-07 00:40:08 -04:00
|
|
|
for (Count = 0; Count < HashTable->Size; Count++) {
|
2015-06-14 05:46:15 -04:00
|
|
|
for (Entry = HashTable->HashTable[Count]; Entry != NULL;
|
|
|
|
Entry = NextEntry) {
|
2013-03-16 03:39:34 -04:00
|
|
|
NextEntry = Entry->Next;
|
2015-06-10 20:27:30 -04:00
|
|
|
if ((Entry->p.v.Val->ScopeID == ScopeID) &&
|
|
|
|
(Entry->p.v.Val->OutOfScope == false)) {
|
2015-06-10 14:55:52 -04:00
|
|
|
#ifdef DEBUG_VAR_SCOPE
|
2015-06-10 13:33:16 -04:00
|
|
|
if (!FirstPrint) PRINT_SOURCE_POS();
|
2013-03-16 03:39:34 -04:00
|
|
|
FirstPrint = 1;
|
2015-06-10 19:49:09 -04:00
|
|
|
printf(">>> out of scope: %s %x %d\n", Entry->p.v.Key,
|
|
|
|
Entry->p.v.Val->ScopeID, Entry->p.v.Val->Val->Integer);
|
2015-06-07 00:40:08 -04:00
|
|
|
#endif
|
2015-06-10 15:24:53 -04:00
|
|
|
Entry->p.v.Val->OutOfScope = true;
|
2013-03-16 03:39:34 -04:00
|
|
|
Entry->p.v.Key = (char*)((intptr_t)Entry->p.v.Key | 1); /* alter the key so it won't be found by normal searches */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Parser->ScopeID = PrevScopeID;
|
|
|
|
}
|
|
|
|
|
2015-06-13 13:05:27 -04:00
|
|
|
int VariableDefinedAndOutOfScope(Picoc *pc, const char* Ident)
|
2013-03-16 03:39:34 -04:00
|
|
|
{
|
|
|
|
int Count;
|
2015-06-10 14:07:58 -04:00
|
|
|
struct TableEntry *Entry;
|
2013-03-16 03:39:34 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Table * HashTable = (pc->TopStackFrame == NULL) ?
|
|
|
|
&(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable;
|
|
|
|
|
2015-06-07 00:40:08 -04:00
|
|
|
for (Count = 0; Count < HashTable->Size; Count++) {
|
2015-06-14 05:46:15 -04:00
|
|
|
for (Entry = HashTable->HashTable[Count]; Entry != NULL;
|
|
|
|
Entry = Entry->Next) {
|
2015-06-10 20:27:30 -04:00
|
|
|
if (Entry->p.v.Val->OutOfScope == true &&
|
|
|
|
(char*)((intptr_t)Entry->p.v.Key & ~1) == Ident)
|
2015-06-10 15:24:53 -04:00
|
|
|
return true;
|
2013-03-16 03:39:34 -04:00
|
|
|
}
|
|
|
|
}
|
2015-06-10 15:24:53 -04:00
|
|
|
return false;
|
2013-03-16 03:39:34 -04:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* define a variable. Ident must be registered */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableDefine(Picoc *pc, struct ParseState *Parser, char *Ident,
|
|
|
|
struct Value *InitValue, struct ValueType *Typ, int MakeWritable)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2015-06-10 14:07:58 -04:00
|
|
|
int ScopeID = Parser ? Parser->ScopeID : -1;
|
2013-03-16 03:39:34 -04:00
|
|
|
struct Value * AssignValue;
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Table * currentTable = (pc->TopStackFrame == NULL) ?
|
|
|
|
&(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 14:55:52 -04:00
|
|
|
#ifdef DEBUG_VAR_SCOPE
|
2015-06-10 19:49:09 -04:00
|
|
|
if (Parser) fprintf(stderr, "def %s %x (%s:%d:%d)\n", Ident, ScopeID,
|
|
|
|
Parser->FileName, Parser->Line, Parser->CharacterPos);
|
2013-03-16 03:39:34 -04:00
|
|
|
#endif
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-06-02 01:51:51 -04:00
|
|
|
if (InitValue != NULL)
|
2015-06-10 20:27:30 -04:00
|
|
|
AssignValue = VariableAllocValueAndCopy(pc, Parser, InitValue,
|
|
|
|
pc->TopStackFrame == NULL);
|
2009-06-02 01:51:51 -04:00
|
|
|
else
|
2015-06-10 19:49:09 -04:00
|
|
|
AssignValue = VariableAllocValueFromType(pc, Parser, Typ, MakeWritable,
|
|
|
|
NULL, pc->TopStackFrame == NULL);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-06-02 01:51:51 -04:00
|
|
|
AssignValue->IsLValue = MakeWritable;
|
2013-03-16 03:39:34 -04:00
|
|
|
AssignValue->ScopeID = ScopeID;
|
2015-06-10 15:24:53 -04:00
|
|
|
AssignValue->OutOfScope = false;
|
2013-03-16 03:39:34 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
if (!TableSet(pc, currentTable, Ident, AssignValue, Parser ?
|
|
|
|
((char*)Parser->FileName) : NULL, Parser ? Parser->Line : 0,
|
|
|
|
Parser ? Parser->CharacterPos : 0))
|
2009-02-02 06:08:36 -05:00
|
|
|
ProgramFail(Parser, "'%s' is already defined", Ident);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-06-02 01:51:51 -04:00
|
|
|
return AssignValue;
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* define a variable. Ident must be registered. If it's a redefinition
|
|
|
|
from the same declaration don't throw an error */
|
2015-06-10 19:49:09 -04:00
|
|
|
struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser,
|
|
|
|
char *Ident, struct ValueType *Typ, int IsStatic, int *FirstVisit)
|
2010-07-24 12:07:56 -04:00
|
|
|
{
|
|
|
|
int DeclLine;
|
|
|
|
int DeclColumn;
|
2015-06-10 14:07:58 -04:00
|
|
|
const char *DeclFileName;
|
|
|
|
Picoc *pc = Parser->pc;
|
|
|
|
struct Value *ExistingValue;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2012-09-23 07:48:27 -04:00
|
|
|
/* is the type a forward declaration? */
|
|
|
|
if (TypeIsForwardDeclared(Parser, Typ))
|
|
|
|
ProgramFail(Parser, "type '%t' isn't defined", Typ);
|
|
|
|
|
2015-06-07 00:40:08 -04:00
|
|
|
if (IsStatic) {
|
2011-02-16 18:38:41 -05:00
|
|
|
char MangledName[LINEBUFFER_MAX];
|
|
|
|
char *MNPos = &MangledName[0];
|
|
|
|
char *MNEnd = &MangledName[LINEBUFFER_MAX-1];
|
|
|
|
const char *RegisteredMangledName;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* make the mangled static name (avoiding using sprintf()
|
|
|
|
to minimise library impact) */
|
2015-06-22 15:16:49 -04:00
|
|
|
memset((void*)&MangledName, '\0', sizeof(MangledName));
|
2011-02-16 18:38:41 -05:00
|
|
|
*MNPos++ = '/';
|
2015-06-07 02:28:10 -04:00
|
|
|
strncpy(MNPos, (char*)Parser->FileName, MNEnd - MNPos);
|
2011-02-16 18:38:41 -05:00
|
|
|
MNPos += strlen(MNPos);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
if (pc->TopStackFrame != NULL) {
|
2011-02-16 18:38:41 -05:00
|
|
|
/* we're inside a function */
|
2015-06-14 05:46:15 -04:00
|
|
|
if (MNEnd - MNPos > 0)
|
|
|
|
*MNPos++ = '/';
|
2015-06-07 02:28:10 -04:00
|
|
|
strncpy(MNPos, (char*)pc->TopStackFrame->FuncName, MNEnd - MNPos);
|
2011-02-16 18:38:41 -05:00
|
|
|
MNPos += strlen(MNPos);
|
|
|
|
}
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2011-02-16 18:38:41 -05:00
|
|
|
if (MNEnd - MNPos > 0) *MNPos++ = '/';
|
|
|
|
strncpy(MNPos, Ident, MNEnd - MNPos);
|
2012-09-22 01:11:44 -04:00
|
|
|
RegisteredMangledName = TableStrRegister(pc, MangledName);
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2011-02-16 18:38:41 -05:00
|
|
|
/* is this static already defined? */
|
2015-06-10 20:27:30 -04:00
|
|
|
if (!TableGet(&pc->GlobalTable, RegisteredMangledName, &ExistingValue,
|
2015-06-14 05:46:15 -04:00
|
|
|
&DeclFileName, &DeclLine, &DeclColumn)) {
|
2011-02-16 18:38:41 -05:00
|
|
|
/* define the mangled-named static variable store in the global scope */
|
2015-06-10 20:27:30 -04:00
|
|
|
ExistingValue = VariableAllocValueFromType(Parser->pc, Parser, Typ,
|
|
|
|
true, NULL, true);
|
|
|
|
TableSet(pc, &pc->GlobalTable, (char*)RegisteredMangledName,
|
|
|
|
ExistingValue, (char *)Parser->FileName, Parser->Line,
|
|
|
|
Parser->CharacterPos);
|
2015-06-10 15:24:53 -04:00
|
|
|
*FirstVisit = true;
|
2011-02-16 18:38:41 -05:00
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* static variable exists in the global scope - now make a
|
|
|
|
mirroring variable in our own scope with the short name */
|
|
|
|
VariableDefinePlatformVar(Parser->pc, Parser, Ident, ExistingValue->Typ,
|
|
|
|
ExistingValue->Val, true);
|
2010-07-24 12:07:56 -04:00
|
|
|
return ExistingValue;
|
2015-06-07 00:40:08 -04:00
|
|
|
} else {
|
2015-06-10 20:27:30 -04:00
|
|
|
if (Parser->Line != 0 && TableGet((pc->TopStackFrame == NULL) ?
|
|
|
|
&pc->GlobalTable : &pc->TopStackFrame->LocalTable, Ident,
|
|
|
|
&ExistingValue, &DeclFileName, &DeclLine, &DeclColumn)
|
2015-06-13 20:06:23 -04:00
|
|
|
&& DeclFileName == Parser->FileName && DeclLine == Parser->Line &&
|
|
|
|
DeclColumn == Parser->CharacterPos)
|
2011-02-16 18:38:41 -05:00
|
|
|
return ExistingValue;
|
|
|
|
else
|
2015-06-10 15:24:53 -04:00
|
|
|
return VariableDefine(Parser->pc, Parser, Ident, NULL, Typ, true);
|
2011-02-16 18:38:41 -05:00
|
|
|
}
|
2010-07-24 12:07:56 -04:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* check if a variable with a given name is defined. Ident must be registered */
|
2012-09-22 01:11:44 -04:00
|
|
|
int VariableDefined(Picoc *pc, const char *Ident)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
|
|
|
struct Value *FoundValue;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 19:49:09 -04:00
|
|
|
if (pc->TopStackFrame == NULL || !TableGet(&pc->TopStackFrame->LocalTable,
|
2015-06-14 05:46:15 -04:00
|
|
|
Ident, &FoundValue, NULL, NULL, NULL)) {
|
2012-09-22 01:11:44 -04:00
|
|
|
if (!TableGet(&pc->GlobalTable, Ident, &FoundValue, NULL, NULL, NULL))
|
2015-06-10 15:24:53 -04:00
|
|
|
return false;
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
2015-06-10 15:24:53 -04:00
|
|
|
return true;
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* get the value of a variable. must be defined. Ident must be registered */
|
2015-06-10 19:49:09 -04:00
|
|
|
void VariableGet(Picoc *pc, struct ParseState *Parser, const char *Ident,
|
|
|
|
struct Value **LVal)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2015-06-10 19:49:09 -04:00
|
|
|
if (pc->TopStackFrame == NULL || !TableGet(&pc->TopStackFrame->LocalTable,
|
2015-06-14 05:46:15 -04:00
|
|
|
Ident, LVal, NULL, NULL, NULL)) {
|
2015-06-07 00:40:08 -04:00
|
|
|
if (!TableGet(&pc->GlobalTable, Ident, LVal, NULL, NULL, NULL)) {
|
2013-03-16 03:39:34 -04:00
|
|
|
if (VariableDefinedAndOutOfScope(pc, Ident))
|
|
|
|
ProgramFail(Parser, "'%s' is out of scope", Ident);
|
|
|
|
else
|
2015-06-08 18:46:25 -04:00
|
|
|
ProgramFail(Parser, "VariableGet Ident: '%s' is undefined", Ident);
|
2013-03-16 03:39:34 -04:00
|
|
|
}
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
2009-01-26 03:57:32 -05:00
|
|
|
}
|
2009-01-23 06:34:12 -05:00
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* define a global variable shared with a platform global. Ident will be registered */
|
2015-06-10 19:49:09 -04:00
|
|
|
void VariableDefinePlatformVar(Picoc *pc, struct ParseState *Parser, char *Ident,
|
|
|
|
struct ValueType *Typ, union AnyValue *FromValue, int IsWritable)
|
2009-02-28 15:46:02 -05:00
|
|
|
{
|
2015-06-10 20:27:30 -04:00
|
|
|
struct Value *SomeValue = VariableAllocValueAndData(pc, NULL, 0, IsWritable,
|
|
|
|
NULL, true);
|
2009-02-28 15:46:02 -05:00
|
|
|
SomeValue->Typ = Typ;
|
2010-01-03 12:45:35 -05:00
|
|
|
SomeValue->Val = FromValue;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
if (!TableSet(pc,
|
|
|
|
(pc->TopStackFrame == NULL) ? &pc->GlobalTable : &pc->TopStackFrame->LocalTable,
|
|
|
|
TableStrRegister(pc, Ident), SomeValue,
|
|
|
|
Parser ? Parser->FileName : NULL,
|
|
|
|
Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0))
|
2009-03-05 00:03:28 -05:00
|
|
|
ProgramFail(Parser, "'%s' is already defined", Ident);
|
2009-02-28 15:46:02 -05:00
|
|
|
}
|
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* free and/or pop the top value off the stack. Var must be
|
|
|
|
the top value on the stack! */
|
2009-02-01 06:31:18 -05:00
|
|
|
void VariableStackPop(struct ParseState *Parser, struct Value *Var)
|
2009-01-26 03:57:32 -05:00
|
|
|
{
|
|
|
|
int Success;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-02-03 19:17:30 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-06-02 03:50:46 -04:00
|
|
|
if (Var->ValOnStack)
|
2015-06-10 19:49:09 -04:00
|
|
|
printf("popping %ld at 0x%lx\n",
|
|
|
|
(unsigned long)(sizeof(struct Value) + TypeSizeValue(Var, false)),
|
|
|
|
(unsigned long)Var);
|
2009-02-03 19:17:30 -05:00
|
|
|
#endif
|
2015-06-07 00:40:08 -04:00
|
|
|
|
|
|
|
if (Var->ValOnHeap) {
|
2009-06-02 03:01:43 -04:00
|
|
|
if (Var->Val != NULL)
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapFreeMem(Parser->pc, Var->Val);
|
2015-06-10 19:49:09 -04:00
|
|
|
Success = HeapPopStack(Parser->pc, Var, sizeof(struct Value)); /* free from heap */
|
2015-06-07 00:40:08 -04:00
|
|
|
} else if (Var->ValOnStack)
|
2015-06-10 19:49:09 -04:00
|
|
|
Success = HeapPopStack(Parser->pc, Var,
|
|
|
|
sizeof(struct Value)+TypeSizeValue(Var, false)); /* free from stack */
|
2009-01-26 03:57:32 -05:00
|
|
|
else
|
2015-06-10 19:49:09 -04:00
|
|
|
Success = HeapPopStack(Parser->pc, Var, sizeof(struct Value)); /* value isn't our problem */
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-01-26 03:57:32 -05:00
|
|
|
if (!Success)
|
2009-02-01 06:31:18 -05:00
|
|
|
ProgramFail(Parser, "stack underrun");
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add a stack frame when doing a function call */
|
2015-06-10 19:49:09 -04:00
|
|
|
void VariableStackFrameAdd(struct ParseState *Parser, const char *FuncName,
|
2015-06-21 21:54:56 -04:00
|
|
|
int NumParams)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-01-29 06:10:46 -05:00
|
|
|
struct StackFrame *NewFrame;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2012-09-22 01:11:44 -04:00
|
|
|
HeapPushStackFrame(Parser->pc);
|
2015-06-10 19:49:09 -04:00
|
|
|
NewFrame = HeapAllocStack(Parser->pc,
|
|
|
|
sizeof(struct StackFrame)+sizeof(struct Value*)*NumParams);
|
2009-02-20 21:35:52 -05:00
|
|
|
if (NewFrame == NULL)
|
2015-06-09 03:45:00 -04:00
|
|
|
ProgramFail(Parser, "(VariableStackFrameAdd) out of memory");
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2011-02-11 23:04:51 -05:00
|
|
|
ParserCopy(&NewFrame->ReturnParser, Parser);
|
2011-02-16 18:38:41 -05:00
|
|
|
NewFrame->FuncName = FuncName;
|
2015-06-10 20:27:30 -04:00
|
|
|
NewFrame->Parameter = (NumParams > 0) ?
|
|
|
|
((void*)((char*)NewFrame+sizeof(struct StackFrame))) : NULL;
|
2015-06-10 19:49:09 -04:00
|
|
|
TableInitTable(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0],
|
|
|
|
LOCAL_TABLE_SIZE, false);
|
2012-09-22 01:11:44 -04:00
|
|
|
NewFrame->PreviousStackFrame = Parser->pc->TopStackFrame;
|
|
|
|
Parser->pc->TopStackFrame = NewFrame;
|
2009-01-26 03:57:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* remove a stack frame */
|
2009-02-01 06:31:18 -05:00
|
|
|
void VariableStackFramePop(struct ParseState *Parser)
|
2009-01-26 03:57:32 -05:00
|
|
|
{
|
2012-09-22 01:11:44 -04:00
|
|
|
if (Parser->pc->TopStackFrame == NULL)
|
2009-02-01 06:31:18 -05:00
|
|
|
ProgramFail(Parser, "stack is empty - can't go back");
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2012-09-22 01:11:44 -04:00
|
|
|
ParserCopy(Parser, &Parser->pc->TopStackFrame->ReturnParser);
|
|
|
|
Parser->pc->TopStackFrame = Parser->pc->TopStackFrame->PreviousStackFrame;
|
|
|
|
HeapPopStackFrame(Parser->pc);
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
2009-03-11 18:28:42 -04:00
|
|
|
|
2015-06-10 20:27:30 -04:00
|
|
|
/* get a string literal. assumes that Ident is already
|
|
|
|
registered. NULL if not found */
|
2012-09-22 01:11:44 -04:00
|
|
|
struct Value *VariableStringLiteralGet(Picoc *pc, char *Ident)
|
2009-03-11 18:28:42 -04:00
|
|
|
{
|
|
|
|
struct Value *LVal = NULL;
|
|
|
|
|
2012-09-22 01:11:44 -04:00
|
|
|
if (TableGet(&pc->StringLiteralTable, Ident, &LVal, NULL, NULL, NULL))
|
2009-03-11 18:28:42 -04:00
|
|
|
return LVal;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* define a string literal. assumes that Ident is already registered */
|
2012-09-22 01:11:44 -04:00
|
|
|
void VariableStringLiteralDefine(Picoc *pc, char *Ident, struct Value *Val)
|
2009-03-11 18:28:42 -04:00
|
|
|
{
|
2012-09-22 01:11:44 -04:00
|
|
|
TableSet(pc, &pc->StringLiteralTable, Ident, Val, NULL, 0, 0);
|
2009-03-11 18:28:42 -04:00
|
|
|
}
|
2009-04-22 03:23:26 -04:00
|
|
|
|
2009-04-25 23:26:04 -04:00
|
|
|
/* check a pointer for validity and dereference it for use */
|
2015-06-14 03:17:11 -04:00
|
|
|
void *VariableDereferencePointer(struct Value *PointerValue, struct Value **DerefVal,
|
|
|
|
int *DerefOffset, struct ValueType **DerefType, int *DerefIsLValue)
|
2009-04-22 03:23:26 -04:00
|
|
|
{
|
2009-06-04 20:55:54 -04:00
|
|
|
if (DerefVal != NULL)
|
2009-05-05 20:25:09 -04:00
|
|
|
*DerefVal = NULL;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-06-04 20:55:54 -04:00
|
|
|
if (DerefType != NULL)
|
|
|
|
*DerefType = PointerValue->Typ->FromType;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-06-04 20:55:54 -04:00
|
|
|
if (DerefOffset != NULL)
|
|
|
|
*DerefOffset = 0;
|
2015-06-07 00:40:08 -04:00
|
|
|
|
2009-06-04 20:55:54 -04:00
|
|
|
if (DerefIsLValue != NULL)
|
2015-06-10 15:24:53 -04:00
|
|
|
*DerefIsLValue = true;
|
2009-05-05 20:25:09 -04:00
|
|
|
|
2010-06-13 10:41:03 -04:00
|
|
|
return PointerValue->Val->Pointer;
|
2009-04-22 03:23:26 -04:00
|
|
|
}
|
2009-11-01 16:02:31 -05:00
|
|
|
|