Saturday, 2 February 2008

The calculator, version one

There are a few loose ends to tie up and then the first pass of the calculator is complete. If you've forgotten where I was up to, here is a quick reminder:

  • The calculator falls over when the numbers get big because I implemented the tree evaluation in a educational but less than practical manner.
  • Whitespace should be ignored.
  • The codebase needs a general cleanup.
None of these are particularly involved - this should be a relatively short post! During the last post I discussed a few ways to implement the tree evaluation. I pointed out the most obvious solution (a switch statement), mentioned polymorphism and then ventured forth into using unbound methods. Upon discovering the issues with the latter approach it was a no brainer to go back to polymorphism:
class OperatorToken
 attr_reader :multitive, :value

 def evaluate(container_node)
   return do_operation(container_node.left_child.evaluate(), container_node.right_child.evaluate())

class AdditionToken < OperatorToken
 def initialize()
   @value = "+"
   @multitive = false

 def do_operation(left_child_value, right_child_value)
   return left_child_value + right_child_value
I think you can guess what the other Tokens look like. The @value field isn't necessary to the implementation but it allowed me to keep a bunch of existing tests. The @multitive field is a replacement of the crappy named "major" field I used to determine whether the operator was higher precedence. I had to make a few minor changes to other sections of the program but it was all very easy. Whitespace is trivial to deal with. I could have easily handled it when implementing the tokenization but I guess it slipped my mind. Lets add a test for it:
  def test_spaces
   assert_equal([14,"+",62,"*",127], tokenize_for_value("  14 +62*   127 ") ); end
The fix is just stripping whitespace from the string each time a token is generated. I added a few small tests and did my best to clean up the code. You can download it here. Some sample output:
irb(main):001:0> require 'calculator_v1'
=> true
irb(main):002:0> calculate "10 + 2*6"
=> 22
irb(main):003:0> calculate "1000000000000000000000000000000000-1"
=> 999999999999999999999999999999999
irb(main):004:0> calculate "x-1"
=> "Syntax Error"
Next post I discuss the what I would like to achieve in the next version.

No comments:

Post a Comment