第116集:表达式类型检查
核心知识点讲解
算术表达式类型检查
算术表达式是最常见的表达式类型,包括加减乘除等操作。算术表达式的类型检查需要考虑以下几点:
操作数类型:
- 算术操作通常要求操作数是数值类型(int, float, double等)
- 不同数值类型之间的操作需要进行类型提升
类型提升规则:
- 当操作数类型不同时,会自动提升到更宽的类型
- 例如:int + float → float
- 例如:float * double → double
结果类型:
- 算术表达式的结果类型通常是操作数提升后的类型
- 例如:int + int → int
- 例如:int + float → float
特殊情况:
- 除法操作:整数除法和浮点数除法的行为不同
- 取模操作:通常只适用于整数类型
关系表达式类型检查
关系表达式用于比较两个值的大小关系,结果为布尔类型。关系表达式的类型检查规则:
操作数类型:
- 关系操作通常要求操作数类型相同
- 数值类型之间可以进行比较
- 某些语言允许字符串之间的比较
结果类型:
- 所有关系表达式的结果类型都是布尔类型(bool)
- 例如:a > b → bool
- 例如:x == y → bool
支持的操作符:
- 等于(==)
- 不等于(!=)
- 小于(<)
- 大于(>)
- 小于等于(<=)
- 大于等于(>=)
逻辑表达式类型检查
逻辑表达式用于组合布尔值,结果也为布尔类型。逻辑表达式的类型检查规则:
操作数类型:
- 逻辑操作通常要求操作数是布尔类型(bool)
- 某些语言(如C)允许整数作为逻辑操作数(0为假,非0为真)
结果类型:
- 所有逻辑表达式的结果类型都是布尔类型(bool)
- 例如:a && b → bool
- 例如:!x → bool
支持的操作符:
- 逻辑与(&&)
- 逻辑或(||)
- 逻辑非(!)
短路求值:
- 逻辑与(&&):如果第一个操作数为假,第二个操作数不会求值
- 逻辑或(||):如果第一个操作数为真,第二个操作数不会求值
- 类型检查需要考虑这种情况,但通常不影响类型检查结果
实用案例分析
算术表达式类型检查实现
def check_arithmetic_expression(self, expr):
"""检查算术表达式的类型"""
# 检查左操作数类型
left_type = self.check_expression(expr.left)
if left_type == "error":
return "error"
# 检查右操作数类型
right_type = self.check_expression(expr.right)
if right_type == "error":
return "error"
# 检查操作数是否为数值类型
if left_type not in ["int", "float"] or right_type not in ["int", "float"]:
self.errors.append(f"Type error: arithmetic operation on non-numeric types {left_type} and {right_type}")
return "error"
# 确定结果类型(类型提升)
if left_type == "float" or right_type == "float":
return "float"
else:
return "int"关系表达式类型检查实现
def check_relational_expression(self, expr):
"""检查关系表达式的类型"""
# 检查左操作数类型
left_type = self.check_expression(expr.left)
if left_type == "error":
return "error"
# 检查右操作数类型
right_type = self.check_expression(expr.right)
if right_type == "error":
return "error"
# 检查操作数类型是否兼容
if left_type != right_type:
# 允许数值类型之间的比较
if (left_type in ["int", "float"] and right_type in ["int", "float"]):
# 数值类型可以比较
pass
else:
self.errors.append(f"Type error: comparing different types {left_type} and {right_type}")
return "error"
# 关系表达式的结果类型总是bool
return "bool"逻辑表达式类型检查实现
def check_logical_expression(self, expr):
"""检查逻辑表达式的类型"""
if expr.op == "!":
# 逻辑非操作符,只有一个操作数
operand_type = self.check_expression(expr.operand)
if operand_type == "error":
return "error"
# 检查操作数是否为布尔类型
if operand_type != "bool":
# 在某些语言中,整数也可以作为逻辑操作数
if operand_type == "int":
# 允许int作为逻辑操作数
pass
else:
self.errors.append(f"Type error: logical not operation on non-boolean type {operand_type}")
return "error"
return "bool"
else:
# 逻辑与或操作符,有两个操作数
left_type = self.check_expression(expr.left)
if left_type == "error":
return "error"
right_type = self.check_expression(expr.right)
if right_type == "error":
return "error"
# 检查操作数是否为布尔类型
if left_type != "bool":
if left_type != "int":
self.errors.append(f"Type error: logical operation on non-boolean type {left_type}")
return "error"
if right_type != "bool":
if right_type != "int":
self.errors.append(f"Type error: logical operation on non-boolean type {right_type}")
return "error"
return "bool"表达式类型检查的完整实现
将上述函数集成到类型检查器中:
class TypeChecker:
def __init__(self, symbol_table):
self.symbol_table = symbol_table
self.errors = []
def check_expression(self, expr):
"""检查表达式的类型"""
if expr.type == "binary_op":
if expr.op in ["+", "-", "*", "/", "%"]:
return self.check_arithmetic_expression(expr)
elif expr.op in ["==", "!=", "<", ">", "<=", ">="]:
return self.check_relational_expression(expr)
elif expr.op in ["&&", "||"]:
return self.check_logical_expression(expr)
elif expr.type == "unary_op":
if expr.op == "!":
return self.check_logical_expression(expr)
elif expr.op in ["+", "-"]:
# 一元加减操作
operand_type = self.check_expression(expr.operand)
if operand_type in ["int", "float"]:
return operand_type
else:
self.errors.append(f"Type error: unary operation on non-numeric type {operand_type}")
return "error"
elif expr.type == "identifier":
symbol = self.symbol_table.lookup(expr.name)
if symbol:
return symbol.type
else:
self.errors.append(f"Type error: undefined variable {expr.name}")
return "error"
elif expr.type == "literal":
if isinstance(expr.value, int):
return "int"
elif isinstance(expr.value, float):
return "float"
elif isinstance(expr.value, bool):
return "bool"
elif isinstance(expr.value, str):
return "string"
return "error"
def check_arithmetic_expression(self, expr):
# 实现见上文
pass
def check_relational_expression(self, expr):
# 实现见上文
pass
def check_logical_expression(self, expr):
# 实现见上文
pass实用案例分析
类型检查示例
算术表达式类型检查
// 正确的算术表达式
int a = 10;
float b = 3.14;
int c = a + 5; // int + int → int
float d = a + b; // int + float → float
float e = b * 2.5; // float * float → float
// 类型错误的算术表达式
int f = 10;
char g = 'a';
int h = f + g; // 在C中允许(char会提升为int)
int i = f + "hello"; // 错误:不能将int与字符串相加关系表达式类型检查
// 正确的关系表达式
int a = 10;
int b = 20;
float c = 3.14;
float d = 2.71;
bool e = a < b; // int < int → bool
bool f = c > d; // float > float → bool
bool g = a == 10; // int == int → bool
// 类型错误的关系表达式
int h = 10;
char* i = "hello";
bool j = h == i; // 错误:比较int和字符串逻辑表达式类型检查
// 正确的逻辑表达式
bool a = true;
bool b = false;
bool c = a && b; // bool && bool → bool
bool d = a || b; // bool || bool → bool
bool e = !a; // !bool → bool
// 在C中的特殊情况(允许int作为逻辑操作数)
int f = 10; // 非0视为true
int g = 0; // 0视为false
bool h = f && g; // int && int → bool复杂表达式类型检查
对于复杂表达式,类型检查需要递归处理子表达式:
// 复杂表达式
int a = 10;
float b = 3.14;
bool c = (a > 5) && (b < 4.0); // 关系表达式的结果作为逻辑表达式的操作数
// 类型检查过程:
// 1. 检查 a > 5: int > int → bool
// 2. 检查 b < 4.0: float < float → bool
// 3. 检查 bool && bool → bool类型提升示例
// 类型提升
int a = 10;
float b = 3.14;
double c = 2.5;
// 类型提升路径:int → float → double
float result1 = a + b; // int + float → float
double result2 = a + c; // int + double → double
double result3 = b + c; // float + double → double小结
表达式类型检查是编译器语义分析的重要组成部分:
- 算术表达式:要求操作数为数值类型,结果类型根据类型提升规则确定
- 关系表达式:要求操作数类型兼容,结果类型总是布尔类型
- 逻辑表达式:要求操作数为布尔类型(或某些语言中的整数),结果类型总是布尔类型
- 递归处理:复杂表达式需要递归检查子表达式的类型
- 类型提升:不同数值类型之间的操作会进行类型提升
通过正确实现表达式类型检查,可以在编译时发现许多潜在的类型错误,提高程序的正确性和可靠性。在实际编译器开发中,还需要考虑更多特殊情况和语言特性,如运算符重载、自定义类型的操作等。