gpt4 book ai didi

parsing - 具有子表达式语法的简单 Instaparse 解析器

转载 作者:行者123 更新时间:2023-12-04 02:48:32 27 4
gpt4 key购买 nike

我正在使用 Instaparse 来解析如下表达式:

$(foo bar baz $(frob))

变成类似的东西:

[:expr "foo" "bar" "baz" [:expr "frob"]]

我几乎明白了,但遇到了歧义问题。这是我重现的语法的简化版本,试图依赖否定的前瞻。

(def simple
(insta/parser
"expr = <dollar> <lparen> word (<space> word)* <rparen>
<word> = !(dollar lparen) #'.+' !(rparen)
<space> = #'\\s+'
<dollar> = <'$'>
<lparen> = <'('>
<rparen> = <')'>"))

(simple "$(foo bar)")

哪些错误:

Parse error at line 1, column 11:
$(foo bar)
^
Expected one of:
")"
#"\s+"

这里我说一个词可以是任何字符,以支持像这样的表达式:


$(foo () `bar` b-a-z)

等注意一个词可以包含 ()但它不能包含 $() .不确定如何在语法中表达这一点。似乎问题是 <word>太贪心了,消费了最后一个)而不是让 expr有它。


更新 从单词中删除空格:

(def simple2
(insta/parser
"expr = <dollar> <lparen> word (<space> word)* <rparen>
<word> = !(dollar lparen) #'[^ ]+' !(rparen)
<space> = #'\\s+'
<dollar> = <'$'>
<lparen> = <'('>
<rparen> = <')'>"))


(simple2 "$(foo bar)")
; Parse error at line 1, column 11:
; $(foo bar)
; ^
; Expected one of:
; ")"
; #"\s+"

(simple2 "$(foo () bar)")
; Parse error at line 1, column 14:
; $(foo () bar)
; ^
; Expected one of:
; ")"
; #"\s+"

更新2个测试用例

(simple2 "$(foo bar ())")
(simple2 "$((foo bar baz))")

更新 3 完整的解析器

对于任何好奇的人来说,这个问题范围之外的完整工作解析器是:

(def parse
"expr - the top-level expression made up of cmds and sub-exprs. When multiple
cmds are present, it implies they should be sucessively piped.
cmd - a single command consisting of words.
sub-expr - a backticked or $(..)-style sub-expression to be evaluated inline.
parened - a grouping of words wrapped in parenthesis, explicitly tokenized to
allow parenthesis in cmds and disambiguate between sub-expression
syntax."
(insta/parser
"expr = cmd (<space> <pipe> <space> cmd)*
cmd = words
<sub-expr> = <backtick> expr <backtick> | nestable-sub-expr
<nestable-sub-expr> = <dollar> <lparen> expr <rparen>
words = word (<space>* word)*
<word> = sub-expr | parened | word-chars
<word-chars> = #'[^ `$()|]+'
parened = lparen words rparen
<space> = #'[ ]+'
<pipe> = #'[|]'
<dollar> = <'$'>
<lparen> = '('
<rparen> = ')'
<backtick> = <'`'>"))

示例用法:

(parse "foo bar (qux) $(clj (map (partial * $(js 45 * 2)) (range 10))) `frob`")

解析为:

[:expr [:cmd [:words "foo" "bar" [:parened "(" [:words "qux"] ")"] [:expr [:cmd [:words "clj" [:parened "(" [:words "map" [:parened "(" [:words "partial" "*" [:expr [:cmd [:words "js" "45" "*" "2"]]]] ")"] [:parened "(" [:words "range" "10"] ")"]] ")"]]]] [:expr [:cmd [:words "frob"]]]]]]

这是我编写的聊天机器人的解析器,yetibot .它取代了以前困惑的基于正则表达式的手动解析。

最佳答案

我不太了解 instaparser,所以我只是阅读了足够多的文档,给我一种错误的安全感。我也没有测试,不知道你的要求是什么。

具体来说,我不知道:

1) $() 是否可以嵌套(我认为你的语法使这不可能,但我觉得这很奇怪)

2) () 是否可以包含空格而不被解析为多个单词

3)()是否可以包含$()

为了编写语法(或者碰巧寻求建议),您需要弄清楚这些事情。

更新:根据评论修改了语法。我删除了 $ () 的产生式,因为它们似乎没有必要,这样尖括号就更容易处理了。

以下是基于回答上述问题“是,否,是”和一些关于正则表达式格式的随机假设。 (我不完全清楚尖括号是如何工作的,但我认为按照你想要的方式输出括号并不容易;我决定只将它们作为单个元素输出。如果我弄明白了什么,我将对其进行编辑。)

<sequence> = element (<space> element)*
<element> = expr | paren_sequence | word
expr = <'$'> <'('> sequence <')'>
<word> = !('$'? '(') #'([^ $()]|\$[^(])+'
<paren_sequence> = '(' sequence ')'
<space> = #'\\s+'

希望对您有所帮助。

关于parsing - 具有子表达式语法的简单 Instaparse 解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18282535/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com