- 编译器在分析阶段把一个源程序划分成各个组成部分,并生成源程序的内部表现形式。这种内部表现称为中间代码。然后,编译器在合成阶段将这个中间代码翻译成目标程序。
- 分析阶段的工作是围绕这编译语言的“语法展开的”。一个程序设计语言的语法描述了该语言程序的正确形式。而该语言的语义定义了程序的含义。即每个程序运行的时候应该做什么事。比如:
- 广泛使用的表示方法来描述语法。上下文无关的文法或bnf范式。
- 使用现有语义表示方法来描述一个语言的语义的难度远远大于描述语言语法的难度。
- 上下文无关文法不仅可以描述一个语言的语法,还可以指导程序的翻译过程。一种面向文法的编译技术,即语法制导翻译技术。后缀表达式是一种将运算符置于运算分量之后的表示方法。
- 9-5+2后缀形式是95-2+
一个编译器前端模型
- 词法分析器可以处理由多个字符组成的构造。比如标识符,标识符由多个字符组成。但是在语法分析阶段被当做一个单元进行处理。这样的单元被称作词法单元。比如:
- count+1,标识符count被当做一个单元。
两种中间代码形式
- 一种是抽象语法树:表示了源程序层次化的语法结构。
- 另一种常见的中间表示形式。是一组“三地址”指令序列。
- x=y op z
- op是一个二目运算符,y和z是运算分量的地址,x是存放结果的地址。三地址指令最多一般只执行一个运算,通常是计算、比较或者分支跳转运算。
- x=y op z
上下文无关文法
- 文法自然的描述了大多数程序设计语言构造的层次化语法结构,例如java中的if-else
- 即一个if-else语句由关键字if、左括号、右括号、一个语句、关键字else和另一个语句连接而成。用expr表示表达式,变量stmt表示语句,这个构造规则表示为
- stmt->if(expr)stmt else stmt
- 关键字if和括号这样的词法元素称为终结符号。像exor和stmt这样的变量表示终结符号的序列,他们被称为非终结符号
文法定义
- 一个上下文无关文法,由四个元素组成:
- 一个终结符号集合,有时也称为词法单元。终结符号是该文法定义的语言的基本符号的集合
- 一个非终结符号的集合,有时也被称为语法变量。每个非终结符号表示一个终结符号串的集合。
- 一个产生式集合,其中每个产生式包括一个称为产生式头或左部的非终结符号。
- 指定一个非终结符号为开始符号
- 词法分析器读入源程序中的字符序列,将他们组织为具有词法含义的词素。生成并输出代表这些词素的词法单元序列。词法单元有两部分组成:名字和属性值。词法单元的名字是语法分析器进行语法分析时使用的抽象符号。这些词法单元名称为终结符号。因为他们在描述程序设计语言的文法中是以终结符号的形式出现的。
- 如果词法单元具有属性?
- 这个值就是一个指向符号表的指针,符号表包括了该词法单元的附加信息。这些附加信息不是文法的组成部分,所以通常将词法单元和终结符号当同义词。
- 如果某个非终结符号是某个产生式的头部,我们就说该产生式时该非终结符号的产生式。一个终结符号串是由零个或者多个终结符号组成的序列。零个终结符号组成的串称为空串。
推导
- 根据文法推导符号串时,首先从开始符号出发。不断将某个非终结符号替换为该非终结符号的某个产生式的体。可以冲开始符号推导得到的所有终结符号串的集合称为该文法定义的语言。
语法分析的任务
- 语法分析的任务:接收一个终结符号串作为输入,找出从文法的开始符号推导出这个串的方法。如果不能从文法的开始推导得到该终结符号串,则报告该终结符号串中包含的语法错误。语法分析是所有编译过程中最基本的问题之一。
- 一般情况下,一个源程序中会包含由多个字符串组成的词素。这些词素由词法分析器组成词法单元,而词法单元的第一个分量就是被语法分析器处理的终结符号。
- 给定一个上下文无关文法,该文法的一颗语法分析树,是具有以下性质的树:
- 根节点的标号为文法的开始符号
- 每个叶子节点的标号为一个终结符号或E
- 每个内部节点的标号为一个非终结符号
- 如果非终结符号A是某个内部节点的标号,并且他的子节点标号从左至右分别为x1、x2.那么必然存在产生式A->X1X2,其中x1、x2既可以是终结符号,也可以是非终结符号。作为一个特殊情况,如果A->E是一个产生式,那么一个标号为A的节点可以只有一个标号为e的子节点。
二义性
- 一个文法可能有多颗语法分析树能够生成同一个给定的终结符号串。这样的文法统称有二义性。需要为编译应用涉及出没有二义性的文法,或者使用二义性文法使用附加的规则来消除二义性。
- 非终结符号stmts产生一个可能为空的语句列表。stmts第二个产生式生成一个空列表e。第一个产生式生成的是一个可能为空的列表再跟上一个语句。分号的放置方式很微妙,他们出现在所有不以stmt结尾的产生式的末尾。这种方法可以避免在if或者while这样的语句后面出现多余的分号。因为if和while语句的最后是一个嵌套的子语句。当嵌套子语句是一个赋值语句或do-while语句时,分号将作为这个子语句的一部分被生成。
语法制导翻译
- 语法制导翻译是通过向一个文法,产生式附加一些规则或程序片段而得到的。比如考虑由如下产生式生成的表达式expr:
- expr->expr1->t=erm
- 属性:属性表示与某个程序构造相关的任意的量。属性可以是多重多样的,比如表达式的数据类型、生成的代码中指令数目或为某个构造生成代码中第一条指令的位置都是属性。用文法符号(终结符号或非终结符号)表示程序的构造,所有将属性的概念从程序构造扩展到表达这些构造的文法符号上。
- 翻译方案:翻译方案是一种将程序片段附加到一个文法的各个产生式上的表示法。当在语法分析过程中使用一个产生式,响应的程序片段就会执行。这些程序片段的执行效果按照语法分析过程中顺序组合起来,得到的结果就是这次分析/综合过程处理源程序得到的翻译结果。
- 综合属性
- 将量和程序构造关联起来(比如吧数值类型和表达式相关联)可以基于文法来表示。将属性和文法的非终结符号相关联。文法的各个产生式附加上语义规则,对于语法分析书中的一个节点,如果他和她的子节点之间关系符合某个产生式,那么该产生式对应的规则就描述了如何计算这个节点上的属性。
简单语法制导定义
* 要得到代码产生式头部的非终结符号的翻译结果的字符串,只需要将产生式体中各非终结符号的翻译结果按照他们在非终结符号中的出现顺序,并在其中穿插一些附加的串即可。具有这个性质的语法制导定义称为简单语法制导定义。
- 语法制导翻译方案是一种在文法产生式中附加一些程序片段来描述翻译结果的表示方法。语法制导翻译方案定义相似,只是显式指定了语义规则的计算顺序。
- 画出一个翻译方案的语法分析树,为每个语义动作构造一个额外的子节点,并使用虚线将他和该产生式头部对应的节点相连。表示上述产生式和语义动作的部分语法分析树。对应的语义动作没有子节点,因此在第一次访问该节点时就会执行这个动作。
语法分析
- 语法分析决定如何使用一个文法生成一个终结符号串的过程。尽管在时间中编译器并没有真的构造出这颗树,然而,原则上语法分析器必须能够构造出语法分析树,否则将无法保证翻译的正确性。
递归下降
- 这种语法分析方法,这种方法可以实现语法分析和语法制导翻译器。另一种是使用软件工具根据翻译方案生成一个翻译器。比如:Yacc
- 对于任意上下文无关文法,都可以构造一个时间复杂度为0(n3)的语法分析器,他是最多使用0(n3)的时间就可以完成一个长度为n的符号串的语法分析。但是3次方的时间代码一般来说过于昂贵。对于实际程序设计语言而言,通常能够设计出一个可以被高效分析的文法。线性时间复杂度的算法足够分析实践中出现的各种程序设计语言。
- 程序设计语言的语法分析器几乎总是一次性从左到右扫描,每次向前看一个终结符号,并在扫描时构造出分析树的各个部分。
- 大多数语法分析都可以归入以下两类:自顶向下方法和自底向上。指的是语法分析树节点的构造顺序,在自顶向下语法分析器中,构造过程从根节点开始,逐步向叶子节点方向进行,而在自底向上的语法分析器中,构造过程从叶子结点开始,逐步构造出根节点。自顶向下语法分析器之所以受欢迎,是因为这种方法可以很容易的构造出高效的语法分析器。自底向上分析方法可以处理更多文法和翻译方案。
- 对于非终结符号和向前看符号;,我们使用optexpr的产生式,因为;和optexpr仅有的另一个产生式不匹配,那个产生式的体是终结符号expr
预测分析法
- 递归下降分析法是一种自顶向下的语法分析方法,他使用一组递归过程来处理输入。文法的每个非终结符号都有一个相关联的过程,这里我们考虑递归下降分析法的一种简单形式,称为预测分析法。各个非终结符号对应的过程中的控制流可以由向前看符号无二意的确定,在分析输入串时出现的过程调用序列隐式的定义了该输入串的一颗语法分析树,如果需要还可以通过这些过程调用来构建一个显示的语法分析树。
- 预测分析器在没有其他产生式可用的时候,将∈产生式作为默认选择使用。
- 预测分析器程序由各个非终结符对应的过程调用。对应于非终结符a的过程完成以下两项任务。
- 检查向前看符号,决定使用a的那个产生式。如果一个产生式的体为a(这里a不是空串∈)且向前看符号在FIRST(a)中,那么就选择这个产生式。对于任何向前看符号,如果两个非空产生式体之间存在冲突,就不能对这种文法使用预测语法分析。如果有a有∈产生式,只有当向前看符号不在A的其他产生式体的FIRST集合中时,才会使用A的∈产生式
- 这个过程模拟被选中产生式的体,也就是说,从左边开始逐个执行斥期间产生式体中的符号。“执行”一个非终结符号的放法是调用该非终结符号对应的过程,一个与向前看符号匹配的终结符号“执行”放法是读入下一个输入符号。如果在某个点上,产生式体中的终结符号和向前看符号不匹配,那么语法分析器就会报告一个语法错误。
左递归
- 递归下降语法分析器有可能进入无线循环,当出现如下所示的“左递归产生式”,分析器就会进入无限循环。
- expr->expr+term
- 非终结符号R和他的产生式R->aR是右递归的。因为这个产生式的右部,因为这个产生式的右部最后一个符号就是R本身。右递归的产生式会使树向右下方向生长。因为树是向右下生长的,对包含了左结合运算符的表达式就变得比较困难。
左递归消除
- 左递归消除工作必须小心的进行,以确保消除后的结果爆出语义动作的顺序。+和-都处于产生式的中间,9-5+2会被错误的处理为952+-,即(9-5)+2的表达式
词法分析
- 一个词法分析从输入中读取字符,并将他们组成“词法单元对象”,除了用于语法分析的终结符号外,一个词法单元对象还包含一些附加信息。这些信息以属性值得形式出现。