我正在尝试使用instaparse库为org模式文件编写解析器。该库采用EBNF表示法并将其转换为解析函数。组织模式文件使用以星号开头的行来制作大纲标题,其中星号设置大纲树中的级别,如下所示
* Headline
** Sub headline1
** Sub headline2
我的第一个尝试是将所有标题放在结果树中的同一级别:
(def outline
(insta/parser
"<S> = Headline-node *
Headline-node = Level <' '> Headline
Level = #'^\\*+'
Headline = #'\\S'+ <'\n'>"))
(outline "* Headline\n** Subheadline\n")
;=>
([:Headline-node [:Level "*"] [:Headline "H" "e" "a" "d" "l" "i" "n" "e"]]
[:Headline-node [:Level "**"] [:Headline "S" "u" "b" "h" "e" "a" "d" "l" "i" "n" "e"]])
也许我可以在之后对树进行转换,将标题放在头条新闻中。但我更喜欢从一开始就在标题内创建一个带有子标题的树。到目前为止,我唯一的想法是手动创建不同的级别:
(def outline
(insta/parser
"<S> = Headline-node1 *
Headline-node1 = <#'^\\* '> Headline (Headline-node2)*
Headline-node2 = <#'^\\*\\* '> Headline
Headline = #'\\S'+ <'\n'>"))
(outline "* Headline\n** Subheadline\n")
;=>
([:Headline-node1 [:Headline "H" "e" "a" "d" "l" "i" "n" "e"]
[:Headline-node2 [:Headline "S" "u" "b" "h" "e" "a" "d" "l" "i" "n" "e"]]])
但我想创建无限级别的头条新闻。有没有办法在EBNF中传达这一点?
答案 0 :(得分:1)
我认为这是不可能的。下推式自动机可以准确识别无上下文的语言。但请考虑下推自动机如何操作以确定示例中标题的级别。
下推自动机具有一组有限的状态。因此,如果我们要允许几乎很深的水平,它就不能使用状态来跟踪航向的水平。所以它必须使用它的堆栈。使用堆栈计数的唯一方法是每次读取*
时推送堆栈符号(也有有限数量的堆栈符号)。假设它位于某些*
开头的输入字符串中的某个位置。它通过推送每*
的堆栈符号来继续。但是当涉及输入字符串中*
s的结尾时,自动机可以用来决定其动作的唯一内容是:输入字符串中的符号,其状态以及堆栈中的顶部符号。我们已经&#34;知道输入符号不是*
,所以这没有帮助。我们知道堆栈的顶部是我们为每*
推送一次的符号,所以这也无济于事。如前所述,状态集是有限的,因此我们不能以某种方式使用状态来计算堆栈上的符号数。