在本章中, 我们将继续探究对复杂语言的表述方法, 介绍 上下文无关语法, 以及 巴克斯 - 诺尔范式 .
我们现在考虑通过某种良好的递归定义 生成 我们所需要的文字并组成语言, 而非构造能够从 L ⋆ \mathscr{L}^{\star} L⋆ 中过滤出所需文字的正则表达式.
在生成文字的过程中, 我们首先从零开始, 以某个字母作为起始点, 并依据一定的规则递归地将现有的文字进行扩展, 最后在有限步后终止. 这是一个机械性的过程. 上下文无关语法 的定义与之类似:
定义3.1.1 上下文无关语法 (Context-free grammars
)
称一个上下文无关语法 (
CFG
) 由下列元素组成:
- 由一系列 终止符 (
Terminal Symbols
) 组成的字母表 Σ \Sigma Σ, 又称其为 对象字母表 (Object alphabet
)- 由一系列 非终止符 (
Non-terminal Symbols
) 组成的字母表 Ξ \Xi Ξ. 非终止符又称为 辅助字符 (Auxiliary Characters
).- 一个位于 Ξ \Xi Ξ 中的 起始字母 S S S
- 一个由有限种 生成规则 组成的集合, 又称 产生式集合. 其中, 每个产生式包含一个称为 “产生式头” 或 “左部” 的非终止符号, 一个箭头以及一个称为 “产生式体” 或 “右部” 的, 由终止符号和非终止符组成的序列.
我们称这样定义的语法为 上下文无关的, 因为在遵循这样的语法规则中, 按照顺序生成文字时, 此前已经生成的片段不会对将来要生成的新片段产生影响, 彼此独立.
定义3.1.2 由语法生成的字符串
称字符串 X ∈ ( Σ ∪ Ξ ) ⋆ X \in (\Sigma \cup \Xi)^{\star} X∈(Σ∪Ξ)⋆ 为由语法 G G G 生成的字符串, 若存在字符串序列:
S = X 0 ⇒ X 1 ⇒ ⋯ ⇒ X n = X S = X_0\Rightarrow X_1\Rightarrow \cdots \Rightarrow X_n = X S=X0⇒X1⇒⋯⇒Xn=X
满足: 任意一步变换 X i ⇒ X i + 1 X_i \Rightarrow X_{i+1} Xi⇒Xi+1 均是通过应用语法 G G G 中的某个规则到非终止符 X i X_i Xi 上实现的.
相应地, 还有:
定义3.1.3 由语法生成的语言
称一切定义在 Σ \Sigma Σ 上, 由语法 G G G 生成的文字所组成的集合为 由语法 G G G 生成的语言.
下面给出 上下文无关语言 的定义:
定义3.1.4 上下文无关语言
称基于字母表 Σ \Sigma Σ 的语言 L \mathscr{L} L 是 上下文无关 (
context-free
) 的, 若它是由某个上下文无关语法所生成的.
我们可以使用上下文无关语法表示一些非正则语言, 而正则语言本身也是上下文无关的. 下面我们介绍使用上下文无关语言表示正则语言的方法:
考虑基于字母表 Σ \Sigma Σ 上的正则语言 L \mathscr{L} L. 根据 算法3 和 算法4, 我们可以构造出一个与之等价的非确定性有穷自动机 ( Q , q ⋅ , F , δ ) (Q, q_{\cdot}, F, \delta) (Q,q⋅,F,δ). 下面我们将从这个自动机中导出一个上下文无关语法:
[补充: 左线性和右线性]
编译器在解读程序时所必须执行的一步是 语法分析 (parsing
). 简而言之, 语法分析是按照将句子拆解成不同的组成部分, 由此判断语句在语法上是否正确的流程. 在这里, 我们所关心的语法分析恰好是我们按照语法生成字符串的逆过程: 给定字符串, 设法找出按照给定语法将其组装起来的步骤. 语法树 (parse tree
) 可以为我们明确提供某个字符串的组合流程.
考虑下列的例子, 5 × 3 + 4 5 \times 3 + 4 5×3+4:
上图所示的即为 5 × 3 + 4 5 \times 3 + 4 5×3+4 的语法树. 语法树的阅读方法是直接阅读整棵树的叶子元素 (leaves
). 任何可以用上下文无关语言所表述的, 较为复杂的文字往往都可以被不止一棵语法树所表示. 本例就可以由上述的两棵语法树所表示.
定义3.2.1 不明确性
若某个文字可以由不止一棵语法树表示, 则称该文字的生成是 不明确的, 对应的语法也是 不明确的.
定义3.2.2 上下文无关语法的不确定性
称一个上下文无关语法是不确定的, 若对于由该语法生成的文字 w w w, 存在不止一棵语法树可以将其正确表示.
Backus-Naur
范式巴克斯 - 诺尔范式常用于在程序设计语言和文法中表示的上下文无关语法, 并且其形式和我们此前在定义中接触到的表示方式有所不同, 因此同样有必要单独介绍.
在巴克斯 - 诺尔范式中, 非终止字母无需记为大写字母, 而使用斜体与其余的符号作区分. 我们也可以将非终止字母替换为由 “<>”
扩起来的描述性语句.
此外, 用于表示替换的箭头 → \rightarrow → 在该范式中用 : = := := 表示.
我们在第二章中介绍过使用正则操作正则语言, 从而生成新的正则语言的方法. 下面我们探讨生成新的上下文无关语法的方式:
连接 Concatenation
:
我们可以使用连接的方式构造新的上下文无关语法. 考虑两个基于 Σ \Sigma Σ 的上下文无关语法, 其非终止字母表分别为 Ξ 1 , Ξ 2 \Xi_1, \Xi_2 Ξ1,Ξ2.
克莱尼星号:
对给定的上下文无关语法应用克莱尼星号并不比连接复杂:
取反:
要对给定的上下文无关语法取反, 我们只需要将它的每一条生成规则替换为该规则的逆.
取并:
我们只需要对两个上下文无关语法的起始字母(表), 非终止字母表, 终止字母表以及生成规则等简单取并即可得到由两个上下文无关语法取并所得到的新语法.
取交和取补:
对任意的两个给定的上下文无关语法应用这两种操作方式并不能得到新的上下文无关语法. 但是, 在一些特殊情况下这两种规则仍是有效的.
在本章中, 我们了解了上下文无关语法的定义和使用上下文无关语法进行语言的生成和描述的具体方式, 了解了使用语法树对某个上下文无关语法进行剖析并确定其是否具有歧义的方法, 并且还明晰了正则语言与上下文无关语法的关系. 最后, 我们介绍了基于给定的上下文无关语法生成新的上下文无关语法的一些方法.
自此, 计算理论的上半部分告一段落. 在后半部分中, 我们将继续研究程序的复杂度 (Complexity
) 并进行复杂度分析的基本介绍, 探讨程序的正确性 (Correctness
) 以及可计算性 (Computability
).