首页 > 其他分享 >7. 中间代码 | 2.抽象语句 --> 树中间语言

7. 中间代码 | 2.抽象语句 --> 树中间语言

时间:2024-04-30 15:58:13浏览次数:28  
标签:语句 Temp -- stm 中间代码 Tr cx exp

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
 (2)    解析真值语句  
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

相关文章

  • Web Audio API 第6章 高级主题
    高级主题这一章涵盖了非常重要的主题,但比本书的其他部分稍微复杂一些。我们会深入对声音添加音效,完全不通过任何音频缓冲来计算合成音效,模拟不同声音环境的效果,还有关于空3D空间音频。重要理论:双二阶滤波器一个滤波可以增强或减弱声音频谱的某些部分。直观地,在频域上它可......
  • P10242 [THUSC 2021] Emiya 家明天的饭
    题目大意有\(n\)个人和\(m\)种菜,第\(i\)个人对第\(j\)道菜的喜爱程度为\(a_{i,j}\)。如果\(a_{i,j}=-1\)则表示不喜欢。现在你要选择一个菜的集合,你会获得喜欢集合中所有菜的人对这些菜的喜爱程度之和的权值,最大化这个权值,\(n\leq20,m\leq10^6,a_{i,j}\leq10......
  • Python: unZip
     importosimportsocketimportstructfromunidecodeimportunidecodeimportreimportjsonimportrequestsfrombs4importBeautifulSoupimportgzipimportzipfilefrompathlibimportPathfromzipfileimportZipFileclassCzip:"""......
  • P10241 [THUSC 2021] 白兰地厅的西瓜
    考虑DP,注意到一个简单路径可以被拆为向上的部分和向下的部分。所以设\(f_{u,i}\)表示\(u\)的子树中从\(u\)向下且第一项是\(i\)的LIS的最大长度,\(g_{u,i}\)表示\(u\)的子树中\(u\)的某个子孙向上到\(u\)且最后一项是\(i\)的LIS的最大长度。从\(u\)到父......
  • 分享一份物联网SAAS平台架构设计
    一、架构图****二、Nginx****用于做服务的反向代理。三、网关****PaaS平台所有服务统一入口,包含token鉴权功能。四、开放平台****对第三方平台开放的服务入口。五、MQTT****MQTT用于设备消息通信、内部服务消息通信。六、Netty****Socket通信设备连接服务。七......
  • 是女儿也是妈妈笔记
     欧阳妮妮的父亲跟她说,要多谈恋爱,你才知道自己适合什么样的男人。1.要把男人灌醉,看酒品。2.和男人打牌,看他牌品,牌品就是人品。3.坐男人开车,看男人的车品。 责任感,担当很重要。经营美貌,依赖性正好应对了男人的保护欲。要找一个爱老婆更多的男人。男人外貌没那么重要,因为......
  • MySQL日志
    一条update的执行流程执行流程分为在server层和存储引擎层;server是MySQL都有的,其日志文件是binlog;存储引擎是不同的,undolog,redolog是innodb特有的。首先是客户端创建请求,然后去服务层请求;然后是server的连接器,连接器的作用是校验用户是否有权限进行查询等等。(在8.0版本之前有......
  • a-table 鼠标滑过显示小手,当前行可点击(转载)
    需求:鼠标滑过表单行时,出现小手,点击时,可以跳转至编辑页文档地址:https://antdv.com/components/table-cn/实践操作:<template><a-table:loading="loading":columns="columns":data-source="dataSource.list"rowKey="Id"......
  • KCP 协议介绍与优化项
    参考:https://luyuhuang.tech/2020/12/09/kcp.htmlhttps://xiaolincoding.com/network/https://coolshell.cn/articles/11564.html1.概述kcp是一个基于udp的应用层协议,其只负责实现ARQ算法,需要调用者提供网络数据收发和时钟驱动能力。其典型图示如下:ikcp_sendi......
  • xxl-job
    部署拉取镜像dockerpullxuxueli/xxl-job-admin:2.4.1docker-composeversion:'3'services:xxl-job-admin:image:xuxueli/xxl-job-admin:2.4.1container_name:xxl-job-adminrestart:alwaysports:-8087:8080environment:......