上下文无关文法和推导

官方信息技术老师·20 页·深入(追求细节与边界)·0 次浏览·2 天前
形式语言上下文无关推导树编译原理

上下文无关文法与推导

搞懂产生式怎样生成合法句子、推导树如何生长、歧义性为何不可避免

按 空格/→ 演示下一步

1 / 20 页

全部页面点击任意一页,跳回舞台从这页播放

形式语言上下文无关推导树编译原理

上下文无关文法与推导

搞懂产生式怎样生成合法句子、推导树如何生长、歧义性为何不可避免

1第 1 页 · 上下文无关文法与推导

什么是上下文无关文法

上一页我们用规则一步步把 S 推成了句子。但「规则」本身到底长什么样?又为什么叫「上下文无关」?这一页拆开它的形式定义。

四元组结构
非终结符集、终结符集、产生式集、起始符四部分
产生式左部
必须恰好一个非终结符,这是「上下文无关」的来源
产生式右部
终结符、非终结符与空串 ε 的任意拼接串
起始符 S
推导的入口,约定为唯一的非终结符
模板里的占位符对应 →非终结符的展开规则

{{name}} 不管出现在哪一句,都用同一条规则换成具体名字,与左右邻居无关

G=(V,T,P,S),Aα,AV, α(VT)G = (V, T, P, S),\quad A \to \alpha,\quad A \in V,\ \alpha \in (V \cup T)^*
2第 2 页 · 什么是上下文无关文法

文法的四元组定义

前面用一句话开始连续替换,知道每次改写都受规则约束。现在把一部文法本身拆开:它记录了哪些符号、允许哪些改写,以及推导从哪里开始?

V:总符号集
包含非终结符 N 与终结符 T;二者互不相交。
T:终结符
最终字符串中保留的基本符号,不能再由产生式替换。
P:产生式集合
有限条改写规则,形式为 A→α;左边 A 只能是单个非终结符。
S:起始符号
指定的起始非终结符,属于 N 也属于 V,推导从这里开始。
工厂生产系统对应 →上下文无关文法

V 像符号总表,T 像不可再拆的零件,P 像加工规则,S 像第一道工序。

\(G=(V,T,P,S)\),其中 \(V=N\cup T,\ N\cap T=\varnothing,\ S\in V\);P 中规则形如 \(A\to\alpha\),\(A\in N,\ \alpha\in V^*\)。
3第 3 页 · 文法的四元组定义

终结符与非终结符

上页我们看到文法的字母表 V 里装着两类符号。一个像是推导的终点站,到此打住;另一个像是中转站,还得继续往下展开。这两类该怎么区分?

终结符 T
无法再被任何产生式展开的原子符号,组成最终句子
非终结符 N
表示语法范畴的变量,必须出现在某个产生式左侧
互斥且穷尽
T∩N=∅ 且 T∪N=V,字母表被一刀切成两半
ε 的归属
空串 ε 既不在 T 也不在 N,是独立的特殊符号
食材 vs 菜名对应 →终结符 vs 非终结符

食材是原子不能再拆;菜名是占位符,还得拆成具体食材和步骤

TN=,TN=VT \cap N = \varnothing,\quad T \cup N = V
4第 4 页 · 终结符与非终结符

产生式的基本形式

上页我们把符号分成终结符与非终结符——非终结符是「待解释」的占位符。那么用什么方式把「待解释」一步步换成「具体字符」?答案就是产生式。

基本形式
一条产生式写作 A → α:左部一个非终结符,右部是任意符号串
上下文无关
左部只许出现一个非终结符,且不被周围符号约束,故称「上下文无关」
递归的钥匙
α 中允许再次出现 A 自身——这是 CFG 能生成无穷语言的根源
直接与间接递归
A 直接出现在 α 中是直接递归;经 B→…→A 绕一圈回来是间接递归
递归必须有出口
若 A 永远无法被替换掉,推导将无止境——必须配「不含 A 的产生式」兜底
递归函数自己调用自己对应 →A → α 且 A ∈ α

都是「用自身定义自身」;递归函数靠 base case 终止,CFG 靠「不带 A 的产生式」终止

A+A    A 是递归非终结符A \stackrel{+}{\Rightarrow} A \;\Longleftrightarrow\; A \text{ 是递归非终结符}
5第 5 页 · 产生式的基本形式

