找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5155

积分

0

好友

672

主题
发表于 2 小时前 | 查看: 4| 回复: 0

上下文无关文法 (CFG) 基础

上下文无关文法(Context-Free Grammar, CFG)是形式语言理论的核心概念,也是编译器前端设计的基础工具。

A context-free grammar (CFG) is G = (V, Σ, R, S),其中:

  • V 是有限个变量(非终结符)的集合。
  • Σ 是有限个终结符的集合,且 ΣV 不相交。
  • R 是有限个产生式规则,形式为 A → α,其中 A ∈ Vα ∈ (V ∪ Σ)*
  • S ∈ V 是开始符号。

示例:回文串语言

如何用 CFG 来描述所有回文串?回顾一下,字符串 w 是回文当且仅当 w = w^R(即正读反读都一样)。

文法 G_pal = ({S}, {0,1}, R, S) 定义了这个集合。规则集 R 简洁地表示为:

S → ε | 0 | 1 | 0S0 | 1S1

你看,通过在变量 S 两侧对称地添加 01,这个递归规则巧妙地捕捉了回文结构的本质。

CFG 的语言:推导与正确性证明

推导的形式化定义

为了从文法生成字符串,我们从开始符号 S 出发,不断用规则的右部替换当前的变量,直到最终只剩下终结符。这个过程就是推导

对于 G = (V, Σ, R, S)

  • A → γ 是规则,则记 αAβ ⇒_G αγβ,表示一步推导。
  • 若经过零步或多步推导,则记为 α ⇒_G^* β

文法 G 的语言 L(G) 定义为所有能被推导出的纯终结符串的集合:
L(G) = { w ∈ Σ* | S ⇒_G^* w }。如果存在某个 CFG G 能生成语言 L,则 L上下文无关语言

证明回文文法的正确性:L(G_pal) = L_pal

任何形式化的定义都需要证明其合理性。我们通过双向包含来严格证明 G_pal 确实精确描述了回文语言 L_pal

包含回文语言形式定义及正确性命题的文本图片

第一部分:证明 L_pal ⊆ L(G_pal)

思路是对回文串 w 的长度进行归纳。基础情况(|w| = 01)显然成立,因为规则直接包含 S → ε | 0 | 1。归纳步骤的关键在于:任何长度大于等于 2 的回文串,其首尾字符必然相同。假设 w = 0x0x 也是回文,根据归纳假设 S ⇒* x,再利用规则 S → 0S0,我们就能得到 S ⇒ 0S0 ⇒* 0x0 = w

证明 CFG 正确性第一部分:归纳步骤详解

第二部分:证明 L(G_pal) ⊆ L_pal

这次我们对推导的步数进行归纳。基础情况:一步推导生成的 ε01 显然都是回文。归纳步骤:任何多步推导的形态必然是 S ⇒ 0S0 ⇒* 0x0S ⇒ 1S1 ⇒* 1x1。根据归纳假设,x 已是回文,那么在它两边加上相同字符得到的 0x01x1 自然也是回文。

至此,双向包含得证,我们确信这个精巧的文法没有任何“漏洞”。

语法分析树 (Parse Trees)

推导过程本质上是线性的,而语法分析树则为我们提供了字符串句法结构的二维层次化视图,这在编译器中至关重要。

对于 CFG G = (V, Σ, R, S),一棵合法的语法树需满足:

  • 每个内部节点标记为 V 中的变量。
  • 叶节点可以是变量、终结符或 ε;标为 ε 的叶子必须是其父节点的唯一孩子。
  • 若内部节点 A 的子节点自左向右为 X_1, X_2, ..., X_k,则 A → X_1 X_2 ... X_k 必须是文法中的规则。
  • 这棵树的产出 (Yield),是将所有叶节点标签从左到右连接而成的字符串。

语法分析树形式化定义与结构图示

推导与语法树的等价性

一个核心定理是:对于 CFG 中的变量 AA ⇒*_G w (存在推导)当且仅当 存在一棵根为 A、产出为 w 的语法树。我们分两步证明。

(⇒) 从推导构造语法树

通过对推导步数进行归纳。关键步骤是:假设推导在最后一步应用了规则 X → X_1...X_n = γ。根据归纳假设,我们已经有一棵以 A 为根、产出包含 X 的树。此时,只需在 X 节点下添加代表 X_1,...,X_n 的子节点,新树的产出即是我们期望的最终字符串。

从推导构造语法树的关键步骤

(⇐) 从语法树构造推导

通过对树中内部节点的数量进行归纳。

基础情况:如果树只有一个内部节点(根),那么该树的结构就如右图所示,产出 α = X_1...X_n。根据树的合法性,A → α 必然是一条规则,因此我们可以一步推出 A ⇒ α

基础情况:单内部节点语法树对应的推导

