picoc/variable.c
zik.saleeba c9abac9fad Fixed an EOF lexing problem.
Added some optional debug.
Turned debug off.
Fixed handling of LValues to work with stack frames better.
Fixed the handling of stack frames in function calls.
Fixed a bug in popping variable stack frames.

git-svn-id: http://picoc.googlecode.com/svn/trunk@65 21eae674-98b7-11dd-bd71-f92a316d2d60
2009-02-04 00:17:30 +00:00

147 lines
4.6 KiB
C

#include <string.h>
#include "picoc.h"
/* the table of global definitions */
struct Table GlobalTable;
struct TableEntry *GlobalHashTable[GLOBAL_TABLE_SIZE];
/* the stack */
struct StackFrame *TopStackFrame = NULL;
/* initialise the variable system */
void VariableInit()
{
TableInit(&GlobalTable, &GlobalHashTable[0], GLOBAL_TABLE_SIZE, TRUE);
TopStackFrame = NULL;
}
/* allocate some memory, either on the heap or the stack and check if we've run out */
void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap)
{
void *NewValue;
if (OnHeap)
NewValue = HeapAlloc(Size);
else
NewValue = HeapAllocStack(Size);
if (NewValue == NULL)
ProgramFail(Parser, "out of memory");
#ifdef DEBUG_HEAP
if (!OnHeap)
printf("pushing %d at 0x%lx\n", Size, (unsigned long)NewValue);
#endif
return NewValue;
}
/* allocate a value either on the heap or the stack using space dependent on what type we want */
struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, int OnHeap)
{
struct Value *NewValue = VariableAlloc(Parser, sizeof(struct Value) + DataSize, OnHeap);
NewValue->Val = (union AnyValue *)((void *)NewValue + sizeof(struct Value));
NewValue->ValOnHeap = OnHeap;
NewValue->ValOnStack = !OnHeap;
return NewValue;
}
/* allocate a value given its type */
struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int OnHeap)
{
struct Value *NewValue = VariableAllocValueAndData(Parser, Typ->Sizeof, OnHeap);
NewValue->Typ = Typ;
return NewValue;
}
/* allocate a value either on the heap or the stack and copy its value */
struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap)
{
struct Value *NewValue = VariableAllocValueAndData(Parser, FromValue->Typ->Sizeof, OnHeap);
NewValue->Typ = FromValue->Typ;
memcpy(NewValue->Val, FromValue->Val, FromValue->Typ->Sizeof);
return NewValue;
}
/* define a variable */
void VariableDefine(struct ParseState *Parser, const char *Ident, struct Value *InitValue)
{
if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL)))
ProgramFail(Parser, "'%s' is already defined", Ident);
}
/* check if a variable with a given name is defined */
int VariableDefined(const char *Ident)
{
struct Value *FoundValue;
if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, &FoundValue))
{
if (!TableGet(&GlobalTable, Ident, &FoundValue))
return FALSE;
}
return TRUE;
}
/* get the value of a variable. must be defined */
void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal)
{
if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal))
{
if (!TableGet(&GlobalTable, Ident, LVal))
ProgramFail(Parser, "'%s' is undefined", Ident);
}
}
/* free and/or pop the top value off the stack. Var must be the top value on the stack! */
void VariableStackPop(struct ParseState *Parser, struct Value *Var)
{
int Success;
#ifdef DEBUG_HEAP
if (Var->ValOnStack)
printf("popping %d at 0x%lx\n", sizeof(struct Value) + Var->Typ->Sizeof, (unsigned long)Var);
#endif
if (Var->ValOnHeap)
{ // XXX - is this a mismatch with allocation?
HeapFree(Var->Val);
Success = HeapPopStack(Var, sizeof(struct Value)); /* free from heap */
}
else if (Var->ValOnStack)
Success = HeapPopStack(Var, sizeof(struct Value) + Var->Typ->Sizeof); /* free from stack */
else
Success = HeapPopStack(Var, sizeof(struct Value)); /* value isn't our problem */
if (!Success)
ProgramFail(Parser, "stack underrun");
}
/* add a stack frame when doing a function call */
void VariableStackFrameAdd(struct ParseState *Parser)
{
struct StackFrame *NewFrame;
HeapPushStackFrame();
NewFrame = HeapAllocStack(sizeof(struct StackFrame));
NewFrame->ReturnParser = *Parser;
TableInit(&NewFrame->LocalTable, &NewFrame->LocalHashTable[0], LOCAL_TABLE_SIZE, FALSE);
NewFrame->PreviousStackFrame = TopStackFrame;
TopStackFrame = NewFrame;
}
/* remove a stack frame */
void VariableStackFramePop(struct ParseState *Parser)
{
if (TopStackFrame == NULL)
ProgramFail(Parser, "stack is empty - can't go back");
*Parser = TopStackFrame->ReturnParser;
TopStackFrame = TopStackFrame->PreviousStackFrame;
HeapPopStackFrame();
}