了解 Rust 的 pest 库时接触到了这个文法。

PEG(解析表达文法)和 CFG(上下文无关文法)十分类似,不过可以确保解析没有二义性。具体而言,PEG 中的 + * ? 这三个操作符总是贪婪匹配,选择操作符 | 总是优先尝试前面的选项,在前面的选项失败时才尝试后面的选项。因其,PEG 很适合递归向下解析。不过相比用作编译器语法分析的前端,作为正则语言的增强版应该更加合适。

比如说,PEG 模式串 a+a 无法匹配字符串 aaa,其中的 a+ 会贪婪地匹配 aaa,导致模式串剩余的 a 无法匹配到字符。而模式串 a | ab 无法完整匹配到字符串 ab,第一个模式 a 匹配首字符 a 匹配之后,模式串匹配成功,不会再尝试使用模式 ab

PEG 中另外有 &! 两个操作符。&e 表示从当前位置开始匹配 e,但是不消耗字符,也就是提前观测后面的字符串能否形成目标模式。!e 与之相反,只有在后面的字符串不能匹配 e 的时候才接着匹配,同样也不消耗字符。

让我们来看一个用文法 匹配 的例子:

S <- &(A c) 'a'+ B
A <- 'a' A? 'b'
B <- 'b' B? 'c'

其中 可以匹配 可以匹配 的规则首先使用 &(A c) 确保我们匹配得到字符串的前缀为 ,然后使用 'a'+ 消耗掉所有的 ,剩下的部分使用 可以进行匹配。

熟悉 CFG 的话可以可以知道这个语言是无法用 CFG 描述(利用泵引理)的,同时我们也可以很简单地写出 PEG 无法处理而 CFG 可以处理的文法 S <- xSx | x。因此 CFG 和 PEG 之间没有包含关系。