3.3 自上而下分析
3.3 自上而下分析
3.3.1 自上而下分析的一般方法
例 文法
S → aCb C
cd | c
为输入串w = acb建立分析树

不能处理左递归的例子

不能处理左递归、复杂的回溯技术、回溯导致语义工作推倒重来、难以报告出错的确切位置、效率低
3.3.2 LL(1)文法
对文法加什么样的限制可以保证没有回溯?
先定义两个和文法有关的函数

LL(1)文法定义

LL(1)文法有一些明显的性质
- 没有公共左因子
- 不是二义的
- 不含左递归
查找非终结符的First集
Step 1. 按产生式顺序来,从开始符找起;
Step 2. 如果右部的串首为终结符,则直接将该终结符填入左部非终结符的First集中;
Step 3. 如果右部的串首为非终结符,则左部非终结符的First集等价于串首非终结符的First集。因而,需要利用Step 2和Step 3继续寻找串首非终结符的First集。
查找非终结符的Follow集
Step 1. 按产生式顺序来,从开始符找起(开始符的Follow集必定包含$);
**Step 2. **从所有产生式右部寻找目标非终结符,若其后紧跟终结符,则将终结符填入目标非终结符的Follow集。特别地,若其后紧跟$,则目标非终结符的Follow集等价于产生式左部非终结符的Follow集。
Step 3. 从所有产生式右部寻找目标非终结符,若其后紧跟非终结符,则将该非终结符的First集元素填入目标非终结符的Follow集。特别地,若该非终结符的First集元素中包含,则需针对情况时做特殊处理,即目标非终结符的Follow集等价于产生式左部非终结符的Follow集。

3.3.3 递归下降的预测分析
- 为每一个非终结符写一个分析过程
- 这些过程可能是递归的

一个辅助过程
void match (terminal t) {
if (lookahead == t) lookahead = nextToken( );
else error( );
}
void type( ) {
if ( (lookahead == integer) || (lookahead == char) ||
(lookahead == num) )
simple( );
else if ( lookahead == ) { match(); match(id);}
else if (lookahead == array) {
match(array); match( [ ); simple( );
match( ] ); match(of ); type( );
}
else error( );
}
void simple( ) {
if ( lookahead == integer) match(integer);
else if (lookahead == char) match(char);
else if (lookahead == num) {
match(num); match(dotdot); match(num);
}
else error( );
}
3.3.4 非递归的预测分析

分析表的一部分

预测分析器接受输入id * id + id的前一部分动作

3.3.5 构造预测分析表

3.3.6 预测分析的错误恢复
1、先对编译器的错误处理做一个概述
- 词法错误,如标识符、关键字或算符的拼写错
- 语法错误,如算术表达式的括号不配对
- 语义错误,如算符作用于不相容的运算对象
- 逻辑错误,如无穷的递归调用
2、分析器对错误处理的基本目标
- 清楚而准确地报告错误的出现,并尽量少出现伪错误
- 迅速地从每个错误中恢复过来,以便诊断后面的错误
- 它不应该使正确程序的处理速度降低太多
3、非递归预测分析在什么场合下发现错误
栈顶的终结符和下一个输入符号不匹配
4、非递归预测分析:采用紧急方式的错误恢复
发现错误时,分析器每次抛弃一个输入记号,直到输入记号属于某个指定的同步记号集合为止
5、同步
- 词法分析器当前提供的记号流能够构成的语法构造,正是语法分析器所期望的
- 不同步的例子
- 语法分析器期望剩余的前缀构成过程调用语句,而实际剩余的前缀形成赋值语句


浙公网安备 33010602011771号