Arithmetic evaluation: Difference between revisions

m ({{out}})
Line 1,764:
 
<lang FreeBASIC>
'Arithmetic evaluation
'
'Create a program which parses and evaluates arithmetic expressions.
'
'Requirements
'
' * An abstract-syntax tree (AST) for the expression must be created from parsing the
' input.
' * The AST must be used in evaluation, also, so the input may not be directly evaluated
' (e.g. by calling eval or a similar language feature.)
' * The expression will be a string or list of symbols like "(1+3)*7".
' * The four symbols + - * / must be supported as binary operators with conventional
' precedence rules.
' * Precedence-control parentheses must also be supported.
'
'Standard mathematical precedence should be followed:
'
' Parentheses
' Multiplication/Division (left to right)
' Addition/Subtraction (left to right)
'
' test cases:
' 2*-3--4+-0.25 : returns -2.25
' 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 : returns 71
 
enum
false = 0
true = -1
end enum
 
enum Symbol
unknown_sym
minus_sym
plus_sym
lparen_sym
rparen_sym
number_sym
mul_sym
div_sym
unary_minus_sym
unary_plus_sym
done_sym
eof_sym
end enum
 
type Tree
as Tree ptr leftp, rightp
op as stringSymbol
value as double
end type
 
dim shared sym as string sym, usr_inputSymbol
dim shared tokenval as double
dim shared usr_input as string
 
declare function expr(byval p as integer) as Tree ptr
 
function isdigit(byval ch as string) as long
return (ch <> "") and Asc(ch) >= Asc("0") and Asc(ch) <= Asc("9")
end function
 
Line 1,784 ⟶ 1,830:
end sub
 
' tokenize the input string
sub getsym()
do
if len(usr_input) = 0"" then
line input usr_input
usr_input += chr(10)
endif
dim as string ch = mid(usr_input, 1, 1) ' get the next char
usr_input = mid(usr_input, 2) ' remove it from input
 
sym = "*unknown*"unknown_sym
select case ch
case " ": continue do
case chr(10), "": sym = ""done_sym: return
case "+": sym = "+"plus_sym: return
case "-": sym = "-"minus_sym: return
case "*": sym = "*"mul_sym: return
case "/": sym = "/"div_sym: return
case "(": sym = "("lparen_sym: return
case ")": sym = ")"rparen_sym: return
case else
if isdigit(ch) then
Line 1,809 ⟶ 1,857:
s += ch
if ch = "." then dot += 1
ch = mid(usr_input, 1, 1) ' get the next char
usr_input = mid(usr_input, 2) ' remove it from input
loop until notwhile isdigit(ch) orelse ch = "."
if ch = "." or dot > 1 then error_msg("bogus number")
usr_input = ch + usr_input ' prepend the char to input
tokenval = val(s)
sym = "*number*"number_sym
return
end if
sym = "*unknown*"
return
end select
Line 1,824 ⟶ 1,870:
end sub
 
function make_node(byval op as stringSymbol, byval leftp as Tree ptr, byval rightp as Tree ptr) as Tree ptr
dim t as Tree ptr
 
Line 1,834 ⟶ 1,880:
end function
 
function is_binary(byval op as stringSymbol) as integer
select case op
return op = "*" orelse op = "/" orelse op = "+" orelse op = "-"
case mul_sym, div_sym, plus_sym, minus_sym: return true
case else: return false
end select
end function
 
function prec(byval op as stringSymbol) as integer
select case op
case "*unary minus*"unary_minus_sym, "*unaryunary_plus_sym: plus*": return 100
case "*"mul_sym, "/"div_sym: return 90
case "+"plus_sym, "-"minus_sym: return 80
case else: return 0
end select
end function
Line 1,851 ⟶ 1,900:
 
select case sym
case "-"minus_sym, "+"plus_sym
dim op as stringSymbol = sym
getsym()
t = expr(prec("*unary minus*"unary_minus_sym))
if op = "-"minus_sym then return make_node("*unary minus*"unary_minus_sym, t, 0)
if op = "+"plus_sym then return make_node("*unary plus*"unary_plus_sym, t, 0)
case "("lparen_sym
getsym()
t = expr(0)
if sym <> ")"rparen_sym then error_msg("expecting rparen")
getsym()
return t
case "*number*"number_sym
t = make_node(sym, 0, 0)
t->value = tokenval
Line 1,877 ⟶ 1,926:
while is_binary(sym) andalso prec(sym) >= p
dim t1 as Tree ptr
dim op as stringSymbol = sym
getsym()
t1 = expr(prec(op) + 1)
Line 1,888 ⟶ 1,937:
if t <> 0 then
select case t->op
case "-"minus_sym: return eval(t->leftp) - eval(t->rightp)
case "+"plus_sym: return eval(t->leftp) + eval(t->rightp)
case "*"mul_sym: return eval(t->leftp) * eval(t->rightp)
case "/"div_sym: return eval(t->leftp) / eval(t->rightp)
case "*unary minus*"unary_minus_sym: return -eval(t->leftp)
case "*unary plus*"unary_plus_sym: return eval(t->leftp)
case "*number*"number_sym: return t->value
case else: error_msg("unexpected tree node")
end select
Line 1,903 ⟶ 1,952:
do
getsym()
if sym = ""eof_sym then continueexit do
if sym = done_sym then continue do
dim t as Tree ptr = expr(0)
print"> "; eval(t)
if sym <>= ""eof_sym then error_msg("unexpectedexit input")do
if sym <> done_sym then error_msg("unexpected input")
loop
</lang>
155

edits