An Interactive Calculator Written In Ruby
I often use the spotlight calculator on my Mac for quick calculations. I recently wondered how interactive calculators actually work, so I decided to build one in Ruby. It functions as an interactive Read-Eval-Print loop (REPL) that reads in expressions and prints the result.
You can view the source code here.
The calculator evaluating some expressions
The calculator handling some bad input
The program provides a nice calculator REPL which supports the following features:
- Standard binary arithmetic operators
/(always floating point division)
- Numbers in integer, decimal and scientific notation
- Minus unary operator (e.g
- Mathematical functions (all that are provided by the Ruby
- Error handling with messages showing where the error originated
- An interactive REPL that allows you to list all functions and constants
The program takes input as a string and does the following:
- Scans the input expressed in infix notation character by character and attempts to tokenize numbers, identifiers (words that can be constants, or functions), arithmetic operators, and other valid characters such as paranthesis and commas.
- Iterates through the list of tokens and uses Edsger Dijkstras Shunting Yard algorithm to parse the infix expression into a postfix form.
- Iterates over elements in the postfix form and uses a stack based evaluation algorithm to produce the result.
I decided to use this algorithm and implement all these steps manually to both improve my understanding, and investigate whether this algorithm could support a more interactive calculator. In addition to the definition on Wikipedia, I hacked in some extra features which I mentioned in the section above. However, there is a TODO list with a bunch of things that would improve the program. You know the drill, more and better unit tests, some of the code can be simplified, implement some more math functions and other features, etc... It would be cool to finish the list, but, who knows if I'll ever get around to it. Time to move onto the next thing!