PLACE |
spec |
solutions |
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 – send
ing 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