<编译器> 7. 中间代码

**前端 ** 中间 后端
词法分析 活动记录 优化
语法分析 中间代码 IR 机器语言
语义分析(类型检查)

知识点

T_exp: 有返回值 表达式
T_stm: 无返回值 表达式
struct Cx: 条件表达式

Tr_exp: translate 模块的表达式,增加中间代码逻辑, 分 Tr_ex, Tr_nx, Tr_cx 三种类型
T_exp: 中间代码解析的 表达式

中间表示树 tree.h

typedef enum{T_eq, T_ne, T_lt, T_gt, T_le, T_ge, T_ult, T_ule, T_ugt, T_uge} T_relOp;  // 比较运算
typedef enum{T_plus, T_minus, T_mul, T_div, T_and, T_or, T_lshift, T_rshift, T_arshift, T_xor} T_binOp; // 二元运算

/*
 * 语句
 */
typedef struct T_stm_ *T_stm;
struct T_stm_{
    enum {T_SEQ, T_LABEL, T_JUMP, ..., T_EXP} kind;
    union {
        struct {T_stm left, right;} SEQ;
        struct {S_symbol name, ... } LABEL;
        // ...

    }u;
};
typedef struct T_stmList_ *T_stmList;
struct T_stmList_{T_stm head; T_stmList tail;};
T_stmList T_StmList(T_stm head, T_stmList tail;);

/*
 * 表达式
 */
typedef T_exp_ *T_exp;
struct T_exp_{
    enum {T_BINOP, T_MEM, T_TEMP, ..., T_CALL} kind; // 表达式类型
    union {
        struct {T_binOp op; T_exp left, right;} BINOP;
        // ...
    }u;
};
typedef struct T_expList_ *T_expList;
struct T_expList_{T_exp head; T_expList tail;};
T_expList T_ExpList(T_exp head, T_expList tail);


/*
 * 语句 stm
 */

// SEQ(s1, s2) 语句 s1后跟 s2
T_stm T_Seq(T_stm left, T_stm right);

// LABEL(name) 定义 name 的常数值为当前机器代码地址  相当于汇编中的 标号
T_stm T_Label(Temp_label label);

// 按 label 跳转
// JUMP(e, labs)  将控制转移到地址 e, 如分支语句
T_stm T_Jump(T_exp exp, Temp_labelList labels);

// 条件跳转
// CJUMP(o, e1, e2, t, f) 计算 "e1 op e2" 为真时跳转 true, 为假时跳转 false
T_stm T_Cjump(T_relOp op, T_exp left, T_exp right, Temp_label true, Temp_label false );

// MOVE(TEMP t, e): 计算e的结果,送入临时单元 t
// MOVE(T_Mem(exp1), exp2): 计算 exp1,得到地址 a, 计算exp2 并将结果存储在从地址 a开始的 wordSize个字节的存储单元中
T_exp T_Move(T_exp exp1, T_exp exp2);

// EXP(e) 计算 e 并忽略结果
T_stm T_Exp(T_exp exp);

/*
 * 表达式 exp
 */
// BINOP(op, e1, e2) 二元操作 op,先算 left, 后算 right, 最后算 "e1 op e2"
T_exp T_Binop(T_binOp op, T_exp left, T_exp right);

// MEM(e) 存储地址 e + wordSize(Frame 模块定义)个字节,  Move(T_Mem(exp1), exp2) 表示对T_Mem(exp1)存储, 其他位置表示读取
T_exp T_Mem(T_exp exp);

// 临时变量 相当于寄存器,但可以有无限多个
T_exp T_Temp(Temp_temp temp);

// exp 序列
// ESEQ(s,e) 先计算 s 作为副作用,再计算 e 做为表达式的结果
T_exp T_Eseq(T_stm stm, T_exp exp);

// 符号常数
// NAME(name)
T_exp T_Name(Temp_label name);

// 整型常数
T_exp T_Const(int num);

// CALL(f, l) 以参数表 l 调用函数 f
T_exp T_Call(T_exp head, T_expList tail);

这段话值得一看:

It is almost possible to give a formal semantics to the Tree language.
However, there is no provision in this language for procedure and function
definitions – we can specify only the body of each function. The procedure
entry and exit sequences will be added later as special “glue” that is different
for each target machine.

Procedure Entry Sequence:
这是指当程序控制流到达一个过程或函数开始执行的地方时的一系列动作。
这个序列可能包括保存现场(例如CPU寄存器、栈帧的设置等)、传递参数以及跳转到函数的实际执行代码入口点的操作。
在没有显式定义函数定义语法的语言中,这部分“胶水代码”(glue code)由编译器或运行时环境生成,确保正确地初始化函数执行所需的环境。
没有显式定义函数定义语法的语言 指没有明确怎么定义函数,或者说不支持定义函数。

Procedure Exit:
这个序列则是指函数或过程完成其任务后返回到调用者之前必须进行的一系列操作。
这通常包括清理局部变量、恢复调用前的状态(如恢复那些在函数执行期间被改变的寄存器值或栈信息)、计算并返回结果(如果有)以及实际的控制流转移回调用位置。
同样,在没有内置过程定义机制的语言中,这些退出序列会作为额外的“胶水代码”添加,以便与不同的目标机器架构兼容。

