第116集:表达式类型检查

核心知识点讲解

算术表达式类型检查

算术表达式是最常见的表达式类型,包括加减乘除等操作。算术表达式的类型检查需要考虑以下几点:

  1. 操作数类型

    • 算术操作通常要求操作数是数值类型(int, float, double等)
    • 不同数值类型之间的操作需要进行类型提升
  2. 类型提升规则

    • 当操作数类型不同时,会自动提升到更宽的类型
    • 例如:int + float → float
    • 例如:float * double → double
  3. 结果类型

    • 算术表达式的结果类型通常是操作数提升后的类型
    • 例如:int + int → int
    • 例如:int + float → float
  4. 特殊情况

    • 除法操作:整数除法和浮点数除法的行为不同
    • 取模操作:通常只适用于整数类型

关系表达式类型检查

关系表达式用于比较两个值的大小关系,结果为布尔类型。关系表达式的类型检查规则:

  1. 操作数类型

    • 关系操作通常要求操作数类型相同
    • 数值类型之间可以进行比较
    • 某些语言允许字符串之间的比较
  2. 结果类型

    • 所有关系表达式的结果类型都是布尔类型(bool)
    • 例如:a > b → bool
    • 例如:x == y → bool
  3. 支持的操作符

    • 等于(==)
    • 不等于(!=)
    • 小于(<)
    • 大于(>)
    • 小于等于(<=)
    • 大于等于(>=)

逻辑表达式类型检查

逻辑表达式用于组合布尔值,结果也为布尔类型。逻辑表达式的类型检查规则:

  1. 操作数类型

    • 逻辑操作通常要求操作数是布尔类型(bool)
    • 某些语言(如C)允许整数作为逻辑操作数(0为假,非0为真)
  2. 结果类型

    • 所有逻辑表达式的结果类型都是布尔类型(bool)
    • 例如:a && b → bool
    • 例如:!x → bool
  3. 支持的操作符

    • 逻辑与(&&)
    • 逻辑或(||)
    • 逻辑非(!)
  4. 短路求值

    • 逻辑与(&&):如果第一个操作数为假,第二个操作数不会求值
    • 逻辑或(||):如果第一个操作数为真,第二个操作数不会求值
    • 类型检查需要考虑这种情况,但通常不影响类型检查结果

实用案例分析

算术表达式类型检查实现

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

小结

表达式类型检查是编译器语义分析的重要组成部分:

  • 算术表达式:要求操作数为数值类型,结果类型根据类型提升规则确定
  • 关系表达式:要求操作数类型兼容,结果类型总是布尔类型
  • 逻辑表达式:要求操作数为布尔类型(或某些语言中的整数),结果类型总是布尔类型
  • 递归处理:复杂表达式需要递归检查子表达式的类型
  • 类型提升:不同数值类型之间的操作会进行类型提升

通过正确实现表达式类型检查,可以在编译时发现许多潜在的类型错误,提高程序的正确性和可靠性。在实际编译器开发中,还需要考虑更多特殊情况和语言特性,如运算符重载、自定义类型的操作等。

« 上一篇 类型检查基础 下一篇 » 语句类型检查