#!/usr/local/bin/mawk -We



# THIS CODE IS PUBLIC DOMAIN, NO WARRANTY!



function push(stack, value){

stack[++stack["lastss"]] = value

}



function pop(stack,locx){

if(stack[mystack["lastss"]] < stack[stack["lastss"]]){

return NULL

} else {

locx = stack[stack["lastss"]]

delete stack[stack["lastss"]--]

return locx

}

}



function stacklook(stack, num){

if(stack["firstss"] > stack["lastss"])

return NULL # stack spent

if(num <= 0){

num = stack["lastss"] + num

if(num < 1) return NULL

return stack[num]

} else {

num = stack["firstss"] + num - 1

if(num > stack["lastss"]) return NULL

return stack[num]

}

}



function stackoutofrange(stack, num){

if(stack["firstss"] > stack["lastss"])

return 3

if(num <= 0){

if(stack["lastss"] + num < stack["firstss"])

return(-1)

else

return(0)

} else {

if(num + stack["firstss"] > stack["lastss"] +1)

return 1

else

return 0

}

}





function stackspent(stack){

return (stack["firstss"] > stack["lastss"])

}



BEGIN{

### INITIALIZE mystack ###

mystack["firstss"] = 10001

mystack["lastss"] = 10000



push(mystack, "one")

push(mystack, "two")

push(mystack, "three")

push(mystack, "four")

push(mystack, "five")



print "===== TESTING stackoutofrange() BELOW ========"

for(i=-7; i < 8; i++){

print "range(" i ") returns ", stackoutofrange(mystack, i)

}



print "===== POSITIVE STACKLOOKS BELOW ========"

for(i=1; !stackoutofrange(mystack, i); i++)

{print "pos " stacklook(mystack, i)}



print "

===== NEGATIVE STACKLOOKS BELOW ========"



for(i=0; !stackoutofrange(mystack,i); i--)

{print "neg " stacklook(mystack,i)}



print "

===== POPS BELOW ========"



while(!stackspent(mystack))

{print "pop " pop(mystack)}



print "

===== MORE RANGE TESTING BELOW ========"

print "===== SHOULD RETURN ALL 3 BECAUSE STACK SPENT ========"

print "===== TESTING stackoutofrange() BELOW ========"

for(i=-7; i < 8; i++){

print "range(" i ") returns ", stackoutofrange(mystack, i)

}

exit 0

}



Stack functions are accomplished by functions push() and pop(). push() simply appends its value argument to the end of the array identified by the stack argument. It increments stack["lastss"] so future pop() and push() and stacklook() calls will work on the right element.



The pop() function deletes the last element from the stack and returns it via function return. Notice the locx "argument". It's not an argument at all -- it's a local variable. In awk local arguments can be declared only in the same parentheses as arguments -- after the arguments.



The stacklook() function is a way to non-destructively observe the stack. stacklook(myarray,0) returns the element that would be returned by pop() if you were to call pop() . stacklook(1) returns the most deeply embedded element in the stack -- the last valid pop() .



Another way to look at stacklook() is to see the stack as an array instead of a stack. Positive numerical arguments to stacklook() correspond to array subscripts. Negative numerical arguments indicate how far from the end of the array you want to look (the stack interpretation would be how many pops you'd need to do before popping that argument).



All three functions, push() , pop() and stacklook() contain code to return NULL if a numerical argument points to something before or beyond the array comprising the stack, or if the stack had no elements, indicating a spent stack. HOWEVER, that can backfire if a NULL element was pushed -- how can you differentiate a deliberate NULL element from a spent stack or out of bounds numerical argument?



Two functions, stackoutofrange() and stackspent() are included to check the actual stack rather than testing the return value. stackspent() returns 0 if the stack is not spent, a positive number otherwise.



stackoutofrange() returns 0 if the stack is not spent and the numerical argument is within the stack's range. It returns 3 if the stack is spent, 1 if a positive numerical argument is too positive, and -1 if a negative numerical argument is too negative.



When using loops, always test using stackoutofrange() and stackspent() , because you never know, especially during development, whether a NULL has accidentally been pushed onto the stack, or arrived on the stack otherwise (using array techniques for instance).







