############################################################################ # # File: parsex.icn # # Subject: Program to parse arithmetic expressions # # Author: Cheyenne Wills # # Date: June 10, 1988 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # Adapted from C code written by Allen I. Holub published in the # Feb 1987 issue of Dr. Dobb's Journal. # # General purpose expression analyzer. Can evaluate any expression # consisting of number and the following operators (listed according # to precedence level): # # () - ! 'str'str' # * / & # + - # < <= > >= == != # && || # # All operators associate left to right unless () are present. # The top - is a unary minus. # # # ::= # ::= && # ::= || # ::= epsilon # # ::= # ::= < # ::= <= # ::= > # ::= >= # ::= == # ::= != # ::= epsilon # # ::= # ::= + # ::= - # ::= - # ::= epsilon # # ::= # ::= * # ::= / # ::= % # ::= epsilon # # ::= ( ) # ::= - ( ) # ::= - # ::= ! # ::= 's1's2' # compares s1 with s2 0 if ~= else 1 # ::= NUMBER # number is a lose term any('0123456789.Ee') # ############################################################################ procedure main() local line writes("->") while line := read() do { write(parse(line)) writes("->") } end procedure parse(exp) return exp ? expr() end procedure expr(exp) local lvalue lvalue := term() repeat { tab(many(' \t')) if ="&&" then lvalue := iand(term(),lvalue) else if ="||" then lvalue := ior(term(),lvalue) else break } return lvalue end procedure term() local lvalue lvalue := fact() repeat { tab(many(' \t')) if ="<=" then lvalue := if lvalue <= fact() then 1 else 0 else if ="<" then lvalue := if lvalue < fact() then 1 else 0 else if =">=" then lvalue := if lvalue >= fact() then 1 else 0 else if =">" then lvalue := if lvalue > fact() then 1 else 0 else if ="==" then lvalue := if lvalue = fact() then 1 else 0 else if ="!=" then lvalue := if lvalue ~= fact() then 1 else 0 else break } return lvalue end procedure fact() local lvalue lvalue := part() repeat { tab(many(' \t')) if ="+" then lvalue +:= part() else if ="-" then lvalue -:= part() else break } return lvalue end procedure part() local lvalue lvalue := const() repeat { tab(many(' \t')) if ="*" then lvalue *:= part() else if ="%" then lvalue %:= part() else if ="/" then lvalue /:= part() else break } return lvalue end procedure const() local sign, logical, rval, s1, s2 tab(many(' \t')) if ="-" then sign := -1 else sign := 1 if ="!" then logical := 1 else logical := &null if ="(" then { rval := expr() if not match(")") then { write(&subject) write(right("",&pos-1,"_"),"^ Mis-matched parenthesis") } else move(1) } else if ="'" then { s1 := tab(upto('\'')) move(1) s2 := tab(upto('\'')) move(1) rval := if s1 === s2 then 1 else 0 } else { rval := tab(many('0123456789.eE')) } if \logical then { return if rval = 0 then 1 else 0 } else return rval * sign end