<编译器> 7. 中间代码 | 1.中间树

知识点

 
T_exp: 有返回值 表达式
T_stm: 无返回值 表达式
struct Cx: 条件表达式
 
Tr_exp:  translate 模块的表达式,增加中间代码逻辑, 分  Tr_ex, Tr_nx, Tr_cx  三种类型, 对接机器
T_exp:  tree 模块的表达式,中间代码解析的 表达式
 
 
中间表示树  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:
这个序列则是指函数或过程完成其任务后返回到调用者之前必须进行的一系列操作。
这通常包括清理局部变量、恢复调用前的状态(如恢复那些在函数执行期间被改变的寄存器值或栈信息)、计算并返回结果(如果有)以及实际的控制流转移回调用位置。
同样,在没有内置过程定义机制的语言中,这些退出序列会作为额外的“胶水代码”添加,以便与不同的目标机器架构兼容。

 

 

 

 

 

 

 

 

 

 

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