Recursive descent parameter in Clojure

I am creating some expert system using Clojure, and I need to develop a recursive descent parkour to read the rules from a text file and create Clojure functions from it. I wrote a function that checks if a text file supports my grammar and gives me a list of strings with elements such as function names, numbers, fact names for my system, arithmetic and logical operators. Here's what my grammar looks like:

RULE := EXPR >> FACT EXPR := ( WSK OpA NUM ) || ( FACT ) || ( EXPR OpL EXPR ) || (WSK OpA WSK) OpL := AND || OR OpA := > || < || == WSK := [AZ]+ FACT := [az]+ NUM := [0-9]+\.?[0-9]* 

And what is my function for checking grammar:

 (defn wyr "new expression" [przetworzone doPrzetworzenia] (cond (empty? doPrzetworzenia) przetworzone (empty? przetworzone) (if (empty? (acceptLP (first doPrzetworzenia))) "error-poczatek";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptLP (first przetworzone)))) (if (empty? (acceptFACT (first doPrzetworzenia))) (if (empty? (acceptWSK (first doPrzetworzenia))) (if (empty? (acceptLP (first doPrzetworzenia))) "error-LP";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptFACT (first przetworzone)))) (if (empty? (acceptPP (first doPrzetworzenia))) "error-FACT";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptWSK (first przetworzone)))) (if (empty? (acceptOpA (first doPrzetworzenia))) (if (empty? (acceptPP (first doPrzetworzenia))) "error-WSK";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptOpA (first przetworzone)))) (if (empty? (acceptNUM (first doPrzetworzenia))) (if (empty? (acceptWSK (first doPrzetworzenia))) "error-OpA";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptPP (first przetworzone)))) (if (empty? (acceptOpL (first doPrzetworzenia))) (if (empty? (acceptImplication (first doPrzetworzenia))) "error-PP";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptOpL (first przetworzone)))) (if (empty? (acceptLP (first doPrzetworzenia))) "error-OpL";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptImplication (first przetworzone)))) (if (empty? (acceptFACT (first doPrzetworzenia))) "error-Implication";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) (not (empty? (acceptNUM (first przetworzone)))) (if (empty? (acceptPP (first doPrzetworzenia))) "error-NUM";todo - error (wyr (cons (first doPrzetworzenia) przetworzone) (rest doPrzetworzenia))) :else "error") ) 

Now I would like to create a Clojure function from my list of strings, which the function above gives me. You do not know how to do this?

UPDATE Here is an example of a rule and its hard encoding:

(ROC> 100) → buy

 (fn (cond (> (ROC) 100) "buy" :else () ) ) 
+4
source share
2 answers

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.

+2
source

Have you tried instaparse ?:

It creates parsers from context free grammar code

 (ns example.core (:require [instaparse.core :as insta]) (def as-and-bs (insta/parser "S = AB* AB = AB A = 'a'+ B = 'b'+")) 
+2
source

Source: https://habr.com/ru/post/1486695/


All Articles