归纳步骤:假设树有 k+1 个内部节点。设根 A 的子节点为 X_1, X_2, ..., X_n,每个子树以 X_i 为根、产出记为 α_i。那么整棵树的产出就是 α = α_1 α_2 ... α_n

归纳步骤:多内部节点语法树的产出分解

由于每个子树最多有 k 个节点,根据归纳假设,我们有 X_i ⇒* α_i。于是,从 A 开始,我们可以这样构造推导:
A ⇒ X_1 X_2 ... X_n (应用规则) ⇒* α_1 X_2 ... X_n ⇒* α_1 α_2 ... X_n ⇒* ... ⇒* α_1 α_2 ... α_n = α

从子树推导合成整棵树推导的步骤序列

小结与上下文无关性

综上所述,推导与语法树是描述 CFG 语言的两种等价视角。这引出了 CFG 一个极其重要的性质——上下文无关性:如果 X ⇒*_G γ,那么在任意上下文 α...β 中,我们都可以独立地将 X 替换为 γ,即 αXβ ⇒*_G αγβ。这个性质是语法分析算法能够模块化工作的理论基石。

CFG 推导与语法树等价性小结及上下文无关性图示

实例:英语句子与算术表达式

语法树的概念不仅适用于形式语言,也能很直观地解释自然语言和编程语言的语法。

例如,英语句子 “the girl hits the boy with the bat” 就能产生两棵不同的分析树(见下文歧义部分)。

英语句子的上下文无关文法规则集

在程序设计语言中,考虑一个包含整数和标识符、仅支持 +* 运算的算术表达式语言。我们可以定义文法 G_exp,其中规则 R 如下:

E → I | N | -N | E + E | E * E | (E)
I → a | b | Ia | Ib
N → 0 | 1 | N0 | N1

算术表达式语言的 CFG 形式化定义

即便是简单的表达式 a + b * a,在 G_exp 中也会生成两棵不同的语法树:一棵对应 (a + b) * a,另一棵对应 a + (b * a)。这直接导致了歧义性问题。

表达式 a+b*a 在歧义文法 G_exp 下的两棵语法树

文法歧义性与消除方法

什么是歧义性 (Ambiguity)?

一个文法是歧义的 (Ambiguous),当且仅当对于语言中的同一个句子,存在两棵结构不同的语法分析树。注意,这里强调的是“语法树不同”,而不仅仅是“推导过程不同”。有多种推导方式指向同一棵语法树并不代表文法有歧义。

歧义性的形式化定义与重要警告

如何消除歧义?

我们可以通过两种主要方式来消除文法歧义:

  1. 利用语义约束:比如在自然语言处理中,上下文的语义信息(“谁拿着球棒”)能帮助我们选择唯一正确的句法树。
  2. 强制优先级与结合性:在程序语言设计中,我们规定 * 的优先级高于 +,或者 else 应与最近的 if 结合。这种约定可以体现在文法规则中。

以下就是一个改造后的无歧义算术表达式文法 G'exp。我们通过引入 F(因子)、T(项)、E(表达式)三个层次,强制实现了运算的优先级:

I → a | b | Ia | Ib
N → 0 | 1 | N0 | N1
F → I | N | -N | (E)
T → F | T * F
E → T | E + T

现在,* 处于比 + 更“深”的 T 层,解析时将自然形成更紧密的结合。

与原歧义文法 G_exp 的规则对比图

来自计算理论的坏消息

然而,歧义性问题远比想象中棘手。理论计算机科学告诉我们:

  • 消歧问题:不存在一个通用算法,能够接收一个任意 CFG 并为其生成一个等价的无歧义文法。
  • 歧义判定问题:甚至,不存在一个通用算法能判定任意给定的 CFG 是否是歧义的。此问题是不可判定的 (undecidable)

固有歧义性

更“悲观”的事实是,有些上下文无关语言是固有歧义的 (Inherently Ambiguous)。这意味着,不论我们尝试什么方法,生成这种语言的所有文法都必然存在歧义。

固有歧义语言的定义与存在性问题

经典例子是语言 L = {a^i b^j c^k | i = j 或 j = k}。对于任何生成 L 的文法,字符串 a^n b^n c^n 总是会产生两棵语法树:一棵用来检查 a 的数量是否等于 b 的数量,另一棵用来检查 b 的数量是否等于 c 的数量。这是一种结构上的、无法克服的歧义。

固有歧义语言的典型示例:L = {a^i b^j c^k ...}

本文梳理了 CFG 与语法分析树的核心理论,从基础定义、推导证明到令人困扰的歧义性难题。理解这些底层原理,对于深入学习编译技术乃至计算理论都大有裨益。在云栈社区,你可以找到更多关于编译原理、操作系统等计算机基础技术的高质量讨论和资料。




上一篇:非上下文无关语言:泵引理与CNF证明经典例题详解
下一篇:开源 TTS 翻车根源:声音与情绪本应分离,IndexTTS2 实战解析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-5-13 21:12 , Processed in 1.004537 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表