2009-01-23 06:34:12 -05:00
|
|
|
#include "picoc.h"
|
|
|
|
|
|
|
|
/* the table of global definitions */
|
|
|
|
struct Table GlobalTable;
|
2009-01-29 17:26:04 -05:00
|
|
|
struct TableEntry *GlobalHashTable[GLOBAL_TABLE_SIZE];
|
2009-01-23 06:34:12 -05:00
|
|
|
|
2009-03-11 18:28:42 -04:00
|
|
|
/* the table of string literal values */
|
|
|
|
struct Table StringLiteralTable;
|
|
|
|
struct TableEntry *StringLiteralHashTable[STRING_LITERAL_TABLE_SIZE];
|
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
/* the stack */
|
2009-01-29 06:10:46 -05:00
|
|
|
struct StackFrame *TopStackFrame = NULL;
|
2009-01-23 06:34:12 -05:00
|
|
|
|
|
|
|
|
|
|
|
/* initialise the variable system */
|
|
|
|
void VariableInit()
|
|
|
|
{
|
2009-02-20 21:35:52 -05:00
|
|
|
TableInitTable(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE, TRUE);
|
2009-03-11 18:28:42 -04:00
|
|
|
TableInitTable(&StringLiteralTable, &StringLiteralHashTable[0], STRING_LITERAL_TABLE_SIZE, TRUE);
|
2009-01-29 06:10:46 -05:00
|
|
|
TopStackFrame = NULL;
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* deallocate the contents of a variable */
|
|
|
|
void VariableFree(struct Value *Val)
|
|
|
|
{
|
|
|
|
if (Val->ValOnHeap)
|
|
|
|
{
|
|
|
|
/* free function bodies */
|
|
|
|
if (Val->Typ == &FunctionType && Val->Val->FuncDef.Intrinsic == NULL)
|
2009-06-02 04:00:02 -04:00
|
|
|
HeapFreeMem((void *)Val->Val->FuncDef.Body.Pos);
|
2009-03-15 06:44:56 -04:00
|
|
|
|
|
|
|
/* free macro bodies */
|
|
|
|
if (Val->Typ == &MacroType)
|
2009-06-02 04:00:02 -04:00
|
|
|
HeapFreeMem((void *)Val->Val->Parser.Pos);
|
2009-03-15 06:44:56 -04:00
|
|
|
|
|
|
|
/* free the value */
|
2009-06-02 04:00:02 -04:00
|
|
|
HeapFreeMem(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 */
|
|
|
|
void VariableTableCleanup(struct Table *HashTable)
|
2009-03-11 06:01:32 -04:00
|
|
|
{
|
|
|
|
struct TableEntry *Entry;
|
|
|
|
struct TableEntry *NextEntry;
|
|
|
|
int Count;
|
|
|
|
|
2009-03-11 18:28:42 -04:00
|
|
|
for (Count = 0; Count < HashTable->Size; Count++)
|
2009-03-11 06:01:32 -04:00
|
|
|
{
|
2009-03-11 18:28:42 -04:00
|
|
|
for (Entry = HashTable->HashTable[Count]; Entry != NULL; Entry = NextEntry)
|
2009-03-11 06:01:32 -04:00
|
|
|
{
|
|
|
|
NextEntry = Entry->Next;
|
2009-03-15 06:44:56 -04:00
|
|
|
VariableFree(Entry->p.v.Val);
|
2009-03-11 06:01:32 -04:00
|
|
|
|
2009-03-11 19:49:10 -04:00
|
|
|
/* free the hash table entry */
|
2009-06-02 04:00:02 -04:00
|
|
|
HeapFreeMem(Entry);
|
2009-03-11 06:01:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 18:28:42 -04:00
|
|
|
void VariableCleanup()
|
|
|
|
{
|
|
|
|
VariableTableCleanup(&GlobalTable);
|
|
|
|
VariableTableCleanup(&StringLiteralTable);
|
|
|
|
}
|
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
/* allocate some memory, either on the heap or the stack and check if we've run out */
|
2009-02-01 06:31:18 -05:00
|
|
|
void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
|
|
|
void *NewValue;
|
|
|
|
|
2009-01-26 03:57:32 -05:00
|
|
|
if (OnHeap)
|
2009-06-02 04:00:02 -04:00
|
|
|
NewValue = HeapAllocMem(Size);
|
2009-01-23 06:34:12 -05:00
|
|
|
else
|
|
|
|
NewValue = HeapAllocStack(Size);
|
|
|
|
|
|
|
|
if (NewValue == NULL)
|
2009-02-01 06:31:18 -05:00
|
|
|
ProgramFail(Parser, "out of memory");
|
2009-01-23 06:34:12 -05: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
|
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate a value either on the heap or the stack using space dependent on what type we want */
|
2009-02-26 04:56:22 -05:00
|
|
|
struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, int IsLValue, struct Value *LValueFrom, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-02-03 05:39:48 -05:00
|
|
|
struct Value *NewValue = VariableAlloc(Parser, sizeof(struct Value) + DataSize, OnHeap);
|
2009-06-02 03:50:46 -04:00
|
|
|
NewValue->Val = (union AnyValue *)((char *)NewValue + sizeof(struct Value));
|
2009-01-26 03:57:32 -05:00
|
|
|
NewValue->ValOnHeap = OnHeap;
|
|
|
|
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;
|
2009-01-23 06:34:12 -05:00
|
|
|
|
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate a value given its type */
|
2009-06-02 01:51:51 -04:00
|
|
|
struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-04-28 23:24:15 -04:00
|
|
|
int Size = TypeSize(Typ, Typ->ArraySize, FALSE);
|
2009-06-02 01:51:51 -04:00
|
|
|
struct Value *NewValue = VariableAllocValueAndData(Parser, Size, IsLValue, LValueFrom, OnHeap);
|
2009-02-20 21:35:52 -05:00
|
|
|
assert(Size > 0 || Typ == &VoidType);
|
2009-01-23 06:34:12 -05:00
|
|
|
NewValue->Typ = Typ;
|
2009-02-23 19:08:11 -05:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate a value either on the heap or the stack and copy its value */
|
2009-02-01 06:31:18 -05:00
|
|
|
struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-02-20 21:35:52 -05:00
|
|
|
int CopySize = TypeSizeValue(FromValue);
|
2009-02-26 04:56:22 -05:00
|
|
|
struct Value *NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap);
|
2009-01-23 06:34:12 -05:00
|
|
|
NewValue->Typ = FromValue->Typ;
|
2009-04-03 23:11:12 -04:00
|
|
|
memcpy((void *)NewValue->Val, (void *)FromValue->Val, CopySize);
|
2009-06-02 01:51:51 -04:00
|
|
|
|
2009-01-23 06:34:12 -05:00
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
2009-02-09 06:40:56 -05:00
|
|
|
/* allocate a value either on the heap or the stack from an existing AnyValue and type */
|
2009-02-26 04:56:22 -05:00
|
|
|
struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom)
|
2009-02-09 06:40:56 -05:00
|
|
|
{
|
2009-02-19 18:29:35 -05:00
|
|
|
struct Value *NewValue = VariableAlloc(Parser, sizeof(struct Value), FALSE);
|
2009-02-09 06:40:56 -05:00
|
|
|
NewValue->Typ = Typ;
|
|
|
|
NewValue->Val = FromValue;
|
|
|
|
NewValue->ValOnHeap = 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;
|
2009-02-09 06:40:56 -05:00
|
|
|
|
|
|
|
return NewValue;
|
|
|
|
}
|
|
|
|
|
2009-02-11 01:47:36 -05:00
|
|
|
/* allocate a value either on the heap or the stack from an existing Value, sharing the value */
|
2009-02-19 18:29:35 -05:00
|
|
|
struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue)
|
2009-02-11 01:47:36 -05:00
|
|
|
{
|
2009-02-26 05:16:49 -05:00
|
|
|
return VariableAllocValueFromExistingData(Parser, FromValue->Typ, FromValue->Val, FromValue->IsLValue, FromValue->IsLValue ? FromValue : NULL);
|
2009-02-11 01:47:36 -05:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* define a variable. Ident must be registered */
|
2009-06-02 01:51:51 -04:00
|
|
|
struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-06-02 01:51:51 -04:00
|
|
|
struct Value *AssignValue;
|
|
|
|
|
|
|
|
if (InitValue != NULL)
|
|
|
|
AssignValue = VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL);
|
|
|
|
else
|
|
|
|
AssignValue = VariableAllocValueFromType(Parser, Typ, MakeWritable, NULL, TopStackFrame == NULL);
|
2009-05-13 20:21:29 -04:00
|
|
|
|
2009-06-02 01:51:51 -04:00
|
|
|
AssignValue->IsLValue = MakeWritable;
|
2009-05-13 20:21:29 -04:00
|
|
|
|
|
|
|
if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, AssignValue))
|
2009-02-02 06:08:36 -05:00
|
|
|
ProgramFail(Parser, "'%s' is already defined", Ident);
|
2009-06-02 01:51:51 -04:00
|
|
|
|
|
|
|
return AssignValue;
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* check if a variable with a given name is defined. Ident must be registered */
|
2009-02-01 06:31:18 -05:00
|
|
|
int VariableDefined(const char *Ident)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
|
|
|
struct Value *FoundValue;
|
|
|
|
|
2009-01-29 06:10:46 -05:00
|
|
|
if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, &FoundValue))
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
|
|
|
if (!TableGet(&GlobalTable, Ident, &FoundValue))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-03-15 06:44:56 -04:00
|
|
|
/* get the value of a variable. must be defined. Ident must be registered */
|
2009-02-01 06:31:18 -05:00
|
|
|
void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-01-29 06:10:46 -05:00
|
|
|
if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal))
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
|
|
|
if (!TableGet(&GlobalTable, Ident, LVal))
|
2009-02-02 06:08:36 -05:00
|
|
|
ProgramFail(Parser, "'%s' is undefined", Ident);
|
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 */
|
2009-02-28 15:46:02 -05:00
|
|
|
void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable)
|
|
|
|
{
|
2009-11-03 21:02:37 -05:00
|
|
|
struct Value *SomeValue = VariableAllocValueAndData(NULL, 0, IsWritable, NULL, TRUE);
|
2009-02-28 15:46:02 -05:00
|
|
|
SomeValue->Typ = Typ;
|
2009-02-28 16:08:00 -05:00
|
|
|
if (Typ->Base != TypeArray)
|
|
|
|
SomeValue->Val = FromValue;
|
|
|
|
|
2009-03-05 00:03:28 -05:00
|
|
|
if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, TableStrRegister(Ident), SomeValue))
|
|
|
|
ProgramFail(Parser, "'%s' is already defined", Ident);
|
2009-02-28 15:46:02 -05:00
|
|
|
}
|
|
|
|
|
2009-01-26 03:57:32 -05: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;
|
|
|
|
|
2009-02-03 19:17:30 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-06-02 03:50:46 -04:00
|
|
|
if (Var->ValOnStack)
|
2009-11-06 13:17:36 -05:00
|
|
|
printf("popping %ld at 0x%lx\n", (unsigned long)(sizeof(struct Value) + TypeSizeValue(Var)), (unsigned long)Var);
|
2009-02-03 19:17:30 -05:00
|
|
|
#endif
|
|
|
|
|
2009-01-26 03:57:32 -05:00
|
|
|
if (Var->ValOnHeap)
|
2009-02-15 00:52:03 -05:00
|
|
|
{
|
2009-06-02 03:01:43 -04:00
|
|
|
if (Var->Val != NULL)
|
2009-06-02 04:00:02 -04:00
|
|
|
HeapFreeMem(Var->Val);
|
2009-06-02 03:01:43 -04:00
|
|
|
|
2009-01-26 03:57:32 -05:00
|
|
|
Success = HeapPopStack(Var, sizeof(struct Value)); /* free from heap */
|
|
|
|
}
|
|
|
|
else if (Var->ValOnStack)
|
2009-02-20 21:35:52 -05:00
|
|
|
Success = HeapPopStack(Var, sizeof(struct Value) + TypeSizeValue(Var)); /* free from stack */
|
2009-01-26 03:57:32 -05:00
|
|
|
else
|
|
|
|
Success = HeapPopStack(Var, sizeof(struct Value)); /* value isn't our problem */
|
|
|
|
|
|
|
|
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 */
|
2009-02-19 18:29:35 -05:00
|
|
|
void VariableStackFrameAdd(struct ParseState *Parser, int NumParams)
|
2009-01-23 06:34:12 -05:00
|
|
|
{
|
2009-01-29 06:10:46 -05:00
|
|
|
struct StackFrame *NewFrame;
|
2009-01-23 06:34:12 -05:00
|
|
|
|
2009-01-29 06:10:46 -05:00
|
|
|
HeapPushStackFrame();
|
2009-02-19 18:29:35 -05:00
|
|
|
NewFrame = HeapAllocStack(sizeof(struct StackFrame) + sizeof(struct Value *) * NumParams);
|
2009-02-20 21:35:52 -05:00
|
|
|
if (NewFrame == NULL)
|
|
|
|
ProgramFail(Parser, "out of memory");
|
|
|
|
|
2009-02-01 06:31:18 -05:00
|
|
|
NewFrame->ReturnParser = *Parser;
|
2009-06-02 03:50:46 -04:00
|
|
|
NewFrame->Parameter = (NumParams > 0) ? ((void *)((char *)NewFrame + sizeof(struct StackFrame))) : NULL;
|
2009-02-20 21:35:52 -05:00
|
|
|
TableInitTable(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE, FALSE);
|
2009-01-29 06:10:46 -05:00
|
|
|
NewFrame->PreviousStackFrame = TopStackFrame;
|
|
|
|
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
|
|
|
{
|
2009-01-29 06:10:46 -05:00
|
|
|
if (TopStackFrame == NULL)
|
2009-02-01 06:31:18 -05:00
|
|
|
ProgramFail(Parser, "stack is empty - can't go back");
|
2009-01-26 03:57:32 -05:00
|
|
|
|
2009-02-01 06:31:18 -05:00
|
|
|
*Parser = TopStackFrame->ReturnParser;
|
2009-02-03 19:17:30 -05:00
|
|
|
TopStackFrame = TopStackFrame->PreviousStackFrame;
|
2009-01-26 03:57:32 -05:00
|
|
|
HeapPopStackFrame();
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
2009-03-11 18:28:42 -04:00
|
|
|
|
|
|
|
/* get a string literal. assumes that Ident is already registered. NULL if not found */
|
|
|
|
struct Value *VariableStringLiteralGet(char *Ident)
|
|
|
|
{
|
|
|
|
struct Value *LVal = NULL;
|
|
|
|
|
|
|
|
if (TableGet(&StringLiteralTable, Ident, &LVal))
|
|
|
|
return LVal;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* define a string literal. assumes that Ident is already registered */
|
|
|
|
void VariableStringLiteralDefine(char *Ident, struct Value *Val)
|
|
|
|
{
|
|
|
|
TableSet(&StringLiteralTable, Ident, Val);
|
|
|
|
}
|
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 */
|
2009-06-04 20:55:54 -04:00
|
|
|
void *VariableDereferencePointer(struct ParseState *Parser, 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;
|
2009-06-04 20:55:54 -04:00
|
|
|
|
|
|
|
if (DerefType != NULL)
|
|
|
|
*DerefType = PointerValue->Typ->FromType;
|
|
|
|
|
|
|
|
if (DerefOffset != NULL)
|
|
|
|
*DerefOffset = 0;
|
|
|
|
|
|
|
|
if (DerefIsLValue != NULL)
|
|
|
|
*DerefIsLValue = TRUE;
|
2009-05-05 20:25:09 -04:00
|
|
|
|
|
|
|
return PointerValue->Val->NativePointer;
|
2009-04-22 03:23:26 -04:00
|
|
|
}
|
2009-11-01 16:02:31 -05:00
|
|
|
|