/* Final classes can be used to implement ADT's.  Finality ensures that you
   can associate specific methods with a value of type IntStack by thwarting
   any attempt to build a sub-class of it. */

interface INTSTACK {

  public boolean empty ();
  public int top ();
  public int pop ();
  public void push (int n);

}

final class IntStack implements INTSTACK {

  private static final int stackmax = 100;

  private int Stack [] = new int [stackmax];
  private int sp = stackmax;

  /* Check for empty. */
  public boolean empty () {
    return (this.sp == stackmax);
  }

  /* Return the top element of the stack. */
  public int top () {
    if (sp < stackmax) {
      return this.Stack[this.sp];
    } else {
      throw new Error ("Attempting to access top of empty stack.");
    }
  }

  /* Pop calls top to retrieve top element. */
  public int pop () {
    int n = this.top ();
    this.sp++;
    return n;
  }

  /* Push an element onto the stack, if possible. */
  public void push (int n) {
    if (this.sp > 0) {
      this.Stack[--this.sp] = n;
    } else {
      throw new Error ("Stack overflow.");
    }
  }

}

/* A stack client that accepts any instance of INTSTACK. */
class StackDemo {

  public static void demo (INTSTACK s) {
    s.push(1); s.push(2); s.push(3);
    System.out.println (s.pop());
    System.out.println (s.pop());
    System.out.println (s.pop());
    if (s.empty ()) {
      System.out.println ("Done.");
    } else {
      throw new Error ("Impossible: stack non-empty.");
    }
  }

}

class FinalDemo {

  public static void main (String argv[]) {
    IntStack s = new IntStack();
    IntStack t = new IntStack();
    StackDemo.demo (s);
    StackDemo.demo (t);
  }

}
