无法编写可以将 AST 转换为 Clojure 代码的解析器

问题描述 投票:0回答:1

给出以下示例

"~a{b=1}&(a{b=1}|a{b=1})|a{b=1}|a{b=1}"
我使用Instaparse

编写了以下解析器
((insta/parser
  "
S = (group | exp)+
group = '~'? <'('> exp+ <')'> op?
exp = '~'? path <'='> (v | r) <'}'> op?
path = (p <'{'>)* p
op = '|' | '&'
<p> = #'[a-z]'
v = #'[a-z0-9]'
r = <'\\''> #'[^\\']*' <'\\''>
")
 "~a{b=1}&(a{b=1}|a{b=1})|a{b=1}|a{b=1}")

运行上面的输出以下输出

[:S
 [:exp "~" [:path "a" "b"] [:v "1"] [:op "&"]]
 [:group
  [:exp [:path "a" "b"] [:v "1"] [:op "|"]]
  [:exp [:path "a" "b"] [:v "1"] [:op "|"]]
  [:exp [:path "a" "b"] [:v "1"]]
  [:op "|"]]
 [:exp [:path "a" "b"] [:v "1"]]]

然而,从这个输出来看,我很难将转换写入 Clojure 表达式。为了进行更直接的转换,我需要更多类似的东西:

[:S
 [:op "|"
  [:op "&"
   [:exp "~" [:path "a" "b"] [:v "1"]]
   [:group
    [:op "|"
     [:exp [:path "a" "b"] [:v "1"]]
     [:op "|"
      [:exp [:path "a" "b"] [:v "1"]]
      [:exp [:path "a" "b"] [:v "1"]]]]]]
  [:exp [:path "a" "b"] [:v "1"]]]]

考虑到这种结构,将其转换为 Clojure 会容易得多。

您将如何编写一个通用解析器,将上述结构解析为 AST,然后使用简单的

insta/transfrom
将其转换为 Clojure 代码?

clojure ebnf instaparse
1个回答
0
投票

我会遵循 运算符优先级中的示例 解析器;这 会给你“单一”

and
/
or
术语,但这应该很容易 在以下步骤中修剪/优化。

S = expr
<expr> = and
and = or ( <'&'> or ) *
or= primary ( <'|'> primary ) *
<primary> = ( group | not | term )
<group> = <'('> expr <')'>
not = <'~'> term
term = #'a\\{b=[0-9]\\}'

例如

((insta/parser
   "
   S = expr
   <expr> = and
   and = or ( <'&'> or ) *
   or= primary ( <'|'> primary ) *
   <primary> = ( group | not | term )
   <group> = <'('> expr <')'>
   not = <'~'> term
   term = #'a\\{b=[0-9]\\}'
   ")
    "~a{b=1}&(a{b=2}|a{b=3})|a{b=4}|a{b=5}")
; →
; [:S
;  [:and
;    [:or [:not [:term "a{b=1}"]]]
;    [:or
;       [:and [:or [:term "a{b=2}"] [:term "a{b=3}"]]]
;       [:term "a{b=4}"]
;       [:term "a{b=5}"]]]]
© www.soinside.com 2019 - 2024. All rights reserved.