转自:https://www.jianshu.com/p/eb63d31ad638php
汇编指令:用符号表示的指令被称为汇编指令
汇编语言:汇编指令的集合称为汇编语言css
转换(也被称为预处理):高级语言之间的翻译,如FORTRAN
到ADA
的转换
编译:高级语言能够直接翻译成机器语言,也能够翻译成汇编语言,这两个翻译过程称为编译
汇编:从汇编语言到机器语言的翻译被称为汇编
交叉汇编:将一个汇编语言程序汇编成为可在另外一机器上运行的机器指令成为交叉汇编
反汇编:把机器语言翻译成汇编语言
反编译:把汇编语言翻译成高级语言前端
(1)语言翻译的两种基本形态程序员
解释器与编译器的主要区别:运行目标程序时的控制权在解释器
而不在目标程序.算法
(2)各自特色后端
工做效率高
,即时间快、空间省;交互性与动态性差,可移植性差
.工做效率低
,,即时间慢、空间费;交互性与动态性好,可移植性好
.共同点:均完成对源程序
的翻译.
差别:编译器采用先翻译后执行,解释器采用边翻译边执行.数组
(0)通用程序设计语言的主要成份 声明+操做=完整定义
ruby
(1)以过程
为基本结构的程序设计语言的组成bash
(2)以阶段划分编译器数据结构
注:符号表管理器和出错处理贯穿编译器工做的各个阶段.
(3)编译器各阶段工做
1> 词法分析:词法分析的输入是源程序
,输出是识别出的记号流
.目的是识别单词
. 至少分如下几类:关键字(保留字)、标识符、字面量、特殊符号
2> 语法分析: 输入是词法分析器返回的记号流
,输出是语法树
.目的是获得语言结构并以树的形式表示.对于声明性语句,进行符号表的查填,对于可执行语句,检查结构合理的表达式运算是否有意义.
3> 语义分析:根据语义规则对语法树中的语法单元进行静态语义检查,如类型检查和转换等,目的在于保证语法正确的结构在语义分析上也是合法的.
4> 中间代码生成(可选):生成一种既接近目标语言,又与具体机器无关的表示,便于代码优化与代码生成.
(到目前为止,编译器与解释器能够一致)
5> 中间代码优化(可选):局部优化、循环优化、全局优化等;优化其实是一个等价变换,变换先后的指令序列完成一样的功能,但在占用的空间上和程序执行的时间上都更省、更有效
6> 目标代码生成:不一样形式的目标代码—汇编语言形式、可重定位二进制代码形式、内存形式(Load-and-Go)
7> 符号表管理:合理组织符号,便于各阶段查找\填写等.
8> 出错处理:
动态错误:源程序中的逻辑错误,发生在程序运行的时候。也称为动态语义错误
静态错误:静态错误分为语法错误和静态语义错误.
<1> 语法错误:有关语言结构上的错误,如单词拼写错误、表达式缺乏操做数、begin和end不匹配 <2> 静态语义错误:分析源程序时能够发现的语言意义上的错误,如加法的两个操做数一个是整形变量,另外一个是数组名
(4)编译器的分析\综合模式
逻辑上把编译器分为分析(前端)部分
和综合(后端)部分
.
1> 分析(前端):语言结构和意义的分析; 从词法分析到中间代码生成各阶段的工做
2> 综合(后端):语言意义处理;从中间代码生成到目标代码生成的各阶段的工做
3> 编译器和解释器的区别每每是在造成中间代码以后开始的.
每一个阶段将程序完整分析一遍的工做模式称为一遍扫描。
(将源程序或源程序的某种形式的中间表示完整分析一遍,亦称做一遍扫描)
(1) 记号、模式与单词
单词的分类:关键字(保留字)、标识符、字面量、特殊符号
模式(pattern):产生/识别单词的规则
记号(token):按照某个模式(或规则)识别出的元素(一组)
单词(lexeme):被识别出的元素的值(字符串自己) ,也称为词值
(2) 词法分析器的做用与工做方式
词法分析器的做用:
1> 识别记号并交给语法分析器(根据模式识别记号)
2> 滤掉源程序中的无用成分,如注释、空格和回车等
3> 处理与具体平台有关的输入(如文件结束符的不一样表示等)
4> 调用符号表管理器和出错处理器,进行相关处理
工做方式:
1.单独一遍扫描
2.做为语法分析器的子程序
3.并行方式
(1) 字符串与语言
语言L是有限字母表∑上有限长度字符串的集合.
定义中强调两个有限,由于计算机的表示能力有限 :
1> 字母表是有限的,即字母表中元素是有限多个;
2> 字符串的长度是有限的,即字符串中字符个数是有限多个。
(字符串与字符串集合相关的概念与运算,如前缀、后缀、子串、子序列等,字符串的并、交、链接、差、闭包)
(2) 正规式与正规集
令Σ是一个有限字母表,则Σ上的 正规式 及其表示的集合递归定义以下: 1. ε是正规式,它表示集合 L(ε) = {ε} 2. 若a是Σ上的字符,则a是正规式,它表示集合L(a)={a} 3. 若正规式r和s分别表示集合L(r)和L(s),则 (a) r|s是正规式,表示集合L(r)∪L(s), (b) rs是正规式,表示集合L(r)L(s), (c) r*是正规式,表示集合(L(r))*, (d)(r)是正规式,表示的集合仍然是L(r)。 括弧用来改变运算的前后次序!
可用正规式描述(其结构)的语言称为 正规语言 或 正规集 。
若运算的优先级和结合性作下述约定: 1. 三种运算均具备左结合性质; 2. 优先级从高到低顺序排列为:闭包运算、链接运算、或运算。 则正规式中没必要要的括号能够被省略。
若正规式P和Q表示了同一个正规集,则称P和Q是等价的,记为P=Q
(3) 简化正规式描述(主要是简化书写上的复杂)
(a) 正闭包 若r是表示L(r)的正规式,则r+是表示(L(r))+的正规式,且下述等式成立:r+ = rr* = rr,r = r+|ε; +与*具备相同的运算结合性和优先级 (b) 可缺省 若r是正规式,则r?是表示L(r)∪{ε}的正规式,且下述等式成立:r? = r|ε ? 与 * 具备相同的运算结合性和优先级 (c) 串 若r是若干字符进行链接运算构成的正规式,则:串“r” = r ,且: ε= “”, a = “a”(a是Σ的任一字符) (d) 字符组 若r是若干字符进行|运算构成的正规式,则可改写为 [r’],其中r’能够有以下两种书写形式: 枚举: 如 a|b|e|h,可写为 [abeh]: 分段: 如0|1|2|3|4|5|6|7|8|9|a|b|c|d|e , 可写为: [0-9a-e] (e) 非字符组 若[r]是一个字符组形式的正规式,则[^r]是表示∑- L([r])的正规式。
(1) 不肯定的有限自动机(NondeterministicFinite Automaton, NFA)
NFA是一个五元组(5-tuple):M =(S,∑,move,s0,F),其中 (1) S是有限个状态(state)的集合; (2) ∑是有限个输入字符(包括ε)的集合; (3) move是一个状态转移函数,move(si,ch)=sj表示,当前状态si下若遇到输入字符ch,则转移到状态sj; (4) s0是惟一的初态(也称开始状态); (5) F是终态集(也称接受状态集),它是S的子集,包含了全部的终态。
<1> 直观的表示方式
① 状态转换图:用一个有向图来直观表示NFA
② 状态转换矩阵:用一个矩阵来直观表示NFA (矩阵中,状态对应行,字符对应列)
<2> NFA(识别记号)的特色
NFA识别记号的最大特色是它的不肯定性,即在当前状态下对同一字符有多于一个的下一状态转移。
具体体现:
定义: move函数是1对多的; 状态转换图:从同一状态出发,可经过多于一条标记相同字符的边转移到不一样的状态; 状态转换矩阵: M[si,a]是一个状态的集合
<3> NFA识别记号存在的问题
1.只有尝试了所有可能的路径,才能肯定一个输入序列不被接受,而这些路径的条数随着路径长度的增加成指数增加
2.识别过程当中须要进行大量回朔,时间复杂度升高且算法复杂
(2) 肯定的有限自动机(Deterministic Finite Automaton, DFA)
定义: DFA是NFA的一个特例,其中: (1)没有状态具备ε状态转移(ε-transition),即状态转换图中没有标记ε的边; (2)对每一个状态s和每一个字符a,最多有一个下一状态。 特色:与NFA相比,DFA的特征:肯定性 定义:move(si, a)函数都是 1对1 的; 转换图 从一个状态出发的任2条边上的标记均不一样; 转换矩阵:M[si,a]是一个状态 且字母表不包括ε。 提示:正规式和有限自动机从两个侧面表示正规式。正规式是描述,自动机是识别。
构造词法分析器的通常方法和步骤: 1. 用正规式描述模式(为记号设计正规式); 2. 为每一个正规式构造一个NFA,它识别正规式所表示的正规集; 3. 将构造的NFA转换成等价的DFA,这一过程也被称为肯定化; 4. 优化DFA,使其状态数最少,这一过程也被称为最小化; 5. 根据优化后的DFA构造词法分析器。
(1) 从正规式到NFA
Thompson 算法
(2) 从NFA到DFA
- smove(S, a):从状态集S出发,标记为a的下一状态全体。与move(s, a)的惟一区别:用状态集取代状态 - ε-闭包(T):从状态集T出发,不经任何字符达到的状态全体 - “子集法”构造DFA
(3) 最小化DFA
① 对于任何两个状态t和s,若从一状态出发接受输入字符串ω,而从另外一状态出发不接受ω.
或者,② 从t出发和从s出发到达不一样的接受状态,则称ω对状态t和s是可区分的.
不可区分的状态位于一个组内,能够合并成一个状态.
主要步骤:
1.初始划分:终态组 , 非终态组;
2.利用可区分的概念,反复分裂划分中的组Gi,直到不可再分裂;
3.由最终划分构造D',关键是选表明和修改状态转移;
4.消除可能的死状态和不可达状态。
分类:表驱动型的词法分析器;直接编码的词法分析器
比较:
表驱动 | 直接编码 | |
---|---|---|
分析器的速度 | 慢 | 快 |
程序与模式的关系 | 无关 | 有关 |
适合的编写方法 | 工具生成 | 手工编写 |
分析器的规模 | 较大 | 较小 |
词法分析:记号的集合,字符串由字母组成,线性结构
语法分析:句子的集合,句子由记号组成,非线性结构(树)
语法分析的双重含义:
许多编译器,特别是由自动生成工具构造的编译器,每每其前端的中心部件就是语法分析器
(1)语法分析器的做用
(2)语法错误的处理原则
源程序中可能出现的错误
语法(包括词法)错误和语义错误(静态语义错误和动态语义错误)
注:跟第一章的分类角度不一样,第一章是从静态错误(语法错误,静态语义错误)和动态错误(动态语义错误)分类的,可是异曲同工。
词法错误:指非法字符或拼写错关键字、标识符等
语法错误:指语法结构出错,如少分号、括号不匹配、begin/end不配对等
静态语义错误:如类型不一致、参数不匹配等
动态语义错误(逻辑错误):如死循环、变量为零时做除数等
(1)上下文无关文法(Context Free Grammar,CFG)
CFG是一个四元组G =(N,T,P,S),其中 (1) N是非终结符(Nonterminals)的有限集合; (2) T是终结符(Terminals)的有限集合,且N∩T=Φ; (3) P是产生式(Productions)的有限集合,A→α,其中A∈N(左部),α∈(N∪T)*(右部),若α=ε,则称A→ε为空产生式(也能够记为A →); (4) S是非终结符,称为文法的开始符号(Start symbol) 注: S ∈ N , N能够出如今产生式左边和右边,T毫不出如今产生式左边.
(2)CFG产生语言的基本方法-推导
CFG(产生式)经过推导的方法产生语言,即(通俗地讲)从开始符号S开始,反复使用产生式:将产生式左部的非终结符替换为右部的文法符号序列(展开产生式,用=>表示),直到获得一个终结符序列。
1> 直接推导:利用产生式产生句子的过程当中,将用产生式A→γ的右部代替文法符号序列αAβ中的A获得αγβ的过程,称αAβ直接推导出αγβ,记做:αAβ=>αγβ
2> 零步或多步推导:若对于任意文法符号序列α1,α2,...αn,有α1=>α2=>...=>αn,则称此过程为零步或多步推导,记为:α1 =*> αn,其中α1=αn的状况为零步推导。
3> 至少一次推导:若α1≠αn,即推导过程当中至少使用一次产生式,则称此过程为至少一步推导,记为:α1 =+> αn
(推导具备自反性和传递性)
4> 由 CFGG 所产生的语言L(G)被定义为: L(G) = { ω┃S ωand ω∈T* },
L(G)称为上下文无关语言(Context Free Language, CFL),ω称为句子。
若S =* > α,α∈(N∪T)*,则称α为G的一个句型。句子必定是句型,反之不是。
5> 在推导过程当中,若每次直接推导均替换句型中最左边的非终结符,则称为最左推导
,由最左推导产生的句型被称为左句型
。 相似的能够定义最右推导与右句型,最右推导也被称为规范推导。
(3)推导、分析树与语法树
一、分析树既反映语言结构的实质,也反映推导过程。
二、对CFGG的句型,分析树被定义为具备下述性质的一棵树。
(1) 根由开始符号所标记;
(2) 每一个叶子由一个终结符、非终结符、或ε标记;
(3) 每一个内部结点由一个非终结符标记;
(4) 若A是某内部节点的标记,且X1,X2,...,Xn是该节点从左到右全部孩子的标记,则A→X1X2...Xn是一个产生式。若A→ε,则标记为A的结点能够仅有一个标记为ε的孩子。
注:分析树的叶子,从左到右构成G的一个句型。若叶子仅由终结符标记,则构成一个句子。
三、对CFG G的句型,表达式的语法树被定义为具备下述性质的一棵树:
(1) 根与内部节点由表达式中的操做符标记;
(2) 叶子由表达式中的操做数标记;
(3)用于改变运算优先级和结合性的括号,被隐含在语法树的结构中。
(4)二义性与二义性的消除
二义性:若文法G对 同 一句子产生不止一棵分析树
,则称G是二义的.
结论:
1> 一个句子有多于一棵分析树,仅与文法和句子有关,与采用的推导方法无关;
2> 形成文法二义的根本缘由:文法中缺乏对文法符号优先级和结合性的规定
二义性消除的方法:
① 改写二义文法为非二义文法;
② 规定二义文法中符号的优先级和结合性,使仅产生一棵分析树。
(1)正规式与上下文无关文法
正规式所描述的语言结构都可以用CFG描述,反之不必定.
(2)上下文有关文法CSG
典型的这类语言结构包含:计数问题的抽象、变量的声明与引用、过程调用时形参与实参的一致性检查等.描述它们的文法被称为上下文有关文法(Context Sensitive Grammar,CSG).这些语言结构没法用上下文无关文法CSG来描述.
(3)形式语言与自动机简介
若文法G=(N,T,P,S)的每一个产生式α→β中,均有α∈(N∪T),且至少含有一个非终结符,β∈(N∪T),则称G为0型文法.
对0型文法施加如下第i条限制,即获得i型文法。
1> G的任何产生式α→β(S→ε除外)知足|α|≤|β|;
2> G的任何产生式形如A→β,其中A∈N,β∈(N∪T)*;
3> G的任何产生式形如A→a或者A→aB(或者A→Ba),其中A和B∈N,a∈T。
文法 | 语言 | 自动机 |
---|---|---|
短语文法(0型) | 短语结构语言 | 图灵机 |
CSG(1型) | CSL | 线性界线自动机 |
CFG(2型) | CFL | 下推自动机 |
正规文法(3型) | 正规集 | 有限自动机 |
分为:递归降低分析法、预测分析法
基本思想:对任何一个输入序列ω,从S开始进行最左推导,直到获得一个合法的句子或发现一个非法结构。整个自上而下分析是一个试探的过程,是反复使用不一样产生式谋求与输入序列匹配的过程。
提早准备——重写文法:1.消除左递归,以免陷入死循环; 2.提取左因子,以免回溯.
(1)消除左递归
定义:若文法G中的非终结符A,对某个文法符号序列α存在推导A =+> Aα,则称G是左递归的。若G中有形如A→Aα的产生式,则称该产生式对A直接左递归。
<1> 消除文法的直接左递归
A→Aα|β 替换为 A →βA' A'→αA'|ε
首先,整理A产生式为以下形式:A→ Aα1|Aα2|...|Aαm|β1|β2|...|βn
而后用下述产生式代替A产生式:A→ β1 A'|β2 A'| ...|βn A'
A'→ α1 A' | α2 A' | ... | αm A' |ε
<2> 消除文法的左递归
核心思想:将无直接左递归的非终结符展开到其余产生式,而后消除其余产生式中的直接左递归(若是有的话)
若G产生句子的过程当中出现A=+A的推导,则没法消除左递归(出现回路)
(2)提取左因子
<1> 提取文法的左因子
左因子产生缘由:公共前缀:A → αβ1|αβ2
方法:将 A → αβ1|αβ2|γ
替换为 A→αA'|γ A'→β1|β2
(3)递归降低分析
直接以程序代码(的方式)模拟产生式产生语言的过程:
基本思想:每一个非终结符对应一个子程序(函数),过程体中:
特色:
1> 子程序是递归的(由于文法是递归的);
2> 程序与文法相关;
3> 它对文法的限制是不能有公共左因子和左递归;
4> 它是一种非形式化的方法,只要能写出子程序,用什么样的方法和步骤都可。
(4)预测分析器
☆ 预测分析器由一张预测分析表、一个符号栈和一个驱动器组成,数学模型是下推自动机。
☆ 对文法的限制是不能有公共左因子和左递归
预测分析器的核心概念:
1> 分析方法:格局与格局变换
2> 分析表+驱动器(模拟算法)
3> 预测分析表的构造
4> LL(文法、语言、分析器)
☆ 开始格局的剩余输入是所有输入序列,而接收格局中剩余输入应该为空,任何其余格局或出错格局中的剩余输入应该是所有输入序列的一个后缀.
☆ 改变格局的动做:
① 匹配终结符: 若top=ip(但≠#),则pop且next(ip);
② 展开非终结符:若top^= X且M[X,ip^]=α(X→α),则pop且push(α);
③ 报告分析成功: 若top ^= ip^ = #,则分析成功并结束;
④ 报告出错:其它状况,调用错误恢复例程.
☆ 驱动器算法
☆ 构造预测分析表
步骤:1. 构造文法符号X的FIRST集合和非终结符的FOLLOW集合;2. 根据两个集合构造预测分析表.
通俗地讲,α的FIRST集合就是从α开始能够导出的文法符号序列中的开头终结符。而A的FOLLOW集合,就是从开始符号能够导出的全部含A的文法符号序列中紧跟A以后的终结符.
<1> 计算X的FIRST集合 -----自下而上计算
<2> 计算全部非终结符的FOLLOW集合 —— 自上而下计算
<3> 构造预测分析表
<4> LL(1)文法
文法G被称为是LL(1)文法,当且仅当为它构造的预测分析表
中不含多重定义
的条目。由此分析表所组成的分析器被称为LL(1)分析器
,它所分析的语言被称为LL(1)语言
。
☆ 第一个L表明从左到右扫描输入序列,第二个L表示产生最左推导,1表示在肯定分析器的每一步动做时向前看一个终结符.
推论3.2 G是LL(1)的,当且仅当G的任何两个产生式A→α|β知足: 1. 对任何终结符a,α和β不能同时推导出以a开始的串;即First(α) ∩ First(β) = ∅ 2. α和β最多有一个能够推导出ε; 3. 若β =*> ε,则α不能导出以FOLLOW(A)中终结符开始的任何串. 即First(α) ∩ Follow(A) = ∅
☆ 不管是递归降低子程序法仍是非递归的预测分析法,他们都只能处理LL(1)文法.
☆ 自上而下分析采用的是推导;自下而上分析采用的是归约(规范归约—剪句柄—移进/归约分析—SLR(1)分析器).
(1)自下而上分析的基本方法
☆ 基本思想:最左归约.
对于每一个输入序列ω:从左到右扫描ω; 从ω开始,反复用产生式的左部替换产生式的右部(即当前句型中的句柄)、谋求对ω的匹配,最终获得文法的开始符号,或者发现一个错误。
☆ 基本概念:
a) > 设αβδ是文法G的一个句型,若存在S=*>αAδ,A=+>β, 则称β是句型αβδ相对于A的"短语". > 特别的,若 有A→β,则 称β是句型αβδ相对于产生式A→β的"直接短语". > 一个句型的最左直接短语被称为"句柄". 特征: 1. 短语:以非终结符为根子树中全部从左到右的叶子; 2. 直接短语:只有父子关系的子树中全部从左到右排列的叶子(树高为2); 3. 句柄:最左边父子关系树中全部从左到右排列的叶子(句柄是惟一的) b)最左归约:若 α是文法G的句子且知足下述条件,则称序列αn,αn-1,...,α0是α的一个最左归约。 1) αn = α 2) α0 = S(S是G 的开始符号) 3) 对任何i(0<i<=n),αi-1是将αi中句柄替换为相应产生式左部非终结符获得的 ☆ 最左归约的逆过程是一个最右推导,分别称最右推导和最左归约为规范推导和规范归约. c)移进-归约分析器 1. 工做方式:格局与格局变换 2. 分析表 3. 驱动器(模拟算法) 4. SLR分析表的构造 5. LR(文法、语言、分析器) ☆ 改变格局的动做: 1. 移进(shift):当前剩余输入的下一终结符进栈。 2.归约(reduce):将栈顶句柄替换为对应非终结符(最左归约) 3.接受(accept):宣告分析成功 4. 报错(error):发现语法错误,调用错误恢复例程
(2) LR分析
a) LR分析与LR文法
LR分析:容许左递归,但不能有二义
定义3.15 若为文法G构造的移进-归约分析表中不含多重定义的条目,则称G为"LR(k)文法",分析器被称为是"LR(k)分析器",它所识别的语言被称为"LR(k)语言"。"L"表示从左到右扫描输入序列,"R"表示逆序的最右推导,"k"表示为肯定下一动做向前看的终结符个数,通常状况下k<=1。当k=1时,简称"LR"。
构造SLR(1)分析器
<1> 活前缀与LR(0)项目
第1步 | 第2~N步 | 状态 | |
---|---|---|---|
词法--DFA | ε-closure(S) | ε-closure(smove(S,a)) | 状态集 |
语法--DFA | closure(I) | closure(goto(I,x)) | 项目集 |
出如今移进-归约分析器栈中的右句型的前缀,被称为文法G的活前缀(viable prefix).
LR(0)项目(简称项目)是这样一个产生式,在它右边的某个位置有一个点"."。对于A→ε,它仅有一个项目A→.。
项目A→α.β显示了分析过程当中看到(移进)了产生式的多少。
β不为空的项目称为可移进项目,β为空的项目称为可归约项目.
<2> 拓广文法与识别活前缀的DFA
G' = G ∪ {S' → S}
其中:S' → S是识别S的初态,S' → S. 是识别S的终态. 目的是使最终构造的DFA状态集中具备惟一的初态和终态. ① closure(I):从项目集I不经任何文法符号到达的项目全体;
② goto(I,x):全部从I经文法符号x能直接到达的项目全体。
项目[S’→.S]和全部“.”不在产生式右部最左边的项目称为核心项目(kernel items),
其它“.”在产生式右部最左边的项目(不包括[S’→.S])称为非核心项目(nonkernel items).
核心项目:J=goto(I,X),S'→.S(做为项目集的表明) 非核心项目:closure(J)-J(特色:可由J某中某项目算得)
<3> 识别活前缀
定义3.21 若存在最右推导S’=*> αAω => αβ1β2ω,则称项目[A→β1.β2] 对活前缀αβ1有效。
当一个项目集中同时存在: 1. A→β1.β2和B→β.:既可移进又可归约,移进/归约冲突 2.A→α.和B→β.:都可指导下一步分析,归约/归约冲突 解决方法:简单向前看一个终结符: 1. 移进/归约冲突:若FIRST(β2)∩FOLLOW(B)=Φ,冲突可解决 2. 归约/归约冲突:若FOLLOW(A)∩FOLLOW(B)=Φ,冲突可解决 若冲突能够解决,则称文法为SLR(1)文法,构造的分析表为SLR(1)分析表。 SLR(1)文法:简单向前看一个终结符便可解决冲突 ☆ 二义文法不是SLR(1)文法
采用语法制导翻译生成中间代码
(1)语法与语义的关系
语法是指语言的结构、即语言的“样子”;
语义是指附着于语言结构上的实际含意,即语言的“意义”.
一个语法上正确的句子,它所表明的意义并不必定正确.
☆ 语义分析的做用
• 检查结构正确的句子所表示的意思是否合法;
• 执行规定的语义动做,如:表达式求值、符号表的查询/填写、中间代码生成等
☆ 应用最广的语义分析方法是语法制导翻译,他的基本思想是将语言结构的语义以属性的形式赋予表明此结构的文法符号,而属性的计算以语义规则的形式赋予由文法符号组成的产生式.
(2)属性/语义规则的定义
定义4.1 对于产生式A→α,其中α是由文法符号X1X2...Xn组成的序列,它的语义规则能够表示为(4.1)所示关于属性的函数f: b := f(c1, c2, ..., ck) (4.1) 语义规则中的属性存在下述性质与关系: (1) 称(4.1)中属性b依赖于属性c1, c2, ..., ck。 (2) 若b是A的属性,c1, c2, ..., ck是α中文法符号的属性,或者A的其它属性,则称b是A的综合属性。 (3) 若b是α中某文法符号Xi的属性,c1, c2, ..., ck是A的属性,或者是α中其它文法符号的属性,则称b是Xi的继承属性。 (4) 若语义规则的形式以下述(4.2),则可将其想像为产生式左部文法符号A的一个虚拟属性。属性之间的依赖关系,在虚拟属性上依然存在。 f(c1, c2, ..., ck) (4.2) ■
☆ 继承属性从前辈和兄弟的属性计算获得,综合属性从子孙和自身的其余属性计算获得.
即,继承属性
"自上而下,包括兄弟",综合属性
"自下而上,包括自身".
(3)语义规则的两种形式
☆ 语义规则的两种形式(忽略实现细节,两者做用等价)
<1> 语法制导定义(Syntax Directed Definition)
用抽象的属性和运算表示的语义规则;(公式,作什么)
<2> 翻译方案(Translation Scheme)
用具体的属性和运算表示的语义规则。(程序段,如何作)
☆ 继承属性
是自上而下计算的,综合属性
是自下而上计算的.
(4)LR分析翻译方案的设计
☆ LR分析中的语法制导翻译实质上是对LR语法分析的扩充:
当执行归约产生式
的动做时,也执行相应产生式对应的语义动做
。因为是归约时执行语义动做,
所以限制语义动做仅能放在产生式右部的最右边
;
增长一个与分析栈
并列的语义栈
,用于存放分析栈中文法符号所对应的属性值
。
☆ 扩充后的LR分析最适合对综合属性的计算,而对于继承属性的计算还须要进行适当的处理.
☆ 中间代码应具有的特性
1)便于语法制导翻译
2)既与机器指令的结构相近,又与具体机器无关.
使用中间代码的好处:一是便于编译器程序的开发和移植,二是代码进行优化处理.
☆ 中间代码的主要形式:后缀式、树、三地址码等.最基本的中间代码形式是树🌲;最经常使用的中间代码形式是三地址码,它的实现形式常采用四元式形式。
☆ 符号表是帮助声明语句实现存储空间分配的重要数据结构。
(1)后缀式
操做数在前,操做符紧随其后,无需用括号限制运算的优先级和结合性;便于求值.
(2)三地址码
① 三元式 形式: (i) (op, arg1, arg2)
三地址码:(i):= arg1 op arg2
序号的双重含义:既表明此三元式,又表明三元式存放的结果
存放方式:数组结构,三元式在数组中的位置由下标决定
弱点:给代码的优化
带来困难
② 四元式 形式: ( i ) (op,arg1,arg2,result)
所表示的计算: result:= arg1 op arg2
四元式与三元式的惟一区别:将由序号所表示的运算结果改成:用(临时)变量来表示。
此改变使得四元式的运算结果与其在四元式序列中的位置无关.为代码的优化提供了极大方便,由于这样能够删除或移动四元式而不会影响运算结果.
③ 树形表示
1> 语法树真实反映句子结构,对语法树稍加修改(加入语义信息),便可以做为中间代码的一种形式(注释语法树)
2> 树的优化表示-DAG
3> 树与其余中间代码的关系
☆ 树表示的中间代码
与后缀式
和三地址码
之间有内在联系
方法:对树进行深度优前后序遍历
,获得的线性序列就是后缀式
,或者说后缀式是树的一个线性化序列;
特色:树的每一个非叶子节点和它的儿子对应
一个三元式或四元式;
方法:对树的非叶子节点进行深度优前后序遍历,即获得一个三元式或四元式序列。
(1)构成名字的字符串
构成名字的字符串的存储方式:直接存储---定长数据(直接将构成名字的字符串放在符号表条目中)和间接存储---变长数据(将构成名字的字符串统一存放在一个大的连续空间内,字符串与字符串之间采用特殊的分隔符隔开,符号表条目中仅存放指向该字符串首字符的指针).
(2)名字的做用域
☆ 程序语言范围的划分能够有两种划分范围的方式:并列
和嵌套
☆ 名字的做用域规则:规定一个名字在什么样的范围内应该表示什么意义.
<1> 静态做用域规则(static-scope rule):编译时就能够肯定名字的做用域,即仅从静态读程序就可肯定名字的做用域 <2> 最近嵌套规则(most closely nested):名字的声明在离其最近的内层起做用
(3)线性表
符号表以栈(线性表)的方式组织.
线性表上的操做:查找、插入、删除、修改
查找:从表头(栈顶)开始,遇到的第一个符合条件的名字;插入:先查找,再加入在表头(栈顶);
关键字 = 名字+做用域;
(4)散列表
名字挂在两个链上(便于删除操做):
相同hash值
的元素,表头在表头数组中;同一做用域
中的元素,表头在做用域表中.☆ 操做:查找、插入、删除
(1)变量的声明
☆ 一个变量的声明应该由两部分来完成:类型的定义
和变量的声明
1> 简单数据类型
的存储空间是预先肯定的,如int能够占4个字节,double能够占8个字节,char能够占1个字节等
2> 组合数据类型变量
的存储空间,须要编译器根据程序员提供的信息计算而定.
(2) 过程
1.过程(procedure):过程头(作什么) + 过程体(怎么作); - 函数: 有返回值的过程 - 主程序: 被操做系统调用的过程/函数 2.过程的三种形式:过程定义、过程声明和过程调用。 过程定义:过程头+过程体; 过程声明:过程头; 3. 左值与右值 1> 直观上,出如今赋值号左边和右边的量分别称为左值和右值; 2> 实质上,左值必须具备存储空间,右值能够仅是一个值,而没有存储空间. 3> 形象地讲,左值是容器,右值是内容. 4. 参数传递 1> 形参与实参 - 声明时的参数称为形参(parameter或formal parameter) - 引用时的参数称为实参(argument或actual parameter) 2> 常见的参数传递形式:(不一样的语言提供不一样的形式) - 值调用(call by value)---过程内部对参数的修改,不影响做为实参的变量原来的值. - 引用调用(call by reference)--- 过程内部对形参的修改,实质上是对实参的修改. - 复写-恢复(copy-in/copy-out)--- ① 过程内对参数的修改不直接影响实参,避免了反作用; ② 返回时将形参内容恢复给实参,实现参数值的返回. - 换名调用(call by name)--- 宏调换 3> 参数传递方法的本质区别: 实参是表明左值、右值、仍是实参自己的正文. 5. 做用域信息的保存 ☆ 可以画出嵌套过程的嵌套关系树(P191 4.33),根据语法制导翻译(P193 4.35)画出分析树,写出推导步骤,构造的符号表
P197 例4.36 主要是变量类型的转换
(1)数组元素的地址计算
(2)☆数组元素引用的语法制导翻译(考试热点之一)
布尔表达式的计算有两种方法:数值表示的直接计算
和逻辑表示的短路计算
☆ 布尔表达式短路计算的翻译:短路计算的控制流,真出口与假出口,真出口链与假出口链,拉链回填技术(P207 例4.41)(考试热点之一)
控制语句的分类:①无条件转移、②条件转移、③循环语句、④分支语句
多看课件PPT,多作题练手