# BASH shell routines to add Forth-like functionality to the shell
# this file matches the documentation of version 32
# http://www.osdata.com/programming/shell/unixbook.pdf
# most recent version of these routines is at
# http://www.osdata.com/programming/shell/forthfunctions
# note that not every revision of the PDF has changes in
# the documentation for this file and its contents

# variables
export DataStackPointer=0
declare -a DataStack; export DataStack
export ReturnStackPointer=0
declare -a ReturnStack; export ReturnStack

# functions

ShowDataStack ()
{
    echo "stack size of " $DataStackPointer;
    if [ "$DataStackPointer" -gt "0" ] ; then
        loopcounter=$DataStackPointer
        while [ $loopcounter -gt 0 ] ;
        do
            echo ${DataStack["$loopcounter"]}
            let "loopcounter=$loopcounter - 1"
        done
    else
        echo "the stack is empty"
    fi
    unset loopcounter #clear out variable 
} # end ShowDataStack

push ()
{
    let "DataStackPointer=$DataStackPointer + 1" #preincrement
    DataStack["$DataStackPointer"]=$1 #push data item on top of stack
} # end push

pop ()
{
    let "DataStackPointer=$DataStackPointer - 1" #postdecrement
} # end pop

popout ()
{
    printf ${DataStack["$DataStackPointer"]} #pop data item from top of stack and print
    let "DataStackPointer=$DataStackPointer - 1" #postdecrement
} # end popout

dot ()
{
    echo ${DataStack["$DataStackPointer"]} #pop data item from top of stack and print
    let "DataStackPointer=$DataStackPointer - 1" #postdecrement
} # end dot

DUP ()
{
    temporary=${DataStack["$DataStackPointer"]} #make temporary copy of data item from top of stack
    let "DataStackPointer=$DataStackPointer + 1" #preincrement
    DataStack["$DataStackPointer"]=$temporary #store duplicate
    unset temporary #clear out variable
} # end DUP

qDUP ()
{
    if [ ${DataStack["$DataStackPointer"]} -eq 0 ] ; then #test for zero string on top of stack
        return 0 #if zero, take no action, return OK
    fi
    temporary=${DataStack["$DataStackPointer"]} #make temporary copy of data item from top of stack
    let "DataStackPointer=$DataStackPointer + 1" #preincrement
    DataStack["$DataStackPointer"]=$temporary #store duplicate
    unset temporary #clear out variable
} # end qDUP

OVER ()
{
    let "TemporaryPointer=$DataStackPointer - 1" #create pointer down one from top of stack
    temporary=${DataStack["$TemporaryPointer"]} #make temporary copy of data item one down in stack
    let "DataStackPointer=$DataStackPointer + 1" #preincrement
    DataStack["$DataStackPointer"]=$temporary #store duplicate
    unset temporary #clear out variable
    unset TemporaryPointer #clear out variable
} # end OVER

PICK ()
{
    let "TemporaryPointer=$DataStackPointer - $1" #create pointer down one from top of stack
    temporary=${DataStack["$TemporaryPointer"]} #make temporary copy of data item one down in stack
    let "DataStackPointer=$DataStackPointer + 1" #preincrement
    DataStack["$DataStackPointer"]=$temporary #store duplicate
    unset temporary #clear out variable
    unset TemporaryPointer #clear out variable
} # end PICK

DROP ()
{
    let "DataStackPointer=$DataStackPointer - 1" #postdecrement
} # end DROP

SWAP ()
{
    let "TemporaryPointer=$DataStackPointer - 1" #create pointer down one from top of stack
    temporary=${DataStack["$TemporaryPointer"]} #make temporary copy of data item one down in stack
    DataStack["$TemporaryPointer"]=${DataStack["$DataStackPointer"]} #move the top item to 2nd location down
    DataStack["$DataStackPointer"]=$temporary #put former 2nd down on top of stack
    unset temporary #clear out variable
    unset TemporaryPointer #clear out variable
} # end SWAP

ROT ()
{
    let "TemporaryPointer=$DataStackPointer - 2" #create pointer down two from top of stack
    let "SecondPointer=$DataStackPointer - 1" #create pointer down one from top of stack
    temporary=${DataStack["$TemporaryPointer"]} #make temporary copy of data item one down in stack
    DataStack["$TemporaryPointer"]=${DataStack["$SecondPointer"]} #move the 2nd down item to 3rd location down
    DataStack["$SecondPointer"]=${DataStack["$DataStackPointer"]} #move the top item to 2nd location down
    DataStack["$DataStackPointer"]=$temporary #put former 3rd down on top of stack
    unset temporary #clear out variable
    unset TemporaryPointer #clear out variable
    unset SecondPointer #clear out variable
} # end ROT

ROLL ()
{
    if [ $DataStackPointer -gt "$1" ] ; then #check to make sure enough items on stack
        let "DestinationPointer=$DataStackPointer - $1"
        SavedItem=${DataStack["$DestinationPointer"]} #save old item
        let "SourcePointer =$DestinationPointer + 1"
        LoopCounter=$1
        while [ $LoopCounter -gt 0 ] ; #move data loop
        do
            DataStack["$DestinationPointer"]=${DataStack["$SourcePointer"]} #move data
            let "DestinationPointer=$DestinationPointer + 1" #post increment
            let "SourcePointer=$SourcePointer + 1" #post increment
            let "LoopCounter=$LoopCounter - 1"
        done
        DataStack["$DataStackPointer"]=$SavedItem
        unset LoopCounter #clear out variable
        unset SavedItem #clear out variable
        unset SourcePointer #clear out variable
        unset DestinationPointer #clear out variable
    fi # end if good input
} # end ROLL

DEPTH ()
{
    temporary=$DataStackPointer #save the existing depth of the stack
    let "DataStackPointer=$DataStackPointer + 1" #preincrement
    DataStack["$DataStackPointer"]=$temporary #push depth on top of stack
} # end DEPTH

