编译原理大复习
Todo:代码优化
消除左递归及提取左公因式题型
一图解决问题。不再赘述
由语言构造文法
虽然有五种方法,但是把卷子做完一遍以后,最有效的应该还是分解法,能用到的两种方法记录一下。
分解法
这个分解法已经写的很清楚了,但是还是拿一个卷子上的例题来记一下:
\(S->a^m(ab)^nb^m(m>=1,n>=0)\)
首先把中间括号拆开,变为am+n以及bm+n,此时将整个产生式分为前后两个部分,分别对其进行进一步拆解,记为A、B
A->a^m+n,这个产生式很好拆解,可以拆解为A->aA|a
同理,B->b^m+n,也按照同样方式拆解,拆解为B->bB|b
最后将二者拼接在一起,形成L即可
对称法
上图说的很清楚了,不再赘述
等价法
首先不难发现,在语言中,a和b的数量应该一样多,于是乎可以先写一层
那么按照数量关系,当以a开头时,S中已经有了一个a,此时需要一个b,那么就创建一个非终结符来完成。下面当以b开头时也是如此。
接下来就分析S、A、B各产生式中非终结符的数量关系:
S中,a和b的数量应该相同。A中,b的数量应该比a的数量多一,弥补a开头的差距。B中,a的数量应该比b的数量多一,弥补b开头的差距。
下一步就是根据数量关系,进一步构造产生式:
- 首先是A产生式,A产生式的职责在上面已经分析完毕了,就是要负责产生b相关的字符串。首先第一个能想到的非常简单,就是不进行递归产生,只弥补一个a开头时数量的差距。也就是只产生一个b。之后就要考虑递归产生问题,和构造S产生式一样,只需要以b开头,然后递归回S就可以了。但是此时A也是可以以a开头的,这样就产生了两个a,根据数量关系,aA构成一个S,此时S中a和b数量相同,只需要考虑把a开头的一个差距弥补,所以最后末尾再补一个A负责产生b即可,最终结果如下图
- 同理,B的产生式也很好构建,即为aS,a,bBB
NFA确定及最小化
写几个自己错误过的点,简单记录一下:
- 首先是转换表第一格,直接求个开始状态的ε闭包。求ε闭包记得要把自身也加进去。
- 之后就是求第一列相对应的Ia、Ib闭包,步骤为先寻找通过第一列对应ε闭包中某一状态节点出发经过
一条
弧可以到达的状态节点的全体,注意是一条arc - 之后就要进行第二步,求解Ia或Ib闭包的ε闭包,将结果填写至表格中
- 最终将含有终态的状态集合记为终态,不含有终态的状态集合记为普通状态画图即可
之后是将DFA最小化的流程: - 首先将整个状态按照终态与非终态的标准划分为两部分集合,之后各对两个集合内部进行进一步划分
- 按照接受某字符到达状态类型是否相同的标准进行进一步划分
逆波兰及三元式
题目一般都很简单,主要重点就是——逆波兰要按计算优先级倒着来,三元式则按计算优先级正着来。
LR(1)文法分析器
其实这想都不用想就知道肯定考LR(1)分析器,因为可以直接把所有的自底向上分析方式全考了。
LR(1)分析是为了解决SLR(1)无法解决的规约/规约冲突类型。有几点需要注意:
- 首先需要拓展文法,加入新的开始符号
- 在创建项目集过程中,读取符号如果扫描到了非终结符,就要将该非终结符的所有产生式都加入项目集中