编译原理讲义
(第九章 出错处理 )
南京大学计算机系赵建华错误种类
词法错误:在词法分析阶段就可以发现的错误。
语法错误:程序的书写不符合语法规则。
语义错误:
– 静态语义错误:编译程序可以发现。
– 动态语义错误:源程序虽然能够被编译和执行,但是结果不对。一般是逻辑上的错误。
违反环境限制的错误:由于实现方面的问题,有些编译器不接受语言的全集。同时语言本身也有限制。
比如:函数说明嵌套的深度,数组的最大层数。
错误复原
编写程序的过程中,出现错误是不可避免的。
编译程序在进行编译的时候,需要检查出程序的错误。并且给出提示。
当编译程序碰到源程序中的错误的时候,应该设法从错误中复原,并继续扫描程序以给出更多的提示信息。更多的信息使得程序员能够更加方便地修改程序。
可能复原是错误的。所以一般来讲,编译程序给出的第一个错误是可靠的,而其他的错误信息可能是不准确的。
错误复原的要点
株连信息的遏制
– 株连信息是指由于源程序中的一个错误而导致编译程序向用户报告很多相关的出错信息。
而这些信息是不真实的。
重复信息的遏制
– 是指源程序中的一个错误而反映在源程序的多处。
株连信息的例子
已经说明过程 p(int a,int b); 在使用的时候写成了 p(a.b)。
编译程序扫描的时候,首先发现,.”是错误的,应为 a不是结构类型的变量。然后,发现 b是错误的。最后发现 p的参数个数不同。
这些信息都是由于将‘,’误写做‘,’而引起的。
重复信息的例子
如果用户忘了申明变量 i( 或者声明的时候变量的拼写错误),而在程序中多出使用 i。
编译程序在每次碰到对 i的使用的时候都可能发现错误:变量 i没有被定义。
这个错误信息将多次出现。而实际上这个错误是唯一的。
语法错误提示信息(自顶向下)
在自顶向下的扫描过程中,如果扫描程序碰到了非预期的符号输入,最简单的提示方法就是,unexpected symbol,‘?’
自顶向下的分析过程中,扫描程序能够十分清楚地知道当前正在按照什么规则进行扫描,所以提示信息也可以给得更加详细:在扫描的时候碰到非预期的符号??。
语法错误提示信息(自底向上)
当栈顶状态为 S,当前符号为 a,而分析表中
A[S,a]没有相应的值得时候,分析程序检查出源程序的错误。
简单的信息提示可以是:预期扫描 {}但是扫描到了?。其中预期扫描的符号是指所有使
A[S,x]有定义的符号 x。
通过分析 S对应的项集,我们可以知道,当前的分析程序试图规约到什么语法成分。那么提示信息何以更加详细。
错误的定位
在扫描程序检查到错误的时候,需要告诉用户,其错误发生在源程序的什么位置。
简单的方法是:在进行词法分析的时候,
记录下每个词法单位(符号)的行和列。
扫描程序碰到非预期的符号时,可以在提示信息中给出该符号的位置。
错误的复原
错误的复原是指编译程序遇到错误的时候,在给出错误提示后试图越过当前的错误继续扫描。
常用的方法是:对于某个语法成分,如果该语法成分有一个非常确定的符号作为结束符号。那么当扫描这个语法成分时发现错误,程序试图继续扫描到该结束符号。并把这个符号之前的东西规约成为相应的语法成分。
自顶向下时的错误复原
由于当前需要扫描的语法结构是很容易确定的,所以复原的工作相对容易。
在使用递归子程序法的时候,对应于每个语法符号的子程序可以添加两个参数:
– 出现错误时,需要向后看那些符号。
– 在扫描过程中,不能够越过哪些符号。
比如,state(…,{‘;’},{‘}’}
自底向上时的错误复原
首先要分析当前栈顶状态符号对应的项集。根据项集中的项,确定该项集的意义。确定该项集可能对应的规约符号,同时也确定如果碰到非预期的符号的时候,针对该项集应该如何扫描到哪个符号为止。
比如:项集 {E?E.+E,E?E.-E},我们可以确定该项集试图规约得到一个表达式。如果我们没有碰到 +或者 -,那么应该扫描到一个‘ ;’为止。