Compiler-建立符号表&错误处理-3
建立符号表和错误处理
类图:

说明:
Compiler是程序的入口
Morpho是词法分析器(ReadFile读入testfile.txt文件)
SyntaxParser是语法分析器
SymbolTable 是符号表类
RParam 是函数实参表类
Error 是错误处理类
Node 是递归下降树构建的结点类
Symbol 是符号类
Token 是词牌类
Tag 是First集类
符号表类

什么时候要创建符号表?
CompUnit
时创建一个rootTable,其prev上层符号表为null
FuncDef
函数定义时MainFuncDef
进入主函数int main时Block
扫描到{
,且当前符号表的defend
为false
时
说明:
table
类型为HashMap
。key
存储Symbol
的name
,value
存储对应的Symbol
prev
类型为SymbolTable
,上一层的符号表isFunc
用于判别此符号表是否为函数定义创建的表position
用于记录当前符号表在上一层符号表的环境位置,其值为这个符号表创建时,当前符号表curTable
中table
的size()(后面发现似乎并不需要这个属性,因为在错误处理的时候是递归过程中进行的)
existReturn
用于判别当前符号表是函数时,是否存在return
语句。defend
只有在函数定义创建符号表的时候设为true
,当进入函数定义的Block
中时,不必再创建一个符号表了,因为在扫描到函数名称的时候就创建过了,之后设置为false
意味着当前函数符号表已经进入到过其本身的Block
中了funcName
和funcType
用于记录当前符号表(函数定义)的函数名称和函数类型.
符号类

什么时候加入符号?
ConstDef
常量定义VarDef
变量定义FuncDef
函数定义,加入到当前符号表中,一般是rootTable
FuncFParam
函数形参,加入到当前函数符号表中
什么时候查询符号?
Stmt
中扫描到LVal
时,是否改变常量LVal
中查询符号(普通变量,一维数组,二维数组)的维度;UnaryExp
中查询符号(函数调用)的维度
上述2/3查询的维度最终加入当前函数的实参列表中,用于错误处理,判断函数调用实参个数和类型(维度)是否匹配
错误处理
b类错误名字重定义:
🧐下面这种也算错误?
1
2int f(int a) {}
void f(int a) {}e类错误: 函数中f(RParam) a[Exp] 所以说
所以存在a(LVal加入当前函数)[Exp→LVal(
加入当前函数)]因此在解读LVal时不应该盲目地将当前的LVal加入当前的函数实参paramMap中,例如
1
2
3
4
5
6
7int f(int x) {return 0;}
int a[2][2] = {{1,2},{3,4}};
int i = 0;
f(a[1][2]);
f(a(0)[(1)b(0)[(1)1(0)](-1)](-2)[(-1)i(0)](-1));
f(a[f(a[i])][0]); //内层函数调用类型出错那是不是也意味着会有
1
2const int n = 0;
a[f(n)];但是这种没要求检测类型不匹配的问题;要求检测函数类型不匹配。
解决方法:
每当进入'['中,就会有widthreal++,说明在[]内时widthreal不为0,则只有当widthreal为零的时候才加入curParam的map中。上述解决方法不行,如果将widthReal设置成全局的,则嵌套调用时上一层的widthReal会丢失,所以想到的解决办法是,每当调用LVal的时候,就新建一个存储其...
其实发现第一种解决方法也是可行的?:
每次扫描到LVal的IDENFR就设置为0,扫描到[就++,扫描到]就减一,但是如果inArray = 0 时扫描到]不要减一了,要保证其永远大于等于0,因为a[b[1]]此处inArray = -1当a[b[1]][此处inArray为零,不正确了i]总结:很简单的思路,当前curParam不等于null,
[
时inArray加一,]
时inArray减一,只有当inArray = 0
时加入当前的curParam的实参列表中即可.(inArray为全局变量.)上面的还是不对....例如
f(a[1][sum(a[0])])
在sum函数中的a[0]就加入不到sum的实参列表中了,所以在RParam中加一个私有参数inArray,而不是全局!测试用例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14int a[2][2] = {{1,2},{3,4}};
int i = 0;
int f(int x) {return 0;}
int sum(int a) {return 0;}
void h(){;}
int main(){
int v[3], i = 0;
if( f(a[1][sum(a[0])])) {}; //e错误
if( f(a[1][sum(a[0][1])])) {}; //正确
f(h());//e错误
f(a[i]);//e错误
f(a[i][i+1]);//正确
return 0;
}注意在构造测试用例的时候:Decl和FuncDef是先后顺序。
对最终输出排序输出用TreeMap
1
2TreeMap sotrdMap = new TreeMap<>(errMap);
对于循环嵌套,多个while需要判断是否是错误的。