赞
踩
词法分析的主要任务:从左向右逐行扫描源程序的字符,识别出各个单词,确定单词的类型。 将识别出的单词转换成统一的机内表示——词法单元(token)形式
语法分析器(parser)从词法分析器输出的token序列中识别出各类短语,并构造语法分析树(parse tree)
语义分析的主要任务
为改进代码所进行的等价程序变换,使其运行得更快一些、占用空间更少一些,或者二者兼顾
字母表∑是一个有穷符号集合
字母表∑1和∑2的乘积( product) ∑1∑2 ={ab|a ∈ ∑1, b ∈ ∑2}
字母表∑的n次幂( power)
∑0 ={ ε }
∑n =∑n-1 ∑ , n ≥ 1
字母表的n次幂:长度为n的符号串构成的集合
字母表∑的正闭包( positive closure)
∑+ = ∑∪∑2∪∑3∪…
字母表的正闭包:长度正数的符号串构成的集合
字母表∑的克林闭包(Kleene closure)
∑ 克林闭包= ∑0∪∑+ = ∑0∪∑∪∑2∪∑3∪…
字母表的克林闭包:任意符号串(长度可以为零)构成的集合
设∑是一个字母表,任意x∈∑克林闭包,x称为是∑上的一个串
串是字母表中符号的一个有穷序列
串s的长度,通常记作|s|,是指s中符号的个数
空串是长度为0的串,用 ε(epsilon)表示
如果 x和y是串,那么x和y的连接(concatenation)是把y附加到x后面而形成的串,记作xy
空串是连接运算的单位元( identity),即,对于任何串s都有,εs = sε = s
设x,y,z是三个字符串,如果 x=yz, 则称y是x的前缀,z是x的后缀
串s的幂运算
串s的n次幂:将n个s连接起来
G=(VT ,VN ,P,S)
VT :终结符集合
VN:非终结符集合
P :产生式集合
S :开始符号
句子的推导(派生)-从生成语言的角度
句子的归约 - 从识别语言的角度
如果 S ->star α,α∈(VT∪VN)star ,则称α是G的一个句型 (sentential form)
如果 S ->star w,w ∈VTstar,则称w是G的一个句子(sentence)
由文法G的开始符号S推导出的所有句子构成 的集合称为文法G生成的语言,记为L(G )。 即
L(G )= {w | S ->star w, w∈ VT star }
前提:α →β
0型文法:α中至少包含1个非终结符
1型文法(CSG) :|α|≤|β|
2型文法(CFG) :α ∈ VN
3型文法(RG):A→wB 或 A→w (A→Bw 或A→w)
给定一个推导 S -> α1-> α2->…-> αn ,对于推导 过程中得到的每一个句型αi,都可以构造出一个 边缘为αi的分析树
给定一个句型,其分析树中的每一棵子树的边缘称为该句型的一个短语(phrase)
如果一个文法可以为某个句子生成多棵分析树, 则称这个文法是二义性的
对于任意一个上下文无关文法,不存在一个算法, 判定它是无二义性的;但能给出一组充分条件, 满足这组充分条件的文法是无二义性的
正则表达式 (Regular Expression,RE ) 是一种用来描述正则语言的更紧凑的表示方法
正则表达式可以由较小的正则表达式按照特定规则递归地 构建。每个正则表达式 r定义(表示)一个语言,记为L(r )。 这个语言也是根据r 的子表达式所表示的语言递归定义的。
运算的优先级:*、连接、|
可以用RE定义的语言叫做正则语言(regular language)或正则集合(regular set)
对任何正则文法 G,存在定义同一语言的 正则表达式 r
对任何正则表达式 r,存在生成同一语言的 正则文法 G
转换图 (Transition Graph)
给定输入串x,如果存在一个对应于串x的从初始状态到某个终止状态的转换序列,则称串x被该FA接收
由一个有穷自动机M接收的所有串构成的集合称为是该FA定义(或接收)的语言,记为L(M )
当输入串的多个前缀与一个或多个模式匹配时, 总是选择最长的前缀进行匹配
在到达某个终态之后,只要输入带上还有符号, DFA就继续前进,以便寻找尽可能长的匹配
概念:指寻找一个状态数比DFA M少的DFA M’,使得L(M)=L(M’)
一个确定有限自动机M是通过①消除多余状态和②合并等价状态而转换成一个最小的与之等价的有限自动机来实现其化简的。
概念:从该自动机的初始状态出发,任何输入串也不能到达的那个状态。
对于给定的DFA M,若它含有多余状态,可以非常简单地将多余状态消除,而得到与之等价的有穷自动机。
在DFA M里如果两个状态若不等价,则称这两个状态是可区别的。
子集分割法:把一个DFA M的状态分割成一些不相交的子集,使得任何不同的两个子集的状态都是可区别的,而同一子集中的两个状态都是等价的。最后,在每个子集中选出一个代表,同时消去其他等价的状态。如果在从M′中删除所有的无用状态(多余状态),则M′便是最简的(状态最少),从而得到把DFA M状态简化了的DFA M’。
每一步推导中,都需要做两个选择
在最左推导中,总是选择每个句型的最左非终结符进行替换
如果S->* α,则称α是当前文法的最左句型 (left-sentential form)
自顶向下的语法分析采用最左推导方式
在最右推导中,总是选择每个句型的最右非终结符进行替换
在自底向上的分析中,总是采用最左归约的方式,因此把最左归约称为规范归约,而最右推导相应地称为规范推导
预测分析是递归下降分析技术的一个特例,通过 在输入中向前看固定个数(通常是一个)符号来选 择正确的A-产生式。
可以对某些文法构造出向前看k个输入符号的预测分析 器,该类文法有时也称为LL(k) 文法类
预测分析不需要回溯,是一种确定的自顶向下分析方法
含有A→Aα形式产生式的文法称为是直接左递归的 (immediate left recursive)
如果一个文法中有一个非终结符A使得对某个串α存在一个推导A->+Aα ,那么这个文法就是左递归的
经过两步或两步以上推导产生的左递归称为是间接左递归的
事实上,这种消除过程就是把左递归转换成了右递归
通过改写产生式来推迟决定,等读入了足够多的输入,获得足够信息后再做出正确的选择
S_文法不含ε产生式
预测分析法的工作过程:从文法开始符号出发,在每一步推导过程中根据当前句型 的最左非终结符A和当前输入符号a,选择正确的 A- 产生式。为保证分析的确定性,选出的候选式必须是唯一的。
可能在某个句型中紧跟在A后边的终结符a的集合,记为FOLLOW(A),FOLLOW(A)={a| S->αAaβ, a∈VT,α,β∈(VT ∪ VN)*}
如果 A是某个句型的的最右符号, 则将结束符 “$” 添加到 FOLLOW(A) 中
产生式A→β的可选集是指可以选用该产生式进行推导时对应的输入符号的集合,记为SELECT( A→β )
SELECT( A→aβ ) = { a }
SELECT( A→ε )=FOLLOW( A )
q_文法不含右部以非终结符打头的产生式
串首第一个符号,并且是终结符,简称首终结符
给定一个文法符号串α, α的串首终结符集FIRST(α)被定义为可以从α推导出的所有串首终结符构成的集合。
产生式A→α的可选集SELECT
文法G是LL(1)的,当且仅当G的任意两个具有相同左部的产生式A → α | β 满足下面的条件
sum=同一非终结符的各个产生式的可选集互不相交
算法:不断应用下列规则,直到没有新的终结符或ε可以被 加入到任何FIRST集合中为止
算法:不断应用下列规则,直到没有新的终结符可以被加 入到任何FOLLOW集合中为止
递归的预测分析法是指:在递归下降分析中,根据预测分析表进行产生式的选择
根据每个非终结符的产生式和LL(1)文法的预测分析表,为每个非终结符编写对应的过程
非递归的预测分析不需要为每个非终结符编写递归下降过程,而是根据预测分析表构造一个自动机,也叫表驱动的预测分析
自底向上语法分析的通用框架:移入 - 归约分析(Shift-Reduce Parsing)
LR文法是最大的、可以构造出相应移入 - 归约语法分析器的文法类
LR(k)分析:需要向前查看k个输入符号的LR分析
k = 0和k = 1这两种情况具有实践意义,当省略 (k) 时,表示 k =1
自底向上分析的关键问题是什么? ans:如何正确地识别句柄
句柄是逐步形成的,用“状态”表示句柄识别的进展程度
右部某位置标有圆点的产生式称为相应文法的一个LR(0) 项目(简称为项目)
项目描述了句柄识别的状态
产生式A→ε 只生成一个项目A→ ·
如果G 是一个以S为开始符号的文法,则G的增广文法 G’ 就是在G中加上新开始符号S’ 和产生式S’ → S而得到的文法
引入这个新的开始产生式的目的是使得文法开始符号仅出现在一个产生式的左边,从而使得分析器只有一个接受状态
同属于一个产生式的项目,但圆点的位置只相差一个符号,则称后者是前者的后继项目
eg A→α· Xβ的后继项目是A→αX·β
可以把等价的项目组成一个项目集( I ) ,称为项目集闭包 (Closure of Item Sets),每个项目集闭包对应着自动机的一个状态
计算给定项目集I的闭包 CLOSURE(I) =I ∪{B→·γ|A→α·Bβ∈CLOSURE(I),B→γ∈P}
返回项目集I对应于文法符号X的后继项目集闭包GOTO( I, X )=CLOSURE({A→αX·β | A→α·Xβ∈I })
规范LR(0) 项集族(Canonical LR(0) Collection)C={I0}∪{I | 存在J∈C, X∈VN∪ VT , I=GOTO(J , X) }
SLR分析存在的问题:SLR只是简单地考察下一个输入符号b是否属于与归约项目A→α相关联的FOLLOW(A),但b∈FOLLOW(A) 只是归约α的一个必要条件,而非充分条件
对于产生式 A→α的归约,在不同的使用位置,A会要求不同的后继符号
在特定位置,A的后继符集合是 FOLLOW(A) 的子集
将一般形式为 [A→α· β, a]的项称为 LR(1) 项,其中A→αβ 是 一个产生式,a 是一个终结符(这里将$视为一个特殊的终结符) 它表示在当前状态下,A后面必须紧跟的终结符,称为该项的展望符
LR(1) 中的1指的是项的第二个分量的长度
在形如[A→α·β, a]且β ≠ ε的项中,展望符a没有任何作用,但是一个形如 [A→α·, a]的项在只有在下一个输入符号等于a时才可 以按照A→α 进行归约
这样的a的集合总是FOLLOW(A)的子集,而且它通常是一个真子集
b∈FIRST(βa)
CLOSURE( I ) = I ∪ { [B→·γ, b] | [A→α·Bβ,a] ∈ CLOSURE( I ), B→γ∈P, b∈FIRST(βa) }
GOTO( I, X ) = CLOSURE({[A→αX·β,a]|[A→α·Xβ, a]∈I })
合并同心项集后,虽然不产生冲突,但可能会推迟错误的发现
合并同心项集不会产生移进 - 归约冲突
合并同心项集后,虽然不产生冲突,但可能会推迟错误的发现
LALR分析法可能会作多余的归约动作, 但绝不会作错误的移进操作,因为合并同心项集不会影响移进
如何表示语义信息?
如何计算语义属性?
将语义规则同语法规则(产生式)联系起来要 涉及两个概念
SDD 是对CFG的推广
SDT是在产生式右部嵌入了程序片段的CFG,这些程序片段称为语义动作。
一个语义动作在产生式中的位置决定了这个动作的执行时间
SDD
SDT
在分析树结点 N上的非终结符A的综合属性只能通过N的子结点或 N本身的属性值来定义
终结符可以具有综合属性:终结符的综合属性值是由词法分析器提供的词法值,因此在SDD中没有计 算终结符属性值的语义规则
在分析树结点 N上的非终结符A的继承属性只能通过N的父结点、N的兄弟结点或 N本身的属性值来定义
终结符没有继承属性:终结符从词法分析器处获得 的属性值被归为综合属性值
一个没有副作用的SDD有时也称为属性文法
属性文法的规则仅仅通过其它属性值和常量来定义一个属性值
按照什么顺序计算属性值?
可行的求值顺序是满足下列条件的结点序列N1, N2, … , Nk :如果依赖图中有一条从结点Ni到 Nj 的边(Ni→Nj), 那么i < j(即:在节点序列中,Ni 排在Nj 前面)
这样的排序将一个有向图变成了一个线性排序, 这个排序称为这个图的拓扑排序(topological sort)
仅仅使用综合属性的SDD称为S属性的SDD,或S-属性定义、S-SDD
一个SDD是L-属性定义,当且仅当它的每个属性要 么是一个综合属性,要么是满足如下条件的继承属 性:假设存在一个产生式A→X1X2…Xn,其右部符 号Xi (1<= i <= n)的继承属性仅依赖于下列属性:
注:每个S-属性定义都是L-属性定义
语法制导翻译方案(SDT )是在产生式右部中嵌入了程序片段(称为语义动作)的CFG
SDT可以看作是SDD的具体实施方案
将一个S-SDD转换为SDT的方法:将每个语义动作都放在产生式的最后
如果一个S-SDD的基本文法可以使用LR分析技术,那么它的SDT可以在LR语法分析过程中实现
将L-SDD转换为SDT的规则
如果一个L-SDD的基本文法可以使用LL分析技术,那么它的SDT可以在LL或LR语法分析过程中实现
扩展语法分析栈
分析栈中的每一个记录都对应着一段执行代码
给定一个以LL文法为基础的L-SDD,可以修改这个文法,并在LR语法分析过程中计算这个新文法之上的SDD
赋值语句翻译的主要任务:生成对表达式求值的三地址码
将数组引用翻译成三地址码时要解决的主要问题是确定数组元素的存放地址,也就是数组元素的寻址
在跳转代码中,逻辑运算符&&、|| 和 ! 被翻译成跳转指令。运算符本身 不出现在代码中,布尔表达式的值是通过代码序列中的位置来表示的
任何SDT都可以通过下面的方法实现:首先建立一棵语法分析树,然后按照从左到右的深度优先顺序来执行这些动作
生成一个跳转指令时,暂时不指定该跳转指令的目标标 号。这样的指令都被放入由跳转指令组成的列表中。同一个列表中的所有跳转指令具有相同的目标标号。等到能够确定正确的目标标号时,才去填充这些指令的目标标号。
编译器在工作过程中,必须为源程序中出现的一些数据对象分配运行时的存储空间
注:静态和动态分别对应编译时刻和运行时刻
在静态存储分配中,编译器为每个过程确定其活动记 录在目标程序中的位置,这样,过程中每个名字的存储位置就确定了。因此,这些名字的存储地址可以被编译到目标代码,过程每次执行时,它的名字都绑定到同样的存储单元。
适合静态存储分配的语言必须满足以下条件
满足这些条件的语言有BASIC和FORTRAN等
顺序分配法
层次分配法
有些语言使用过程、函数或方法作为用户自定义动作的单 元,几乎所有针对这些语言的编译器都把它们的(至少一 部分的)运行时刻存储以栈的形式进行管理,称为栈式存 储分配
当一个过程被调用时,该过程的活动记录被压入栈;当过程结束时,该活动记录被弹出栈
这种安排不仅允许活跃时段不交叠的多个过程调用之间共 享空间,而且允许以如下方式为一个过程编译代码:它的非局部变量的相对地址总是固定的,和过程调用序列无关
用来描述程序运行期间控制进入和离开各个活动的情况的树称为活动树
过程调用和过程返回都需要执行一些代码来管理活动记录 栈,保存或恢复机器状态等
调用序列
实现过程调用的代码段。为一个活动记录在栈中分配空间,并在此记录的字段中填写信息
返回序列
一个调用代码序列中的代码通常被分割到调用过程(调用者) 和被调用过程(被调用者)中。返回序列也是如此。
一个过程除了可以使用过程自身定义的局部数据以 外,还可以使用过程外定义的非局部数据
语言可以分为两种类型
变量的存储分配和访问
嵌套深度
静态作用域规则:只要过程b的声明嵌套在过程a的声明中,过程b就可以访问过程a中声明的对象
建立访问链的代码属于调用序列的一部分
假设嵌套深度为nx的过程x调用嵌套深度为ny的过程y (x→y)
符号表的组织:为每个作用域(程序块)建立一个独立的符号表
实际上,这种为每个过程或作用域建立的符号表与编译时的活动记录是对应的。一个过程的非局部名字的信息可以通过扫描外围过程的符号表而得到
红色箭头在建表的时候完成,蓝色箭头在表建好之后完成。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。