我读到的一切都表明Treetop像正则表达式一样回溯,但我很难做到这一点。
假设我有以下语法:
grammar TestGrammar
rule open_close
'{' .+ '}'
end
end
这与字符串{abc}
不匹配。我怀疑那是因为.+
消耗了a
以后的所有内容。即当我只想要消费abc}
时,它会消耗abc
。
这似乎与类似的正则表达式不同。正则表达式/{.+}/
将匹配{abc}
。我的理解是这是可能的,因为正则表达式引擎在使用}
作为.+
的一部分后关闭}
后回溯,然后无法匹配。
Treetop可以做那样的回溯吗?如果是这样,怎么样?
我知道你可以使用否定来匹配“{ab}c}
以外的任何东西”。但这不是我的意图。假设我希望能够匹配字符串{
。在这种情况下,我想要的标记是开头ab}c
,中间字符串}
和结束{a b {c d}}
。这是一个人为的例子,但在使用{{1}}等嵌套表达式时它变得非常重要。
答案 0 :(得分:2)
Treetop是Parsing Expression Grammar解析器的实现。 PEG的一个好处是它们的灵活性,速度和内存要求的结合。然而,这种平衡行为有一些权衡。
引自维基百科的文章:
零或多个,一个或多个和可选的运算符分别消耗其子表达式e的零个或多个,一个或多个,或零个或一个连续重复。然而,与无上下文语法和正则表达式不同, 这些运算符始终表现得很贪婪 ,消耗尽可能多的输入并且 永远不会回溯 > 即可。 [...]表达式(a* a)
将始终失败,因为第一部分(a*)
永远不会为第二部分留下任何匹配。
(强调我的。)
简而言之:虽然某些PEG运营商可以回溯试图采取另一条路线,但+
运营商却不能。
相反,为了匹配嵌套的子表达式,您需要在分隔的子表达式(先检查)后跟非表达式字符之间创建一个替换。像(未经测试)的东西:
grammar TestGrammar
rule open_close
'{' contents '}'
end
rule contents
open_close / non_brackets
end
rule non_brackets
# …
end
end