语义分析
语法分析只是分析了代码在语法上是不是合法的, 但是代码仍然有可能存在问题, 比如一些需要上下文才能分析的错误, 语法分析就不能分析出来. 比如下面的代码
a = 10;
从语法上来看, 这是一句合法的赋值语句. 但是从语义上看, 我们并不知道a
有没有被声明为变量, 类型是否和10
匹配. 这一次我们将介绍语义分析.
分析内容
不同的人做语义分析, 分析的内容都有不同, 比如有些人会把数组越界作为分析的内容, 而我认为这并没有意义, 因为我们的代码实际上是允许数组下标为变量的, 不到运行时是没法判断的, 所以我将数组越界作为运行时错误处理, 类型不匹配也是在运行时检查. 我在语义分析中会检查如下内容:
- 变量未声明
- 除0
但我们的语义分析并非一个独立的过程, 而是在代码生成的同时完成的.
代码生成
这里的代码指的是中间代码, 虽然我不明白为什么解释器需要生成中间代码, 老师非得要求, 我也只好做了, 不做就是0分. 我的代码生成器其实是从最早的解释器改造过来的, 所以只要搞清楚TreeNode
中存储的数据的意义, 完全可以不进行代码生成直接解释. 这里按照需要生成中间代码的情况进行处理.
中间代码的定义
我发现这事其实比较坑, 没有看到中间代码的详细定义, 那么我为了方便, 自己定义了一些中间代码, 虽然是有冗余, 不过用起来比较方便就是.
下面是中间代码的所有种类:
public static final String JMP = "jmp";
public static final String READ = "read";
public static final String WRITE = "write";
public static final String IN = "in";
public static final String OUT = "out";
public static final String INT = "int";
public static final String REAL = "real";
public static final String ASSIGN = "assign";
public static final String PLUS = "+";
public static final String MINUS = "-";
public static final String MUL = "*";
public static