前言
参考课上PPT内容。 该学习笔记目前仅打算个人使用。
后续会进一步整理,包括添加笔记内容,标明参考资料。
更新中。。。
跳过目录
目录
- 一、错误处理方法
- 二、错误改正
- 三、错误局部化处理
-
- 一般原则
- 错误局部化处理的实现(递归下降分析法)
- 提高错误局部化程度的方法
- LL分析的错误恢复——补充(第四章内容!)
一、错误处理方法
发现错误后,在报告错误的同时还要对错误进行处理,以便编译能继续进行下去。
目前有两种处理办法:
- 错误改正
- 错误局部化处理
二、错误改正
指编译诊察出错误以后,根据语言的文法和对程序意图作某种猜测,进行错误改正。
例:
A[i, j := B + * C
- 编译可根据 A 的定义(声明),查符号表知道 A 是二维数据,所以应加上“ ] ”;
- 根据表达式定义去掉
(但也有可能去掉*
)+
但不是总能做到改正错误
例:
- 多一个右括号还是少一个左括号?
- 若是少了左括号,少在何处?
所以,要正确地改写错误是很困难的。
三、错误局部化处理
指当编译程序发现错误后,尽可能将把错误的影响限制在一个局部的范围,避免错误扩散和影响程序其它部分的分析。
一般原则
当诊断到错误以后,就暂停对后面符号的分析,跳过错误所在的语法成分(一旦跳过就认为该语法成分是正确的)然后继续往下分析。
词法分析:
- 发现不合法字符,显示错误,并跳过该标识符(单词)继续往下分析。
语法语义分析:
- 跳过所在的语法成分(短语或语句),一般是跳到语句右界符,然后从新语句继续往下分析。
错误局部化处理的实现(递归下降分析法)
CX:全局变量,存放错误信息。
- 用递归下降分析时,如果发现错误,便将有关错误信息(字符串或者编号)送CX,然后转出错误处理程序;
- 出错程序先打印或显示出错位置以及出错信息,然后跳出一段源程序,直到跳到语句的右界符(如
、end
),或正在分析的语法成分的合法后继符号为止,然后再往下分析。;
例:条件语句分析
有如下分析程序:
void if_statement()
{
nextsym(); // 读下个单词符号
B(); // 调用布尔表达式处理程序
if (class ! = thensy)
{
cx = 错误'缺then'的编号; // 错误性质送cx
error(); // 调用出错处理程序
}
else
{
nextsym();
statement(); // 调用语句分析程序
}
if (class == elsesy)
{
nextsym();
statement();
}
} // end of if_statement()
局部化处理的出错程序为:
void error()
{
printf("%d, %d, %d\n", cx, 源程序行号, 序号);
do
{
nextsym();
}
until(class == semicolon || class == endsy || class == elsesy)
} //end of error()
可以看出,如发现错误就立即跳到语句结尾处(语句右界符 end , ; 等)。这样的处理比较粗糙,将跳过太多。上例中缺then,就将跳过整个条件语句,使得then后面的语句都被跳过而不分析,其中若有错误就发现不了。
例:ALGOL说明
real x, 1a, a, bed, 2fg;
语法分析时,可发现第二个标识符有错,按上述处理办法则跳到该语句的右界符
;
,这导致最后一个标识符的错误未检查出来,且因为正确说明的标识符 a 、 bed 未进
行分析,则后面对这两个标识符 的引用都将被判定为未 声 明 。
提高错误局部化程度的方法
设:
- S1:合法后继符号集 (某语法成分的后继符号)
- S2:停止符号(跳读必须停止的符号集)
当发现错误时:error( S1, S2 )
procedure error( S1, S2 )
begin
write( line-no, char-no, cx);
repeat
nextsym
until( class in S1 or class in S2 );
end error;
上面例题中的 if 语句中,若<B>有错,则可跳到then;
若statement有错,则可跳到 else。
LL分析的错误恢复——补充(第四章内容!)
当符号栈顶的终结符和下一个输入符号不匹配,或栈顶是非终结符A,输入符号a,而M [A , a]为空白(即error)时,则分析发现错误。
错误恢复的基本思想是:跳过一些输入符号,直到期望的同步符号之一出现为止。
同步符号(可重新开始继续分析的输入符号)集合通常可按以下方法确定:
- 把FOLLOW(A)的所有符号加入A的同步符号集。如果我们跳读一些输入符号直到出现FOLLOW(A)的符号,之后把 A 从栈中弹出,继续往下分析即可。
- 只用FOLLOW(A)作为非终结符A的同步符号集是不够的(容易造成跳读过多,如输入串中缺少语句结束符分号时)。此时可将作为语句开头的关键字加入它的同步符号集,从而避免这种情况的发生。
- 把FIRST(A)的符号加入非终结符A的同步符号集中。
- 如果非终结符A可以产生空串,那么推导ε的产生式可以作为缺省的情况。这样做可以推迟某些错误检查,但不会漏过错误。
- 如果终结符在栈顶而不能匹配,则可弹出该终结符并发出一条信息后继续分析。这好比把所有其他符号均作为该符号的同步集合元素。
-
目标程序运行时错误检测与处理
对于这类错误,要正确地报告出错误位置很难,因为目标程序与源程序之间难以建立位置上的对应关系。
在编译时生成检测该类错误的代码。
• 下标变量下标值越界
• 计算结果溢出
• 动态存储分配数据区溢出
一般处理办法:
当目标程序运行检测到这类错误时,就调用异常处理,打印错误信息和运行现场(寄存器和存储器中的值)等,然后停止程序运行。