Arithmetic evaluation: Difference between revisions

Line 648:
: 1 > :c 1
21/4</pre>
 
=={{header|Clojure}}==
<lang Clojure>(def precedence '{* 0, / 0
+ 1, - 1})
 
(defn order-ops
"((A x B) y C) or (A x (B y C)) depending on precedence of x and y"
[[A x B y C & more]]
(let [ret (if (<= (precedence x)
(precedence y))
(list (list A x B) y C)
(list A x (list B y C)))]
(if more
(recur (concat ret more))
ret)))
 
(defn add-parens
"Tree walk to add parens. All lists are length 3 afterwards."
[s]
(clojure.walk/postwalk
#(if (seq? %)
(let [c (count %)]
(cond (even? c) (throw (Exception. "Must be an odd number of forms"))
(= c 1) (first %)
(= c 3) %
(>= c 5) (order-ops %)))
%)
s))
 
(defn make-ast
"Parse a string into a list of numbers, ops, and lists"
[s]
(-> (format "'(%s)" s)
(.replaceAll , "([*+-/])" " $1 ")
load-string
add-parens))
 
(def ops {'* *
'+ +
'- -
'/ /})
 
(def eval-ast
(partial clojure.walk/postwalk
#(if (seq? %)
(let [[a o b] %]
((ops o) a b))
%)))
 
(defn evaluate [s]
"Parse and evaluate an infix arithmetic expression"
(eval-ast (make-ast s)))
 
user> (evaluate "1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1")
60</lang>
 
=={{header|D}}==
Anonymous user