RPN Explanation

Generally, the calculator in question was designed to allow visualization of order of operations for computer calculations.

Token Class

The Token class represents individual components in a mathematical expression, such as operators and parentheses. Each token has a character representation (token), a precedence level (precedence), and a calculation method (calculation). This class extends Token and adds a value field for numerical values. It handles both operators and numerical values in expressions. The Tokens class manages a collection of TermOrOperator objects using a HashMap. It provides methods to add and retrieve tokens efficiently.

Each input string is tokenized, or split into individual terms (numbers, operators, parentheses).

private void termTokenizer() {
    int start = 0;  // Initialize start position for multi-character terms
    StringBuilder multiCharTerm = new StringBuilder();  // Buffer for multi-character terms

    // Iterate over each character in the expression
    for (int i = 0; i < this.expression.length(); i++) {
        Character c = this.expression.charAt(i);  // Get the current character
        
        // Check if the current character is an operator or a separator
        if (operators.contains(c) || seperators.contains(c)) {
            // If there is a buffered multi-character term, add it to the list of terms
            if (multiCharTerm.length() > 0) {
                this.terms.add(new TermOrOperator(this.expression.substring(start, i)));
            }

            // Get the operator or separator TermOrOperator object
            TermOrOperator t = operators.get(c);
            if (t == null) {
                t = seperators.get(c);
            }

            // If the term is not a space, add it to the list of terms
            if (t != null && t.getToken() != ' ') {
                this.terms.add(t);
            }

            // Update the start position for the next term and reset the buffer
            start = i + 1;
            multiCharTerm = new StringBuilder();
        } else {
            // Append the current character to the buffer for multi-character terms
            multiCharTerm.append(c);
        }
    }

    // Add any remaining buffered multi-character term to the list of terms
    if (multiCharTerm.length() > 0) {
        this.terms.add(new TermOrOperator(this.expression.substring(start)));
    }
}

Stack Storage

Each operator/value is stored in its respective stack before processing.

For example: 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3

``` RPN List: [] Operator Stack: []

Token: 3 (Value) RPN: [3] Stack: []

Token: + (Operator) RPN: [3] Stack: [+]

Token: 4 (Value) RPN: [3, 4] Stack: [+]

Token: (Operator) RPN: [3, 4] Stack: [+, *]

Token: 2 (Value) RPN: [3, 4, 2] Stack: [+, *]

Token: / (Operator) RPN: [3, 4, 2] Stack: [+, *, /]

Token: ( (Separator) RPN: [3, 4, 2] Stack: [+, *, /, (]

Token: 1 (Value) RPN: [3, 4, 2, 1] Stack: [+, *, /, (]

Token: - (Operator) RPN: [3, 4, 2, 1] Stack: [+, *, /, (, -]

Token: 5 (Value) RPN: [3, 4, 2, 1, 5] Stack: [+, *, /, (, -]

Token: ) (Separator) (Here, the operator is pushed to the RPN stack because closed parentheses indicate this expression needs to be evaluated first) RPN: [3, 4, 2, 1, 5, -] Stack: [+, *, /]

Token: ^ (Operator) RPN: [3, 4, 2, 1, 5, -] Stack: [+, *, /, ^]

Token: 2 (Value) RPN: [3, 4, 2, 1, 5, -, 2] Stack: [+, *, /, ^]

Token: ^ (Operator) RPN: [3, 4, 2, 1, 5, -, 2] Stack: [+, *, /, ^, ^]

Token: 3 (Value) RPN: [3, 4, 2, 1, 5, -, 2, 3] Stack: [+, *, /, ^, ^]

Empty the stack to RPN from last to first. RPN: [3, 4, 2, 1, 5, -, 2, 3, ^, ^, /, *, +] Stack: []

RPN Notation

Now that the RPN has been created, we just need to evaulate. The algorithm works by scanning from left to right for the first operator and using the operator on the preceding two values. Once this is calculated, the used values are removed from the stack and the first value is replaced with the new calculated value. This is done until all values and operators have been used.