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.Stack;
  31. import java.util.HashMap;
  32. import java.util.Iterator;
  33. import java.lang.reflect.Method;
  34. import java.lang.reflect.InvocationTargetException;
  35.  
  36. /**
  37.  * Implements a RPN Calculator (stack based)
  38.  * UPN is the german name for RPN
  39.  * See http://en.wikipedia.org/wiki/Reverse_Polish_notation for more info
  40.  *
  41.  * @version 1.0
  42.  * @author Manuel Mausz (manuel at mausz.at)
  43.  * @author http://manuel.mausz.at/
  44.  */
  45. class Upn
  46. {
  47. private Stack<Integer> stack = new Stack<Integer>();
  48. private static HashMap<String, String> operators = new HashMap<String, String>();
  49.  
  50. /**
  51.   * constructor
  52.   * adds the supported operators and their method name
  53.   * to the internal hashmap
  54.   */
  55. Upn()
  56. {
  57. operators.put("+", "opAdd");
  58. operators.put("-", "opSub");
  59. operators.put("*", "opMul");
  60. operators.put("/", "opDiv");
  61. operators.put("s", "opSwap");
  62. }
  63.  
  64. /**
  65.   * check wheter the passed operator is supported
  66.   *
  67.   * @param op operator
  68.   * @return true if supported, false otherwise
  69.   */
  70. public static boolean supportsOperator(String op)
  71. {
  72. return operators.containsKey(op);
  73. }
  74.  
  75. /**
  76.   * push operand to the internal stack
  77.   *
  78.   * @param int operator
  79.   */
  80. public void addOperand(int op)
  81. {
  82. stack.push(op);
  83. }
  84.  
  85. /**
  86.   * get the method assigned to the operator
  87.   * pop the amount of operands required from the stack
  88.   * and finally invoke the method
  89.   *
  90.   * @param op operator
  91.   * @return true on success, false otherwise
  92.   */
  93. public boolean addOperator(String op)
  94. throws UpnException, NoSuchMethodException, IllegalAccessException
  95. {
  96. if (!supportsOperator(op))
  97. throw new UpnException("Unknown operator");
  98.  
  99. Object ret;
  100. try
  101. {
  102. /* get the method */
  103. String methodname = operators.get(op);
  104. Method method = null;
  105. for (Method m : this.getClass().getMethods())
  106. {
  107. if (m.getName() == methodname)
  108. {
  109. method = m;
  110. break;
  111. }
  112. }
  113. if (method == null)
  114. throw new UpnException("Unknown method assigned to operator");
  115.  
  116. /* pop required operands from stack */
  117. Integer[] params = new Integer[method.getParameterTypes().length];
  118. for (int i = 0; i < method.getParameterTypes().length; i++)
  119. {
  120. if (stack.empty())
  121. {
  122. /* NOTE:
  123.   * EPROG specification doesn't specify whether the unused operand should
  124.   * be pushed back on stack. I think it should BUT eprog test cases don't!
  125.   */
  126. /*for (Integer v : params)
  127.   {
  128.   if (v != null)
  129.   stack.push(v);
  130.   }*/
  131. throw new UpnException("Insuifficent operands on stack");
  132. }
  133. params[i] = stack.pop();
  134. }
  135.  
  136. /* invoke the method */
  137. ret = method.invoke(this, (Object[]) params);
  138. }
  139. /* reflection encapsulate exceptions thrown during invoke. unpack them */
  140. catch (InvocationTargetException e)
  141. {
  142. throw new UpnException(e.getCause().getMessage());
  143. }
  144.  
  145. if (!(ret instanceof Boolean))
  146. throw new UpnException("Unknown datatype returned from operation");
  147.  
  148. return (Boolean)ret;
  149. }
  150.  
  151. /**
  152.   * Addition
  153.   *
  154.   * @param op1
  155.   * @param op2
  156.   * @return true on success, false otherwise
  157.   */
  158. public boolean opAdd(int op1, int op2)
  159. {
  160. stack.push(op2 + op1);
  161. return true;
  162. }
  163.  
  164. /**
  165.   * Subtraction
  166.   *
  167.   * @param op1
  168.   * @param op2
  169.   * @return true on success, false otherwise
  170.   */
  171. public boolean opSub(int op1, int op2)
  172. {
  173. stack.push(op2 - op1);
  174. return true;
  175. }
  176.  
  177. /**
  178.   * Multiplication
  179.   *
  180.   * @param op1
  181.   * @param op2
  182.   * @return true on success, false otherwise
  183.   */
  184. public boolean opMul(int op1, int op2)
  185. {
  186. stack.push(op2 * op1);
  187. return true;
  188. }
  189.  
  190. /**
  191.   * Divison
  192.   *
  193.   * @param op1
  194.   * @param op2
  195.   * @return true on success, false otherwise
  196.   */
  197. public boolean opDiv(int op1, int op2)
  198. {
  199. if (op1 == 0)
  200. throw new UpnException("Division by zero");
  201. stack.push(op2 / op1);
  202. return true;
  203. }
  204.  
  205. /**
  206.   * Swap
  207.   *
  208.   * @param op1
  209.   * @param op2
  210.   * @return true on success, false otherwise
  211.   */
  212. public boolean opSwap(int op1, int op2)
  213. {
  214. stack.push(op1);
  215. stack.push(op2);
  216. return true;
  217. }
  218.  
  219. /**
  220.   * returns internal stack converted to string
  221.   *
  222.   * @return string
  223.   */
  224. public String toString()
  225. {
  226. String str = "";
  227. Iterator it = stack.iterator();
  228. while(it.hasNext())
  229. str += it.next() + "\n";
  230. return str;
  231. }
  232. }
  233.