# RPN Calculator in Io

The `evalrpn` procedure in the following program is implemented as a method of `List`, the prototypical object of Io's lists. An already tokenized RPN expression, in the form of a list of tokens, is evaluated by `evalrpn` recursively. Each call of `evalrpn` modifies the list so that the corresponding (sub)expression is replaced by its result. For a correctly constructed RPN expression this will eventually result in a single number left in the list.

`evalrpn` works as follows. An item `tk` is popped off the list's end, and checked if it denotes an operator. If it does, the method calls itself twice, popping the results off the list. The first result is stored as `y` so that, together with `tk`, it is sent in a `perform` message to the second obtained result – this is how the corresponding arithmetic operation is computed. A list item which is not an operator is analyzed whether it reads as a number: a possible arithmetic sign is stored as a ±1 factor and removed, then the remaining string is scanned to ensure that it contains at least one digit, at most one decimal dot, and nothing else. If a string fails that test, an exception is raised. On success, `tk` is converted to a number using `asNumber`, and the arithmetic sign is taken account of. (`asNumber` itself cannot be relied upon for parsing a numeric token as it happens to not signal trailing characters not belonging to the number.)

Note that the items that are added to the list in `evalrpn` are numbers, not strings, but they are pulled back off immediately and never get parsed like the rest of the items do. These numbers only join the list as a way to represent a result of a partial evaluation and the respective remaining part of the list as a single value.

The main part of the program makes use of the `while` and `readLine` methods to read lines until the latter method returns `nil`. Each line `s` is split into tokens and the possible empty ones of them (appearing whenever the input line contains successive blanks) are filtered out. The resulting list of tokens, if not empty, is sent the `evalrpn` message, and if a one-item list is returned, that item is the result of the evaluation which gets printed by letting it perform the `println` method on itself.

Both the evaluation and the final checking if there are not unused tokens left is done in the context of the `try` method. Any syntax incorrectness results in signalling an exception, in which case `try` returns that exception. For a correctly parsed and computed RPN expression, `nil` is returned. The outcome of `try` is sent the `catch` method which reacts to an exception by printing an error message while not paying attention to a `nil`.

As Io has no character literals, at two places we use single-element strings and refer to their content by means of a subscript (`at(0)`). We could have used ASCII codes instead, e.g. `45 asCharacter` for the minus sign, but this would have obscured the text.

```List evalrpn := method (
tk := pop
push (
c := tk at(0)
if (tk size == 1 and "+-*/" contains(c)
, y := evalrpn pop
evalrpn pop perform(tk asString,y)
, sgn := 1
if ("+-" contains(c)
, if ("-" at(0) == c, sgn := -1)
tk := tk slice(1))
nd := np := 0
tk foreach(c, if (c isDigit, nd := nd+1
, if (c == "." at(0), np := np+1, np:=2)))
if (nd==0 or np>1, Error raise(""))
tk asNumber * sgn
)
)
)

while (s := File standardInput readLine,
s := s split select (isEmpty not)
(s isEmpty) ifFalse (
try (
r := s evalrpn
if (r size > 1, Error raise(""))
r first println
) catch(Exception,"error" println)
)
)
```

boykobbatgmaildotcom