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.
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
readcommand, storing each line in theexpressionarray. - Empty lines are skipped, and the script moves to the next line.
- Tokens in the
expressionarray 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
bccommand-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
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