文章目录
绪论
编译的流程
:词法分析,语法分析,语义分析和中间代码生成,优化,目标代码生成
词法分析任务
:按照词法规则,对构成源程序的字符串进行扫描和分解,识别出一个个的单词,单词包括基本字、运算符、界限符、标识符、常数,将其添加到符号表,并转换成统一规格输出,格式为(类号,内码)/(单词种类符号,单词自身值);
词法分析核心
是扫描器,描述词法规则的有效工具是正规式(正规文法/3型文法)和有限状态自动机。
基本字、运算符、界限符、标识符是一个符号一个种类,值就是按机器字节划分的内码
常数一个类型一个种类,值就是自身的二进制表示
得到DFA的细节
:根据单词符号确定正规集,根据正规集确定正规式,根据正规式确定 NFA,将 NFA 转换为 DFA,化简 DFA,基于 DFA 进行程序实现
语法分析任务
:在词法分析的基础上,根据语法规则,把单词符号组成各类的语法单位:短语、字句、语句、过程,构成一颗语法树。语法分析的核心是下推自动机和上下文无关文法。语法分析的理论基础有推导和规约。自上而下推导:LL1分析法、递归下降分析法,自下而上规约:简单优先分析法、算符优先分析法、LR分析法。
语法规则
:就是文法,规定单词如何构成短语、字句、语句、过程、程序。
语义分析和中间代码生成任务
:对语法分析识别出来的各类语法范畴(语法树),按照语义规则,分析其语义(使用属性文法),进行初步翻译,产生中间代码。两阶段工作:对每种语法范畴进行静态语义检查,语义正确就进行中间代码的翻译。中间代码形式:四元式、三元式、逆波兰式,树形表述法。中间代码生成方法:语法制导翻译,描述工具是属性文法
语义分析
又称类型检查,上下文相关分析,任务是负责检查程序(语法树)的上下文相关的属性。其他问题:类型相容性、错误诊断、代码生成
优化
:对前面产生的中间代码进行加工变换,以期待在最后阶段能产生更为有效的目标代码。原则:等价变换。方法:提取公共子表达式,合并已知量,删除无用子表达式,强度削弱(乘法变成加法),循环优化。
目标代码生成
:把经过优化的中间代码转化成特定机器上的低级语言代码。目标代码的形式:绝对指令代码,汇编指令代码,可重定位指令代码。
表格
:记录源程序的各种信息以及编译过程中的各种状况。如:符号表(登记源程序中的常量名,变量名,数组名,过程名等,以及他们的性质、定义和引用情况),常数表,标号表,分程序入口表,中间代码表等
出错
:语法错误(词法分析和语法分析阶段检测)和语义错误(语义分析阶段检测)
遍:指对源程序或者源程序的中间结果从头到尾扫描一次,并做有关的加工处理,生成新的中间结果或者目标代码。遍与阶段毫无干系。
编译基础知识
chomsky根据对产生式施加的限制对文法进行分类:
0型文法
:短语文法,能够识别0型语言的自动机称为图灵机。要求:左边至少含有一个非终结符,其余不加任何限制;
1型文法
:上下文有关文法,长度增加文法。能够识别1型语言的自动机称为线性界限自动机。要求:它在 0 型文法的基础之上,右边的长度 >= 左边的长度(终结符或非终结符的个数)。但是有个特例:S->空除外
2型文法
:上下文无关文法。能够识别2型语言的自动机称为下推自动机,大部分程序设计语言近似于2型文法。要求:在 1 型的基础上,左边必须是非终结符(个数不限)。
3型文法
:正规文法,左右线性文法。能够识别3型语言的自动机称为有限状态自动机。要求:在 2 型的基础上,要么一个非终结符推出一个终结符,要么一个非终结符推出一个终结符并且带一个非终结符,要么一个非终结符推出一个非终结符并且带一个终结符。
关系
:覆盖范围:0>1>2>3,严格程度:3>2>1>0
由语言构造文法,并对文法进行化简。
化简步骤
:删除p->p的产生式;删除推导过程中用不到的产生式;删除推导不出终结符的产生式
构造无空串产生式的上下文无关文法
:
二义性
:
判断是否二义:找到一个句子,存在两个语法树即可
使用语法树判断文法的二义性:文法产生的一个句子存在两棵或者两棵以上的语法树,这个句子就是二义的,这个文法就是二义的。
消除二义性:规定算符的优先级、重写文法
词法分析
三者之间的关系
:正规文法,正规集(正规文法定义或者正规式定义的语言的集合就是正规集),正规式(正规集的形 式化表示),一个正规式和一个有限自动机等价
证明正规式等价
就是根据正规式写出相应的正规集->两个正规式所表示的正规集相同,则这两个正规式等价
有限状态自动机
:
首先,能够识别正规文法构成的语言的自动机称为有限状态自动机,它在词法分析阶段使用。他包括输入带、输出带、读头和控制器。它分为确定的有限自动机DFA和不确定有限自动机NFA
他的作用是,按照词法规则,对构成源程序的字符串进行扫描和分解,识别出一个个的单词,并转换成(类号,内码)的格式输出。
确定有限自动机DFA
是一个五元式,包括有限状态集,有限字母表,有限状态集上的单值映射,唯一的初态,终状集。他的映射关系可以使用状态装换矩阵或者状态装换图表示。
不确定有限自动机NFA
是一个五元式,包括有限状态集,有限字母表,有限状态集上的映射,初态集合,终状集。
两者的区别
:
初始状态不同:DFA只有一个初态,而NFA可以有若干个初态;
弧上的标记不同:DFA的转移边上是字符,而NFA的转移边上可以是字符也可以是正规式
转换关系不同:DFA上的一个状态通过识别字符转移到一个确定状态,而NFA上的一个状态通过识别字符或者正规式可以转移到多个状态;
DFA是NFA的特例
自动机等价
:能够识别相同的语言
NFA的确定化
:使用子集法,核心思想就是使用NFA中的若干状态组成覆盖片,也就是DFA中的一个状态。DFA的状态I0就是NFA的所有初态组成的一个覆盖片,将I0加入DFA的状态集合中,然后对于I0覆盖片内的所有状态经过NFA的转移函数得到包括若干个状态的新覆盖片,也就是DFA的新状态I1,若该状态未出现在DFA的状态集中,将其加入状态集,并继续对其使用转移函数,若该状态已出现在DFA的状态集中,忽略他。
DFA的最小化
:使用划分法,核心思想就是将DFA的状态化为互不相交的子集,这些子集内部状态等价,而不同子集之间状态不等价;那么每个子集内部挑一个代表,然后删去子集内其他的状态,并把原先射入子集内其他等价状态的弧改为射入相应的代表状态即可。
划分法
:先将集合划分为终态集和非终态集,然后对于所有的集合进行测试,测试就是对读入字符按照转移函数进行转移,若转移到的状态不在当前集合内,则对其进行划分,否则不对其变动;若所有集合都不可在划分,则DFA最小化完成。
有限自动机转化为正规式
:
对含有空弧的NFA的确定化
:使用子集法,核心思想就是使用NFA中的若干状态组成覆盖片,也就是DFA中的一个状态。DFA的状态集I0就是NFA的所有初态进行空闭包之后组成的一个覆盖片,将I0加入DFA的状态集合中,然后对于I0覆盖片内的所有状态经过NFA的转移函数得到包括若干个状态,再求闭包得到新覆盖片,也就是DFA的新状态I1,若该状态未出现在DFA的状态集中,将其加入状态集,并继续对其使用转移函数,若该状态已出现在DFA的状态集中,忽略他。
右线性文法转换为有限自动机:不确定有限自动机NFA是一个五元式,包括有限状态集,有限字母表,有限状态集上的映射,初态集合,终态集。
那么对应的有限状态集就是所有的非终结符和终结状态T,有限字母表是所有的终结符,初态就是开始符号S,终结状态就是T,但是如果产生式中有s->空,那么S也是终结状态,映射f就是 A->aB对应的映射就是f(A,a)=B或A->a对应的映射就是f(A,a)=T
有限自动机转换为右线性文法
:
词法分析程序的任务
:按照词法规则,对构成源程序的字符串进行扫描和分解,识别出一个个的单词,单词包括基本字、运算符、界限符、标识符、常数,将其添加到符号表,并转换成统一规格输出,格式为(类号,内码)/(单词种类符号,单词自身值);过滤掉程序中的注释和空白;将编译器生成的错误信息和源程序的位置联系起来,记录行号
但是在词法分析之前会进行一些操作,如预处理和超前搜索。
扫描器相关
:
自上而下的语法分析->推导
下推自动机(PDA)->识别上下文无关文法所描述的语言
组成:输入带、输出带、有限状态控制器、下推栈
动作的决定因素:当前状态、读头所指符号、下推栈栈顶符号
输入串呗PDA接受:输入串为空并且下推栈为空;输入串读完,控制器到达终态
7元组包含:输入符号字母表、下推栈字母表、状态集、初态、终态集、栈顶字符、映射函数
自上而下分析法-一般方法
:试探法,或者说是带回溯的自上而下分析法
自上而下分析法-优秀方法
:LL1分析法
步骤
:文法先化简,再消除左递归,然后提取公共左因子,求first集fellow集
一些解释
:其中消除左递归是为了避免无限循环,求first集是为了进行预测,减少回溯,也就是确定当读头下是当前符号时候,使用哪个产生式去替换栈顶的非终结符
提取左因子是为了使得生成的first集两两不相交,那么就可以使预测结果唯一
求fellow集是因为找不到一个产生式对栈顶非终结符替换,使得栈顶能出现读头下的符号,那么只能使用A->空进行替换,还有一线生机,但是使用这个产生式之后,就相当于读头下的符号得是这个非终结符的下一个符号,这样才能匹配,否则还是无法匹配,所以引入了follow集,当使用空串替换非终结符时,确定后面的字符能否正确匹配。
消除左递归
:
先将间接左递归转换为直接左递归。方法为:对非终结符排序,然后对于每一个非终结符的产生式,将其中序号小于当前非终结符的非终结符使用其产生式替换,直到不存在小于当前非终结符序号的非终结符,然后消除直接左递归。
提取公共左边因子
:
First集合
是什么:FIRST集的全名叫做终结首符集,每一个非终结符都有。就是由该非终结符能够推导出的第一个终结符或空字组成的集合。
求first集
:
Follow集
:FOLLOW集是推导过程中非终结符紧接着的终结符组成的集合。
注:对于起始符的FOLLOW集需要引入“#”符号,在FOLLOW集中不可能出现空字ε
求follow集
:
构造预测分析表例子
:
LL1文法的定义
:消除左递归和提取最左公因子之后的文法G的任意两个具有相同左部的产生式A->α|β满足以下条件:(1)如果α、β均不能推导出ε,则FIRST(α)∩FIRST(β)=Φ。(2)α和β最多有1个能推导出ε,如果β能推导出ε,则FIRST(α)∩FOLLOW(A)=Φ。将满足上述条件的文法称为LL(1)文法。
或者若文法的预测分析表中不含有多重定义项,则该文法为LL(1)文法。
其中第1个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将用最左推倒,1表明只需向右看一个符号便可决定如何推倒即选择哪个产生式进行推导。LL1文法是上下文无关文法的一个子集
例子
:
递归下降分析法
:
自下而上的语法分析->优先分析法
优先分析法-简答优先分析法
:
核心
就是对句型中相邻的文法符号定义优先级,以寻找句型中的句柄->句柄内的各相邻符号之间优先级相同,句柄两端符号的优先级别高于句柄两端之外又与句柄相邻的符号的优先级。
基本思想
:
优先分析法-算符优先分析法
:->非规范分析->算法优先分析得到的分析树不一定是语法树
核心
是对所有算符(指终结符)定义优先关系,然后比较两个相继出现的算符的优先级而决定采取的动作
基本思想
:直观算符分析法使用两个工作栈:一个算符栈 (OPTR)存放运算符和括号;一个算量栈(OPND)用于存放操作数和运算结果;OPTR栈的栈顶符号用θ 表示,OPND栈的栈顶符号用π表示。
算法的流程
和中缀表达式的计算一样:
主要是看操作符栈,读入一个单词,
如果是算量,移进算量栈;
如果栈顶符号优先级小于读头下的符号,入栈;
如果栈顶符号优先级大于读头下的符号,弹出算符栈顶元素,弹出两个算量栈元素,规约之后压入算量栈;
否则出错
优点
:简单明了,易于手工实现,而且快(因为跳过了很多非终结符的规约),适于分析各种算术表达式;很容易翻译成目标代码
缺点
:算法采用两个栈,有时会把错误句子当成合法句子(因为忽略了非终结符在规约中的作用);而且,它也无法指出输入串出错位置;不好处理单目正负号
算符优先文法
:定义:产生式右部不包含两个连续的非终结符,且产生式右部的候选式中不包含空串就是算符文法
构造算符优先分析表
:
例子:
自下而上的语法分析->LR分析法
优点
:适应文法范围更广,能力更强,识别效果好;在扫描过程中能发现错误并指出出错位置
缺点
:工作量大,必须使用自动产生这种分析程序的产生器
LR分析器核心
:总控程序和分析表
基本思想
:在规范化规约(规范规约的关键是找句柄 每次都对句柄进行规约)的过程中,借助历史、展望和现实的信息。历史
:记录在栈中的符号串的移进、规约的历史情况,展望
:预测句柄之后可能出现的信息,现实
:读头下的符号
LR文法
:文法能够构造出一张分析表,使得表中每一元素至多只有一种明确动作,该文法就是LR文法,LR分析法适用的文法范围比LL1分析法适用范围广。二义文法绝不是LR文法
覆盖范围
:LR1>SLR>LR0
判断一个文法是不是LR文法
:先构造LR1分析表,满足LR1的定义就继续往下看,否则不是LR文法。接着将有规约的行全部用该规约表达式填充,看有无冲突,有冲突则非LR0,否则看能否使用SLR的方法解决,能就是SLR,不能就是LR1
文法拓广
:引入s’->s,使得文法的DFA中只有一个初态一个终态
LR0分析表的基本思想
:只根据历史信息识别呈现于栈顶的句柄
LR0分析表的构造
:对文法进行拓广,根据文法写出项目,再由项目构造含有空串的NFA,然后使用子集法对NFA进行确定化得到DFA,此时DFA的每个状态就是LR0的项目集,整个状态集就是LR0项目集规范簇,根据它填写action表和goto表得到LR0分析表。
这个DFA的作用
是识别文法中的活前缀,活前缀
是指不含句柄之后任何符号的前缀,分为归态活前缀和非归态活前缀,前者是指活前缀的尾部正好是句柄的尾部,可以进行规约,规约之后变为另一句型的活前缀,后者是指句柄尚未形成的状态
LR0分析表存在的问题
:规约-规约冲突和移进-规约冲突
LR0文法
:构造出来的分析表不含多重定义项,那该文法就是LR0文法
例子
:
SLR分析表基本思想
:基于LR0改进,在考虑历史情况的前提下,同时考虑现实(读头下的符号),可以解决LR0存在的 规约-规约冲突,但是无法解决移进-规约冲突
简单来说
加入对follow集的考虑,根据读头下的字符决定用哪个产生式规约
LR1文法
:构造出来的LR1分析表不含有多重定义项
引入原因
:FOLLOW 集提供的信息太泛,其中有些字符其实并不会出现
LR1分析表基本思想
:给每个LR0项目添加展望信息,即添加句柄之后可能出现的终结符。假设有n个终结符,那么一个LR0项目就会分裂成n个LR1项目,但是这其中只有少部分项目是有效的
例子
:
LALR1文法
:构造出来的LALR分析表不含有多重定义项
LALR分析表基本思想:在LR1的基础上进行同心合并得到,同心指的是两个项目集去掉搜索符之后是相同的。能够得到与LR0状态数相同的项目集簇,并且可以合并LR1的分析表,得到与LR0分析表形同的LALR分析表。
性质
:
项目集个数 = SLR(1)
通过合并 LR(1) 中的同心集得到,如果 LR(1) 中原本就没有 “移进-归约” 冲突,则 LALR 中也不会有,但可能会出现 “归约-归约” 冲突
LALR分析表基于LR1构建,分析能力比LR1弱,比SLR强,报错能力没有减弱分析表尺寸与SLR相同
属性文法和语法制导翻译
语法制导翻译
:通俗解释就是在语法分析得到的抽象语法树上为每个结点标注语义。核心是计算属性,而属性的计算方式有依赖图的属性计算方法、树遍历的属性计算方法、一遍扫描(最常用)的计算方法
一边遍扫描
的语法制导翻译:为每个产生式配置一个语义子程序,当语法分析进行规约或推导时,调用语义子程序,完成一部分翻译工作。语法分析完成,翻译工作也完成了。分为自上而下语法制导翻译和自下而上语法制导翻译(LR语法制导翻译)。
依赖图的属性计算方法
:在语法分析得到的语法分析树之后,根据属性文法构造属性依赖图,对结点进行拓扑排序,按照拓扑排序的次序计算属性。
树遍历的属性计算方法
:在语法分析得到的语法分析树之后, 深度优先遍历计算属性。
一遍扫描
:就是在语法分析的过程中,借助属性文法,同时进行一个属性计算,最终生成的语法分析树就是带有属性了的。S、L两种属性文法都可用于一遍扫描的分析过程,L是自上而下,S是自下而上
抽象语法树
:是什么?语法分析树中去除与语义无关的成分,就成了抽象语法树。怎么构造?使用特殊的属性文法。
属性
:比如变量的类型,变量的值等等,对文法中的每一个符号(终结符或非终结符)指派若干表达语义的值。
属性文法
:就是在上下文无关文法的基础上,为每个文法符号(终结符和非终结符)配备若干相关的“值”(也称属性),对于文法的每个产生式都配备了一组属性的计算规则(语义规则 就是符号属性之间的计算法则)。
属性文法的作用
:为文法配置上语义规则,当发生语法分析时,若是自底向上的语法分析,则当发生归约时,自动调用该规则所配置的语义规则。若是自顶向下的语法分析,则当发生向下推导时,将语义规则代入语义栈中处理。
S-属性文法
是只包含综合属性,所以对于S属性文法的计算是结合着自下而上进行的。实际实现时S-属性文法是结合LR分析器完成的,不同的地方是在栈中增加了一个存放属性的域,L属性文法
:既含有综合属性还含有继承属性(属性值的计算 实通过左边或者上面传下来的),S属性文法是L属性文法的特例
翻译模式
:翻译模式就是语法制导翻译中比较特殊的一种,根据翻译模式,可以让人更明白到了哪步需要干哪件事。翻译模式穿插在产生式中,当下一项是翻译模式时就执行该翻译模式的动作。也可认为翻译模式就是动作.
属性文法关注做什么,翻译模式关注怎么做
综合属性
:用于自下而上传递信息;在语法树中,一个结点的综合属性由其子结点的属性值确定,因此,通常使用自底向上的方法在每一个结点处使用语义规则计算综合属性的值。
继承属性
:用于自上而下传递信息;在语法树中,一个结点的继承属性由此结点的父结点或兄弟结点的某些属性确定。
综合属性和继承属性的主要区别
是依赖关系不同。一般来说,综合属性在自底向上的语法分析过程中计算,而继承属性在自上而下的语法分析过程中计算。继承属性总是由位于产生式右边的字符定义,而综合属性由左边定义。其实这个是封装性的要求。限制了在一个产生式范围内只能计算产生式左边非终结符的综合属性,只能计算产生式右边非终结符的继承属性。
注
:综合属性由子节点决定,继承属性由父节点及兄弟节点决定。那在语法分析树中,叶子节点没有子节点,根节点也没有兄弟或父节点。所有做了一些特殊规定:叶子结点的综合属性事先准备好(由词法分析器提供,叶子节点一般都是变量值这类的),而根节点的继承属性只能预先给出。
数据流分析
代码优化程序的结构
:控制流分析->数据流分析->中间代码优化,前面的控制流分析、数据流分析就是静态的分析,中间代码优化才是动态的
控制流分析
:中间代码生成的时候做了,主要是分析出程序的循环结构。
数据流分析
:对中间代码优化需要的全局数据进行采集,主要是变量值的获得和使用情况的数据流信息。包括到达定值分析、活跃变量分析、可用表达式分析。
到达定值分析
:使用数据流方程,当前基本快的流入就是上一基本块的流出,当前块的流出就是当前块产生的新数据和(当前块流入-当前块kill的数据)了两部份
活跃变量分析
:活着的放入寄存器,死了的不需要寄存器。优化时,无用变量删除、代码外提、强度削弱都需要活跃变量分析
可用表达式分析
:用于检测公共子表达式
语义分析和中间代码生成
语义分析的主要任务
:静态语义分析和中间代码生成
静态语义分析
:类型检查(检查运算操作符的类型相容性)、控制流检查(控制语句应有合法转折点)、一致性检查(在相同作用域标识符只能说明一次),若无误则进行中间代码生成
中间代码生成
生成方法
:语法制导翻译
中间代码形式
:逆波兰式,树形表示法,三元式,四元式(最常用)
语法制导翻译
:通俗解释就是在语法分析得到的语法树上为每个结点标注语义。核心是计算属性,而属性的计算方式有依赖图的属性计算方法、树遍历的属性计算方法、一遍扫描(最常用)的计算方法
一遍扫描的语法制导翻译
:为每个产生式配置一个语义子程序,当语法分析进行规约或推导时,调用语义子程序,完成一部分翻译工作。语法分析完成,翻译工作也完成了。分为自上而下语法制导翻译和自下而上语法制导翻译(LR语法制导翻译)。
PDA的下推栈扩充为状态栈,符号栈和语义栈
赋值语句的翻译,类型转换,BOOL表达式的翻译(再逻辑演算中,在控制语句中,),控制语句的翻译(goto语句,条件语句,循环语句),数组的翻译(数组赋值等等),过程调用的翻译
逆波兰式,语法制导产生后缀式
运行时的数据区管理
存储单元的分配方式
:
静态存储分配
:不允许递归调用,不含有可变数组的语言
动态存储分配
:允许递归调用,含有可变数组的语言,推式存储分配(运行程序持有一个大的存储区域,每次申请就从堆中拿一块,释放就放回堆中),栈式存储分配(进入过程就在栈顶分配一块空间,退出过程退还给系统)
允许递归调用但是不允许过程嵌套的语言(如C)的栈式存储管理
允许递归调用也允许过程嵌套的语言(如pascal)的栈式存储管理
推式存储管理
:固定常块管理,可变长块管理(首次匹配,最优匹配,最差匹配),按块长不同分为若干集合,堆空间释放,无用单元收集,
c语言的3种存储分配方式
:静态存储分配、栈式存储分配、堆式存储分配
代码优化
中间代码优化分类
:
(对基本块的优化)局部优化
(合并已知量,删除公共子表达式,变量传播和无用赋值删除),
循环优化
(循环不变运算外提,降低运算强度,变换循环控制变量i并删除自增赋值式)
全局优化(
经过循环优化之后,再做局部优化。再合并程序中的已知量,删除不同块内的公共子表达式,变量传播),需要做数据流分析
合并已知量
:对于编译时已知的常量,不必生成目标代码到运算时才计算,而是可以对其直接计算,用结果代替表达式的计算结果
删除公共子表达式
:对于两个相同的表达式,若其运算结果相同,没有必要重复生成两条运算指令
变量传播
:主要针对表达式中无用的过渡赋值,越过中间变量,直接赋值
无用赋值删除
:顾名思义
循环不变运算外提
:将循环内不变运算提到循环外面
降低运算强度
:将乘法转换为加法
变换循环控制变量i并删除自增赋值式
:使用其他必须的变量的值的变化,替换循环变量,减少额外计算
优化流程
:程序基本快划分(找到入口语句)->基本块的DAG表示->根据DAG进行块内优化
程序流图、循环优化->必经结点集和循环查找(以深度位主查找、求回边)
循环优化第一步
:找到程序流图(中间代码)中的循环
算法:1、求必经结点集,使用深度位主排序算法提高求必经节点集的效率
查找循环,利用必经结点集求回边,基于回边查找循环
求必经结点集
:初始时,第一个结点的必经结点集合是他自己一个点,其余每个结点的必经结点都是所有结点。算法开始,每个结点的必经结点集就是他所有的父结点的必经结点集并起来 然后在和当前结点或起来就是
求回边
:若有有向边a->b,但是又有b属于a的必经结点集,则a->b是回边
循环结点
就是:a,b还有a,b直接相连的结点
例题
:
目标代码生成:
将中间代码的结果如四元式,翻译为目标代码
在变量的符号表中记录待用信息和活跃信息的栏,使得寄存器的分配更加优化,目标代码执行更加高效
以基本块为单位生成目标代码
依次把四元式的中间代码变换成目标代码
在基本块的范围内考虑如何充分利用寄存器
进入基本块时,所有寄存器空闲
离开基本块时,把存在寄存器中的现行的值存回主存中,释放所有寄存器
不特别说明,所有说明变量在基本块出口之后均为非活跃变量