【编译原理】原理笔记
随便记点防止期末烂掉
自顶向下
直接左递归的消除
实际就是左递归转右递归
法1:直接替换
法2:矩阵法
前置知识:
原理:
例题
求FIRST集
就只看右边推出来的第一个字符就好了
\(A\to B\):FIRST 就是 \(B\) 的第一个字符(B可以是一坨)
求FOLLOW集
起始符先加入一个 # 到集合中
看右边的右边:\(B\to \alpha A\beta\) (\(\beta\) 可以是一坨东西)
看产生式右边的 \(\beta\):
- \(\beta\) 是终结符,= 终结符
- \(\beta\) 是非终结符,= FIRST(\(\beta\))- ε
- \(\beta\) 是空,= FOLLOW(\(B\))
FOLLOW里面不可能有 \(\epsilon\)
\(\forall X\in V_N\),有 # $ \in FOLLOW(X)$,条件是: \(S\Rightarrow^* \alpha X\),其中 \(\alpha\in(V_N ∪ V_T)^*\)
SELECT集
对于 \(A\to \alpha\)
\(\alpha\) 能推出空:\(\{FIRST(\alpha)-\epsilon\} \,\,∪\,\,\{FOLLOW(A)\}\)
\(\alpha\) 不能推出空:\(FIRST(\alpha)\)
LL(1)文法
同一非终结集的文法的 \(SELECT\) 集无交集
自底向上
LR(0)分析表构造
1.扩展文法:加一条 \(E'\to E\),并且把所有并在一起的拆开来写成单产生式
2.写 \(I_0\):扩展后的文法,每一条右边加上 \(·\),比如 \(E'\to E\) 变为 \(E'\to ·E\)
3.对 \(I_0\) 中的每一条产生式分析,根据 · 后面接收的字符转移到下一个状态。新状态中 · 右移一位,右移后 · 的右边如果接的是非终结符,则要把该非终结符对应的所有产生式写在当前新状态里。例:\(E\to ·ET\) 接收 \(E\) 转移到 \(\{E\to E·T\),\(T\to ...\),\(T\to ...\}\)
4.注意新生成的状态中,如果产生式是已经存在于某个状态的,就直接转移过去(也有可能转移到自身)
5.一直重复对状态的转移,直至状态中所有的产生式的 · 都在最右边
6.状态转移图生成完之后就可以开始写分析表了,框架是:列为状态,有多少个状态就写多少列;行是所有产生式右侧出现过的符号,分为终结符ACTION和非终结符GOTO
7.接着开始根据状态图填表:按出边填
- 当前状态有出边:转移到ACTION要在状态前加一个s,转移到GOTO直接写下状态的数字
- 当前状态无出边(终结态):如果当前状态对应的是第 \(i\) 条产生式,直接把这一行的ACTION全部写上 \(r_i\)
- 确定 \(acc\) 态:\(E'\to E\,·\) 所在的状态,# 那列
例题
LR(0) 分析步骤
分析串s
1.表头:状态,符号,输入串
2.第一行:0,#,s#
3.查ACTION表,看上一行状态的最后一位接收串的第一个字符后到达什么状态:
- \(s_i\) :状态后加上 \(i\);当前输入串的第一个字符挪到符号后;
- \(r_i\) :找到第 \(i\) 个产生式,把符号后缀对应的产生式右侧(假设长度为 \(n\))替换为左侧非终结符。此时为了保证状态数和符号数一样,对应状态也要舍去后面的\(n\) 个状态。舍去后状态数比符号数少一个,继续查GOTO表,当前状态的最后一位接收符号的最后一位得到的数字填上去,保证数量一样。输入串不变。
- \(acc\):接收成功,分析结束
4.注意状态数和符号数始终相等
例题
第五章
综合属性继承属性
addtype
参考
$$
:产生式左侧的字符的属性