shithub: 9ficl

ref: 67757267d0b9c6b15a0f9a87abab74ab152d9b09
dir: /stack.c/

View raw version
/*******************************************************************
** s t a c k . c
** Forth Inspired Command Language
** Author: John Sadler ([email protected])
** Created: 16 Oct 1997
** $Id: stack.c,v 1.15 2010/12/04 21:38:47 asau Exp $
*******************************************************************/
/*
** Copyright (c) 1997-2001 John Sadler ([email protected])
** All rights reserved.
**
** Get the latest Ficl release at http://ficl.sourceforge.net
**
** I am interested in hearing from anyone who uses Ficl. If you have
** a problem, a success story, a defect, an enhancement request, or
** if you would like to contribute to the Ficl release, please
** contact me by email at the address above.
**
** L I C E N S E  and  D I S C L A I M E R
** 
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/

#include <stdlib.h>

#include "ficl.h"

/*
** N O T E: Stack convention:
**
** THIS CHANGED IN FICL 4.0!
**
** top points to the *current* top data value
** push: increment top, store value at top
** pop:  fetch value at top, decrement top
** Stack grows from low to high memory
*/

/*******************************************************************
                    v m C h e c k S t a c k
** Check the parameter stack for underflow or overflow.
** size controls the type of check: if size is zero,
** the function checks the stack state for underflow and overflow.
** If size > 0, checks to see that the stack has room to push
** that many cells. If less than zero, checks to see that the
** stack has room to pop that many cells. If any test fails,
** the function throws (via vmThrow) a VM_ERREXIT exception.
*******************************************************************/
void ficlStackCheck(ficlStack *stack, int popCells, int pushCells)
#if FICL_ROBUST >= 1
{
    int depth = ficlStackDepth(stack);
    int nFree = stack->size - depth;

    if (popCells > depth)
    {
        ficlVmThrowError(stack->vm, "Error: %s stack underflow", stack->name);
    }

    if (nFree < pushCells - popCells)
    {
        ficlVmThrowError(stack->vm, "Error: %s stack overflow", stack->name);
    }

    return;
}
#else /* FICL_ROBUST >= 1 */
{
	FICL_IGNORE(stack);
	FICL_IGNORE(popCells);
	FICL_IGNORE(pushCells);
}
#endif /* FICL_ROBUST >= 1 */

/*******************************************************************
                    s t a c k C r e a t e
** 
*******************************************************************/

ficlStack *ficlStackCreate(ficlVm *vm, char *name, unsigned size)
{
    ficlCell *base = (ficlCell*)ficlMalloc(size * sizeof (ficlCell));
    ficlStack *stack = (ficlStack*)ficlMalloc(sizeof (ficlStack));

    FICL_VM_ASSERT(vm, size != 0);
    FICL_VM_ASSERT(vm, base != NULL);
    FICL_VM_ASSERT(vm, stack != NULL);

    stack->size = size;
    stack->base = base;
    stack->frame = NULL;

	stack->vm = vm;
	stack->name = name;

	ficlStackReset(stack);
    return stack;
}


/*******************************************************************
                    s t a c k D e l e t e
** 
*******************************************************************/

void ficlStackDestroy(ficlStack *stack)
{
    if (stack != NULL) {
	if (stack->base != NULL)
	    ficlFree(stack->base);
        ficlFree(stack);
    }
    return;
}


/*******************************************************************
                    s t a c k D e p t h 
** 
*******************************************************************/

int ficlStackDepth(ficlStack *stack)
{
    return (stack->top - stack->base) + 1;
}

/*******************************************************************
                    s t a c k D r o p
** 
*******************************************************************/

void ficlStackDrop(ficlStack *stack, int n)
{
    FICL_VM_ASSERT(stack->vm, n > 0);
    stack->top -= n;
    return;
}


/*******************************************************************
                    s t a c k F e t c h
** 
*******************************************************************/

ficlCell ficlStackFetch(ficlStack *stack, int n)
{
    return stack->top[-n];
}

void ficlStackStore(ficlStack *stack, int n, ficlCell c)
{
    stack->top[-n] = c;
    return;
}


/*******************************************************************
                    s t a c k G e t T o p
** 
*******************************************************************/

ficlCell ficlStackGetTop(ficlStack *stack)
{
    return stack->top[0];
}

#if FICL_WANT_LOCALS

/*******************************************************************
                    s t a c k L i n k
** Link a frame using the stack's frame pointer. Allot space for
** size cells in the frame
** 1) Push frame
** 2) frame = top
** 3) top += size
*******************************************************************/

void ficlStackLink(ficlStack *stack, int size)
{
    ficlStackPushPointer(stack, stack->frame);
    stack->frame = stack->top + 1;
    stack->top += size;
    return;
}


/*******************************************************************
                    s t a c k U n l i n k
** Unink a stack frame previously created by stackLink
** 1) top = frame
** 2) frame = pop()
*******************************************************************/

void ficlStackUnlink(ficlStack *stack)
{
    stack->top = stack->frame - 1;
    stack->frame = (ficlCell*)ficlStackPopPointer(stack);
    return;
}
#endif /* FICL_WANT_LOCALS */


/*******************************************************************
                    s t a c k P i c k
** 
*******************************************************************/

void ficlStackPick(ficlStack *stack, int n)
{
    ficlStackPush(stack, ficlStackFetch(stack, n));
    return;
}


/*******************************************************************
                    s t a c k P o p
** 
*******************************************************************/

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


/*******************************************************************
                    s t a c k P u s h
** 
*******************************************************************/

void ficlStackPush(ficlStack *stack, ficlCell c)
{
    *++stack->top = c;
}

void ficlStackPushPointer(ficlStack *stack, void *ptr)
{
    *++stack->top = FICL_LVALUE_TO_CELL(ptr);
}

void ficlStackPushInteger(ficlStack *stack, ficlInteger i)
{
    *++stack->top = FICL_LVALUE_TO_CELL(i);
}

void ficlStackPushUnsigned(ficlStack *stack, ficlUnsigned u)
{
    *++stack->top = FICL_LVALUE_TO_CELL(u);
}

void  ficlStackPush2Unsigned(ficlStack *stack, ficl2Unsigned du)
{
    ficlStackPushUnsigned(stack, FICL_2UNSIGNED_GET_LOW(du));
    ficlStackPushUnsigned(stack, FICL_2UNSIGNED_GET_HIGH(du));
    return;
}

void  ficlStackPush2Integer(ficlStack *stack, ficl2Integer di)
{
	ficlStackPush2Unsigned(stack, FICL_2INTEGER_TO_2UNSIGNED(di));
    return;
}

#if (FICL_WANT_FLOAT)
void ficlStackPushFloat(ficlStack *stack, ficlFloat f)
{
    *++stack->top = FICL_LVALUE_TO_CELL(f);
}
#endif


/*******************************************************************
                    s t a c k R e s e t
** 
*******************************************************************/

void ficlStackReset(ficlStack *stack)
{
    stack->top = stack->base - 1;
    return;
}


/*******************************************************************
                    s t a c k R o l l 
** Roll nth stack entry to the top (counting from zero), if n is 
** >= 0. Drop other entries as needed to fill the hole.
** If n < 0, roll top-of-stack to nth entry, pushing others
** upward as needed to fill the hole.
*******************************************************************/

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;
    }
    return;
}


/*******************************************************************
                    s t a c k S e t T o p
** 
*******************************************************************/

void ficlStackSetTop(ficlStack *stack, ficlCell c)
{
    FICL_STACK_CHECK(stack, 1, 1);
    stack->top[0] = c;
    return;
}




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;
    }
    return;
}