1. 表达式 A_exp -> T_exp , T_stm
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 |
then ts ...这时生成真值对应的标号 Temp_label t,更新 stm1 对象 为 stm1 = T_Cjump(T_gt, c, d,t, NULL); (3) 解析假值语句 没有假值语句,语句不变 (4) 结束 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); }
T_stm unNx(Tr_exp exp):转换为无返回值语句
// T_stm T_Seq(T_stm left, T_stm right); static T_stm unNx(Tr_exp exp){ switch (exp->kind) { case Tr_ex: return T_Exp(exp->u.ex); case Tr_nx: return exp->u.nx; 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_Seq(exp->u.cx.stm, T_Seq(T_Label(t), T_Label(f))); } }
T_exp unCx(Tr_exp e) : exp 转换为条件语句 结构体
// struct Cx {patchList trues; patchList falses; T_stm stm} // T_stm T_Cjump(T_relOp op, T_exp left, T_exp right, Temp_label true, Temp_label false) 为真时跳转 true,否则 false static struct Cx unCx(Tr_exp exp){ struct Cx cx = (Cx)checked_malloc(sizeof (struct Cx)); Temp_label t = Temp_newlabel(), f = Temp_newlabel(); struct Cx cx; switch (exp->kind) { case Tr_ex: // cx.stm = T_Exp(exp.u.ex); cx.stm = T_Cjump(T_ne, exp->u.ex, T_Const(0),NULL, NULL); cx.trues = PatchList(&cx.stm->u.CJUMP.true, NULL); // 要跳转到的 true 分支 cx.falses = PatchList(cx.stm->u.CJUMP.false, NULL); // 要跳转到的 false 分支 return cx; case Tr_nx: // 不会走到这一步 ? cx.stm = exp->u.nx; cx.trues = NULL; cx.falses = NULL; return cx; case Tr_cx: return exp->u.cx; } }
2. 简单变量
struct expty { Tr_exp exp; // 存放中间代码 Ty_ty ty; } // 构造函数 struct expty expTy(Tr_exp e, Ty_ty t) { struct expty et; et.exp = e; et.ty = t; return et; }
MEM ( BINOP ( PLUS, TEMP fp, CONST k )当调用父级函数中定义的变量时: 静态链
3. 静态链
编译原理中的静态链指的是在编译时就已经确定的程序执行路径,编译器会根据预先定义好的静态链来生成最终代码。
这种方式的优势在于编译后生成的代码可以直接执行,不需要再进行动态判断,因此执行效率更高。
访问外层定义的变量 x :
// k1,..., kn : 变量 x 在每一导的栈帧中的位移
MEM(+(CONST kn, MEM(+(CONST k_n-1, ...
MEM(+(CONST k1, TEMP FP)) ))))
4. 数组 : 记录赋值 & 指针赋值
与 C 语言不同,Tiger 模糊了 对象 和 指针的区别, 在C 语言中,如下赋值会报错,因为 将指针 b 赋值给了 数组 a
int a[12], b[12];
a = b;
但是 tiger 语言中,"a := b" 编译器自动进行了 "转换", 并转为 "指针赋值"
tiger 的 记录也是指针, 记录赋值 = 指针赋值
let
type intArray := array of int
var a := intArray[12] of 0
var b := intArray[12] of 7
in
a := b
end
5. 左值 l-values , 结构化左值 structured l-values
标量 scalar:整数,指针 , 只有一个成员, 占用一个字存储,可以放在寄存器中。 Tiger 中所有的变量和左值都是标量, 数组 及 记录变量(record)也是指针。 结构化左值 : structured l-values, 非标量的左值,C 中就是结构体, Pascal 中就是 数组 和 记录(record )
6. 下标,域选择 a[2], a.val, ...
// s: 字长
// l: 下标下界, 一般为0
// a: 数组基地址
a[i] : ( i - l ) x s + a
左值与 MEM 结点:
左值是地址
左传转换为右值 (取): 从该地址中读数
左值赋值 (存): 对地址存数
一开始将 MEM() 看成左值
MEM 即表示存入,也可以表示取出
7. 字符串
Pascal 语言的字符串: 长度固定的数组,文字常数的尾部填充空格。 C 语言的字符串: 以字符数组的形式存储的,并以 ASCII值为0 的 '\0' 作为结尾。 '\0' 称为 空字符(null character)或 终止符(terminator) Tiger 语言的字符串: 任意8位码。 (2^8 = 256) 字符串指针指向: | 长度数字 | 字符串本体 | => 汇编
8. 数组,记录 array & record
tiger 语言中, record 的生存器为什么可以长于 创建他的过程? 在Tiger语言中,记录(record)的生存器(lifetime)可以长于创建它的过程,这通常与内存管理和作用域规则有关。 Tiger是一种教学用的编程语言,旨在帮助学生理解编译原理和内存管理的基本概念。 堆分配:在Tiger语言中,记录可能是在堆上分配的,而不是在栈上。栈上的变量通常在其作用域退出时自动销毁,而堆上的变量则需要在某个时候显式地释放。因此,即使创建记录的过程已经返回,只要还有对记录的引用存在,记录就会继续存在于堆上。 引用计数或垃圾收集:Tiger语言可能使用引用计数或垃圾收集机制来管理堆上的内存。这意味着记录的生存器不仅取决于创建它的过程,还取决于其他对记录的引用。只要还有对记录的引用存在,记录就不会被释放。 返回值和参数:记录可能作为函数或过程的返回值,或者作为参数传递给其他函数或过程。在这些情况下,记录的生存器会延伸到接收它的函数或过程的作用域。 全局变量或静态变量:记录也可能被存储为全局变量或静态变量,这意味着它们在整个程序执行期间都存在,而不是仅限于创建它们的过程。 因此,在Tiger语言中,记录的生存器不仅受创建它的过程控制,还受其他多种因素影响,包括内存分配策略、引用计数或垃圾收集机制、返回值和参数传递,以及变量的作用域和存储类别等。 堆分配 or 栈分配 ? 堆分配和栈分配是计算机内存管理的两种主要方式,它们各自具有不同的原理和特点。栈时报时销,不再使用自动销毁,堆则创建后需要垃圾回收,否则会导致性能问题。 记录的创建与初始化: 数组的创建与初始化:
9. while & for
while:
test:
if not(conditions) goto done
body
goto test
done:
break 语句:
1. 没有嵌套在其他 while 语句中:直接换成 JUMP done
2. 嵌套在其他 while 语句中:
transExp(body)中 每个 while 语句生成自己的 break{done 标号}
for:
重写为 while 语句
for i:lo to hi
do body
转为:
let var i := lo
var limit := hi
in while i <= limit
do (body; i := i+1)
end
10. 函数调用: 静态链
f(a1,...,an)
转化为:
CALL ( NAME lf, [sl, e1, ..., en] )
标签:语句,Temp,--,stm,中间代码,Tr,cx,exp
From: https://www.cnblogs.com/wuoshiwzm/p/18168132