#include "ficl.h"
#define STKDEPTH(s) (((s)->top - (s)->base) + 1)
void
ficlStackCheck(ficlStack *stack, int popCells, int pushCells)
{
#if FICL_ROBUST >= 1
int nFree = stack->size - STKDEPTH(stack);
if (popCells > STKDEPTH(stack))
ficlVmThrowError(stack->vm, "Error: %s stack underflow",
stack->name);
if (nFree < pushCells - popCells)
ficlVmThrowError(stack->vm, "Error: %s stack overflow",
stack->name);
#else
FICL_IGNORE(stack);
FICL_IGNORE(popCells);
FICL_IGNORE(pushCells);
#endif
}
ficlStack *
ficlStackCreate(ficlVm *vm, char *name, unsigned size)
{
size_t totalSize = sizeof (ficlStack) + (size * sizeof (ficlCell));
ficlStack *stack = ficlMalloc(totalSize);
FICL_VM_ASSERT(vm, size != 0);
FICL_VM_ASSERT(vm, stack != NULL);
stack->size = size;
stack->frame = NULL;
stack->vm = vm;
stack->name = name;
ficlStackReset(stack);
return (stack);
}
void
ficlStackDestroy(ficlStack *stack)
{
if (stack)
ficlFree(stack);
}
int
ficlStackDepth(ficlStack *stack)
{
return (STKDEPTH(stack));
}
void
ficlStackDrop(ficlStack *stack, int n)
{
FICL_VM_ASSERT(stack->vm, n > 0);
stack->top -= n;
}
ficlCell
ficlStackFetch(ficlStack *stack, int n)
{
return (stack->top[-n]);
}
void
ficlStackStore(ficlStack *stack, int n, ficlCell c)
{
stack->top[-n] = c;
}
ficlCell
ficlStackGetTop(ficlStack *stack)
{
return (stack->top[0]);
}
#if FICL_WANT_LOCALS
void
ficlStackLink(ficlStack *stack, int size)
{
ficlStackPushPointer(stack, stack->frame);
stack->frame = stack->top + 1;
stack->top += size;
}
void
ficlStackUnlink(ficlStack *stack)
{
stack->top = stack->frame - 1;
stack->frame = ficlStackPopPointer(stack);
}
#endif
void
ficlStackPick(ficlStack *stack, int n)
{
ficlStackPush(stack, ficlStackFetch(stack, n));
}
ficlCell
ficlStackPop(ficlStack *stack)
{
return (*stack->top--);
}
void *
ficlStackPopPointer(ficlStack *stack)
{
return ((*stack->top--).p);
}
ficlUnsigned
ficlStackPopUnsigned(ficlStack *stack)
{
return ((*stack->top--).u);
}
ficlInteger
ficlStackPopInteger(ficlStack *stack)
{
return ((*stack->top--).i);
}
ficl2Integer
ficlStackPop2Integer(ficlStack *stack)
{
ficl2Integer ret;
ficlInteger high = ficlStackPopInteger(stack);
ficlInteger low = ficlStackPopInteger(stack);
FICL_2INTEGER_SET(high, low, ret);
return (ret);
}
ficl2Unsigned
ficlStackPop2Unsigned(ficlStack *stack)
{
ficl2Unsigned ret;
ficlUnsigned high = ficlStackPopUnsigned(stack);
ficlUnsigned low = ficlStackPopUnsigned(stack);
FICL_2UNSIGNED_SET(high, low, ret);
return (ret);
}
#if (FICL_WANT_FLOAT)
ficlFloat
ficlStackPopFloat(ficlStack *stack)
{
return ((*stack->top--).f);
}
#endif
void
ficlStackPush(ficlStack *stack, ficlCell c)
{
*++stack->top = c;
}
void
ficlStackPushPointer(ficlStack *stack, void *ptr)
{
ficlCell c;
c.p = ptr;
*++stack->top = c;
}
void
ficlStackPushInteger(ficlStack *stack, ficlInteger i)
{
ficlCell c;
c.i = i;
*++stack->top = c;
}
void
ficlStackPushUnsigned(ficlStack *stack, ficlUnsigned u)
{
ficlCell c;
c.u = u;
*++stack->top = c;
}
void
ficlStackPush2Unsigned(ficlStack *stack, ficl2Unsigned du)
{
ficlStackPushUnsigned(stack, FICL_2UNSIGNED_GET_LOW(du));
ficlStackPushUnsigned(stack, FICL_2UNSIGNED_GET_HIGH(du));
}
void
ficlStackPush2Integer(ficlStack *stack, ficl2Integer di)
{
ficl2Unsigned du;
FICL_2UNSIGNED_SET(FICL_2UNSIGNED_GET_HIGH(di),
FICL_2UNSIGNED_GET_LOW(di), du);
ficlStackPush2Unsigned(stack, du);
}
#if (FICL_WANT_FLOAT)
void
ficlStackPushFloat(ficlStack *stack, ficlFloat f)
{
ficlCell c;
c.f = f;
*++stack->top = c;
}
#endif
void
ficlStackReset(ficlStack *stack)
{
stack->top = stack->base - 1;
}
void
ficlStackRoll(ficlStack *stack, int n)
{
ficlCell c;
ficlCell *cell;
if (n == 0)
return;
else if (n > 0) {
cell = stack->top - n;
c = *cell;
for (; n > 0; --n, cell++) {
*cell = cell[1];
}
*cell = c;
} else {
cell = stack->top;
c = *cell;
for (; n < 0; ++n, cell--) {
*cell = cell[-1];
}
*cell = c;
}
}
void
ficlStackSetTop(ficlStack *stack, ficlCell c)
{
FICL_STACK_CHECK(stack, 1, 1);
stack->top[0] = c;
}
void
ficlStackWalk(ficlStack *stack, ficlStackWalkFunction callback,
void *context, ficlInteger bottomToTop)
{
int i;
int depth;
ficlCell *cell;
FICL_STACK_CHECK(stack, 0, 0);
depth = ficlStackDepth(stack);
cell = bottomToTop ? stack->base : stack->top;
for (i = 0; i < depth; i++) {
if (callback(context, cell) == FICL_FALSE)
break;
cell += bottomToTop ? 1 : -1;
}
}