You are implementing a 4-function calculator. Think of a simple casio or basic calculator app. The display shows the current number you are typing, or an intermediate calculation result. It does not display any operands or other info, except the occasional “error” when appropriate. The skeleton of the program is given to you; you will update the controller and model to add functionality. First you will implement simple left-to-right evaluation using two stacks. Second you will implement operator precedence. Finally you will add extensions of your choice.
This calculator application follows the Model-View-Controller (MVC) design pattern:
CalculatorModel.java
): Manages
the data and calculation logic, including operand and operator
stacks.CalculatorUI.java
): Handles the
user interface elements including display and buttons.CalculatorController.java
): Processes user input
and coordinates between the model and view.Calculator.java
):
Entry point that initializes the MVC components.Supporting classes include: - Operator.java
: Constants
for calculator operations - DebugStack.java
: Extended Stack
implementation for debugging
The calculator uses two stacks to manage calculations: - Operand Stack: Stores numeric values (operands) for calculations - Operator Stack: Stores operators (+, -, ×, ÷, etc.)
These stacks allow for sequential processing of operations. When operations are performed, values are popped from the stacks, calculations are made, and results are pushed back.
CalculatorController.java
:handleClear()
: Reset the calculator
state, clear display and stacks.handleBackspace()
: Remove the last
character from the display.CalculatorModel.java
:appendDecimalPoint()
: Add a decimal
point to the current display value if not already present.backspace()
: Remove the last character
from the display value.calculate()
: Perform one calculation
using operands and operators from the stacks.reduce(String operator)
: Calls
calculate
one or more times based on the current stack
contents (in phase 1 this is basically a pass-through function, you
always call calculate exactly once)precedence(String operator)
: Return
the precedence level of an operator (for Phase 2).DebugStack.java
:Extend the Stack class to print stack contents after push, pop, and clear operations. For example:
@Override
public E push(E item) {
= super.push(item);
E result System.out.println("Push: " + item + ", Stack: " + this);
return result;
}
precedence()
method to assign priorities
to operatorsreduce()
and related methods to respect operator
precedenceDebugStack
implementation should be helpful for
visualizing how the stacks change during operationsHere’s a simple example of how to calculate the expression
3 + 425 × 2
using the two-stack approach with left-to-right
evaluation (Phase 1 approach without operator precedence):
Read current display value (425) and push to Operand Stack
Operand Stack: [3, 425]
Operator Stack: [+]
Since we have 2 operands and 1 operator, perform calculation:
After reduction, push × to Operator Stack
Operand Stack: [428]
Operator Stack: [×]
Display: “428”
Read current display value (2) and push to Operand Stack
Operand Stack: [428, 2]
Operator Stack: [×]
Since we have 2 operands and 1 operator, perform calculation:
Since “=” was pressed, we don’t push it to the Operator Stack
Operand Stack: [856]
Operator Stack: [ ]
Display: “856”
Note: In Phase 1, operations are performed strictly left-to-right as shown above (3 + 4 × 2 = 14). In Phase 2 with operator precedence, multiplication would be performed before addition, resulting in 3 + (4 × 2) = 11.