This is a program which acts as a reverse polish notation calculator, there are two versions, one using Linked Lists, the other uses Arrays.
Example 4.2. Advanced Kenya Features Example - With Linked Lists.
/** * Tristan Allwood (toa02 AT doc.ic.ac.uk) * Reverse Polish Notation calculator example in Kenya * Demonstrating enumerated types, generics, autoboxing * * This version uses Linked-List based stacks. * * Input on std input an RPN calculation (e.g. * 1 2 + 3 * means 1 + 2 * 3 * 4 2 / means 4 / 2 * and on std out printed is the result ( e.g. 9 and 2 above ). * Error cases are not handled gracefully here, esp no input = crash. * Operators are +, -, *, /, % everything else that is not a number [0-9] is * interpreted as ignorable whitespace. */ /** * Program entry point, prints a welcome and then calls necessary methods * to run the program */ void main(){ //Print a welcome println("Welcome to the calculator!"); println("Please enter a calculation to be performed in reverse polish notation"); //Build the stacks of numbers and operators Pair<Stack<int>,Stack<Operator>> stacks = buildStacks(); //Calculate the result from these int result = mainLoop(stacks.b,stacks.a); //Print out the result println( "The answer is: " + result ); } /** * An enumeration of the Operators / Elements of the processed input stack. * Number means that that element is a number ( found in the numbers stack ) */ enum Operator{ Plus, Minus, Times, Divide, Modulo, Number; } /** * Processes a stack of operators and a stack of numbers and uses them * to calculate the result of the calculation. */ int mainLoop( Stack<Operator> operators, Stack<int> numbers ){ Stack<int> tmpNums; while( hasNext(operators) ){ Operator op = pop(operators); if ( op == Operator.Number ) { push( tmpNums, pop(numbers) ); } else { int snd = pop(tmpNums); int fst = pop(tmpNums); switch( op ) { case Plus:{ push(tmpNums, fst + snd); break; } case Minus:{ push(tmpNums, fst - snd); break; } case Times:{ push( tmpNums, fst * snd); break; } case Divide:{ push( tmpNums, fst / snd); break; } case Modulo:{ push( tmpNums, fst % snd ); break; } } } } return pop(tmpNums); } /** * Builds the safer Stacks of operators and ints by parsing standard input. */ Pair< Stack<int>, Stack<Operator> > buildStacks(){ Stack<int> numStack; Stack<Operator> wholeStack; Stack<char> inputStack = getInputStack(); for( char c = pop(inputStack) ; hasNext( inputStack ) ; c = pop(inputStack) ){ if( '0' <= c & c <= '9' ){ push( inputStack, c ); int value = readNumber( inputStack ); push(numStack, value ); push(wholeStack, Operator.Number ); } else { switch( c ){ case '+':{ push( wholeStack, Operator.Plus ); break; } case '-':{ push( wholeStack, Operator.Minus ); break; } case '/':{ push( wholeStack, Operator.Divide ); break; } case '*':{ push( wholeStack, Operator.Times ); break; } case '%':{ push( wholeStack, Operator.Modulo ); break; } default:{ /* any other letter is just ignored */ } }//switch } //else }//for Pair< Stack<int>, Stack<Operator> > retVal; reverseStack(numStack); reverseStack(wholeStack); retVal.a = numStack; retVal.b = wholeStack; return retVal; }//method /** * Converts a number representation on the stack (e.g. [1,2,3] ) * into its real value ( 123 ) */ int readNumber( Stack<char> source ){ int number = 0; char c = pop(source); while( '0' <= c & c <= '9' ){ number = number * 10 + ( c - '0' ); c = pop(source); } push( source , c ); return number; } /** * Turns standard input into a stack of characters. */ Stack<char> getInputStack(){ Stack<char> theStack; for( char c = read() ; c != toChar(-1) ; c = read() ){ push(theStack, c); } reverseStack(theStack); return theStack; } /* -------------------------- */ /* *** Pair utility class *** */ /* -------------------------- */ class Pair<T,Q> { T a; Q b; } /* ----------------------------------------- */ /* *** General Stack Library Stuff Below *** */ /* ----------------------------------------- */ /** * Reverses the given stack. */ <T> void reverseStack( Stack<T> stack){ Stack<T> out; while( hasNext(stack) ){ push( out, pop(stack) ); } stack.head = out.head; } /** * Prints out the given stack. */ <T> void printStack(Stack<T> stack){ LinkedList<T> top = stack.head; print("[ " ); while( top != null ) { print( top.node + " "); top = top.next; } print("]"); } /** * Returns true iff the given stack has a "next" element */ <T> boolean hasNext( Stack<T> stack ){ return stack.head != null; } /** * pushes a value onto the top of the given stack */ <T> void push( Stack<T> stack, T value ){ LinkedList<T> top; top.node = value; top.next = stack.head; stack.head = top; } /** * pops a value off the top of a given stack */ <T> T pop( Stack<T> stack ){ T value = stack.head.node; stack.head = stack.head.next; return value; } /** * A Stack class ( holds a pointer to a LinkedList ) */ class Stack<T>{ LinkedList<T> head; } /** * A LinkedList class ( used to back a Stack ) */ class LinkedList<T>{ LinkedList<T> next; T node; }
Example 4.3. Advanced Kenya Features - With Arrays
/** * Tristan Allwood (toa02 AT doc.ic.ac.uk) * Reverse Polish Notation calculator example in Kenya * Demonstrating enumerated types, generics, autoboxing * * This version uses Array based stacks. * * Input on std input an RPN calculation (e.g. * 1 2 + 3 * means 1 + 2 * 3 * 4 2 / means 4 / 2 * and on std out printed is the result ( e.g. 9 and 2 above ). * Error cases are not handled gracefully here, esp no input = crash. * Operators are +, -, *, /, % everything else that is not a number [0-9] is * interpreted as ignorable whitespace. */ const int BUFFER_SIZE = 30; // how big a buffer to use for the arrays. /** * Program entry point, prints a welcome and then calls necessary methods * to run the program */ void main(){ //Print a welcome println("Welcome to the calculator!"); println("Please enter a calculation to be performed in reverse polish notation"); //Build the stacks of numbers and operators Pair<Stack<int>,Stack<Operator>> stacks = buildStacks(); //Calculate the result from these int result = mainLoop(stacks.b,stacks.a); //Print out the result println( "The answer is: " + result ); } /** * An enumeration of the Operators / Elements of the processed input stack. * Number means that that element is a number ( found in the numbers stack ) */ enum Operator{ Plus, Minus, Times, Divide, Modulo, Number; } /** * Processes a stack of operators and a stack of numbers and uses them * to calculate the result of the calculation. */ int mainLoop( Stack<Operator> operators, Stack<int> numbers ){ Stack<int> tmpNums = newStack( new Integer[BUFFER_SIZE]); while( hasNext(operators) ){ Operator op = pop(operators); if ( op == Operator.Number ) { push( tmpNums, pop(numbers) ); } else { int snd = pop(tmpNums); int fst = pop(tmpNums); switch( op ) { case Plus:{ push(tmpNums, fst + snd); break; } case Minus:{ push(tmpNums, fst - snd); break; } case Times:{ push( tmpNums, fst * snd); break; } case Divide:{ push( tmpNums, fst / snd); break; } case Modulo:{ push( tmpNums, fst % snd ); break; } } } } return pop(tmpNums); } /** * Builds the safer Stacks of operators and ints by parsing standard input. */ Pair< Stack<int>, Stack<Operator> > buildStacks(){ Stack<int> numStack = newStack( new Integer[ BUFFER_SIZE] ); Stack<Operator> wholeStack = newStack( new Operator[BUFFER_SIZE] ); Stack<char> inputStack = getInputStack(); for( char c = pop(inputStack) ; hasNext( inputStack ) ; c = pop(inputStack) ){ if( '0' <= c & c <= '9' ){ push( inputStack, c ); int value = readNumber( inputStack ); push(numStack, value ); push(wholeStack, Operator.Number ); } else { switch( c ){ case '+':{ push( wholeStack, Operator.Plus ); break; } case '-':{ push( wholeStack, Operator.Minus ); break; } case '/':{ push( wholeStack, Operator.Divide ); break; } case '*':{ push( wholeStack, Operator.Times ); break; } case '%':{ push( wholeStack, Operator.Modulo ); break; } default:{ /* any other letter is just ignored */ } }//switch } //else }//for Pair< Stack<int>, Stack<Operator> > retVal; reverseStack(numStack); reverseStack(wholeStack); retVal.a = numStack; retVal.b = wholeStack; return retVal; }//method /** * Converts a number representation on the stack (e.g. [1,2,3] ) * into its real value ( 123 ) */ int readNumber( Stack<char> source ){ int number = 0; char c = pop(source); while( '0' <= c & c <= '9' ){ number = number * 10 + ( c - '0' ); c = pop(source); } push( source , c ); return number; } /** * Turns standard input into a stack of characters. */ Stack<char> getInputStack(){ Stack<char> theStack = newStack( new Character[BUFFER_SIZE] ); for( char c = read() ; c != toChar(-1) ; c = read() ){ push(theStack, c); } reverseStack(theStack); return theStack; } /* -------------------------- */ /* *** Pair utility class *** */ /* -------------------------- */ class Pair<T,Q> { T a; Q b; } /* ----------------------------------------- */ /* *** General Stack Library Stuff Below *** */ /* ----------------------------------------- */ /** * Since in generics you can't create an array of * Template type at runtime, you have to provide * the backing buffer when you create a new Stack. * This is a method that emulates the constructor. */ <T> Stack<T> newStack( T[] backBuffer ){ Stack<T> newStack; newStack.store = backBuffer; return newStack; } /** * Reverses the given stack. */ <T> void reverseStack( Stack<T> stack){ T[] array = stack.store; int max = stack.cPos - 1; for( int i = 0 ; i < max ; i++ ){ T tmp = array[i]; array[i] = array[max]; array[max] = tmp; max--; } } /** * Prints out the given stack. */ <T> void printStack(Stack<T> stack){ print("[ "); for( int i = 0 ; i < stack.cPos ; i++ ){ print( stack.store[i] + " " ); } println("]"); } /** * Returns true iff the given stack has a "next" element */ <T> boolean hasNext( Stack<T> stack ){ return stack.cPos > 0; } /** * pushes a value onto the top of the given stack */ <T> void push( Stack<T> stack, T value ){ stack.store[stack.cPos] = value; stack.cPos++; } /** * pops a value off the top of a given stack */ <T> T pop( Stack<T> stack ){ stack.cPos--; T value = stack.store[stack.cPos]; stack.store[stack.cPos] = null; // just for safety return value; } /** * A Stack class */ class Stack<T>{ T[] store; int cPos; }