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