Download | Plain Text | No Line Numbers


  1. /*
  2.  * Copyright (c) 2008, Manuel Mausz <manuel at mausz.at>
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are met:
  7.  * * Redistributions of source code must retain the above copyright
  8.  * notice, this list of conditions and the following disclaimer.
  9.  * * Redistributions in binary form must reproduce the above copyright
  10.  * notice, this list of conditions and the following disclaimer in the
  11.  * documentation and/or other materials provided with the distribution.
  12.  * * Neither the name of the copyright holders nor the
  13.  * names of its contributors may be used to endorse or promote products
  14.  * derived from this software without specific prior written permission.
  15.  *
  16.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  20.  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  22.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  23.  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  25.  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  26.  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  27.  * DAMAGE.
  28.  */
  29.  
  30. import java.util.HashMap;
  31. import java.lang.reflect.Method;
  32.  
  33. /**
  34.  * Implements a RPN Calculator (stack based)
  35.  * UPN is the german name for RPN
  36.  * See http://en.wikipedia.org/wiki/Reverse_Polish_notation for more info
  37.  *
  38.  * @version 1.0
  39.  * @author Manuel Mausz (manuel at mausz.at)
  40.  * @author http://manuel.mausz.at/
  41.  */
  42. class UpnCalculator
  43. {
  44. private Stack stack = new Stack(20);
  45. private static HashMap<String, String> operators = new HashMap<String, String>();
  46. private String errorMsg = null;
  47.  
  48. /**
  49.   * constructor
  50.   * adds the supported operators and their method name
  51.   * to the internal hashmap
  52.   */
  53. UpnCalculator()
  54. {
  55. operators.put("+", "opAdd");
  56. operators.put("-", "opSub");
  57. operators.put("*", "opMul");
  58. operators.put("/", "opDiv");
  59. }
  60.  
  61. /**
  62.   * check wheter the passed operator is supported
  63.   *
  64.   * @param String operator
  65.   * @return true if supported, false otherwise
  66.   */
  67. public static boolean supportsOperator(String op)
  68. {
  69. return operators.containsKey(op);
  70. }
  71.  
  72. /**
  73.   * push operand to the internal stack
  74.   *
  75.   * @param int operator
  76.   */
  77. public void addOperand(int op)
  78. {
  79. stack.push(op);
  80. }
  81.  
  82. /**
  83.   * push operator to the internal stack
  84.   * and invoke the method assigned to the operator
  85.   *
  86.   * @param String operator
  87.   * @return true on success, false otherwise
  88.   */
  89. public boolean addOperator(String op)
  90. {
  91. if (!supportsOperator(op))
  92. {
  93. setError("Unknown operator");
  94. return false;
  95. }
  96.  
  97. int op1, op2;
  98. if (!stack.hasNext())
  99. {
  100. setError("Insuifficent operands on stack");
  101. return false;
  102. }
  103. op1 = stack.pop();
  104.  
  105. if (!stack.hasNext())
  106. {
  107. /* NOTE:
  108.   * EPROG specification doesn't specify whether the unused operand should
  109.   * be pushed back on stack. I think it should BUT eprog test cases don't!
  110.   */
  111. //stack.push(op1);
  112. setError("Insuifficent operands on stack");
  113. return false;
  114. }
  115. op2 = stack.pop();
  116.  
  117. String methodname = operators.get(op);
  118. Object ret;
  119. try
  120. {
  121. Method method = this.getClass().getMethod(methodname, new Class[] { int.class, int.class });
  122. ret = method.invoke(this, new Object[] { op1, op2 } );
  123. }
  124. catch(Exception e)
  125. {
  126. setError(e.getMessage());
  127. return false;
  128. }
  129.  
  130. if (!(ret instanceof Boolean))
  131. {
  132. setError("Unknown datatype returned from operation");
  133. return false;
  134. }
  135.  
  136. return (Boolean)ret;
  137. }
  138.  
  139. /**
  140.   * Addition
  141.   *
  142.   * @param op1
  143.   * @param op2
  144.   * @return true on success, false otherwise
  145.   */
  146. public boolean opAdd(int op1, int op2)
  147. {
  148. stack.push(op2 + op1);
  149. return true;
  150. }
  151.  
  152. /**
  153.   * Subtraction
  154.   *
  155.   * @param op1
  156.   * @param op2
  157.   * @return true on success, false otherwise
  158.   */
  159. public boolean opSub(int op1, int op2)
  160. {
  161. stack.push(op2 - op1);
  162. return true;
  163. }
  164.  
  165. /**
  166.   * Multiplication
  167.   *
  168.   * @param op1
  169.   * @param op2
  170.   * @return true on success, false otherwise
  171.   */
  172. public boolean opMul(int op1, int op2)
  173. {
  174. stack.push(op2 * op1);
  175. return true;
  176. }
  177.  
  178. /**
  179.   * Divison
  180.   *
  181.   * @param op1
  182.   * @param op2
  183.   * @return true on success, false otherwise
  184.   */
  185. public boolean opDiv(int op1, int op2)
  186. {
  187. if (op1 == 0)
  188. {
  189. setError("Division by zero");
  190. return false;
  191. }
  192. stack.push(op2 / op1);
  193. return true;
  194. }
  195.  
  196. /**
  197.   * check if an error has occured
  198.   * use getLastError() to get the error string
  199.   *
  200.   * @return boolean
  201.   */
  202. public boolean hasError()
  203. {
  204. return (errorMsg != null);
  205. }
  206.  
  207. /**
  208.   * returns error message
  209.   *
  210.   * @return string
  211.   */
  212. public String getLastError()
  213. {
  214. return errorMsg;
  215. }
  216.  
  217. /**
  218.   * reset internal error state
  219.   */
  220. public void resetError()
  221. {
  222. setError(null);
  223. }
  224.  
  225. /**
  226.   * set error string
  227.   *
  228.   * @param msg error string
  229.   */
  230. private void setError(String msg)
  231. {
  232. errorMsg = msg;
  233. }
  234.  
  235. /**
  236.   * returns internal stack converted to string
  237.   *
  238.   * @return string
  239.   */
  240. public String toString()
  241. {
  242. return stack.toString();
  243. }
  244. }
  245.