Compiler-建立符号表&错误处理-3
建立符号表和错误处理
类图:
说明:
Compiler是程序的入口
Morpho是词法分析器(ReadFile读入testfile.txt文件)
SyntaxParser是语法分析器
SymbolTable 是符号表类
RParam 是函数实参表类
Error 是错误处理类
Node 是递归下降树构建的结点类
Symbol 是符号类
Token 是词牌类
Tag 是First集类
符号表类
什么时候要创建符号表?
CompUnit时创建一个rootTable,其prev上层符号表为nullFuncDef函数定义时MainFuncDef进入主函数int main时Block扫描到{,且当前符号表的defend为false时
说明:
table类型为HashMap。key存储Symbol的name,value存储对应的Symbolprev类型为SymbolTable,上一层的符号表isFunc用于判别此符号表是否为函数定义创建的表position用于记录当前符号表在上一层符号表的环境位置,其值为这个符号表创建时,当前符号表curTable中table的size()(后面发现似乎并不需要这个属性,因为在错误处理的时候是递归过程中进行的)
existReturn用于判别当前符号表是函数时,是否存在return语句。defend只有在函数定义创建符号表的时候设为true,当进入函数定义的Block中时,不必再创建一个符号表了,因为在扫描到函数名称的时候就创建过了,之后设置为false意味着当前函数符号表已经进入到过其本身的Block中了funcName和funcType用于记录当前符号表(函数定义)的函数名称和函数类型.
符号类
什么时候加入符号?
ConstDef常量定义VarDef变量定义FuncDef函数定义,加入到当前符号表中,一般是rootTableFuncFParam函数形参,加入到当前函数符号表中
什么时候查询符号?
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需要判断是否是错误的。