什么是推导

前面看到一条产生式左边可以替换成右边。那怎么从「一句完整的话」开始,一步步展开成「一个具体的句子」呢?这就是推导要做的事。

推导的定义
从起始符出发,反复用产生式右侧替换左侧非终结符的过程
一步推导 ⇒
用一条产生式替换一个非终结符,记作 α ⇒ β
多步推导 ⇒*
经过零步或多步替换得到的结果,记作 α ⇒* β
句型与句子
含非终结符的中间形式叫句型,全是终结符才是句子
最左/最右推导
约定每次替换最左或最右非终结符,得到唯一推导
做菜按菜谱展开对应 →文法推导

从「一道菜」出发,每步把抽象食材替换成更具体的食材,直到变成可下锅的实物

αβαβ\alpha \Rightarrow \beta \qquad \alpha \Rightarrow^{*} \beta
6第 6 页 · 什么是推导

最左推导与最右推导

不同的推导路径,相同的结果

最左推导与最右推导
不同的推导路径,相同的结果
7第 7 页 · 最左推导与最右推导

规约:推导的逆过程

推导是从 S 一路往下推到句子 w;规约就是反过来——拿着 w,往回找最后用上的那条产生式,把右部换回左部,直到只剩 S。

规约的方向
从句子出发,逆向应用产生式,最终回到起始符 S
单步操作
在串中找到某条产生式的右部,用对应左部非终结符替换
与推导对偶
推导序列倒过来读就是规约序列,每一步互为逆操作
自底向上基础
移进-规约分析等自底向上算法,本质就是反复做规约
拆乐高成品回设计图对应 →规约的过程

推导像搭乐高:设计图(S)→零件→成品 w;规约就是从成品倒拆,最后拼上的那块先拆

推导: Sw规约: wS\text{推导: } S \Rightarrow \cdots \Rightarrow w \quad\Longleftrightarrow\quad \text{规约: } w \Leftarrow \cdots \Leftarrow S
8第 8 页 · 规约:推导的逆过程

推导过程的代码演示

python

用 Python 把「最左推导」一步步跑出来,看句型从 S 演变到 aaaabbbb。

代码高亮加载中…

4 个高亮行就是推导机制的四要素:产生式集合 P、选产生式的策略 strategy、`index('S')` 锁最左非终结符、切片替换完成一次展开。

9第 9 页 · 推导过程的代码演示

语法分析树的概念

推导是一条线性序列:每一步左写当前句型,右写下一步句型。但推导本质是「哪个符号展开成什么」,把这个信息单独画出,从 S 开始层层往下,就得到一棵树——语法分析树。

树的三类节点
根节点是开始符号 S,内部节点都是非终结符,叶节点全是终结符
节点与产生式
每个非终结符节点的子节点序列从左到右对应一条产生式 A → α
推导的可视化
推导每一步「哪个非终结符展成什么」,在树中就是一层的展开
推导不唯一
同一棵分析树可对应多种推导顺序,但最左和最右推导各自唯一
公司组织架构图对应 →语法分析树

CEO 对应开始符号 S,部门是非终结符,员工是终结符

Sw    T: root(T)=S, yield(T)=wS \Rightarrow^{*} w \;\Longleftrightarrow\; \exists\,T:\ \mathrm{root}(T)=S,\ \mathrm{yield}(T)=w
10第 10 页 · 语法分析树的概念

语法分析树的构成

从下往上读这棵树:底部黄色是叶节点(终结符),中部青色是内部节点(产生式展开),顶部红色是根节点(推导起点)。

图解渲染中…
R根节点:唯一的起始非终结符 EI1内部节点:每个非终结符对应一次产生式展开L2叶节点:终结符,与输入 token 一一对应
11第 11 页 · 语法分析树的构成

分析树的完整示例

自顶向下读:从根 S 出发,每一步用一条产生式把非终结符展开成子树,直到全部叶子为终结符,从左到右拼成输入串 aabb。

图解渲染中…
r推导起点,文法开始符号 S,对应输入串 aabbs1内部未展开的 S,将继续用产生式替换e由 S → ε 产生,对应 aabb 中间两个 a 和 b 之间的空位
12第 12 页 · 分析树的完整示例

推导与分析树的对应

