编译阶段
编译的过程分为词法分析、语法分析、语义分析、中间代码生成、机器无关代码优化、目标代码生成、机器相关代码优化等几个步骤。词法分析、语法分析、语义分析、中间代码生成统一称为分析部分(前端),目标代码生成、机器相关代码优化被统一称为综合部分(后端)。 当语法分析、语义分析、中间代码生成三个部分合在一起时称为语法制导翻译。
词法分析
词法分析的主要任务是从左向右扫描源程序的字符,识别出各个单词,确定单词的类型,并将识别出的单词转换为统一的机内表示——词法单元( token)形式。
自顶向下分析
从文法的开始符号开始进行分析的过程被称为自顶向下分析.
最左推导: 从文法开始符号的产生式中最左的符号开始替换的推导方式被称为最左推导。 最左推导对应的规约方式被称为最右规约。
最右推导: 从文法开始符号的产生式中最右的符号开始替换的推导方式被称为最右推导。 最右推导对应的规约方式被称为最左规约。
递归下降分析: 递归下降解析器由一组相互递归的程序(或等价的非递归程序)构建而成,其中每个程序都实现了文法中的一个非终结符。
左递归: 若
左递归的消除:
通过引入非终结符和空产生式将直接左递归转化为右递归;
如下算法消除间接左递归:
sort all non-terminal
; : : - rewrite
into , where ;
- rewrite
eliminate directly left-recursion.
几类重要集合
First 集是指文法
如果
对于串
if
, return ; , ; forall
: ; ? , break;
? ; return
.
Follow 集是指文法
如果
计算非终结符
; forall
: if
is like , ; elif
is like , ; elif
is like , ; else continue;
return
.
计算文法
- forall
, supose is like : ; - forall
: ;
- repeate #1 until no changes.
可选集是指选用产生式
从而对于产生式
LL(1) 文法
即从左(left)向右扫描的最左(left)推导文法, 且有一个(1) 前看符号.
称文法
若
, 则 ; 和 至多有一个推导出 ; , 若 则 .
表驱动的预测分析法
使用 PDA 进行分析预测的方式即为表驱动的预测分析法,也称为非递归的预测分析法.
首先根据文法
然后设置驱动程序为:
输入: 符号串
和文法 的分析表 ; 输出: 若
, 则输出 的最左推导,否则给出错误指示; 设
为驱动程序采用的 PDA, 则算法为: be current stack series, ; while
: if
: ; ;
elif
: - raise error;
elif
: - raise error;
elif
: output
; .
即可进行表驱动的预测分析.
注意
表驱动预测分析法的步骤:
消除二义性, 消除左递归;
提取左公因子,消除回溯;
求
集合; 若
有交集,则非 LL(1) 文法,无法进行自顶向下分析; 否则 根据
集合求出预测分析表; 使用驱动程序进行预测分析.
自底向上分析
从输入串
移入-规约分析时自底向上分析普遍采用的分析形式.
移入-规约分析的下推自动机:
be a PDA: ; ; for
: ; , if no reduction; , if ; , if , where is a state has been analyzed; , if . otherwise
.
, otherwise .
项是指文法
增广文法(Augmented Grammar)是指在
项目闭包是指项目集合
项目闭包的计算算法为:
; , : if
: ;
repeat #1 until no new item added to
.
Goto 集合是指状态集合
显然,我们要求每一个状态
LR(0) 文法
即从左(left)向右扫描的最右(right)推导的文法, 且向前零个(0)符号.
LR(0) 分析器就是上述移入-规约分析的下推自动机, 当
若
, ; 若
, .
而对于 LR(0) 的规约,则为
因而 LR(0) 只能处理前缀不同的规约规则.
SLR(1) 文法
即从左(left)向右扫描的最右(right)推导的文法, 且向前看一个(1)符号, 采用极简(S)的前看方式.
SLR(1) 的自动机的栈被修改为
SLR(1) 的
SLR(1) 能处理有相同前缀的情况,但是却不能处理一个规则有不同后继的情况.
LR(1) 文法
即从左(left)向右扫描的最右(right)推导的文法, 且向前看一个(1)符号.
LR(1) 根据产生式的
同时,项目集闭包的算法也有所不同:
; , : : if
: ;
repeat #1 until no new item added to
.
同样,
LR(1) 分析器也不会改变对
若
, ; 若
, .
而对于 LR(1) 的规约,则为
即后继状态
由于后继状态依赖于前看符号,因此 LR(1) 能处理不同后缀的文法,但是也正因此,LR(1) 的状态数量急剧膨胀.
LALR(1) 文法
为解决 LR(1) 的状态膨胀的问题,LALR(1) 引入合并同心项目集合的操作.
若
将具有相同核心的状态合并为同一个状态的操作,则称为合并同心项目集.
将 LR(1) 分析表进行合并同心项目集即可得到 LALR(1).
但是合并同心项目集合有可能导致归约-归约冲突, 这是因为在合并时忽略了前看符号.
仅合并具有相同项目