抽象语法 -----> 树中间语言

1. 表达式 A_exp -> T_exp , T_stm

image

struct Tr_exp_{
    // Tr_ex 表达式, Tr_nx 无结果语句, Tr_cx 每件语句
    enum {Tr_ex, Tr_nx, Tr_cx}kind;
    union {T_exp exp, T_stm nx, struct Cx cx;}u;
};

struct Cx {patchList trues; patchList falses; T_stm stm;}
// Tr_exp 构造函数
static Tr_exp Tr_Ex(T_exp ex); // T_exp -> Tr_exp
static Tr_exp Tr_Nx(T_stm nx); // T_stm -> Tr_exp
static Tr_exp Tr_Cx(patchList trues, patchList falses, T_stm stm); // T_stm + 回填表 -> Tr_exp

// 相当于以上构造函数的逆转
static T_exp unEx(Tr_exp e); // Tr_exp -> T_exp
static T_stm unNx(Tr_exp e); // Tr_exp -> T_stm
static struct Cx unCxc(Tr_exp e); // Tr_exp -> struct Cx

解析表达式 a>b | c<d :

Temp_label z = Temp_newlabel();
// 这里返回 T_stm 类型,因为是 无结果语句
T_stm s1 = T_Seq(
    // 如果 a>b,语句为 true, 不用再判断后面的 c<d,跳转到 NULL 稍后回填 true patch list
    // 如果 a<b,语句为 false, 则需要判断后面的 c<d, 跳转到标号 z
    T_Cjump(T_gt, a, b, NULL, z), 
    T_Seq(
        T_Label(z), // 标号z ,代表语句 "c<d"
        T_Cjump(T_lt, c, d, NULL, NULL)  // 判断 c<d
    )
);

T_Cjump(T_gt, a, b, NULL, z), 中的 NULL 对应真值 稍后回填: true patch list
T_Cjump(T_lt, c, d, NULL, NULL) , 中的 两个NULL 对应真值和假值 稍后回填: true patch list, false patch lsit

1.2 真/假值标号回填表 true patch list / false patch list

以下语句为例 :

if c>d
then ts...

条件类表达式 c > d , 真分支 ts... , 无假分支
**1. 解析定义阶段 **
if c>d

这时还没解析到到后面对应的真/假分支语句,先都填入 NULL。
T_stm stm1 = T_Cjump(T_gt, c, d, NULL, NULL);
把两个 NULL 对应的语句和位置记录在 回填表 patchLis 中:
真值回填表 假值回填表
stm1.u.CJUMP.true stm1.u.CJUMP.false

2. 解析真值语句
then ts ...

这时生成真值对应的标号 Temp_label t,更新 stm1 对象 为
stm1 = T_Cjump(T_gt, c, d,t, NULL);

3. 解析假值语句
没有假值语句,语句不变
4. 结束
image

image

1.3 表达式的转换 表达式1 := 表达式2

以下将 条件表达式 struct Cx (a>b | c<d) 转换为 返回值表达式 T_exp flag
flag := (a>b | c<d) // struct Cx (a>b | c<d) ---> T_exp flag;

T_exp unEx(Tr_exp e) : 将条件表达式 Cx,  无值表达式 Nx, 值表达式 Ex 转化为 "值表达式"  T_exp
// 条件结构体 struct Cx {patchList trues; patchList falses; T_stm stm};
// T_Eseq(T_stm stm, T_exp exp) 执行 stm, 返回 exp
// T_exp T_Temp(Temp_temp temp) 生成一个临时变量
static T_exp unEx(Tr_exp e) {
    switch (e->kind) {
        case Tr_ex: // 有返回值表达式
            return e->u.ex;

        case Tr_nx:
            // 1. 先计算无返回值表达式 e->u.nx
            // 2. 返回值固定设为 T_Const(0))
            return T_Eseq(e->u.nx, T_Const(0));

        case Tr_cx:
            Temp_temp r = Temp_newtemp();
            T_exp er = T_Temp(r) // 返回值

            // t:真值回填标号 f:假值回填标号
            Temp_label t = Temp_newlabel(), f = Temp_newlabel();
            // 将真/假值回填表中的标号全部换成 t, f
            doPatch(e->u.cx.trues, t);
            doPatch(e->u.cx.falses, f);

            return T_Eseq(T_Move(er, T_Const(1)), // er 先默认赋值 1
                          T_Eseq(e->u.cx.stm, // 执行条件判断语句,如果为true 就会跳转到 t, 否则跳转 f
                                 T_Eseq(T_Label(f), // 跳转到 f
                                        T_Eseq(T_Move(er, T_Const(0)), // er 赋值为 0
                                                      T_Eseq(T_Label(t),  // 跳转到 t
                                                             er // 最后返回 er (为1或0)
                                                      )))));
    }
    assert(0);
}

image

posted @ 2024-04-09 09:55  Leon大帝  阅读(4)  评论(0编辑  收藏  举报