Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

RPN CALCULATOR - hope somebody can help me with this! public class Foothill09 { public static void main(String[] args) { String[] rpnExpressions = { //

RPN CALCULATOR - hope somebody can help me with this! public class Foothill09 { public static void main(String[] args) { String[] rpnExpressions = { // Invalid expressions "1 0 /", "", "1 1", "1 1 + +", "1 1 fly", "random junk", // Valid expressions "1", "1 1 +", "15 5 +", "15 5 -", "15 5 *", "15 -5 *", "-15 5 *", "-15 -5 *", "15 5 /", "1 1 1 + -", "4 3 * 2 1 / -", "5 5 + 10 2 3 * - -", "15 7 1 1 + - / 3 * 2 1 1 + + -" }; for (int i = 0; i < rpnExpressions.length; i++) { try { int result = RpnCalculator.eval(rpnExpressions[i]); System.out.println("(" + rpnExpressions[i] + ") = " + result); } catch (RuntimeException e) { System.out.println("(" + rpnExpressions[i] + ") fails to be evaluated: " + e.getMessage()); } } } } class RpnCalculator { public static final String OPERATOR_PLUS = "+"; public static final String OPERATOR_MINUS = "-"; public static final String OPERATOR_MULTIPLY = "*"; public static final String OPERATOR_DIVIDE = "/"; public static int eval(String rpnExpression) { String[] tokens = parse(rpnExpression); return eval(tokens); } private static String[] parse(String rpnExpression) { // trim() removes leading and trailing space. split("\\s+") splits on one or more spaces. return rpnExpression.trim().split("\\s+"); } private static int eval(String[] tokens) { IntegerStack integerStack = new IntegerStack(tokens.length); for (int i = 0; i < tokens.length; i++) { String token = tokens[i]; try { // If the token is an integer, push it onto the stack. int integer = Integer.parseInt(token); integerStack.push(integer); } catch (NumberFormatException e) { // If the token is not an integer, check what operator it is. // Operand2 is on top of stack, so pop that first. int operand2 = integerStack.pop(); int operand1 = integerStack.pop(); if (token.equals(OPERATOR_PLUS)) { integerStack.push(operand1 + operand2); } else if (token.equals(OPERATOR_MINUS)) { integerStack.push(operand1 - operand2); } else if (token.equals(OPERATOR_MULTIPLY)) { integerStack.push(multiply(operand1, operand2)); } else if (token.equals(OPERATOR_DIVIDE)) { integerStack.push(operand1 / operand2); } else { throw new RuntimeException("Unknown operator " + token); } } } int result = integerStack.pop(); if (!integerStack.isEmpty()) { // If the stack still has integers in it, there's not enough operators. throw new RuntimeException("Not enough operator"); } return result; } private static int multiply(int a, int b) { if (b < 0) { return -multiply(a, -b); } else if (b == 0) { return 0; } else { return a + multiply(a, b - 1); } } } class IntegerStack { public static final int MIN_SIZE = 0; private int stack[]; private int topOfStack; /** * Allocate a stack that can store 'size' number of String's. * @param size maximum number of String's that can be stored in the stack * @throws RuntimeException if size is less than or equal to 0 */ public IntegerStack(int size) { if (size <= MIN_SIZE) { throw new RuntimeException("Size for stack should not be less than or equal to " + MIN_SIZE); } topOfStack = 0; stack = new int[size]; } /** * Push an item to the top of the stack. * @param item: the item to be pushed to the stack * @throws RuntimeException if stack is full */ public void push(int item) { if (isFull()) { throw new RuntimeException("IntegerStack is full when pushing + " + item); } stack[topOfStack++] = item; } /** * Pop and return the item at the top of the stack * @return the item at the top of the stack * @throws RuntimeException if stack is empty */ public int pop() { if (isEmpty()) { throw new RuntimeException("IntegerStack is empty"); } return stack[--topOfStack]; } /** * Check if the stack is empty * @return true if stack is empty, false otherwise */ public boolean isEmpty() { return (topOfStack == 0); } /** * Check if the stack is full * @return true if stack is full, false otherwise */ public boolean isFull() { return (topOfStack == stack.length); } }

There are two goals for this assignment:

You'll get some practice on how to use function as value

You'll learn about a technique called data-driven programming

To achieve those goals, you'll modify your RPN Calculator from LAB Assignment 9 - RPN Calculator in one significant way. In RpnCalculator.eval(), you've written a somewhat long if/else if/else block that performs different operation depending on the operator. The if/else if/else block is hard to maintain if the number of supported operations become large, so you'll replace it with a lookup table (that's the data-driven part), where each entry in the table contains the operator and the function to perform for that operator (that's the function as value part). When you have to support new operations, you add them to the lookup table rather than modifying the RpnCalculator.eval() logic.

Program Specifications

You should start by making a copy of your Foothill09.java (or with the instructor's solution), and name it Foothill10.java.

Operation Class Specification

You'll add one new class, called Operation, which represents an operation that the RPN calculator can perform. It has 2 private instance fields:

private String operator; private BiFunction function;

The operator field can have values such as "+" that is, well, the operator that the RPN calculator supports. The function field is of the type BiFunction which, as discussed in lecture, is a function that takes two parameters of type Integer (same as int), and returns an Integer as the result. Its value is a lambda function that corresponds to the operator; for "+", it would be (a, b) -> a + b.

You'll only have 3 methods for this class:

public Operation(String operator, BiFunction function)

The usual parameterized constructor. To keep things simple, you do not need to validate the input (for this assignment only).

public String getOperator()

The usual getter for the operator field.

public BiFunction getFunction()

The usual getter for the function field.

That's right, no setters necessary.

RpnCalculator Class Specification

We'll make the following 4 changes to the RpnCalculator class.

? Change #1: Add an array of Operation instances to RpnCalculator class.

Its declaration and initialization should look like this:

private static final Operation[] operations = { ... }

This is the lookup table for operations. The array initially should contain 4 instances of Operation, one for each of the supported operators (addition, subtraction, multiplication, and division). You should know what values to pass to the operator and function parameters of the Operation constructor.

? Change #2: Add a lookupOperation() method to find the Operation instance given an operator.

The method signature is:

private static Operation lookupOperation(String operator)

The operator parameter should be values such as "+", and the method should look through the operations array defined above to find the corresponding Operation instance, and return it. If the operator cannot be found in the table, throw a NoSuchElementException with a descriptive message.

? Change #3: Modify the eval() method to use lookupOperation().

Most of you use a if/else if/else block to check if the token is a particular operator, then performs the operation. Instead, now you should use lookupOperation() to find the Operation instance for the token (if it's an operator), then apply the function of the Operation instance on the operands popped from the stack. Remember, to apply a BiFunction to two operands, you do

int operand1 = ..., operand2 = ...; BiFunction function = ... int result = function.apply(operand1, operand2);

Depending on how you structure your code, you may or may not have to catch the NoSuchElementException thrown by lookupOperation(). Once done, if you want to add more supported operations, you do not have to modify eval() anymore.

? Change #4: Add 3 new supported operations.

All 3 new operations are integer operations, just like the existing ones. They are:

pow(base, exponent): raise base to the exponent-th power, e.g. pow(5, 2) produces 25

max(a, b): return the larger of a and b, e.g. max(1, 2) produces 2

min(a, b): return the smaller of a and b, e.g. min(1, 2) produces 1

You should know how and where to add the new operations. For each of these operations, you can simply use the their counterparts in the Math library. Note that Math.pow() returns double, which you can cast to int. I hope you appreciate how easy it is now to add an operation.

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Decisions Based On Data Analytics For Business Excellence

Authors: Bastian Weber

1st Edition

9358681683, 978-9358681680

More Books

Students also viewed these Databases questions