Arithmetic evaluation: Difference between revisions

m (→‎{{header|Ruby}}: slight rewording of explanation.)
Line 957:
* handles left and right associativity and different precedences,
* accepts integers, reals, and radix constants (e.g. 3r10 is 3 in base 3), but not E notation
* accepts the Icon operators + - * / % (remainder) and ^ (exponentiation) and unary operators + and -
* string invocation is used to evaluate binary operators hence other Icon binary operators (including handle multiple character ones) can be easily added
* uses Icon style type coercion on operands
* accepts single unary operators, e.g. +(+3) works but ++3 will break it
* represents the AST is a nested list eliminating unneeded parenthesis.
==={{header|Icon}}===
<lang Icon>procedure main() #: simple arithmetical parser / evaluator
write("Usage: Input expression = Abstract Syntax Tree = Value, ^Z to end.")
 
repeat {
write("Usage: Input expression = Abstract Syntax Tree = Value, ^Z to end.")
writes("Input expression : ")
repeat {
if not writes("Input expressionline := "read()) then break
if not writes if map(line) ? { (x := readE()) then& breakpos(0) } then
if map(line) ? { write(x" := E", showAST(x)), &" pos(0)= }", thenevalAST(x))
else
write(" = ", showAST(x), " = ", evalAST(x))
else write(" rejected")
}
end
 
procedure evalAST(X) #: return the evaluated AST
local x
 
if type(X) == "list" then {
Line 986 ⟶ 985:
 
procedure showAST(X) #: return a string representing the AST
local x,s
 
s := ""
Line 993 ⟶ 992:
return s
end
 
########
# When you're writing a big parser, a few utility recognisers are very useful
#
procedure ws() # skip optional whitespace
suspend tab(many(' \t')) | ""
end
 
procedure digits()
suspend tab(many(&digits))
end
 
procedure radixNum(r) # r sets the radix
static chars
initial chars := &digits || &lcase
suspend tab(many(chars[1 +: r]))
end
########
 
global token
Line 998 ⟶ 1,015:
 
procedure opinfo()
static O
initial {
O := HansonsDevice([],table(&null)) # parsing table
put(O.precedence, [ "+", "-" ], [ "*", "/", "%" ], [ "^" ] ) # Lowest to Highest precedence
every O.associativity[!!O.precedence] := 1 # default to 1 for LEFT associativity
O.associativity["^"] := 0 # RIGHT associativity
}
return O
end
 
procedure E(k) #: Expression
local lex, pL
static opT
initial opT := opinfo()
 
/k := 1
Line 1,019 ⟶ 1,036:
else {
put( lex, E(k+1) )
while ws() & put( lex, token := =!pL ) do
put( lex, E(k+opT.associativity[token]) )
}
Line 1,026 ⟶ 1,043:
 
procedure F() #: Factor
suspend ws() & ( # skip optional whitespace, and ...
suspend 2( ="-(", [-1,"*",E()], =")") | 2( =("+("|"("), E() , =")") | ( =("-" | "+" | "") || V() )
(="+" & F()) | # unary + and a Factor, or ...
(="-" || V()) | # unary - and a Value, or ...
(="-" & [-1, "*", F()]) | # unary - and a Factor, or ...
2(="(", E(), ws(), =")") | # parenthesized subexpression, or ...
V() # just a value
)
end
 
procedure V() #: Value
local r
suspend ws() & ( # skip optional whitespace, and ...
suspend ( =(r := 1 to 36) || ="r" || tab(many((&digits || &lcase)[1:r+1])) ) | (tab(many(&digits)) || ((="." || tab(many(&digits))) | ""))
( =(r := 1 to 36) || ="r" || radixNum(r) ) | # N-based number, or ...
(digits() || ((="." || digits() ) | "")) # plain number with optional fraction
)
end</lang>
 
Anonymous user