【问题标题】:Recursive descent parser in ClojureClojure 中的递归下降解析器
【发布时间】:2013-06-24 14:44:11
【问题描述】:

我正在使用 Clojure 创建一些专家系统,我需要开发递归下降解析器来从文本文件中读取规则并从中创建 clojure 函数。我已经编写了一个函数,它检查文本文件是否符合我的语法,它给了我字符串列表,其中包含函数名称、数字、我的系统的事实名称、算术和逻辑运算符等元素。这就是我的语法的样子:

 RULE := EXPR >> FACT 
 EXPR := ( WSK OpA NUM ) || ( FACT ) || ( EXPR OpL EXPR ) || (WSK OpA WSK)

 OpL := AND || OR 
 OpA := > || < || == 
 WSK := [A-Z]+ 
 FACT := [a-z]+ 
 NUM := [0-9]+\.?[0-9]*

这就是我检查语法的功能:

(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")
  )

现在我想从上面的函数给我的字符串列表中创建一个 clojure 函数。你知道怎么做吗?

更新 以下是规则及其硬编码版本的示例:

( ROC > 100 ) >> 购买

(fn
  (cond
    (> (ROC) 100) "buy"
    :else
    ()
  )
)

【问题讨论】:

  • 您能否包含更多上下文(双关语);)在哪里定义了acceptFACT acceptLP等。
  • 您的示例中的 ROC 来自哪里(现有函数、参数或其他内容)?鉴于您正在调用它,它看起来像一个函数。另外,外部函数是否接受任何参数?我现在假设函数并且没有参数。
  • 你的语法正确吗?它不支持 WSK 和 FACT 有多个字符,并且 FACT 只是小写,而您给出的示例使用大写。同样的问题也适用于购买 - 我不知道它来自哪里。既然你没有调用它,我将假设变量,尽管它看起来也像一个字符串。
  • 好的,我更新了我的更新。阻止,ROC 是一个没有参数的函数,如果名为 ROC 的函数返回的值大于 100,我想返回字符串“buy”。我还更新了我的语法,所以现在 WSK 和 FACT 可以有多个字符。

标签: clojure expert-system recursive-descent


【解决方案1】:

首先,我同意@Arthur 关于使用Instaparse 生成语法的观点。

下一步是编写一个函数,将您的语法转换为表示代码的 Clojure 数据结构。

例如,如果语法解析为

[:S [:EXPR [:WSK "ROC"] [:OpA ">"] [:NUM "100"]] :>> [:FCT "BUY"]] ; "ROC > 100 << BUY"

您的函数需要获取适当的部分并将它们翻译成相应的代码。例如,该表达式可能会被解析为 (&gt; (ROC) 100),尽管如果没有示例输入和预期输出就很难判断。

生成函数就像正常的 Clojure 数据操作一样。获取解析器的结果,将其转换为代码。然后在宏中使用生成的代码。这是一个简化的示例,用于处理此示例需要处理的内容。

(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) ()))))

尝试运行

(parse-expr [:EXPR [:WSK "B"] [:OpA "<"] [:NUM "1"]])

(macroexpand-1 '(generate-funcs [:S [:EXPR [:WSK "B"] [:OpA "<"] [:NUM "1"]] :>> [:FCT "b"]]))

为了更好地理解我所说的将数据转换为代码的含义。

【讨论】:

  • 好的,但是如果我可以使用 str 函数创建字符串表达式,获取已解析数据结构的适当元素,然后对其进行评估?我也想在某个列表中包含我的规则,这样我就可以检查该列表是否可以运行一些规则并生成新的事实。
  • 您不需要使用str 生成并评估字符串。相反,我希望代码生成类似(list (symbol "&lt;") (symbol "A") (Integer/valueOf "1")) 的东西,然后这可能是 Clojure 函数内容的一部分。一些示例规则和这些规则的硬编码版本会很有帮助,很难说你需要生成的代码做什么。
  • deterb 但是例如(变量​​ part1-val)是什么意思?因为我收到一个错误 Unable to resolve symbol: variable in this context.
  • 应该是var,而不是variable,抱歉。当你运行它时,你需要确保你有一个具有该名称的变量是可访问的。您可能希望将其解析为符号;我不确定您的代码运行的上下文是否能告诉您哪个更合适。
  • 感谢您的解释。我改用了符号,但是宏的扩展有一些问题。我想作为 generate-funcs sth like (grammar line) 的 arg 传递,其中 line 是一个字符串,而语法是我声明的解析器。这是一个问题,因为 generate-funcs 宏上的引用。
【解决方案2】:

你试过instaparse吗?:

它从上下文无关语法生成解析器

(ns example.core
  (:require [instaparse.core :as insta])

(def as-and-bs
  (insta/parser
    "S = AB*
     AB = A B
     A = 'a'+
     B = 'b'+"))

【讨论】:

猜你喜欢
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多