跳转至

4 类型表达式等价

如何解释类型表达式相同?

  • 主要是考虑到这种情况:在一些语言中存在 typedef 这样的别名功能,比如 typedef UINT unsigned,UINT 的出现作为新的类型或者作为别名,在没有其他约束的情况下可能出现二义性。

  • 结构等价、名字等价

结构等价

  • 无类型名(别名)时,要求两个类型表达式完全相同
  • 有类型名时,用类型名所定义的类型表达式代换别名之后的表达式完全相同(要求别名定义是无环的)
  • 结构等价测试(无类型名、环时)
bool sequiv(s, t) {
    if (s和t是相同的基本类型) return true;
    else if (s == array(s1, s2) && t == array(t1, t2)) 
        return sequiv(s1, t1) && sequiv(s2, t2); // 递归检查
    else if (s == s1 × s2 && t == t1 × t2) 
        return sequiv(s1, t1) && sequiv(s2, t2);
    else if (s == pointer(s1) && t == pointer(t1)) 
        return sequiv(s1, t1);
    else if (s == s1  s2 && t == t1  t2) 
        return sequiv(s1, t1) && sequiv(s2, t2);
    else return false;
}

名字等价

  • 把每个类型名都看成一个需要区别的类型
  • 两种类型名字等价 \Leftrightarrow 不做任何名字代换就结构等价

记录类型

记录类型可看成其各个域类型的笛卡尔积类型

记录和积之间的主要区别是:记录的域有名字

typedef struct {
    int address;
    char lexeme[15];
} row;

类型表达式为 record ( address : int, lexeme : array (15, char) )

新增定型规则

\displaystyle (Type\ Record)\quad\quad\frac{\Gamma\vdash T_1,...,\Gamma\vdash T_n}{\Gamma\vdash record(l_1:T_1,...,l_n:T_n)}\quad l_i\text{ varies}

变量(M_i)记录类型:

\displaystyle (Val\ Record)\quad\quad\frac{\Gamma\vdash M_1:T_1,...,\Gamma\vdash M_n:T_n}{\Gamma\vdash record(l_1=M_1,...,l_n=M_n):record(l_1:T_1,...,l_n:T_n)}\quad l_i\text{ varies}

变量成员选择:

\displaystyle (Val\ Record\ Select)\quad\quad\frac{\Gamma\vdash M:record(l_1:T_1,...,l_n:T_n)}{\Gamma\vdash M.l_j:T_j\quad(1\le j\le n)}\quad l_i\text{ varies}

类型表示中的环

引入环的话,递归定义的类型名(比如链表、树)可以替换掉

image-20221101214854924

C 语言对除记录(结构体)、共用体以外的所有类型 使用结构等价,而对记录类型用的是名字等价,以避免类型图中的环(上面右图)。

本文阅读量