PLACE
spec
solutions
Ruby

RPN Calculator in Ruby

Input lines are read by calling the method gets.

Each line is processed by a call to scan, which transforms it into a token series. As soon as scan obtaines a token, it calls the associated block {...}, passing the token to it. Within the block, the token is accessed as the value of the parameter tk.

The block takes care of pushing the value of the if-else-end onto the stack (array) st. If tk is one of +, -, * and /, that value is the result of applying the corresponding operation – sending the method whose name is in tk – on two numbers popped off st. When tk is a number, that number is the value of the if.

The code between begin and rescue is guarded against exceptions. An exception occurs when the input is erroneous in some way. The call to send will raise an exception if x, y or both are nil, which happens when, trying to pop, there is no value left on st. Also, calling Float raises an exception if the string tk does not contain a number. Finally, fail is a means to ‘throw’ an exception explicitly.

The part between rescue and end is where exceptions are handled and eventually cancelled.

while gets
  begin
    st = []
    $_.scan(/\S+/) {
      |tk|
      st << if tk=~/^[-+*\/]$/
              y,x = st.pop,st.pop
              x.send(tk,y)
            else
              Float(tk)
	    end
    }
    fail if 1<st.size
    puts st.pop unless st.empty?
  rescue
    puts "error"
  end
end

And here is a recursive variant of the program. Each input line is split up into an array of tokens v, which is then traversed backwards recursively to obtain the result. Exceptions occur as in the above program, only this time the execution of the method rpn is included as a possible source of them.

Note the great similarity of rpn's body to that of the block above.

def rpn(v)
  tk = v.pop
  if tk=~/^[-+*\/]$/
    y,x = rpn(v),rpn(v)
    x.send(tk,y)
  else
    Float(tk)
  end
end

while gets
  begin
    v = $_.split
    next if v.empty?
    x = rpn(v)
    fail unless v.empty?
    puts x
  rescue
    puts "error"
  end
end

boykobbatgmaildotcom