Skip to content

RPN Calculator in Bash

This Bash script implements a Reverse Polish Notation (RPN) calculator. It reads input from standard input, interprets each line as an RPN expression, and evaluates the expressions by performing arithmetic calculations.

Usage

To use the RPN calculator, follow these steps:

  1. Clone the repository or download the rpn_calculator.sh file.
  2. Make the script executable by running the following command:
    chmod +x rpn_calculator.sh
    
  3. Run the script by executing:
    ./rpn_calculator.sh
    
  4. Enter your RPN expressions, one expression per line.
  5. Press Enter to evaluate each expression.
  6. The result or an error message will be displayed for each expression.

Examples

  • Addition
$ ./rpn_calculator.sh
5 2 +
7
  • Subtraction
$ ./rpn_calculator.sh
8 3 -
5
  • Multiplication
$ ./rpn_calculator.sh
4 6 *
24
  • Division

    $ ./rpn_calculator.sh
    10 2 /
    5.00
    

  • Invalid expression

$ ./rpn_calculator.sh
5 +
error

Implementation Details

  • The script uses the IFS (Internal Field Separator) variable to define delimiters for splitting strings into words, considering space and tab characters as delimiters by default.
  • Input is read from standard input using the read command, storing each line in the expression array.
  • Empty lines are skipped, and the script moves to the next line.
  • Tokens in the expression array are processed sequentially:
  • Numbers are validated using regular expressions, and if valid, are pushed onto the stack.
  • Operators (+, -, *, /) require sufficient operands. If valid, the calculation is performed and the result is updated in the array.
  • The script relies on the bc command-line utility for performing floating-point arithmetic.
  • If the final expression array has exactly one element, it is the result. Otherwise, an error message is displayed.

The full reverse notation script

#!/usr/bin/env bash
# - iNFO --------------------------------------
#
# Author: wuseman <wuseman@nr1.nu>
# FileName: dc_like_calc_with_bc.sh
# Created: 2023-06-17 (04:52:25)
# Modified: 2023-06-17 (04:52:28)
# Version: 1.0
# License: MIT
#
# iRC: wuseman (Libera/EFnet/LinkNet)
# GitHub: https://github.com/wuseman/
#
# - Description -------------------------------
#
# This bash script is a calculator that performs calculations using Reverse Polish Notation (RPN). It reads input from standard input,
# interprets each line as an RPN expression, and evaluates the expressions by performing arithmetic calculations.
#
# The script supports the following operators:
# - Addition (+)
# - Subtraction (-)
# - Multiplication (*)
# - Division (/)
#
# It uses the 'bc' command for floating-point arithmetic calculations and allows for decimal places in the results.
#
# The script skips empty lines and outputs the result of each expression on a new line. If an expression is invalid or contains insufficient operands, it outputs 'error'.
#
# - End --------------------------------------
IFS=$' \t' # Set the Internal Field Separator (IFS) to include space and tab characters
while read -r -a expression; do
        ((n = ${#expression[*]}))
        # Skip empty lines
        if [ $n -eq 0 ]; then continue; fi
        ((i = 0))
        # Process each element in the expression
        while :; do
                element=${expression[i]}
                # Check if the element is a valid number
                if [[ $element =~ ^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)$ ]]; then
                        ((++i)) # Increment the index to move to the next element
                elif [[ $element =~ ^[-+*/]$ ]]; then
                        # Check if there are enough operands to perform the operation
                        if [ $i -lt 2 ]; then break; fi
                        # Perform the calculation using the appropriate operator
                        case $element in
                        "+") expression[i - 2]=$(echo "${expression[i - 2]} + ${expression[i - 1]}" | bc) ;;          # Addition
                        "-") expression[i - 2]=$(echo "${expression[i - 2]} - ${expression[i - 1]}" | bc) ;;          # Subtraction
                        "*") expression[i - 2]=$(echo "${expression[i - 2]} * ${expression[i - 1]}" | bc) ;;          # Multiplication
                        "/") expression[i - 2]=$(echo "scale=2; ${expression[i - 2]} / ${expression[i - 1]}" | bc) ;; # Division
                        esac
                        # Remove the used operands and operator from the array
                        expression[i]=
                        ((--i)) # Decrement the index to adjust for the removed elements
                        expression[i]=
                        ((n -= 2))                      # Adjust the number of elements in the expression
                        expression=("${expression[@]}") # Compact the array by removing the empty elements
                else
                        break
                fi
                # Check if all elements have been processed
                if [ $i -eq $n ]; then break; fi
        done
        # Check if the result is valid and print it, or print an error message
        if [ $i -eq $n ] && [ $n -eq 1 ]; then
                echo "${expression}" # Output the result
        else
                echo 'error' # Output error message
        fi
done