8 错误处理

1 概述

1.1 错误处理是编译器的必备功能之一

  • 正确的源程序:通过编译,生成目标代码。
  • 错误的源程序:通过编译,发现并指出错误。
    对于错误的源程序不能一发现就停止,而是要能检查出错误的性质和出错位置,并使编译能继续下去,同时尽可能多而准确地发现错误和指出各种错误

1.2 编译器的错误处理能力

  1. 诊察错误的能力。
  2. 报错及时准确(出错位置,错误性质)。
  3. 一次编译尽量找出所有错误。
  4. 改正错误的能力。
  5. 遏制重复错误信息的能力。重复的错误报一次就好

2 错误的分类

  • 语法错误
    程序结构不符合语法(包括词法)规则的错误。
    A[x, y := 3,1416+T(T+H)
  • 语义错误
    程序不符合语义规则超越具体计算机系统的限制
    超越系统限制:(计算机系统和编译系统)
    1. 数据溢出错误,常数太大,计算结果溢出。(计算机系统限制)
    2. 符号表、静态存储分配数据区溢出。 (计算机系统限制)
    3. 动态存储分配数据区溢出。 (计算机系统限制)
    4. 标识符要先声明再引用。 (编译系统限制)
    5. 过程调用时,实参和形参个数必须相等,依次具有相同的类型。(编译)

3 错误的诊断和报告

3.1 错误诊察

  1. 违反语法和语义规则以及超过编译系统限制的错误。
    编译程序在语法和语义分析过程中诊察出来。(语义分析要借助符号表)
  2. 下标越界、计算结果溢出以及动态存储数据区溢出等
    在目标程序运行时才能检测,因此由目标程序诊察。
    对此,编译程序要生成相应的目标程序代码进行检查并处理。

3.2 错误报告

  1. 出错位置:即源程序中出现错误的位置。
    实现:设立行号计数器 line-no
    设立单词序号计数器 char-no
    一旦诊察出错误,当前的计数器内容就是出错位置。
  2. 出错性质
    可直接显示文字信息
    可给出错误编码
  3. 报告错误(两种方式)
    1. 分析以后再报告(显示或者打印)
      编译程序可设一个保存错误信息的数据区(可用记录型数组),将语法语义分析所诊断到的错误送数据区保存,待源程序分析完以后,统一显示或打印错误信息。
      Pasted image 20250925104620.png
    2. 边分析边报告
      在分析一行源程序时若发现有错,可以立即输出该行源程序,并在其下输出错误信息。
      Pasted image 20250925104639.png

4 错误处理技术

发现错误后,在报告错误的同时还要对错误进行处理,以方便编译能继续进行下去。目前有两种处理办法

4.1 错误改正

指编译诊察出错误以后,根据文法进行错误改正

但不是总能做到,如:A := B – C * D + E )

  • 是多一个右括号还是少一个左括号?
  • 如果是少了左括号,应该少在何处?

4.2 错误局部化处理

指当编译程序发现错误后,尽可能将把错误的影响限制在一个局部的范围,避免错误扩散和影响程序其它部分的分析。

  1. 一般原则
    当诊断到错误以后,就暂停对后面符号的分析,跳过错误所在的语法成分(一旦跳过就认为该语法成分是正确的)然后继续往下分析。
    • 词法分析:发现不合法字符,显示错误,并跳过该标识符(单词)继续往下分析。
    • 语法语义分析跳过所在的语法成分(短语或语句),一般是跳到语句右界符,然后从新语句继续往下分析。
  2. 错误局部化处理的实现
    CX:全局变量,存放错误信息。
    • 用递归下降分析时,如果发现错误,便将有关错误信息(字符串或者编号)送CX,然后转出错误处理程序;
    • 出错程序先打印或显示出错位置以及出错信息,然后跳出一段源程序,直到跳到语句的右界符(如end、; ),或正在分析的语法成分的合法后继符号为止,然后再往下分析。
例子

Pasted image 20250925105812.png
Pasted image 20250925105830.png

  1. 提高错误局部化程度的方法
    设 S1: 合法后继符号集 (某语法成分的后继符号)
    S2: 停止符号(跳读必须停止的符号集)
    Pasted image 20250925105937.png

4.3 目标程序运行时错误检测与处理

  • 下标变量下标值越界
  • 计算结果溢出
  • 动态存储分配数据区溢出

在编译时生成检测该类错误的代码对于这类错误,要正确地报告出错误位置很难,因为目标程序与源程序之间难以建立位置上的对应关系。

  • 一般处理办法:
    当目标程序运行检测到这类错误时,就调用异常处理,打印错误信息和运行现场(寄存器和存储器中的值)等,然后停止程序运行

4.4 遏制重复的错误信息

  • 语义错误主要来源于标识符未声明和类型不一致等,这些错误往往会多次出现。
    该标识符的每一次引用都会出现“标识符未声明”错误。
    • 处理办法:
      建立一张错误名字表,每当发现出错名字后,先查表,若有,则不再打印错误信息;否则登入该表,并打印错误信息。
  • 溢出错误:编译程序所需的工作区或源程序所需的数据区域溢出
    需要使编译正常运行,同时遏制重复的错误信息
    • 处理办法:
      对各数据区分别设置一个标志单元,初始为0,当发生溢出时,则查看单元内容,若为0,表示刚发生溢出,打印错误信息,置1;若为1,不再重复打印。
Built with MDFriday ❤️