编译原理期末复习
改写文法,消除左递归
通俗地讲,若在一个文法中,一个非终结符A经过多次推导得到了$A\alpha$,则称这个文法是左递归的。左递归会使分析陷入到无限循环之中:
消除直接左递归
如果A→A α,则称文法G是直接左递归的。
引入一个新的字符$P`$,将左递归变成右递归。
消除间接左递归
简介左递归的表现
手动执行下面的伪代码,消除间接左递归
例子:
根据产生式构造每个非终结符的FIRST集合和FOLLOW集合
求解FIRST集合
步骤:
例子:
求解FOLLOW集
步骤:
例子:
利用FIRST集合和FOLLOW集合构造LL(1)分析表M[A,a]
自顶向下的分析步骤(推导),和下面的自下而上的分析(规约)都要考察。
非递归的预测分析表
何为预测分析表?
填写步骤:
- 先针对FIRST集,若$\alpha \in FIRST(A)$,则找到此推导的第一个产生式,将其写在$M[A,\alpha]$的格子上;
- 再针对FOLLOW集,若$\xi \in FIRST(A)$,则将产生式$A \rightarrow \xi$写在$M[A,\alpha]$上,其中$\alpha \in FOLLOW(A)$;
例子,手推一遍
根据分析表构造分析步骤(表格)
步骤,认真看可以理解
例子,手推一遍
判断文法是否具有二义性
找到一个句子,画两个不同的语法分析树推导,可证明文法具有二义性。
NFA的确定化,NFA转换为DFA
NFA和DFA的概念
用五元组定义的有穷自动机DFA,记为$D_1={k,\Sigma,M,S,F }$。
- $k$表示状态的集合;
- $\Sigma$表示终结符的集合,即可接受的输入字符;
- $M$表示转换函数,产生式$A \rightarrow \alpha$对应的转化函数为$M(S,a)=A$;
- $S$表示文法的开始符号(也叫识别符号);
- $F$表示终结符集合。
一个DFA的例子
不确定的有穷自动机NFA:图中至少有一条弧上有两个字符,即一个字符a经过同一个字符b的产生后,得到两个不同的结果c和d;
一个NFA的例子:
NFA和DFA的区别:
新概念:$\xi-闭包$
- 状态$q$的$\xi-闭包$记作$\xi-closure(q)$;
- 状态$q$的$\xi-闭包$为从$q$出发,只经过空弧($\xi$)到达的状态集合;
- $q \in \xi-closure(q)$;
- 从$q$出发,经过任意条空弧到达的所有状态$q`\in \xi-closure(q)$;
- 状态集合$I$的$\xi-闭包$:由$I$中所有状态的$\xi-闭包$的并集组成,记作:$\xi-closure(I)={ q
| q
\in\xi-closure(q) 且q \in I}$; - 状态集合$I$的$a$转换$I_a$:$I_a=\xi-closure(J)$,其中J为从I中任意状态出发,经过一条a(可以先经过任意条空弧),到达的所有状态的集合;
子集法将NFA转换为DFA
- 由正规式得到NFA,一般题目直接给定,以下面的NFA为例子说明NFA转换为DFA的过程:
- 由于NFA中初始状态和终止状态均不唯一(虽然本例子中是唯一的),引入新的初始状态X和新的终止状态Y,加入到原NFA中:
- 通过引入新的状态,简化弧上的标记(将多个变成一个)。即对每条有多个字符的弧,做如下变换:
将原先的NFA转换成:
- 构造计算状态集的转换表。NFA中具有2个终结符,所以转换表为3列。
- 首先,令转换表第一行第一列为开始符号的$\xi-闭包$,求出这一列的$I_a和I_b$;
- 检查得到的$I_a和I_b$是否在第一列中出现,若未出现,则补上;
- 计算下一行的$I_a和I_b$;
- 重复上述过程,直到所有2,3列的子集全部出现在第一列为止。
例子中的转换表为:
- 像上面的黄色笔迹那样给每个状态集标上号,将得到的转换表转换为转换矩阵,并依据转换矩阵得到DFA。
转换矩阵
DFA
语法制导的翻译
可以不看那些复杂的概念,先从下至上实现输入字符串的规约过程,每用到一条产生式就执行其语义属性(代码)。
类型转换(书写代码)
根据拓广文法的产生式求规范项目集和LR分析表
LR分析法
LR分析法是自下而上的分析方法,跟之前的不一样。
短语,直接短语和句柄
最右推导称为规范推导,规范推导的逆过程称为规范规约。
由规范推导得到的句型称为规范句型。
LR文法
LR(0)分析
对于每一条产生式,可以在其中间的任意位置加上·
,加上·
的产生式称为项目。
项目的分类:
- 移进项目:圆点后面是终结符的项目;
- 待约项目:圆点后面是非终结符的项目;
- 规约项目:圆点在产生式最右端的项目;
- 接受项目:形似与
Z->S·
,其中s
是文法的识别符号(开始符号),接受项目是规约项目的一种。
LR(0)项目集规范族的构造
- 先拓广文法,引入新的开始符号,将原先的开始符号作为新产生式的右部;
- 从以新的开始符号为左部的产生式开始,生成项目;
- 对于待约项目(圆点后面是非终结符),把圆点后端的终结符的产生式的第一个项目也加入到当前项目集;
- 重复上面的过程,直到各项目集中的项目不再增加,且每个产生式的每个项目都在项目集中。
对于文法:
构造识别其活前缀的DFA:
构成识别一个文法活前缀的DFA的项目集(状态)的全体称为文法的LR(0)项目集规范族。
因此,上图中框框内的$I_1-I_{11}$就是这个文法的项目集规范族。
分析表(ACTION子表和GOTO子表)
- 将项目集$I_k$的下标k作为分析器的状态,即分析表的行标;
- 规定s表示移进(shift),r表示规约(reduce);
- ACTION[k,a]表示当当前项目集$I_k$遇到终结符a的时候需要采取的动作;GOTO[k,a]表示当前项目集$I_k$遇到非终结符A的时候需要进入哪个项目集,用行标数字表示;
- ACTION子表的动作分为三类:①
sk
,其中k为数字,表示用$I_k$个项目集移进;②rk
,k表示数字,表示用第k条产生式规约;③acc
表示接受;
步骤:
例子:
一般来讲,拓广文法中新增加的那条产生式编号为0。
根据产生式写出文法的规范规约过程
属于算符优先分析的内容,和上面的分析预测不一样。
- 算符优先分析是从下至上的规约过程,是由输入串得到文法的开始符号的过程;
- 分析预测是至上而下的推导过程,是由文法的开始符号得到输入串的过程;
- 上述两种不同的顺序在各自的算法中需要体现在表格里面。
步骤(仅供参考):
- 先按照规范推导(最右推导)的过程得到语法推导树;
- 再开始画表格,开始时符号栈中什么都没有(若是分析预测,符号栈中最开始会有一个开始符号),首先将输入串的第一个字符移进;
- 查看语法推导树,若当前的字符是当前推导树的句柄,则进行规约,否则进行移进;
- 重复上述过程,直到接受。
例题
答案: