编译原理学习笔记

1.    第一章
2.    第二章 一个简单的语法制导翻译器
以一个将中缀表达式翻译为后缀表达式的例子介绍一个简单的翻译器
2.1    引言
编译流程:源程序-> 词法串 –> 语法树 –> 中间代码 -> 机器代码
语法和语义:语法描述了语言的正确形式,语义描述程序的含义。使用上下文无关文法(BNF)描述语法,2.2节介绍。语义难以用形式化语言描述。
翻译:上下文无关文法还可以指导翻译:语法制导翻译(语法制导定义、翻译方案?)
本章内容:先使用每个字符即是一个词法单元的模型,介绍语法分析器,之后再通过扩展一个词法分析器,增加处理多个字符组成词法单元的能力,还可以处理换行和空白字符。接下来是中间代码生成:抽象语法树和三地址码。(抽象语法树和语法分析树?语法分析树的内部节点是非终结符号,着重于分析是否满足语法,所以节点是语法符号;抽象语法树的内部节点是操作符,着重于代码的中间表示)
2.2    语法定义
2.2.1    文法定义
上下文无关文法:终结符号集合,非终结符号集合,产生式集合,开始符号(0个终结符号组成的串ε)
2.2.2    推导
推导:从开始符号起,不断将非终结符号替换为其产生式的体。所有能由开始符号推导出的终结符号串为该文法定义的语言。
语法分析器的任务:对给定词法串,找出从开始符号推导出该词法串的方法。如果不能推导出来,则报告语法错误。
2.2.3    语法分析树
语法分析树:语法分析树展现了从文法的开始符号推导出终结符号串的过程。
1.    根节点是开始符号
2.    叶子节点是终结符号
3.    内部节点是非终结符号
4.    内部节点的子节点串与该节点的某个产生式中的文法符号串对应
叶子节点从左到右构成了推导出的词法串。
2.2.4    二义性
一个文法有多棵语法分析树对应同一个终结符号串,则该文法具有二义性。不同的语法树,通常具有不同的语义,应避免二义性文法。(可以通过语法树找出可并行的指令?)
2.2.5    运算符的结合性
左结合运算符:如果运算分量两边都有运算符,那么运算分量参与左边运算符的运算过程,例如a+b+c
右结合运算符:如果运算分量两边都有运算符,那么运算分量参与右边运算符的运算过程,例如 a = b = c
2.2.6    运算符的优先级
9+5*2可以解释为两种情况: (9+5)*2 9+(5*2)
因而需要额外的规则来确定运算符的优先级关系
运算符的优先级表:
左结合:+、-
左结合:*、/
每个优先级创建一个非终结符号
例如expr对应+、-优先级表
term对应*、/的优先级表
用facter表示基本单元
expr -> expr + term | expr – term|term
term -> term * facter|term / facter |facter
facter -> (expr) | digit
可以推广到有n层优先级的情况,需要n+1非终结符。
2.2.7    2.2节的练习
练习没看
2.3    语法制导翻译
向产生式中附加一些规则或者程序片段,实现翻译。
两个与语法制导翻译相关的概念:
属性:表示与某个程序构造相关的量
翻译方案:将程序片段附加到产生式的翻译方法,通过再语法分析中,执行产生式中的代码片段,就可以得到翻译结果。
2.3.1    后缀表示
后缀表示的定义:
1)    如果E为常量或者变量(终结符),E的后缀表示为E
2)    E1 op E2的后缀表示为E1’ E2’ op,E1’和E2’分别为E1和E2的后缀表达式
3)    (E)的后缀表示为E’(E的后缀表达式)
例:(9-2)+3的后缀表示
9-2:92-
(9-2):92-
(9-2)+3:92-3+
9-(5+2)的后缀表示:
5+2:52+
(5+2):52+
9-(5+2):952+-
后缀表达式只有一种解码方式,不需要括号。
后缀表达式的计算:从左往右查找运算符,找到后,往前查找两个运算量,进行计算,用计算结果替换原来的两个运算分量和运算符,重复该过程,直到找不到运算符
例:952+-3*
952+-3* -> 97-3* 23* -> 6
2.3.2    综合属性
节点的某个属性由该节点及其子节点确定,则该属性为综合属性。对语法分析树进行一次自底向上的遍历,即可计算出所有节点的属性值。(继承属性是另一种属性:属性有本节点,节点的兄弟节点及父节点确定)
注释语法分析树:语法分析树上的所有节点都标注了属性。
语法制导定义:把节点与一个属性集合关联,产生式和一组计算属性的语义规则关联。对于一棵语法分析树,叶子节点对应终结符号,其属性值由词法分析器确定;树中的非终结符号都对应一个产生式,可由该产生式,计算出该节点的属性,进行自底向上的遍历后,即可计算出树中所有节点的属性,其根节点的属性即为翻译结果。
2.3.3    简单语法制导定义
对于一个产生式的翻译:将产生式体中的非终结符好的翻译按顺序连接起来,再在其中输入一些附加的串(产生式体中的非终结符号的顺序与翻译后的非终结符号的翻译的顺序一致)。
2.3.4    树的遍历
使用深度优先遍历(后序遍历?),即可计算出所有非终结符号的综合属性值。综合属性值由子节点及自身决定,因而在计算某个节点的属性时,只需要该节点的子节点属性即可,后序遍历完美契合。
如果仅有继承属性,猜测可用先序遍历。
既有综合属性,又有继承属性时,计算流程会变得复杂(5.2节)。
2.3.5    翻译方案
语法制导定义将所有结果都存到语法分析树的节点的属性中,当待翻译的代码规模较大时,其需要的额外的保存属性的空间也会变大。
    翻译方案:在产生式中增加一些可执行的程序片段,用来输出翻译结果。不需要额外的空间来保存翻译结果,例如:
    expr -> expr1 + term {printf(“+”);}
    term -> 0 {printf(“0”);}
{}中是附加的可执行程序片段。
2.3.6    2.3节的练习
练习没看
2.4    语法分析
确定文法如何推导出终结符号串。递归下降语法分析:可实现语法分析和语法制导翻译。Yacc:根据翻译方案自动生成翻译器(4.9节)
    如果采用回溯的方式进行语法分析,其效率较低。实际中可以设计出不需要回溯的分析方法,实现线性的时间复杂度。
    两种语法分析方法:
