1.1 类型检查
1.1.1 表达式类型检查
1.1.1.1 _Expression节点扩展
为_Expression节点类分别添加一个表示表达式类型的域
//语义分析相关
public:
string expressionType;//区别于type,这个值表示表达式的具体类型,即int、real、char、bool、error,其中error表示表达式中包含类型不一致的操作数等情况
1.1.1.2 _VariantReference节点扩展
为_VariantReference节点类分别添加一个表示变量、常量或数组元素类型的域
public:
string variantType;//int、real、char、bool、error,其中error表示数组某一维下标表达式的类型不为"int"或标识符不存在
1.1.1.3 _FunctionCall节点扩展
为_FunctionCall节点类分别添加一个表示返回值类型的域
public:
string returnType;//int、real、char、bool、error,其中error表示函数标识符不存在
1.1.1.4 _Expression节点类型分析
节点类型 | 分析 |
---|---|
“var” |
其取值由_VariantReference类表示,有可能是变量、常量或者数组。获取_VariantReference的类型即为当前var的类型。注意当_VariantReference表示数组时,当某一维的下标表达式类型不为”int”时,其类型应设为”error”,但是返回给其父_Expression节点时,应返回查符号表得到的元素类型。 |
“int” |
返回”int”。 |
“real” |
返回”real”。 |
“function” |
其返回值由_FunctionCall类表示,获取_FunctionCall的类型即可。 |
“compound”:: “relop” |
关系运算符,如果两个子表达式类型一致,且不为error,或者其中一方类型为”int”,另一方类型为”real”,则返回”bool”;否则返回”error”。 |
“compound”:: “NOT” |
取非运算符,如果子表达式类型为”bool”,则返回”bool”;否则返回”error”。 |
“compound”:: “minus” |
取相反数运算符,如果子表达式类型为”int”,则返回”int”;如果子表达式类型为”real”,则返回”real”;否则返回”error”。 |
“compound”:: “bracket” | 直接调用子表达式的获取类型的方法。 |
“compound”:: ”+” || ”-” || ”*” || ”/” | 算术运算符,如果两个子表达式类型一致,且不为error,则类型为子表达式的类型;如果其中一方类型为”int”,另一方类型为”real”,则类型为”real”;否则类型为”error”。 |
“compound”:: ”div” || ”mod” | 如果两个子表达式类型均为”int”,则类型为“int”;否则类型为”error”。 |
“compound”:: ”and” || ”or” |
如果两个子表达式类型均为”bool”,则类型为”bool”;否则类型为”error”。 |
_FunctionCall节点类型分析 | 检查函数调用各个实际参数与符号表中形式参数的一致性(也仅支持int到real的隐式类型转换) 查符号表,如果没有查到,则为error;查到但不为function,也为error;查到且为function,返回其类型 |
1.1.1.5 _VariantReference节点类型分析
如果是数组,则需检查各维下标表达式的类型是否为"int"<br /> 如果是变量或常量,则需查符号表,方法类似functionCall
1.1.2 语句的类型检查
在程序设计语言中,像语句、语句序列、程序等这样的语法成分是没有数据类型的,这里所说的语句的类型检查是一种广义的类型检查,即,如果这些结构中不含有类型错误,就把回避类型void指派给它;如果在语句中发现了类型错误,则将类型error指派给它。
1.1.2.1 AST语句类扩展
_Statement基类添加语句类型域,各派生类通过继承获得该类型域。
string statementType;//区别于type,取值为"void"或"error"
1.1.2.2 各种语句类型分析
语句类型 | 分析 |
---|---|
赋值语句 |
检查左边变量类型和右边表达式类型是否相同(或有隐式转换),不匹配则报错 |
过程调用语句 |
①首先检查符号表中是否有该函数/过程,如果没有则报错; ②如果有检查参数的个数以及各参数的类型与其对应的符号表中形参类型是否匹配,如果不匹配则报错 |
if条件语句 |
①检查表达式和语句的类型是否为error,如果有任何一个是error则报错 ②检查if后的表达式是否为bool,不是则报错 |
for循环语句 |
①检查终值、初值是否均为int,如果不是则报错 ②检查语句类型是否为error,如果是则报错 |
while循环语句 |
①检查表达式的类型是否为bool,如果不是则报错 ②检查语句的类型是否为error,如果是则报错 |
repeat循环语句 |
①检查表达式是否有类型错误以及语句类型是否为error,如果有则报错 ②检查until后的表达式类型是否为bool,不是则报错 |
compound语句 | 检查vector中每一条Statement是否有类型错误,任意一条有错则报错,由于compound语句是继承statement的子类,因此要调用子类的属性需要将statement类型的参数利用reinterpret_cast函数转化成compound类之后,再对其进行语义分析。 |
1.1.3 程序调用参数类型检查
1.1.3.1 用户自定义程序的调用
遇到用户自定义程序的调用时,在形参与实参个数相同的前提下,只需要检查对应位置的形参和实参的类型是否相同,实参的类型通过对实参类型表达式的语义分析获得,形参的类型则通过查符号表的固定位置即可(参见1符号表设计),即第1到第amount个位置存放的是当前程序所定义的所有参数。
1.1.3.2 库程序的调用
read在实参个数和种类为变量(普通变量、参数、数组元素)的情况下,要求其类型不能为boolean。
write和writeln对实参表达式没有任何限制。
exit在函数定义中出现时,作为该函数的返回值语句,要求其唯一的实参表达式的类型与当前所在函数定义的返回值类型一致。(按照前文,直接找到当前符号表最前面的记录,就可以找到当前函数定义的类型)。
另外,还必须强调传值参数和引用参数的区别。当形式参数为传值参数时,支持实参为integer,形参为real的隐式类型转换,但当形式参数为引用参数时,类型必须强一致,不支持隐式类型转换。
1.1.4 函数返回值类型检查
如果检测到当前语句是返回值语句,需检查提供的返回值表达式与函数返回值类型是否一致,函数返回值语句的两种表现形式前文已提及,不再赘述。
1.1.5 数组下标表达式类型检查
引用数组元素时,其下标应为integer类型,所以需检查数组下标表达式是否为integer类型。
1.1.6 循环变量类型检查
for语句中的循环变量应检查是否为integer类型。