Symbol Table and Exception
错误处理和符号表
类的设计
SysYTree
- 主要作用:遍历抽象语法树,检查语义。
- 成员方法:
SymbolTable check(SymbolTable table, boolean inLoop)
:在遍历过程中对所有语法结点检查语义。
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
。