笔者自行整理,有错误请见谅~
题型
简答题、综合计算题
往年题
22-23软工知识点
简答
1.编译原理的程序框图
-
词法分析器:输入源程序,进行词法分析,输出单词符号;
(扫描字符流,滤掉空白符、换行符、制表符、注释等,分离出词素,输出词法单元序列)
-
语法分析器:根据文法构建分析表,对单词符号进行语法分析,检查程序是否符合语法规则;
-
语义分析与中间代码生成器:按照文法翻译规则对语法分析器归约出的语法单位进行语义分析,并把它们翻译成一定形式的中间代码;
-
优化器:对中间代码进行优化处理;
-
目标代码生成器:把中间代码翻译成目标代码。
2.有穷自动机?DFA和NFA的区别?
有限自动机:是一种偏数学的算法描述手段。分为两类,非确定有限自动机和确定有限自动机。
NFA:对边上的标号没有限制,一个符号可以作为标号出现在离开同一个状态的多条边上,ϵ可以做标号
DFA:对于每个状态以及每个标号,有且只有一条边
对于每个可以用正则表达式描述的语言,均可用某个NFA或DFA来识别。
3.推导和归约的概念
推导:将非终结符替换为它的某个产生式的体。分为直接推导、间接推导、最左推导、最右推导
最左推导:任何一步α => β都是对阿尔法中的最左非终结符进行替换。
正式定义:
归约:归约是推导的逆过程。分为直接、间接、最左、最右归约
csdn:
4.SDD,简述S-SDD和L-SDD。
SDD:即语法制导定义,将每个产生式和一组语义规则相关联,这些规则用于计算该产生式中各文法符号的属性值。
S-SDD:每个属性都是综合属性,都是根据子构造的属性计算出父构造的属性。
L-SDD:每个属性是综合属性,或是继承属性,且A→X1 X2 … Xn 中计算Xi.a的规则只用到A的继承属性,或Xi左边的文法符号Xj的继承属性或综合属性,或Xi自身的继承或综合属性。
5.划分基本块的算法
综合
正规式→DFA LL(1) LR(0) SLR(1) LR(1) LALR(1)
1.正规式→NFA→DFA→SDFA(最小化)
a
(
(
b
(
a
∣
b
)
∗
)
∣
ϵ
)
b
a
a((b(a|b)^*)|\epsilon)ba
a((b(a∣b)∗)∣ϵ)ba
可以看这个UP主的视频: 【编译原理正规式-NFA_DFA_SDF】
剩余见草稿。
2.对给定文法:
证明是**LL(1)**文法,写出FOLLOW和FIRST;画出预测分析表;给定符号串cdccccd,写出TOP-DOWN的推导过程(分析栈)
G
(
S
)
:
S
→
C
C
C
→
c
C
C
→
d
G(S):S→CC\\ \quad \quad C→cC\\ \quad \quad C→d
G(S):S→CCC→cCC→d
3.对给定文法:
证明是LR(0)文法;写出预测分析表;根据预测分析表,accd自底向上的推导过程
E
→
a
A
∣
b
B
A
→
c
A
∣
d
B
→
c
B
∣
d
E→aA|bB\\A→cA|d\\B→cB|d
E→aA∣bBA→cA∣dB→cB∣d
4.简述语法制导翻译的思想
(baidu)将语言结构的语义以属性的形式赋予代表此结构的文法符号,而属性的计算以语义规则的形式赋予由文法符号组成的产生式,在语法分析的每一步中,通过语义规则实现对属性的计算。
(往年)从概念上讲,基于属性文法的处理过程如下:对单词符号串进行语法分析,构造语法分析树,然后根据需要遍历语法树并在语法树的各节点处按照语义规则进行计算。这种有源程序的语法结构驱动的处理办法就是语法制导翻译法。
5.简述四个优化代码的算法
(1)删除公共子表达式
如果表达式 x op y 先前已被计算过,并且从先前的计算到现在,x op y 中变量的值没有改变,称为公共子表达式。可以将其删除。
(2)删除无用代码
无用代码,其计算结果永远不会被使用的语句。例如重复对多个变量赋相同的值。
(3)常量合并
如果在编译时刻推导出一个表达式的值是常量,就可以使用该常量来替代这个表达式。替换后,节省一次内存访问。
(4)代码移动
对于那些不管循环执行多少次都得到相同结果的表达式,在进入循环之前就对它们求值。
(5)强度削弱
用较快的操作代替较慢的操作。
21-22知识点
简答
2.判断一个文法是不是二义文法
给定文法,若存在某个句子,有多个最左/右推导,即可以生成多棵解析树,则这个文法就是二义的。(看一下后面的例子)
3.给一个句型,找它的句柄
句柄,也是归约项,是指在进行归约操作时,被替换的右侧产生式的符号串。
5.消除左递归(看一下后面的例子)
(不知道简答是要问什么)
6.DFA转化为正规式(找例子)
20-21
简答
1.综合属性继承属性概念:
综合属性:假设分析树结点N对应非终结符A,只能通过N的子结点或N本身的属性值**来定义的属性称为A的综合属性。终结符综合属性由语法分析器提供。
继承属性:假设解析树结点N对应非终结符A,只能通过N的父结点、N的兄弟结点或N本身的属性值来定义的属性称为A的继承属性。终结符没有继承属性。
综合
1.用语法制导翻译思想,把语句翻译成三地址码序列。while a < b do if c > d then x = y * z
19-20
简答
1.编译的前端,后端,什么是一遍扫描
前端:前端对源语言进行分析,并产生中间表示,处理与源语言相关的细节,与目标机器无关
后端:后端对中间表示进行分析、优化,并产生新的中间表示;处理与目标机器相关的细节,生成目标机器代码
一遍扫描:对源程序扫描一次被称为一遍
2.在语法制导翻译中,空返产生式的作用(M->ε)
综合
1.自己写正规式,一个单词表由a,b组成,请写出代表偶数个a的正规式,NFA,并确定化、最小化
17-18
简答
1.描述LR语法分析算法
2.
–
简答
1.举例说明文法二义性
2.符号表作用
- 收集符号属性
- 上下文语义的合法性检查的依据
- 作为目标代码生成阶段地址分配的依据
3.给文法,证明二义性
4.写出文法,表示{0、1}集上的所有正规式
5.利用语法制导思想写四元式/三地址码
6.解释LL(1)文法
(往年)一个文法满足下面条件:
(1)文法不含左递归
(2)对于文法中每一个非终结符A的各个产生式的候选首符集不相交
(3)对于于文法中每一个非终结符A,若它存在的某个候选首符集包含ε,那么first(A)∩follow(A)=空
7.写出语言L的上下文无关文法
L
=
{
a
n
b
m
c
m
d
n
∣
n
>
=
1
且
m
>
=
1
}
答案:
S
→
a
S
d
∣
a
A
d
A
→
b
A
c
∣
b
c
L=\{a^nb^mc^md^n|n>=1且m>=1\}\\ 答案: S→aSd|aAd\\ A→bAc|bc
L={anbmcmdn∣n>=1且m>=1}答案:S→aSd∣aAdA→bAc∣bc
8.正规式的概念
(baidu)正则表达式是一种用来描述正则语言的更紧凑的表示方法。
(gpt)正则表达式(Regular Expression)是一种用于描述字符串模式的形式语言。
9.语言和文法的概念
语言:语言 (language) 是某个给定字母表上的串的可数集合
文法:文法(Grammar)是一种形式化的表达式,用于描述一种语言的语法规则。文法由一组产生式组成,每个产生式定义了一种语法结构及其对应的生成方式。
一般包括四个部分:终结符、非终结符、产生式、开始符
10.现有一个词法分析方法GetToken(),和ACTION和GOTO的LR(0)预测分析表,请用伪代码完成自底向上的语法分析
11.写出比101大的二进制数的正规表达式
12.代码优化目的是什么
(gpt)提高程序的性能;减小程序的体积;提高程序的可维护性和可读性;降低程序的错误率
13.简述算符优先文法原理
PPT
CH 1-2 引论
编译器与解释器:
编译原理程序框图:
-
词法分析器:输入源程序,进行词法分析,输出单词符号;
(扫描字符流,滤掉空白符、换行符、制表符、注释等,分离出词素,输出词法单元序列)
-
语法分析器:根据文法构建分析表,对单词符号进行语法分析,检查程序是否符合语法规则;
-
语义分析与中间代码生成器:按照文法翻译规则对语法分析器归约出的语法单位进行语义分析,并把它们翻译成一定形式的中间代码;
-
优化器:对中间代码进行优化处理;
-
目标代码生成器:把中间代码翻译成目标代码。
1.预先概念
-
词素(lexeme):源程序中一段连续的字符序列。if,else,>=,pi标识符,2这种,是具体的字符值。
-
词法单元 (token):包含Token名和属性值。if,else,comparison,id,number这种,是类别。
当一个token对应多个词素时,必须通过属性来传递附加的信息
2.词法单元的模式(正则表达式)
串:
字母表,字符流中允许出现的字符
子串,一定是连续的一部分
语言:
语言的运算:
本质是集合的运算。包括并、连接、格林闭包(包含空串)、正闭包(不包含空串)
例子:
运算律
正则定义(对正则表达式引入变量):
例子:
运算符扩展:
连接、选择、格林闭包、一个或多个实例:‘+’、零个或一个实例:‘?’、‘-’ 如[a - e]等价于a | b | c | d | e
3.词法单元的识别(状态转换图)
状态转换图:状态、边
保留字和标识符的识别:1.在符号表中先填关键词,并指明它们不是普通标识符(实验用的是这种)
2.为保留字建立独立的、高优先级的状态转换图
4.构造词法分析器
有限自动机是实现词法分析器的基础
分类:非确定有限自动机(NFA)
确定有限自动机 (DFA)
DFA是特殊的NFA,没有标号为ϵ的转换,并且对于每个状态s和每个输入符号a,有且仅有一条标号为a的边离开s。
判断一个串能否被一个DFA接受(相对于NFA)更高效
每一个NFA都有一个与之等价的DFA
输入字符串x的接受与拒绝:当且仅当存在一条从开始状态到某个接受状态的路径,且该路径各条边上的标号按顺序组成x
关系:正则表达式定义语言,将语言的子集(组成字符串)输入词法分析器,词法分析器用程序模拟自动机,最后词法分析器输出接受或不接受这个字符串。
构造词法分析器的步骤:
-
第1步:选择词法单元
-
第2步:给出词法单元的正则表达式
-
第3步:将正则表达式转换为有限状态自动机
-
第4步:以有限状态自动机为基础设计词法分析程序
?如何将正则表达式转换为有限状态自动机
-
正则表达式⟹NFA(Thompson算法)
-
NFA ⟹ DFA(子集构造法)
一般综合题会给一个正则表达式,根据它构造NFA,然后转换成DFA
- Thompson例子:(忘记了可以看一下ppt)
按照Thompson算法构造的NFA都只有一个接受状态。
- 子集构造法例子:
算法需要用到三个函数,ε-closure(s),ε-closure(T),move(T,a)
解释:ε-closure(s),从状态s开始,只通过ε转换到达的状态的集合(闭包)(闭包,包含自己)
ε-closure(T),T是一个状态集合,集合中所有状态的ε-closure(s)(闭包)
move(T,a),从T中的某个状态出发,通过a的转换到达的状态集合(非闭包)
算法解释:初始,s0是开始状态0,初始T为ε-closure(s0),计算move(T,a),即从T中状态出发,能到达的状态集合,再计算这个集合的ε闭包得U。 将U加入到Dstates中:即供后续while中的未标记T进行选择。
具体还是看例子吧,多看几遍就记住了。(Notability)
子集构造算法不一定得到最简DFA
确定化NFA后的处理:
问题?如果DFA的某个接受状态含有多个对应于不同模式的NFA接受状态, 则表示存在冲突。
解决?在上述多个模式中,找出第一个尚未分配给其它DFA接受状态的模式
模式示例:
冲突示例:
DFA状态数量的最小化:(lHopcroft算法)
状态之间可区分关系
算法描述:从两个特殊状态开始,把所有可区分的状态分开 。最终没有区分开的状态就是等价的。从每个等价类中选取一个代表,构造新DFA。初始状态是{最终状态}和{剩余其他状态}的集合。
做题看看。
CH 4 语法分析
1.语法分析器的作用
根据Token流生成AST。
2.上下无关文法(CFG)
包含:终结符、非终结符、产生式、开始符
巴科斯-诺尔范式(BNF):将相同优先级的运算符归为一组
扩展的巴科斯-诺尔范式(EBNF):包含* ? +等字符。+ 出现一次或多次 * 出现零次或多次
推导概念:
文法类型:无约束文法、上下文相关文法、上下文无关文法、正则文法。要求逐渐变紧。
正则文法是特殊的上下文无关文法,要求产生式P →a, P →aQ,或P →ϵ,其中,a与ϵ为终结符(左侧为终结符)
编程语言通常使用上下文无关文法描述其语法,理由:便于设计解析算法;对于绝大多数编程语言,足够用了;应用中,CFG可以方便地将编程语言构造成分划分为几个类别:声明、表达式、语句
推导和解析树是多对一的。
**最左推导和解析树是一对一的。**最右推导和解析树是一对一的
二义性:
给定文法,若存在某个句子,有多个最左/右推导,即可以生成多棵解析树,则这个文法就是二义的。
消除二义性:
二义性主要来源:①算术表达式(算符结合性二义,算符优先级二义)②悬空else(dangling else,else与哪个then匹配二义)
消除的方法:①改写原文法 ②引入消除二义性的规则
改写原文,实现左结合;改写原文,确定优先级;改写原文,解决悬空else(即else到底与哪个then匹配)。
二义性的消除方法没有规律可循
或引入规则:例如,else和最近未匹配的then匹配。
上下无关文法的不足:文法只能描述一部分语法,剩余需通过语义分析来剔除一些符合文法、但不合法的程序。
3.语法分析技术
两种常用,自顶向下和自底向上。
自顶向下:
思想:沿根⟶叶的总体方向构造解析树,使其叶子与输入匹配,不成功则报错。(这其中的选择不是随意选,第二个选择不同分为不同的自顶向下的算法)
回溯算法:
第一个选择一样,选择当前非终结符的第一个非终结符孩子进入下一层迭代。第二个选择,按顺序选一个产生式,若与输入不匹配就回溯,换一个产生式再尝试。
缺点:对某些文法,算法会陷入无限循环(或递归)(对于左递归的文法);对于简单文法尚可应付,对于复杂文法,往往因频繁回溯,耗时过多,从而不堪用;特别地,若输入串有语法错误,则最坏时间复杂度是指数级的。
缺点1解决:消除左递归
左递归定义:
这个例子是直接左递归。经过两步或两步以上的推导出现左递归,为间接左递归。
消除直接左递归:(算法是通用的)
找准α和β,并引入新的非终结符。依次替换。
消除间接左递归:先将间接转变为直接。
缺点2解决:预测分析算法
每次为非终结符号选择适当的产生式。通过向前查看输入中的一个或多个尚未被匹配的终结符来选定产生式。
优点:对于非左递归文法,因不再回溯,从而更快
缺点:对于某些文法,仍无法选定适当的产生式,因此能处理的文法是仍有限的
分类:
LL(1)文法,第一个“ L”表示从左向右扫描输入,第二个“ L”表示最左推导,1表示向前看1个输入符号。
通过解析表,有组织地选择适当的产生式。
解析表的构建依赖于两个函数:First() Follow()。
解释:First(α),可以出现在α导出(推导)的句型的开头的终结符的集合。First(α)是符号(终结符)的集合。
计算First(X),①X本身是终结符,那么就先把它加入。 ②X是非终结符,观察它的产生式,那么按照下面的两种规则进行迭代,直到First集合不变为止。
无ε时,其实,就是说,A→B,AB都是非终结符,那么B前面是空,First(B)都要加入到First(A)中;有ε,按照上面进行迭代
计算串的First集合:
解释:Follow(X),非终结符的Follow集合。可以在某些句型中紧跟在X右边的终结符的集合。eg,若有产生式S → αAaβ,则终结符a ∈ FOLLOW(A)
计算Follow(X),关注产生式右侧,X后面的终结符/非终结符β(非ε),FIRST(β)中所有非ϵ的终结符都加入,非ε!!。
A→αX,或者A→ αXβ且FIRST(β)包含ϵ,那么FOLLOW(A)中的所有符号都加入FOLLOW(X)中
(对于开始符,先加入$。)
求Follow函数时,关注产生式右侧。按照产生式右侧中非终结符出现的顺序求follow。注意先提前把开始符的$符号加入。
Start()函数,START(A → β)–基于FIRST(β)和FOLLOW(A)
文字解释一下start。β可能是串,对应串的first计算**。填写解析表时,按照文法产生式的顺序依次填入**,关注产生式右侧,若无ε,则在first(β)集合中的终结符对应的列填入该产生式。若有ε,在上面并集中的终结符对应的列填入该产生式。剩余空白项填入error。
所以,要与先计算出所有非终结符的first和follow集合,对应求出start。
LL(1)文法:给定一个文法,若其解析表的任何一个表项至多有一个产生式,则该文法是LL(1)文法。不然表项冲突了。只能通过定义判断,即构造解析表。
左递归消除,改造为LL1文法。
有左公共因子,一定不是LL(1)文法。两个例子:
左公共因子消除算法:可能变成LL1文法,也可能不是。
通过例子说明步骤:
递归下降算法,借助系统栈实现预测分析。
自底向上:一边从左⟶右扫描输入1,一边自叶⟶根构造解析树,不成功则报错。
通用框架:移入–归约
自底向上方向,归约,反之,最右推导。
句柄:是指在进行归约操作时,被替换的右侧产生式的符号串(或子串),也称为归约项(reducible production)。
移入归约分析:
使用一个栈来保存移入/归约的文法符号,开始时,栈中只包含
$,输入的字符串结尾也为$。
在一个最右句型中,句柄右边只有终结符 ?后面懂了回来写解释
从文法的开始符经过最右推导得到的句型称为最右句型。
句柄被识别时总是出现在栈的顶部
面临的问题:①如何识别句柄 ②两种冲突:移入归约冲突;归约归约冲突
解决:LR语法分析技术
LR分析器的不同体现在,LR解析表不同,是否向前看/向前看几个符号。
分类:LR(0) SLR(1) LR(1) LALR(1)
LR(0):
(项)加点的产生式,标识,对某个产生式,处理进展到哪一步。
点先移到哪个产生式的最右侧,就用哪个进行归约。
三个概念:增广文法、项集闭包、GOTO函数
构造增广文法的规范项集族:
先求开始产生式的闭包(闭包:·后面紧接着是产生式,如果是终结符,则只有它本身)作为C,对于C中每一个产生式,找哪几个产生式可以跨越X,并将其加入C,然后·移一位。X就是当前点·后面的符号。
得到的项集族如下图所示:
LR(0)解析表构造算法:
移入 归约 都不考虑别的。
注意解析表表头:
开始对应的状态为I0
,其余方块表示的状态随意。从状态0开始,观察箭头去向I1
,且读入为终结符,则(填入s1)action为移入且状态为指向的状态;读入为非终结符,则goto的对应位置填入。若当前状态2读入后点·后面为空,且非开始状态,则归约当前状态(填入r2)。若开始状态S,·后为空,则记为accept。
顺利填写完成解析表,没有发生冲突(表项唯一),则当前文法为LR(0)文法。
SLR(1):
着眼解决上述两种冲突(移入/归约冲突,归约/归约冲突)
移入:·后为终结符 移入 非终结符 goto
归约:下一个符号属于followBi就归约
不足:a不仅包含在an中,还在follow(B)中,再次冲突。
原因:SLR(1)未考虑 (按照规则归约时,在不同的位置,要求A的后继符号不同)这种特殊性。
LR(1):
LR(1)项中包含了更多信息,来剔除某些归约动作。项的形式 [A→α⋅β", " b]。
b表示:如果将来要按照A→αβ进行归约,下一个输入符号必须是b。
构造过程,CLOSURE和GOTO与规范LR(0)有所不同。
与SLR(1)基本要求相同,只是引入展望符使得刻画更精确。
项集族构造过程:(看例子)
从开始项求闭包,(开始项的展望符为$)
解析表构造:
移入部分与前相同,展望符并没有发挥作用。
归约部分,按照展望符与下一个字符相匹配的项进行归约。
对于一个给定的文法,如果其LR(1)分析表中没有语法分析动作冲突, 那么该文法就称为LR(1)文法
LR(1)分析能力强大,代价是状态数量庞大
LALR(1):
将LR(1)缩减状态数量 得到LALR(1)。能力接近LR(1),状态数量接近SLR(1)
不计展望符,将项相同的状态合为一个。
合并不会导致移入/归约冲突,但仍有可能会引起归约/归约冲突。
二义性文法:
之前的均为非二义性文法。有二义性的文法构造解析表一定有冲突。
二义性文法:优先级结合性、悬空else
事先规定(二义性消除规则)优先级,可以消除冲突。
else悬空:遇到e就移入,保证与最近的then匹配。
二义性文法要慎用。
CH 5 语法制导翻译 语义分析
1.语法制导翻译
[baidu]语法制导翻译的基本思想,将语言结构的语义以属性的形式赋予代表此结构的文法符号,而属性的计算以语义规则的形式赋予由文法符号组成的产生式,在语法分析的每一步中,通过语义规则实现对属性的计算。
CFG中的文法符号设置语义属性,以表示其对应的语义信息。通过语义规则来计算文法符号的语义属性值,而语义规则与文法符号所在的产生式(语法规则)紧密相关。
SDD语法制导定义:将每个产生式和一组语义规则相关联,这些规则用于计算该产生式中各文法符号的属性值
SDT语法制导翻译方案:可以看作是对SDD的一种补充,是SDD的具体实施方案
文法符号的属性分为综合属性 继承属性
综合属性:假设分析树结点N对应非终结符A,只能通过N的子结点或N本身的属性值**来定义的属性称为A的综合属性。终结符综合属性由语法分析器提供。
继承属性:假设解析树结点N对应非终结符A,只能通过N的父结点、N的兄弟结点或N本身的属性值来定义的属性称为A的继承属性。终结符没有继承属性。
例子:
属性文法:在属性文法的语义规则中,仅仅通过其它属性值和常量来定义一个属性值。没有副作用(print)。
属性值计算顺序:依赖图(属性之间的依赖关系)的拓扑排序。
如果图中没有环,那么至少存在一个拓扑排序。
存在两类SDD,不允许产生带有环的依赖图。S属性定义 L属性定义
S属性定义:每个属性都是综合属性
L属性定义:范围更广,综合属性、继承属性(依赖的继承属性是前面算过的)
2.抽象语法树AST
浓缩的解析树。
CH 6 中间代码生成
1.中间代码表示
静态类型检查和中间代码生成的过程都可以通过遍历抽象语法树来实现
三地址码:
一种常用的中间代码。每条指令右侧最多有一个运算符。
一般形式:x = y op z
包括四元式、三元式、、、
CH 7-8 运行时环境 代码生成
运行时环境:硬件(寄存器、虚拟内存)、应用程序等。
CH 9 代码优化
1.基本块和控制流
将中间代码划分为基本块,除基本块的最后一条指令外,控制流不会跳转/停机。
控制流图的结点是基本块,边指明了哪些基本块可 以跟在一个基本块之后运行
划分基本块算法:
①确定首指令(指令序列第一条、转移指令的目标指令、转移指令后的指令)②从首指令到下一个首指令之前为一个基本块
明确,跳转指令一定位于所在基本块的最后一条指令;在基本块内部,指令是连续执行的。
控制流图:
节点:基本块
边:因跳转而生成、因为顺序而生成
2.优化的分类
- 机器无关优化
针对中间代码
- 机器相关优化
针对目标代码
- 局部代码优化
单个基本块范围内的优化
- 全局代码优化
面向多个基本块的优化
3.常用的优化方法
- 删除公共子表达式
表达式 x op y 先前已被计算过,且变量x y的值没变,则为公共表达式。
例如,第二次无需再计算,直接将前面计算过的变量赋值即可。
- 删除无用代码
例如重复对多个变量赋相同的值。
无用代码,其计算结果永远不会被使用的语句。
- 常量合并
如果在编译时刻推导出一个表达式的值是常量,就可以使用该常量来替代这个表达式。替换后,节省一次内存访问。
- 代码移动
对于那些不管循环执行多少次都得到相同结果的表达式,在进入循环之前就对它们求值。
- 强度削弱
用较快的操作代替较慢的操作。
较快:耗费时钟周期较少的运算