Stack

A stack is a data structure that keeps the data in Last In First Out (LIFO) manner. It has two main operations defined: push, pop. The data can be accessed only the top-of-stack item.  It can be easily implemented as an array and use a "stack pointer" to keep track of the latest item.  For example, a stack of integer

stack[MAX]
bottom = 0
MAX = 100
sp = bottom

push x is  
  sp++,  stack[sp] = x
pop is
  a = stack[sp], sp--, ret a
 
To make it safe from unexpected behaviour, we must check for "out-of-range" access to the stack.  We can do this using two additional operators: empty?, full?

empty? is
  if sp <= bottom ret true else ret false

full?  is
  if sp >= MAX ret true else ret false

then we add this check to push, pop.

push x is
  if full? then error "stack is overflow"
  else sp++, stack[sp] = x

pop is
  if empty? then error "stack is underflow"
  else a = stack[sp], sp--, ret a

Running time

All operations (push, pop) are running in a constant time O(1).

Applications

Stack is widely used in computer language execution.  The "trace of execution" when one function called another function resembles the stack.  Let "program-counter (PC)" stores the point of return of a function call.  See the following example:  let f calls g which calls h.

     trace of execution

 f -------  call g  (pc1)     --------- ...
          |                  |
          |    call h (pc2)  |
         g --------      ----- g ret
                   |     |
                   |     |
              pc3  h ----  h ret


call ads is  
   push pc
   goto ads  

ret is
   pc = pop

then the following picture shows the stack that keeps "return point" when h is during the execution:

   top
     |     |
     | pc2 |
     | pc1 |
     -------
   bot

So, the "return points " are kept in the stack appropriately.

Another example of the use of stack, it can be used to "evaluate" a postfix expression.  Let an expression be a simple arithmetic operations such as the
follwing "2 + 3".  It composed of literals and arithmetic operators.  "2 + 3" is an infix expression, because the operator is in the middle of its arguments.  A
"postfix" expression is an expression that an operator is at the end of its arguments, for example "2 3 +".

An evaluation is the execution of the operator in an expression to return a value. So, eval "2 + 3" = 5.  For a postfix, eval "2 3 +" = 5.  We can give rule to
evaluate a postfix expression as follows: (using a stack to support the execution of the rules)

Assume we read one token of an expression at a time:

1)  if it is a literal push it.
2)  if it is an operator apply it.

Applying an operator means, poping its correct number of arguments off the stack and do the operation then push the result back to the stack.  Let's try these rules on the expression "2 3 + 4 +":  I will give the picture of the stack for each token read:

read "2"      | 2 |
              -----
            
read "3"      | 3 |
              | 2 |
              -----

read "+"      | 5 |   is  push ( pop + pop )
              -----

read "4"      | 4 |
              | 5 |
              -----

read "+"      | 9 |
              -----

stop

Infix to postfix

Another example of the use of stack is an algorithm to transform an infix expression into a postfix expression (so that we can apply "eval" above to
"execute" it.)

Let start with a naive rule set that almost work:

Read a token at a time at the end of input it reads "#".
Let use two stacks: D (for data), and Op (for operator).

1)  if it is a literal push it to D.
2)  if it is an operator push it to Op.
3)  while it is not "#"
       look at the operator at top-of-stack of Op
       we will know its arity.
       for i=1 to arity
          out pop D       
       will out the appropriate number of argument
       out pop Op   

For a simple expression it seems to work.  Let try it on "2 + 3 #"

           D       Op

read "2"  | 2 |   |   |
          -----   -----

read "+"  | 2 |   | + |
          -----   -----

read "3"  | 3 |   | + |
          | 2 |   -----
          -----

read "#"   out "3", out "2", out "+"  --> "3 2 +"

But when the expression is nested it fails.  Try this "2 + 3 + 4 #".
when it read "#" the stack picture is:

          | 4 |   | + |
          | 3 |   | + |
          | 2 |   -----
          -----

executing the rule 3)  we will get the following output:

       "4 3 + 2 ? ... "

at ? it tries to pop D for one more argument but D will underflow.
How to repair the rules so that it work properly?

Functional application

Another interesting use of stack is to hold the data for a "functional" computer language.  A functional language can be imagine as a computer language that does not use any variable name.  How can you write a program without using variables?

A procedural language:

square(x) = x * x

How can we manipulate data without naming them?  The answer is simple, use stack.  We never "name" data in a stack, don't we?  Let define some operator that manipulate data in a stack.  We need only one in this example: dup. (duplicate)

dup is  copy top-of-stack and push it

With "dup" we can write square as,

square is dup mul

The way to use "square" is to write it as a postfix expression: "2 square" = 4. The rule to apply a function is the apply its sequence of operators in its body
one-by-one.  In this case "dup" and then "mul".  Here is the picture of stack:

read "2"        | 2 |
                -----

read "square"
apply "dup"     | 2 |
                | 2 |
                -----

apply "mul"     | 4 |
                -----

stop

Using a computer language this way, it will be free of "side-effect".  An application of a function has a property called "referencial transparency" that
means an expression in the language has the same meaning no matter wherever it is written, for example "4 square 2 square square".  One can infer the meaning of this expression by inferring the meaning of "square" alone without bothering about its position in the expression.  Another name of this kind of the language is "concatenative" language.  (look it up on the web!).

Homework

Make amend to my rule set so that the infix-to-postfix algorithm work correctly. Hand-in not later than next Wednesday (10 Sept 2008).

5 Sept 2008