Symbol Table and Exception

错误处理和符号表

类的设计

SysYTree

  • 主要作用:遍历抽象语法树,检查语义。
  • 成员方法:
    • SymbolTable check(SymbolTable table, boolean inLoop):在遍历过程中对所有语法结点检查语义。

ast

SysYException

  • 主要作用:错误类,继承自Exception
  • 成员属性:
    • EKind kind:错误种类。
    • int line:错误所在行。

SymbolTable

  • 主要作用:建立符号表,用于错误处理。
  • 成员属性:
    • Map<String, SysYSymbol>:根据符号名索引符号节点。
    • SymbolTable parent:记录父符号表。
  • 成员方法:
    • SysYSymbol findSymbol(String name):在当前符号表内查找符号。
    • SysYSymbol findSymbolInAll(String name):在当前符号表及所有父符号表中查找符号。
    • void addSymbol(SysYSymbol symbol):添加一个符号,若当前符号表中冲突则报错。

Writer

  • 主要作用:按格式输出错误行数及种类。
  • 成员属性:
    • List<Token> tokens:记录该文件所有读入的Token
    • String filename:记录输出的文件名。
    • BufferedWriter bw:用来输出文件内容。
  • 成员方法:
    • void writeError(SysYException error):将错误按格式输出到对应文件中。

Compiler

  • 主要作用:主编译器,调用所有类和方法完成编译过程。

错误处理

借鉴了叶学长的思路,将错误分为三类,分别在词法分析,语法分析和遍历语法树的过程中处理错误。

词法分析过程

a类错误比较简单,只需遍历一次字符串即可,且与其他错误关系不大,可以在词法分析中完成(当然,在后面完成也是可以的)。

语法分析过程

主要负责处理i,j,k类错误,这三个错误较为类似,与其他错误关系不大,且在生成抽象语法树时不会保存分隔符这些意义不大的信息,因此可以在语法分析过程中处理。

遍历语法树过程

剩下的复杂的错误都在这个过程中处理。

基础设计

基类SysYSymbol

  • 需要加入到符号表中的类,包括SysYDef, SysYFuncDef, SysYFuncParam, SysYMainFuncDef
  • 定义了抽象方法SymbolKind getKind(),符号种类包括CONST, VARIABLE, FUNCTION, PARAMETER, MAIN_FUNCTION

符号表类SymbolTable

  • 定义了成员属性STkind kind,符号表种类包括INT_FUNCTION, VOID_FUNCTION, BLOCK
  • 每次进入一个新的block时,需要新建一个符号表,根据是否为函数和函数返回类型赋予符号表种类,并与现符号表建立联系。

基类SysYExpression

  • 定义了抽象方法ReturnKind getRetKind(),返回值类型包括VOID, INT, ONE_DIM, TWO_DIM

具体实现

主体函数为SymbolTable check(SymbolTable table, boolean inLoop),对于每一个语法树结点,传入一个符号表,处理后返回一个符号表。

  • b:在当前符号表内加入一个符号,若产生冲突则报错。
  • c:在当前符号表及其所有父符号表中查找该符号,若没有结果则报错。
  • d,e:
    • 遇到函数调用时,先搜索符号,若符号不存在或符号不是函数定义类,则报c类错误;
    • 搜索到之后,判断形参个数与实参个数是否相同,不同则报d类错误;
    • 再依次判断每个参数的类型是否符号,此处可以调用getRetKind()来判断。
  • f,g:当进入一个block且该block对应的符号表为函数时,需要进行判断:
    • 若函数返回类型为int且函数体最后一句不为return,报g类错误;
    • 若函数返回类型为void且函数体中出现某一句return后有返回值,报f类错误。
  • h:在赋值语句检查时,若左值查找为常量则报错。
  • l:可以类比d类错误,不再赘述。
  • m:根据参数inLoop判断,记得在while结点检查时将inLoop设为true