PLACE |
spec |
solutions |
Icon |
Expression orientation and goal-directed computation being characteristic features of Icon, they are intensively used in this calculator implementation. The program shown below is of the stack-based kind and works as follows.
The main loop (re)sets the stack stk
to an empty array and attempts reading a line from the standard input.
If an end of input is encountered, read
fails, the loop breaks, and the program terminates. If read
succeeds, its result is enclosed in a pair of blank characters for ease and uniformity of the parsing that follows.
The main loop's body has only two statements, of which the first one is a ‘scan’ operator (?
) that does most of the work.
It sets line
as the string being parsed and another while
loop – the right argument of ?
– as the parsing action.
The condition part of that while
extracts non-blank substrings s
from line
, so that s
can be parsed in the loop's body.
Here, many
returns the index of the first non-blank character, starting from the current position in line
.
Similarly, upto
returns the index of the first blank after that.
In both cases we need to call tab
so as to advance the current scan position within line
and return the string between the old and the new current positions: that is how we obtain the current token in s
.
Note that the calls to many
and upto
do not mention line
explicitly as their argument.
They do not have to, because we use them in the context of the ?
operator, where the subject string is implied.
The body of the parsing while
is a single but complex expression.
It calls real
on s
, thus attempting to parse it as a number, and if that is successful, the number is pushed (put
) on the stack.
Failing to be a number, s
might be an operator, so we check whether its length (*s
) is 1
and whether it is a substring of "+-*/"
.
We also try pull
ing off the stack twice, and if all this is successful, we finally invoke the procedure corresponding to the arithmetic operation denoted by s
– that procedure's name is the string s
itself.
The result is pushed onto the stack.
If s
is neither a number nor an operator, the last alternative of the expression is in turn: it prints an error message and does break next
to exit the current loop and jump to the next iteration of the enclosing one, which is reading a new line.
Note how all the components of the above described long expression are connected to each other with |
and &
to ensure the proper succession of the actions taken according to the logic of the computation.
When the parsing is complete and no error occured so far, it remains to see whether there is exactly one number left on the stack; if so, we print it.
More than one entries means that the input expression was incorrect (having too few operators), so in this case we print "error"
.
If line
was initially empty, the stack is empty as well, therefore the call of pull
fails.
Then so does the if
, and thus nothing at all is printed, as it has to be.
procedure main() ws := ' \t' while stk := [] & line := " " || read() || " " do { line ? while tab(many(ws)) & s:=tab(upto(ws)) do put(stk,real(s)) | (1=*s & find(s,"+-*/") & y:=pull(stk) & put(stk,s(pull(stk),y))) | (write("error") & break next) if y:=pull(stk) then write((0=*stk & y) | "error") } end
boykobbatgmaildotcom