First, I agree with @Arthur regarding using Instaparse to generate your grammar player .
The next step is to write a function that transforms your grammar into the Clojure data structures that represent the code.
For example, if a grammar analyzes on
[:S [:EXPR [:WSK "ROC"] [:OpA ">"] [:NUM "100"]] :>> [:FCT "BUY"]] ; "ROC > 100 << BUY"
your function should take the appropriate parts and translate them into the appropriate code. The expression is likely to be analyzed, for example, at (> (ROC) 100) , although it is difficult to say without input and the expected results.
Function generation is similar to normal Clojure data processing. Take the result of the analyzer, turn it into code. Then use this generated code in the macro. Here's a simplified example of working with what this example should handle.
(defn parse-expr [expr] (let [[_ [part1-type part1-val] [part2-type part2-val] [part3-type part3-val]] expr] (if (and (= :WSK part1-type) (= :OpA part2-type) (= :NUM part3-type)) (let [wsk (variable part1-val) opa (variable part2-val) num (Integer/valueOf part3-val)] (list opa (list wsk) num))))) (defmacro generate-funcs [parse-tree] (let [[_ expr _ [_ fact]] parse-tree expr (parse-expr expr) fact (symbol fact)] `(fn [] (if ~expr (str ~fact) ()))))
Try to run
(parse-expr [:EXPR [:WSK "B"] [:OpA "<"] [:NUM "1"]])
and
(macroexpand-1 '(generate-funcs [:S [:EXPR [:WSK "B"] [:OpA "<"] [:NUM "1"]] :>> [:FCT "b"]]))
to better understand what I mean by translating data into code.
source share