PLACE |
spec |
solutions |
Euphoria |
The program below consists of several functions and a following main part. The latter is a (nominally) infinite loop where we read lines s
from the standard input defice (0
), call evalrpn
to evaluate an RPN expression from s
and print the result or an error message. As we shall see, evalrpn
returns one of several possible kinds of values. If an atom, that must be the result of a successful evaluation – a number, which we print out by the ?
command. A non-empty, non-numeric value would signify an error, and in such a case we act by printing "error"
. If evalrpn
returns an empty string, the input line was empty (or only contained blanks), so we do nothing there.
We have to use the puts
function for printing a string on the standard output (1
) and not ?
, as the latter prints the string contents as integers instead of the string proper.
The program ends by exit
ing the loop upon receiving -1
– an atom – instead of a string from gets
, the -1
signaling end-of-input. Note that puts
is called after each line reading to print an empty line. This is confusing but, by definition in Euphoria, it is the only way to ensure proper interleaving of input and output lines. (No actual empty lines are added to the output because of this; the program behaves just as required.)
Evaluating the expression within evalrpn
takes place by reading tokens from the string s
and maintaining a stack st
where the intermediate results go. After reading a token, it gets assigned to tk
, while the corresponding initial sub-string is removed from s
. If tk
is non-empty, we check whether it is an operator. If so, and if the stack holds at least two arguments for that operation, we perform it and store the result back on the stack top. If, instead, tk
appears to parse as a number, the value of that number is obtained and pushed onto st
. (The function value
, which does the actual extracting from tk
, returns a two-item sequence where the value we are interested in is the second entry. The library file get.e
is include
d in the program to give access to the value
function.)
When there are no more tokens in s
, gettoken
returns an empty string. Then, if there is only one number on the stack, that number is returned. We actually return x
, making use of the fact that x
is always equal to the stack top. On having more than one items on the stack, the stack itself is returned, i.e. a value of type sequence. Other errors, namely a token being neither an operator nor a number, as well as an operation missing one or two of its arguments, are dealt with by returning the string "e"
.
The function number
is used for testing whether a token represents a number. It removes from tk
a possible arithmetic sign, and then similarly removes a decimal dot if present. The remaining string must be non-empty, and consisting of digits. If this is not so, the token was not a number.
Note that number
does not have to really compute the number from the string, only to check if it parses correctly. For the rest we use value
. The latter, on the other hand, is not good at parsing, as it would have been satisfied by any initial substring of the token that reads as a number, and there is no way to know if there would have been left a remainder of the token that is not parsed by value
. That is why we need both number
and value
.
The function number
exemplifies a specific feature of the language. As seen, it is designated by the word type
instead of function
. In Euphoria, a type is a one-argument, Boolean-valued function, i.e. one with regard to the result of which we only distinguish between non-zero (true) and zero (false), and it is assumed that if a non-zero is returned for a certain value as an argument, that value has the type named by the function. Therefore, we have a type number
defined here.
This is Euphoria's mechanism for user-defined types. A type's name can be used in variable declarations or as a predicate to typecheck a value, and thus user-defined datatypes have equal power to that of the predefined types. We only use number
as a predicate in this program.
include get.e object s,r function gettoken() integer i,j i = 1 while s[i]=' ' or s[i]='\t' do i += 1 end while j = i while 0=find(s[j]," \t\n") do j += 1 end while r = s[i..j-1] s = s[j..$] return r end function type number(sequence tk) integer i if tk[1]='+' or tk[1]='-' then tk = tk[2..$] end if i = find('.',tk) if i then tk = tk[1..i-1]&tk[i+1..$] end if i = length(tk) if i=0 then return 0 end if while i and find(tk[i],"0123456789") do i -= 1 end while return i=0 end type function evalrpn() sequence tk,st object x,y,o st = {} while 1 do tk = gettoken() if equal(tk,"") then if length(st)=1 then return x else return st end if end if o = tk[1] if length(tk)=1 and find(o,"+-*/") then if length(st)<2 then return "e" end if x = st[$-1] y = st[$] if o='+' then x += y elsif o='-' then x -= y elsif o='*' then x *= y else x /= y end if st = st[1..$-1] st[$] = x elsif number(tk) then x = value(tk) x = x[2] st = st&x else return "e" end if end while end function while 1 do s = gets(0) puts(1,"\n") if atom(s) then exit end if r = evalrpn() if atom(r) then ?r elsif not equal(r,"") then puts(1,"error\n") end if end while
boykobbatgmaildotcom