上一节的分析树把推导过程「压扁」成了图。但推导有顺序(先选哪个非终结符展开),树没有——那么一棵树背后藏着多少种推导?

树与推导的对应
分析树把推导过程折叠成结构:每个内部节点对应一次产生式展开
一树对应多推导
同一棵树,可由多种不同顺序的推导得到——只要最终展开到的内部节点都相同
最左与最右只是特例
最左与最右推导是众多顺序中的两种极端——都能得到同一棵树
最左规范化后一一对应
无论中间顺序多乱,最左规范化只留一条路径:每棵树对应唯一的最左推导
同一栋楼的施工顺序对应 →同一棵分析树的推导顺序

图纸固定,工人可先砌三楼再砌二楼,只要结构最终长成图纸

13第 13 页 · 推导与分析树的对应

最左推导vs最右推导的树

两条推导路径可能产生截然不同的中间序列,却总是推出同一棵树。

最左推导
  • 每步替换最左侧非终结符
  • 树的左分支优先展开
  • 对应先根遍历次序
  • 自顶向下分析的自然镜像
最右推导
  • 每步替换最右侧非终结符
  • 树的右分支优先展开
  • 对应后根遍历次序
  • 自底向上分析的自然镜像
树的唯一性才是关键:推导顺序只是过程,殊途同归到同一棵树
14第 14 页 · 最左推导vs最右推导的树

规约在分析树中的体现

规约沿推导的逆路径,从叶子逐层向上合并节点,最终回到根。从下往上看即规约推进方向。

图解渲染中…
n5叶子终结符 id,规约的物理出发处n3终结符 + 自身不参与规约,只是树的形态锚点n1根节点 E,规约终点即文法开始符号
15第 15 页 · 规约在分析树中的体现

上下文无关语言的定义

前面看了推导、规约、分析树,知道了'一个串怎么从文法里推出来'。但文法能推出一堆串——有的还含非终结符。得划条线:哪些算语言里的句子?这就是上下文无关语言的形式定义。

形式定义
L(G) = { w ∈ Σ* | S ⇒* w },从S出发、只含终结符、能被推导出的所有串
句子
L(G)中的每个w叫G生成的一个句子,w ∈ Σ*是核心约束
不是所有语言都是CFL
{aⁿbⁿcⁿ | n≥0}无法用CFG描述——三计数同时相等,CFG做不到
CFL泵引理
证明某语言不是CFL的工具:对长串抽取必破坏三计数结构
做菜的菜谱对应 →上下文无关文法

菜谱一步步把食材做成成品,能做出的菜就是'菜谱语言'。但'三味调料等量'这类规则菜谱写不出来

L(G)={wΣSw}L(G) = \{ w \in \Sigma^* \mid S \Rightarrow^* w \}
16第 16 页 · 上下文无关语言的定义

CFG与其他语言类

CFG 和正则文法都能描述 a*b* 这类重复,但面对 a^n b^n 这种需要"数几层"的嵌套就分出高下——这是理解两者边界最锋利的一刀。

正则语言
  • 能描述重复/并列,如 a*b*
  • 无法识别 a^n b^n(状态有限)
  • 对应有限状态自动机
  • 用正则表达式描述
上下文无关语言
  • 也能描述重复,还能嵌套递归
  • 可识别 a^n b^n(递归展开 n)
  • 对应下推自动机(多一个栈)
  • 用 CFG 产生式描述
看到"两层以上嵌套计数"就用 CFG;只有平铺重复用正则就够——前者严格更强,但代价是分析复杂度上升。
17第 17 页 · CFG与其他语言类

核心概念自测

点击作答

同一棵语法分析树,可以对应多少种不同的推导过程?

18第 18 页 · 核心概念自测

本章要点回顾

  • 产生式只看单个非终结符如何展开,与上下文无关
  • 推导、语法树、规约是同一过程的三种观察视角
  • 最左与最右推导是搜索策略,不改变所生成的语言
  • CFG擅长描述嵌套结构,但管不了跨位置的上下文约束
延伸主题:文法的二义性问题自顶向下与自底向上分析乔姆斯基范式(CNF)
19第 19 页 · 本章要点回顾

课后思考

带着问题继续探索形式语言的边界

课后思考
带着问题继续探索形式语言的边界
20第 20 页 · 课后思考
上下文无关文法和推导 · 知识图解