自顶向下:从根节点开始,逐步构造出叶子节点,适合手工构造出高效语法分析器。
自底向上:从叶子节点开始,逐步构造出根节点,适用于自动生成语法分析器。
2.4.1    自顶向下分析方法
从根节点开始,不断执行以下步骤,知道所有非终结符号都已确定产生式:
1)    为非终结符号选择一个产生式,并将产生式体中的语法符号作为该节点的子节点;如果所有产生式都已尝试,无法选择可用的产生式,则返回父节点,重新执行本步骤。若根节点已无可用产生式,则报告错误。
2)    对子节点从左到右进行处理,若子节点为终结符号,则将其与词法分析器返回的向前看符号对比,如果匹配则处理下一个语法符号,若不匹配则将词法分析器读取的向前看符号返回,并取消本次的产生式,跳回到父节点,重新执行步骤1;若为非终结符号,则执行步骤1。
这种方式逻辑上比较简单,但是在失败时需要进行回溯。只有在选择产生式后,尝试对产生式进行匹配,才能知道该产生式是否合适。
2.4.2    预测分析法
如果选择一个非终结符号的产生式,可以仅由向前看即可确定,那么就可以不回溯的进行语法分析。这种方法称为预测分析法。
预测分析法的关键在于通过向前看符号,如果明确使用哪一个产生式。
为此引入FIRST(α):α表示语法符号串,FIRST(α)则表示该语法符号串能推导出的任意终结符号串的第一个终结符号的集合。FIRST(α)的计算方法:如果α以终结符号起始,则FIRST(α)为该终结符;如果α以非终结符号开始,则FIRST(α)为该终结符号的所有产生式的FIRST集合的合集。
确定终结符号的所有产生式的FIRST集后,并且各个产生式的FIRST集两两不想交,则可通过FIRST选择正确的产生式:选择存在向前看符号所在的FIRST集所对应的产生式;没有满足条件的FIRST集时,如果有ε产生式,则选择ε产生式。
2.4.3    何时使用ε产生式
将ε作为默认产生式,所有的非ε产生式均不能匹配向前看符号时,才选择ε产生式,由于ε是最后一个可能符合要求的产生式,当选择ε后,仍然解析失败,则可判定语法分析失败,不需要回溯。(4.4.3节会详细介绍通过FOLLOW集选择ε产生式)
2.4.4    设计一个预测分析器
从开始符号开始,执行以下步骤:
1)    根据非终结符号的RIRST集和向前看符号,选择对应的产生式,如果向前看符号在某个产生式的FIRST集中,则选择该产生式,否则选择ε产生式。
2)    对于已经选择的产生式,依照产生式中的词法单元依次匹配:如果待匹配的语法单元为终结符号,则直接与向前看符号匹配,匹配失败语法分析失败;如果待匹配的语法单元为非终结符号,则执行步骤1。
当一个产生式已全部匹配完毕,则返回上一层,处理非终结符号的下一个语法单元。当返回到开始符号时,则语法分析成功。
对于翻译方案中附加的可执行语句,依据其在产生式中的位置,在词法分析的对应位置执行其代码。
2.4.5    左递归
当产生式体的第一个语法符号是终结符号本省时,在进行语法分析时,选择该产生式,向前看符号不更新,且下一次语法分析流程依然需要选择该产生式,语法分析过程进入原地踏步的状态,无法完成。
例如:A -> Aα|β,无法进行语法分析。需要构建非左递归的,能够描述与该产生式相同的语言的产生式,替换原本的左递归产生式。原产生式实际上描述的是以β起始,并串接有限个α的语法符号串。先构建有限个α的产生式:R -> αR|ε;再更新原产生式,用β串接R即可:A-> βR。
以上方法也可以推广到有多个左递归产生式和多个非左递归产生式的情况。
2.4.6    2.4节的 练习
练习没看
2.5    简单表达式的翻译器
由运算符(+、-)分割的数位序列(9+3-1) –> 其后缀形式(93+1-)。后续再扩展这个翻译器,使其支持其它运算符(*、/)和数字(91、21)以及空白字符(空格、制表符、换行符)。
翻译方案与语法分析的矛盾:需要支持翻译方案的文法,也需要便于语法分析的文法。先构造方便翻译的翻译方案,在对翻译方案进行改造,使其支持语法分析。即现在原始文法中添加翻译方案的附加代码,再对原始文法进行改造,消除左递归等,使其能进行语法分析。(先消除左递归会是文法与原始文法出现差异,不易构建翻译方案?)
2.5.1    抽象语法与具体语法
抽象语法树:内部节点是运算符,其子节点是运算分量。扩展到一般语法结构,内部节点是该结构的表示,其叶子节点是该结构的子分量。(语法分析树的差别:语法分析树内部节点是非终结符,其子节点是非终结符的产生式的节点)。
2.5.2    调整翻译方案

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值