编译原理总结

编译原理总结

编译原理总结



前言

总结编译原理的重点。


一、编译的过程

编译分为前端和后端。

具体流程如下图所示:
在这里插入图片描述

前端包括词法分析,语法分析,语义分析,中间代码生成。

后端主要负责对中间代码进行优化,生成目标平台代码,对目标平台代码进行优化等。

前端与目标平台基本无关,因此有通用的工具:词法分析有工具lex,语法分析和语义分析有工具Yacc。

如果不想要自己实现前端代码,那么可以使用现有的工具,通过描述词法单词规则和语法,来生成中间代码。

二、前端

1.词法分析

词法分析主要是将程序解析为一个个的“单词” token。

具体使用的方法是确定有限自动机DFA,但是DFA比较难实现,一般会通过词法规则,产生NFA,再将NFA转化为DFA。

工作原理是类似于按照正则表达式的形式,实现状态跳转的自动机,匹配token。

一个NFA的状态转换图如下图所示:
在这里插入图片描述


2.语法分析

语法分析将单词组成符合语法结构的语法分析树。
主要有两种方式:LL分析和LR分析。

2.1 LL分析

LL分析即为自顶向下的分析,将语法从抽象到具体的推导出代码形式。

需要使用预测分析器,而预测分析器需要first集合和follow集合才能产生。

分析预测器使用first/follow集产生的终结符——非终结符的表格进行识别。

但是LL分析可能存在二义性,需要使用消除左递归。

2.2 LR分析

LL分析只是向前看N个字符,更有表达能力的是LR分析。
LR分析通过使用栈,逐个处理token流,使用action表和goto表。

action表是状态——终结符表。表中的内容表示使用哪个表达式进行规约,或者只是移入动作。
goto表是状态——非终结符表。表格表示跳转到哪个状态。

在这里插入图片描述

但是LR(0) 分析也有二义,因此可以结合使用follow集,用来预测,即SLR分析,即为simplified LR分析。
SLR分析的不同在于其只在非终结符是终结符的follow集的情况下,才进行规约。

表达力更强的问法是LR(1)分析,结合first集进行分析。一般采用LR(1)分析足够解决问题。

在这里插入图片描述

赋值语句 position = initial + rate * 60的语法分析树如下图所示:
在这里插入图片描述


3.语义分析

语义分析即分析代码的语义是否正确,比如变量是否未经声明就被使用或者如果语言本身不支持类型转换,代码中对不同类型的变量进行计算等。

一般在语法分析构建抽象语法树的过程中,附加上语义动作,进行分析,因此一般语法分析和语义分析也是同时进行的,比如LLVM。

4.中间代码

语义分析之后,遍历抽象语法树,即可输出中间代码。中间代码是介于上层抽象语言C/C++和机器汇编语言之间的代码。

如下图所示,不同的语言,经过针对该语言的前端处理后,得到了通用的中间代码(IR,intermediate representation 中间表示)。

IR后面经过被不同的机器后端处理,即可得到不同平台的机器代码。

因此IR可以看做是超脱语言种类和平台种类的中间表示,可以在IR上进行通用的优化;而在IR被后端处理为机器指令后,可以针对不同的平台进行针对平台特性的优化。
在这里插入图片描述


三、后端

3.1 指令选择

中间代码表示的每个节点只能表示简单的一种操作,比如从存储器读取或者存储,加或减,条件转移等。然而真实的机器可能支持一条指令完成从存储器读取后进行加减操作,因此需要指令选择。即找出实现一个给定的中间表示树的指令序列。

3.2 活跃性分析

在程序中,如果临时变量a和b不会同时活跃,那么可以把它们分配到统计个寄存器中。为了实现这个目的,我们需要进行活跃性分析。

活跃性分析举例如下:

  = ...b;   // 1
....
a = ....;	// 2
...
  = ...c;	// 3
  = ...a;	// 4

上面所示代码中,如果从1到2之间,没有对b的引用,从4之后没有对a的引用,那么1处即为b的最后一次引用,其活跃周期截止到1;而2处,对a进行了定值,在4处对a进行了引用,因此a的活跃范围即为2~4。

a和b的活跃范围不冲突,因此a和b可以分配到相同的寄存器上,但是a和c活跃范围冲突,因此不能分配到相同的寄存器上。

可以看出,活跃范围主要取决于最后一次引用,因此从程序尾部回溯分析,方便进行活跃分析。

3.3 寄存器分配

活跃分析的主要用处就是进行寄存器分配,寄存器分配首先会分析活跃范围有重叠的变量,认为它们是冲突的,需要分配到不同的寄存器。可以将变量组成图,有冲突的变量通过边相连,即组成冲突图,通过图着色法,进行寄存器分配。

3.4 数据流分析

数据流分析包括

  • 到达定值分析 user-define 链分析
  • 定值到达分析define-use链分析
  • 可用表达式分析
  • 活跃分析

详见

3.5 静态单赋值

LLVM的IR的格式即为静态单赋值。静态单赋值的即为:每次赋值都在IR中生成新的临时变量。

a = .....
... = ...a

a = .....
... = ...a

上面翻译成IR之后结果类似于:

a0 = .....
... = ...a0

a1 = .....
... = ...a1

在数据流分析中,会产生user-define链和define-user链,在链中进行索引,时间复杂度较大。在静态单赋值中,LLVM采用了value[]和use[]表示定值和引用数组,大大加快了对程序的优化。


总结

文章总结。


欢迎关注我的公众号《处理器与AI芯片》

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值