Download | Plain Text | Line Numbers
/*
* Copyright (c) 2008, Manuel Mausz <manuel at mausz.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the copyright holders nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
import java.util.HashMap;
import java.lang.reflect.Method;
/**
* Implements a RPN Calculator (stack based)
* UPN is the german name for RPN
* See http://en.wikipedia.org/wiki/Reverse_Polish_notation for more info
*
* @version 1.0
* @author Manuel Mausz (manuel at mausz.at)
* @author http://manuel.mausz.at/
*/
class UpnCalculator
{
private Stack stack = new Stack(20);
private static HashMap<String, String> operators = new HashMap<String, String>();
private String errorMsg = null;
/**
* constructor
* adds the supported operators and their method name
* to the internal hashmap
*/
UpnCalculator()
{
operators.put("+", "opAdd");
operators.put("-", "opSub");
operators.put("*", "opMul");
operators.put("/", "opDiv");
}
/**
* check wheter the passed operator is supported
*
* @param String operator
* @return true if supported, false otherwise
*/
public static boolean supportsOperator(String op)
{
return operators.containsKey(op);
}
/**
* push operand to the internal stack
*
* @param int operator
*/
public void addOperand(int op)
{
stack.push(op);
}
/**
* push operator to the internal stack
* and invoke the method assigned to the operator
*
* @param String operator
* @return true on success, false otherwise
*/
public boolean addOperator(String op)
{
if (!supportsOperator(op))
{
setError("Unknown operator");
return false;
}
int op1, op2;
if (!stack.hasNext())
{
setError("Insuifficent operands on stack");
return false;
}
op1 = stack.pop();
if (!stack.hasNext())
{
/* NOTE:
* EPROG specification doesn't specify whether the unused operand should
* be pushed back on stack. I think it should BUT eprog test cases don't!
*/
//stack.push(op1);
setError("Insuifficent operands on stack");
return false;
}
op2 = stack.pop();
String methodname = operators.get(op);
Object ret;
try
{
Method method = this.getClass().getMethod(methodname, new Class[] { int.class, int.class });
ret = method.invoke(this, new Object[] { op1, op2 } );
}
catch(Exception e)
{
setError(e.getMessage());
return false;
}
if (!(ret instanceof Boolean))
{
setError("Unknown datatype returned from operation");
return false;
}
return (Boolean)ret;
}
/**
* Addition
*
* @param op1
* @param op2
* @return true on success, false otherwise
*/
public boolean opAdd(int op1, int op2)
{
stack.push(op2 + op1);
return true;
}
/**
* Subtraction
*
* @param op1
* @param op2
* @return true on success, false otherwise
*/
public boolean opSub(int op1, int op2)
{
stack.push(op2 - op1);
return true;
}
/**
* Multiplication
*
* @param op1
* @param op2
* @return true on success, false otherwise
*/
public boolean opMul(int op1, int op2)
{
stack.push(op2 * op1);
return true;
}
/**
* Divison
*
* @param op1
* @param op2
* @return true on success, false otherwise
*/
public boolean opDiv(int op1, int op2)
{
if (op1 == 0)
{
setError("Division by zero");
return false;
}
stack.push(op2 / op1);
return true;
}
/**
* check if an error has occured
* use getLastError() to get the error string
*
* @return boolean
*/
public boolean hasError()
{
return (errorMsg != null);
}
/**
* returns error message
*
* @return string
*/
public String getLastError()
{
return errorMsg;
}
/**
* reset internal error state
*/
public void resetError()
{
setError(null);
}
/**
* set error string
*
* @param msg error string
*/
private void setError(String msg)
{
errorMsg = msg;
}
/**
* returns internal stack converted to string
*
* @return string
*/
public String toString()
{
return stack.toString();
}
}