1、1编 译 原 理教案课时安排 2授课题目(教学章、节或主题):第一章 引论 授课时间 第 1 周 第 1、2 节 教学目的、要求(分掌握、熟悉、了解三个层次):简单介绍学习此课程的目的和要求初步了解编译技术的基本原理和方法熟悉 Compiler 的基本概念掌握 Compiler 的结构和功能教学重点和难点:编译程序的基本结构和功能授课类型(请打):理论课 讨论课 实验课 练习课 其他教学方式(请打):讲授 讨论 示教 指导 其他教学资源(请打):多媒体 模型 实物 挂图 音像 其他讨论、思考题、作业:编译程序的基本结构如何?各部分功能?教学内容0 课程学习的要求及任务,学习方法介绍,成 绩考核
2、标准。第一章 引论1.1 什么叫编译程序?通常所说的翻译程序是指这样的一个程序,它能够把某一种语言程序(称为源语言程序)转换成另一种语言程序(称为目标语言程序),而后者与前者在逻辑上是等价的。如果 源语言是诸如 FORTRAN、Pascal、C、Ada、Smalltalk 或 Java 这样的“高级语言 ”,而目标语言是诸如汇编语言或机器语言之类的“低级语言” ,这样的一个翻译程序就称为编译程序。 2高级语言程序除了像上面所说的先编译后执行外,有时也可“ 解释”执行。一个源语言的解释程序是这样的程序,它以该语言写的源程序作为输入,但不产生目标程序,而是 边解释边执行源程序本身。本书将不对解释程
3、序作专门的讨论。实际上,许多编译程序的构造与实现技术同样适用于解释程序。根据不同的用途和侧重,编译程序还可进一步分类。专门用于帮助程序开发和调试 的编译程序称为诊断编译程序(Diagnostic Compiler),着重于提高目标代码效率的编译程序叫优化编译程序(Optimizing Compiler)。现在很多编译程序同时提供了调试、优化等多种功能,用户可以通过“开关”进行选择。运行编译程序的计算机称宿主机,运行编译程序所产生目标代码的计算机称目标机。如果一个编译程序产生不同于其宿主机的机器代码, 则称它为交叉编译程序(CrOSS Compiler)。如果不需重写 编译程序中与机器无关的部分
4、就能改 变目标机,则称该编译程序为可变目标编译程序(Retargetable Compiler)。1.2 编译过程概述编译程序过程: 从输入源程序开始到输出目标程序为止的整个编译过程可分为以下五个阶段:词法分析,语法分析,语义分析,中间代码产生,优化和目标代码生成.1.3 编译程序的结构编译程序的结构可以按照从输入源程序开始到输出目标程序为止的整个编译过程可分为以下五个阶段:词法分析,语法分析,语义分析,中间代码产生,优化和目标代码生成。 1.3.1 编译程序总框 编译程序的结构可以按照这五个阶段的任务分模块进行设计。下图给出了编译程序的总框。31.3.2 表格与表格管理编译程序在工作过程中需
5、要保持一系列的表格,以登记源程序的各类信息和编译各阶段的进展状况。在编译程序使用的表格中,最合理的是符号表。 编译程序在工作过程中需要保持一系列的表格,以登记源程序的各类信息和编译各阶段的进展状况。合理地设计和使用表格是编译程序构造的一个重要问题。在编译程序使用的表格中,最重要的是符号表。它用来登记源程序中出现的每个名字以及名字的各种属性。例如,一个名字是常量名、变量名,还是过程名等等;如果是变量名,它的类型是什么、所占内存是多大、地址是什么等等。通常,编译程序在处理到名字的定义性出现时,要把名字的各种属性填人到符号表中;当处理到名字的使用性出现时,要对名字的属性进行查证。当扫描器识别出一个名
6、字(标识符)后,它把该名字填人到符号表中。但这时不能完全确定名字的属性,它的各种属性要在后续的各阶段才能填人。例如,名字的类型等要在语义分析时才能确定,而名字的地址可能要到目标代码生成才能确定。由此可见,编译各阶段都涉及到构造、查找或更新有关的表格。41.3.3 出错处理遍:是对源程序或源程序的中间结果从头到尾扫 描一次,并作有关的加工处理,生产新的中间结果或目标程序。一个编译程序不仅应能对书写正确的程序进行翻译,而且应能对出现在源程序中的错误进行处理。如果源程序有错误, 编译程序应设法发现错误,把有关错误信息报告给用户。这部分工作是由专门的一组程序(叫做出错处理程序)完成的。一个好的编译程序
7、应能最大限度地发现源程序中的各种错误,准确地指出错误的性质和发生错误的地点,并且能将错误所造成的影响限制在尽可能小的范围内,使得源程序的其余部分能继续被编译下去,以便进一步发现其它可能的错误。如果不仅能够发现错误,而且还能自动校正错、 误,那当然就更好了。但是,自动校正错误的代价是非常高的。编译过程的每一阶段都可能检测出错误,其中,绝大多数错误可以在编译的前三阶段检测出来。源程序中的错误通常分为语法错误和语义错误两大类。语法错误是指源程序中不符合语法(或词法)规则的错误,它们可在词法分析或语法分析时检测出来。例如,词法分析阶段能够检测出“非法字符”之类的错误;语法分析阶段能够检测出诸如“ 括号
8、不匹配 ”、“缺少;” 之类的错误。语义错误是指源程序中不符合语义规则的错误,这些错误一般在语义分析时检测出来,有的语义错误要在运行时才能检测出来。语义错误通常包括:说明错误、作用域错误、 类型不一致等等。1.3.4 遍遍:是对源程序或源程序的中间结果从头到尾扫 描一次,并作有关的加工处理,生产新的中间结果或目标程序。通常,每遍的工作由从外存上获得的前一遍的中间结果开始(对于第一遍而言,从外存上获得源程序),完成它所含的有关工作之后,再把结果记录于外存。既可以将几个不同阶段合为一遍,也可以把一个阶段的工5作分为若干遍。例如,词法分析这一阶段可以单独作为一遍,但更多的 时候是把它与语法分析合并为
9、一遍;为了便于处理,语法分析和语义分析与中间代码产生又常常合为一遍。在优化要求很高时,往往 还可把优化阶段分为若干遍来实现。当一遍中包含若干阶段时,各阶段的工作是穿插进行的。例如,我 们可以把词法分析、语法分析及语义分析与中间代码产生这三阶段安排成一遍。这时, 语法分析器处于核心位置,当它在识别语法结构而需要下一单词符号时,它就调用词法分析器,一旦识别出一个语法单位时,它就 调用中间代码产生器,完成相 应的语义分析并产生相应的中间代码。一个编译程序究竟应分成几遍,如何划分,是与源语言、 设计要求、硬件设备等诸因素有关的,因此难于统一划定。遍数多一点有个好处,即整个 编译程序的逻辑结构可能清晰一
10、点。但遍数多势必增加输入输出所消耗的时间。因此,在主存可能的前提下,一般还是遍数尽可能少一点为好。应当注意的是,并不是每种 语言都可以用单遍编译程序实现。1.3.5 编译前端与后端概念上,我们有时把编译程序划分为编译前端和编译后端。前端主要由与源语言有关但与目标机无关的那些部分组成。这些部分通常包括词法分析、语法分析、语义分析与中间代码产生,有的代码优化工作也可包括在前端。后端包括编译程序中与目标机有关的那些部分,如与目标机有关的代码优化和目标代码生成等。通常,后端不依赖于源语言而仅仅依赖于中间语言。可以取编译程序的前端,改写其后端以生成不同目标机上的相同语言的编译程序。如果后端的设计是经过精
11、心考虑的,那么后端的改写将用不了太大工作量,这样就可实现编译程序的目标机改变。也可以设想将几种源语言编译成相同的中间6语言,然后为不同的前端配上相同的后端, 这样就可为同一台机器生成不同语言的编译程序。然而,由于不同语言存在某些微妙的区别,因此在 这方面所取得的成果还非常有限。 为了实现编译程序可改变目标机,通常需要有一种定义良好的中间语言支持。例如在著名的 Ada 程序设计环境 APSE 中,使用的是一种称为 Diana 的树形结构的中间语言一个 Ada 源程序通过前编译转换为 Diana 中间代码,由编译后端把Diana 中间代码转换为目标 代码。 编译前端与不同的编译后端以 Diana
12、为界面,实现编译程序的目标机改变。又如,在 Java 语言环境中,为了使编译后的程序从一个平台移到另一个平台,Java 定义一种虚拟机代码 -Bytecode。只要 实际使用的操作平台上实现了的 Java解释器,这个操作平台就可以执行各种 Java 程序。这就是所谓 Java 语言操作平台无关性。1.4 编译程序与程序设计环境开发通常还需要一些其它的工具;如编辑程序、连接程序,调试工具等等。 编译程序与这些程序设计工具一起构成所谓的程序设计环境。在高级语言发展的早期,这些程序设计工具往往是独立的,缺乏整体性,而且也缺乏对软件开发全生命周期的支持。随着软件技术的不断发展,现在人们越来越倾向于构造
13、集成化的程序设计环境。一个集成化的程序设计环境的特点是,它将相互独立的程序设计工具集成起来,以便为程序员提供完整的、一体化的支持,从而进一步提高程序开发效率,改善程序质量。在一个好的集成化程序设计环境中,不仅包含丰富的程序设计工具,而且 还支持程序设计方法学,支持程序开 发的全生命周期。有代表性的集成化程序设计环境有 Ada 语言程序设计环境APSE、LISP 语言程序设计环境 INTERLISP 等。广大读者所熟悉的7Pascal、TurboC、VisualC+等语言环境也都可认为是集成化的程序设计环境。1.5 编译程序的生成以前人们构造编译程序大多是用机器语言或汇编语言做工具的。为了发挥各
14、种不同硬件系统的效率,为了满足各种不同的具体要求,现在许多人仍然采用这种工具来构造编译程序。但是,越来越多的人倾向于使用高级语言作为工具来构造编译程序。因为,这样可以节省大量的程序设计时间,而且所构造出来的 编译程序也易于阅读、修改和移植。人们已经建立了多种编制部分编译程序或整个编译程序的有效工具。有些能用于自动产生扫描器,有些可用于自动产生语法分析器,有些甚至可用来自动产生整个的编译程序。如:编译程序-编译程序、 编译程序产 生器、翻 译程序书写系统等,它们是按照对源语言和目标语言(或机器)的形式描述(作为输入数据)而自动产生编译程序的。本课程将把自动产生器作为一个重要课题来讨论。 近些年来
15、,有些人主张采用“ 自编译方式 ”产生编译程序。意思是,先对语言的核心部分构造一个小小的编译程序(可用手编实现),再以它为工具构造一个能够编译更多语言成分的较大编译程序。如此扩展下去,就象 滚雪球一样,越 滚越大,最后形成人们所期望的整个编译程序。这种通过一系列自展途径而形成编译程序的过程叫作自编译过程。现在,有些编译程序是通过“移植”得到的。即把某一机器上的编译程序移植到另一机器上。着需要寻求某种适当的“中间语言” 。但是,由于建立通用中 间语言实际上办不到,因此,移植也只能在几种语言和几种机器之间进行。授课题目(教学章、节或主题):第二章 词法分析课时安排 128授课时间第 1 周 第 3
16、-6 节 第 2 周 第 1-6 节第 3 周 第 1、2 节 教学目的、要求(分掌握、熟悉、了解三个层次):了解词法分析器的构造方法熟悉词法分析的任务和过程掌握正规式和有限自动机的基本概念教学重点和难点:词法分析器的设计、正规表达式和有限自动机、正规表达式和有限自动机的等价性、正规文法和有限自动机间的转换授课类型(请打):理论课 讨论课 实验课 练习课 其他教学方式(请打):讲授 讨论 示教 指导 其他教学资源(请打):多媒体 模型 实物 挂图 音像 其他讨论、思考题、作业:P63:3,6, 7,8,12,14教学内容第二章 词法分析2.1 对于词法分析器的要求首先讨论词法分析器输出的单词符
17、号的一般形式,然后研究词法分析器应如何和语法分析器相衔接。2.1.1 词法分析器的功能和输出形式 词法分析器的功能是输入源程序,输出单词符号。单词符号是一个程序语言的基本语法符号,程序语言的单词符号一般可分为下列五种:1 基本字 如 FORTRAN 中的 DIMENSION、IF 和 DO 等等;2 标识符 用来表示各种名字,如变量名、数 组名和过程名等等;93 常 数 各种类型的常数,如 125,0.718、TRUE 等等; 4 运算符 如+、-、*、 /等等; 5 界 符 如逗号、括号、分号等等。标识符一般统归为一种。常数则宜按类型(整、实、复或布 尔)分种。基本字可将其全体视为一种,也可
18、以一字一种。运算符可采用一符一种的分法,但也可以把具有一定共性的算符(如所有关系符)视为一种。界符一般用一符一种的分法。如果一个种别只含一个单词符号,那么,对于这个单词符号,种 别编码就完全代表它自身了。若一个种别含有许多个单词符号,那么对于它的每个单词符号,除了给出种别编码之外,还应给出自身的值。2.1.2 词法分析器作为一个独立子程序可以使整个编译程序的结构更简洁、清晰和条例化。2.2 词法分析器的设计 我们将按照词法分析的任务和作为一个独立子程序的要求来考虑词法分析器的设计。2.2.1 输入、预处理词法分析器工作的第一步是输入源程序文本。输入串一般是放在一个缓冲区中,这个缓冲区称为输入缓
19、冲区。词法分析的工作(单词符号的识别)可以直接在这个缓冲区中进行。但在许多情况下,把 输入串预处理一下, 对单词符号的识别工作将是比较方便的。预处理的工作包括:剔除无用的空白、跳格、回车和换行符等编辑性字符;预处理工作还可以包括源程序和出错信息的列表打印。2.2.2 单词符号的识别:超前搜索10词法分析器的结构如下图所示:当词法分析器调用预处理子程序处理出一串输入字符放进扫描缓冲区之后,扫描器就从此缓冲区中逐一识别单词符号。当缓冲区里的字符串被处理完之后,它又调用预处理程序装入新串。图 3.1 词法分析器下面我们来介绍一下单词符号识别的一个简单方法超前搜索。基本字的识别 有些语言的基本字的输入
20、表示有特殊标志,如加双引号(如“BEGIN”),在这种情况下,基本字的识别是很直接的,不存在什么困难。 象FORTRAN 这样 的语言,基本字不加特殊保护,基本字和用户自定义的标识符或标号之间没有特殊的界符作间隔,这就使得基本字的识别甚为麻烦。这里就需要用到超前搜索。2.2.3 状态转换图 使用状态转换图是设计词法分析程序(扫描器)的一种好途径。转换图是一张有限方向图。在状态转换图中,结点代表状态,用圆圈表示。状态之间用箭弧连结。箭弧上的标记(字符)代表在射出结(即箭弧始节)状态下可能出现的输入字符或字符类。如下图 3.2(a)所示。源 程 序 串 输 入 缓 冲 区 列 表 预 处 理 子
21、程 序 扫 描 器 单 词 符 号 扫 描 缓 冲 区 11在状态 1 下,若输入字符 X,则读进 X,并转换到状态 2。若输入字符 Y,则读进Y,并转换 到状 态 3。一 张转换图只包含有限个状态(即有限个结点),其中有一个被认为是初态,而且实际上至少要有一个终态(用双圈表示)。图 3.2(a)状态转换图 示例2.2.4 状态转换图的实现 一个状态转换图可用于识别(或接受)一定的字符。大多数程序语言的单词符号都可以用转换图予以识别。转换图非常易于用程序实现,最简单的办法是让每个状态结点对应一小段程序。下面我们将引进一组全局变量和过程,把它们作为实现转换图的基本成分。这些变量和过程是:1. C
22、HAR 字符变量,存放最新 读进的源程序字符。2. TOKEN 字符数 组,存放构成单词符号的字符串。3. GETCHAR 子程序过程,把下一个输入字符读到 CHAR 中,把搜索指示器前移一字节位置。4. GETBC 子程序过程, 检查 CHAR 中的字符是否 为空白.若是,则 GETCHAR 直到 CHAR 中进入一个非空白符。5. CONCAT 子程序过程,把 CHAR 中的字符连接 TOKEN 之后。例如,TOKEN12原来的值为AB,而 CHAR 中存放着C, 经调用 CONCAT 后, TOKEN 的值就变为ABC。6. LETTER 和 DIGIT 布尔函数过程,它 们分别 CHA
23、R 中的字符是否为字母和数字,从尔给出真值 TRUE 或假值 FALSE。 7. RESERVE 整型函数过程, 对 TOKEN 中的字符串 查找保留字表,若它是一个保留字则返回它的编码,否则返回 0 值(假定 0 不是保留字的编码)。8. RETRACT 子程序过程,把搜索指示器回调一个字节位置,把 CHAR 中的字符置为空白。2.3 正规表达式与有限自动机2.3.1 正规式与正规集设 是一个有穷字母表,它的每个元素称为一个字符。 上的一个字(也叫字符串)是指由 中的字符所构成的一个有 穷序列。不包含任何字符的序列称为空字,记为 。用 * 表示 上的所有字的全体 ,空字 也包括在其中。 例如
24、,若=a,b,则 *=,a,b,aa,ab,ba,bb,aaa下面是正规 式和正规集的递归定义:1.和 都是 上的正规式,它们所表示 的正规集分别为 和 ;2.任何 ,是 上的一个正 规式,它所表示的正 规 集为 ;3.假定 U 和 V 都是 上的正规式,它 们所表示的正规集分别记为 L(U)和 L(V),那么, (U V)、(U|V)和(U)*也都是正规式,它 们所表示的正规集分别为 L(U)L(V)、L(U).L(V)(连接 积)和 (L(U)*(闭包)。仅由有限次使用上述三步骤而定义的表达式才是 上的正规式,仅由这些正规式所表示的字集才是 上的正 规集。算符的优先顺序为:先“*“,次“.
25、“,最后“|“。例如,令 =a,b ,下面是 上的正规式和相应的正规集:13ba*: 上所有以 b 为首后跟任意多个 a 的字a(a| b)* : 上所有以 a 为首的字(a| b)* (aa| bb)(a|b)*: 上所有含有两个相 继的 a 或两个相继的 b 的字 又例如,令 =A,B,0,1 ,则 (A|B)(A|B|0|1)* : 上的“标识符“ 的全体 (0|1)(0|1)* : 上的“ 数“的全体 若两个正规式所表示的正规集相同,则认为二者等价。两个等价的正规式 U 和 V记为 U=V。 令 U、V 和 W 均为正规式,显而易见 ,下列关系普遍成立 1. V=V|U (交换律) 2
26、. U|(V|W)=(u|v)|w(结合律) 3. U|(V|W)=(U|V)|W(结合律) 4. U|(VW)=UV|UW(分配律) (V|W)U=VU|WU 5.U=U =U 2.3.2 确定有限自动机(DFA) 设一个确定的有限自动机(DFA)M 是一个五元式 M=(S, ,f,S0, Z)其中1. S 是一个有限集,它的每个元素称 为一个状态;2. 是一个有穷字母表 ,它的每个元素称为一个输入字符;3. f 是一个从 S 至 S 的(单值)部分映照。f (s,a)=s意味着:当现行状态为 s,输入字符 a 时,将转换到下一状态 s。我们把 s称为 s 的一个后继状态;4. S0S,是唯
27、一的一个初 态;5. ZS,是一个终态集(可空)。一个 DFA 可用一个矩阵表示, 该矩阵的行表示状态,列表示输入字符,矩阵元素表示 f(s,a)的值,这个矩阵称为状态转换矩阵。 14例如,有 DFA M=(0,1,2,3 ,a,b ,f,0,3 其中 f 为: f(0,a)=1 f(0,b)=2f(1,a)=3 f(4,b)=2f(2,a)=1 f(2,b)=3f(3,a)=3 f(3,b)=3则对应的状态转换矩阵如下表 3.2 所示:表 3.2 状态转换矩阵状态 a b0 1 21 3 22 1 33 3 3一个 DFA 也可以表示成一张(确定的)状态转换图 。对于 *中的任何字,若存在一
28、条从初 态结到某一条终态结的道路,且这条路上所有弧的标记符连接成的字等于,则称 可为 DFA M 所识别(读出或接受)。若 M 的初态结同时又是终态结, 则空字 可为 M 所 识别(或接受)。上例所定义的 DFA M 相 应的状态转换图如下所示:它能 识别 上所有含有相继两个 a 或相继 两个 b 的字。图 3.5 状态转换图2.3.3 非确定有限自动机(NFA) 15设一个确定的有限自动机(DFA)M 是一个五元式 M=(S,f,S0, Z)其中1. S 是一个有限集,它的每个元素称 为一个状态;2. 是一个有穷字母表,它的每个元素称为一个输入字符;3. f 是一个从 S*到 S 的子集的映
29、照,即 f:S* 2S4. S0S,是非空初态集;5. Z S,是一个终态集(可空)。2.3.4 正规文法与有限自动机的等价性 对于正规文法 G 和有限自动机 M,如果 L(G)L (M),则称 G 和 M 是等价的。关于正规文法和有限自动机的等价性,有以下结论:(1( 对每一个右线性正规文法 G 或左线性正规文法 G,都存在一个有限自动机(FA)M,使得 L(M)L(G)。(2( 对每一个 FA M,都存在一个右线性正规文法 GR 或左线性正规文法 GL,使得 L(M)L(G R)L(G L)2.3.5 正规式与有限自动机的等价性我们可以证明:(1( 对任何 FA M,都存在一个正规式 r,
30、使得 L(r)L (M)。(2( 对任何的正规式 r,都存在一个 FA M,使得 L(M)L(r)。上述结论加上前面章节所证明的结论,说明正规文法、正规式、确定有限自 动机和非确定有限自动机在接收语言的能力上是互相等价的。2.3.6 确定有限自动机的化简 等价状态;最少化。2.4 词法分析器的自动产生 教学目的:使用状态转换图构造词法分析程序;上机实践 LEX 的实现。162.4.1 语言 LEX 的一般描述 一个 LEX 源程序主要包括两部分。一部分是正 规定义式,另一个是识别规则。 产生式(也称产生规则或简称规则)是定义语法范畴的一种书写规则。一个产生式的 形式是 Aa 其中,箭头(有时也
31、用:) 左边的 A 是一个非终结符,称为产生式的左部符号;箭头右边的 a 是由终结符号或非终结符号组成的符号串,称 为产生式的右部。我们有时也说, 产生式 Aa 是关于 A 的一条产生规则。 产生式是用来定义语法范畴的。例如,令 i 代表已定 义的范畴“变量”,那么, 产生式 算术表达式 i 意味着把“ 算术表达式”这 个范畴定义为 “变量”。在有的 书上, “”也用“:” 表示:这种表示方法也称巴科斯范式。2.4.2 超前搜索 在某些语言中,要识别一个单词符号必须超前看若干字符。2.4.3 LEX 的 实现 LEX 的编译 程序旨在将一个 LEX 源程序改造 为一个词法分析器 L,这个词法分
32、析器 L 将像有限自动机那样工作。相关介绍:人们已建立了多种编制部分编译程序或整个编译程序的有效工具。有些能用于自动产生扫描器(如 LEX),有些可用于自动产生语法分析器(如 YACC),有些甚至可用来自动产生整个的编译程序。这些构造编译程序的工具称为编译程序编译程序、编译程序产生器或翻译程序书写系统,它们是按对源程序和目标语言(或机器) 的形式描述(作为输入数据) 而自动产生编译程序的。17课时安排 6授课题目(教学章、节或主题):第三章 语法分析-上下文无关文法、形式语言和文法 授课时间 第 3 周 第 3-6 节 第 4 周 第 1、2 节 教学目的、要求(分掌握、熟悉、了解三个层次):
33、理解和定义上下文无关文法,为学习和构造编译程序打下良好基础。理解语言和文法的定义掌握文法的等价变换及语法描述方法了解文法的分类教学重点和难点:文法的直观概念、文法和语言的形式定义、文法的类型、 语法树和二义性、文法中的实用限制、句型的分析授课类型(请打):理论课 讨论课 实验课 练习课 其他教学方式(请打):讲授 讨论 示教 指导 其他教学资源(请打):多媒体 模型 实物 挂图 音像 其他讨论、思考题、作业:P36:6,8, 11教学内容3.1.1 上下文无关文法 箭头读为“定义为”,直竖|读为“ 或”,它 们是元语言符号。在后面的讨论中,根据不同情况,我们将用大写字母 A、B、C或汉语词组(
34、如,算术表达式)代表非终结符号,特别是用小写字母 a、b、c代表终结 符,用 、 等代表由终结符和非终结符组成的符号串。为简便起见,当引用具体的文法例子时, 仅列出产生式和指出开始符号。例如,下面是一个上下文无关文法:Ei|EAEA+|*其中,E、 A 是非终结符,E 是开始符号,而 i、+和*是终结符。一个上下文无关文法如何定义一个语言呢?其中心思想是,从文法的开始符号出18发,反复连续使用产生式,对非终结符施行替换和展开。例如,我们考虑下面的文法 G: EE 十 E | E*E | (E) |i 其中,唯一的非终结符 E 可以看成是代表一类算术表达式。我们可以从 E 出发,进行一系列的推导
35、,推出种种不同的算术表达式来。例如,根据 规则 E 一(E)我们可以说:从E可直接(一步地)推出(E) 。与前面一 样,我 们用 表示“ 直接推出”,这样,这句话就可表示为:E (E)。若 对(E)中的 E 使用规则 EE+E,就有(E)(E+E)。即,从(E)可直接推出(E+E)。把上述这两步合并起来,就有E(E)(E+E)。再对(E+E)中的 E 相继两次使用规则 Ei 之后,我们就有(E) (E+E)(i+E)(i+i)。我们称这样的一串替换序列是从 E 推出(i+i)的一个推导。这个推导提供了一个证明,证明(i+i)是文法(2.1) 所定义的一个算术表达式。注意,推 导每前进一步总是引
36、用一条规则(产生式), 而符号指仅推导一步的意思。我们可以用一种图示化的方法来表示这种推导,如下图 2.1,说明 He gave me a book 是一个语法正确的句子。这种图形表示称为语法分析树。定义 “he gave me a book”这个英文句子的规则可以说就是一个上下文无关文法。其中,He ,me,book,gave,a 等,称为终结符号;、 、 、等,称为非终结符号;这个文法最终是要定义的语法结构,所以 在 这里称 为开始符号;这种书写形式称为产生式。归纳起来,一个上下文无关文法 C 包括四个组成部分:一 组终结符号,一组非终结符号,一个开始符号,以及一组产生式。所谓终结符号乃是
37、组成语言的基本符号,在程序语言中就是以前屡次提到的单词符号,如基本字、标识符、常数、算符和界符等。从语法分析的角度来看,终19结符号是一个语言的不可再分的基本符号。图 2.1 语法树非终结符号(也称语法变量)用来代表语法范畴。例如, “算术表达式”、 “布尔表达式”、“赋值句”、 “分程序” 、“过程”等,它 们都是现今程序语言常见的语法范畴。我们也可以说,一个非终结符代表一个一定的语法概念。因此,一个非 终结符是一个类(或集合)记 号,而不是一个个体记号。例如, “算术表达式”这个非终结符乃代表一定算术式组成的类。因而,也可以说,每个非 终结符号表示一定符号串的集合 (由终结符号和非终结符号
38、组成的符号串)。开始符号是一个特殊的非终结符号,它代表所定义的语言中我们最终感兴趣的语法范畴,这个语法范畴通常称为“句子”。但在程序语言中,我们最终感兴趣的是“程序”这个语法范畴,而其它的语法范畴都只不过是构造“程序” 的一块块砖石。3.1.2 语法分析树与二义性 前面我们提到过可以用一张图表示一个句型的推导,这种表示称为语法分析树, E(根 ) ( E ) E + E E * E i i i he gave me a book20或简称为语法树。语法树有助于理解一个句子语法结构的层次。语法树通常表示成一棵倒立的树,根在上,枝叶在下。语法树的根结由开始符号所标记。随着推导的展开,当某个非终结符
39、被它的某个候选式所替换时,这个非终结符的相应结就产生出下一代新结,候选式中自左至右的每个符号对应一个新结,并用这些符号标记其相应的新结。每个新结和其父结间都有一条连线。在一棵语法树生长过程中的任何时刻,所有那些没有后代的端末结自左至右排列起来就是一个句型。例如,对于文法(2.1),关于(i*i+i) 的推导(2.2)的语法 树如图 2.2 所示。图 2.2 语法树这就是说,一棵语法树表示了一个句型种种可能的(但未必是所有的)不同推导过程,包括最左( 最右)推导。这样的一棵语法树是这些不同推导过程的共性抽象,是它们的代表。如果我们坚持使用最左(最右)推导,那么,一棵 语法树就完全等价于一个最左(
40、最右)推导 ,这种等价性包括树的步步成长和推导的步步展开之间的完全一致性。但是,一个句型是否只对应唯一的一棵语法树呢?也就是,它是否只有唯一的一个最左(最右) 推导呢? 不尽然。 3.1.3 形式语言鸟瞰 前面乔姆斯基把文法分成四种类型,即 0 型, 1 型, 2 型,和 3 型。0 型强于 1 型,1 型强于 2 型,2 型强于 3 型。 这几类文法的差别在于对产生式施加不同的限制。0 型文法:也称短语文法,其能力相当于图灵机。任何 0 型语言都是递归可枚举的,反之,递归可枚举集必定是一个 0 型语言。1 型文法:也称上下文有关文法,对非终结符进行替换时务必联系上下文,并且一般不允许替换成空
41、串。212 型文法:也称上下文无关文法3 型文法:也称右线性文法,这类文法等价于正规式,所以也称正规文法。只有下面两种形式的产生式:ABa 或 Aa。3.2.1 文法等价的概念:若 L(G1)=L(G2),则称文法 G1 和 G2 是等价的例如:下列两个文法是等价的G1A: A 0R A 01 R A1G2A:S 0S1 S 01因为 L(G1)=L(G2)=0n1n|n 1定义:对文法进行变换,使变换后的文法满足某种要求并于原文法等价,这种变换成为文法的等价变换。3.2.2、增广文法定义:设文法 GS=VN,VT,P,S,构造文法 GS=(VNS,VT,P,S),其中,P=A |A PS S
42、,显然 L(G)= L(G),称 G为文法 G 的增广文法。例:Z:Z abZA|a Ab经等价变换后可得到增广文法 GA:Z ZZ abZA|aAb3.2.3、提取左因子定义:若文法中有产生式 P1|2|n,则称该文发含有左因子 。其中 P VN ,1,2 n (VN VT)*。例:文法S: S iEtS|iEtSeS|a E b提取左因子该文法变为:GS: S iEtSS |aS eS| E b3.2.4、消除左递归定义:若文法中存在推导:P + P,则称该文法含有左递归。若存在产生式 P P,则称该文法含有直接左递归。若存在产生式 P P1,P1 P2, ,Pn-1 22Pn,Pn P,
43、则称该文法含有间接左递归。其中 P,P1, ,Pn VN, , , , (VN VT)*。直接左递归的消除方法:假设非终结符 P 存在产生式 P P|删除左递归产生式 P P引入新的非终结符 P消除文法中的左递归,得:P PP P|间接左递归的消除方法:将间接左递归转化为直接左递归;消除直接左递归;化简文法,删除含有从起始符号无法到达的非终结符的产生式最后,作为描述程序语言的上下文无关文法,我们对它有几点限制。(1)文法中不含任何下面形式的产生式: PP 因为这种产生式除了产生二义性外没有任何用处。(2)每个非终结符 P 必须有用 处。 这一方面意味着,必须存在含 P 的句型;也就是,从开始符
44、号出发,存在推导 S*P.另一方面意味着,必须存在终结符串VT*,使得 P+;也就是, 对于 P 不存在永不终结的回路。我们以后所讨论的文法均假定满足上述两条件。23课时安排 12授课题目(教学章、节或主题):第三章 语法分析自上而下分析 授课时间 第 4 周 第 3-6 节 第 6 周 第 1-6 节第 7 周 第 1-2 节 教学目的、要求(分掌握、熟悉、了解三个层次):了解确定的自顶向下分析思想熟悉某些非 LL(1)文法到 LL(1)文法的等价变换掌握 LL(1)文法的判别、确定的自顶向下分析方法教学重点和难点:语法分析器的功能、确定的自顶向下分析思想、LL(1)文法的判别、某些非 LL
45、(1)文法到 LL(1)文法的等价变换、不确定的自顶向下分析思想、确定的自顶向下分析方法授课类型(请打):理论课 讨论课 实验课 练习课 其他教学方式(请打):讲授 讨论 示教 指导 其他教学资源(请打):多媒体 模型 实物 挂图 音像 其他讨论、思考题、作业:P81:1,2, 4教学内容第三章 语法分析自上而下分析3.1 语法分析器的功能 语法分析器:是这样的一个程序,它将按文法的产生式,识别输入符号串是否为一个句子。输入串是指由单词符号(文法的终结符)组成的有限序列。语法分析的方法:可大致分为两类,一类是自下而上分析法,另一类是自上而下分24析法。所谓自下而上分析法就是从输入串开始,逐步进
46、行“ 归约”,直至归约到文法的开始符号。自上而下分析过程恰好与此相反,它从文法的开始符号出发,反复使用各种产生式,寻找“匹配”于输入串的推导。3.2 自上而下分析面临的问题 本本 节节 主要是通主要是通 过过 例子使我例子使我 们认识们认识 到,作自上而下分析所遇到的主要困到,作自上而下分析所遇到的主要困 难难 是是 语语 法法的左的左 递归递归 性使分析陷入无限循性使分析陷入无限循 环环 ;回溯的不确定性,要求我;回溯的不确定性,要求我 们们 将已将已 经经 完成工作推完成工作推倒重来, 为为 解决解决 这这 些些 问题问题 我我 们们 要消除左要消除左 递归递归 和消除回溯。和消除回溯。3
47、.3 LL(1)分析法 自上而下分析方法不允许文法含有任何左递归。为构造不带回溯的自上而下分析算法,首先要消除文法的左递归性,并找出克服回溯的充分必要条件。3.3.1 左递归的消除 假定关于非终结符 P 的规则为 :P P| 其中,每个 都不以 P 开头,那么我们可以把 P 的规则改写成如下的非直接左递归形式:p -pp- p|( 为空字)这种形式和原来的形式是等价的,也就是说,从 P 推出的符号串是相同的。3.3.2 消除回溯、提左因子 我我 们们 首先来看一下在不得回溯的情况下首先来看一下在不得回溯的情况下 对对 于文法有什么要求。前面已于文法有什么要求。前面已 经说过经说过 ,欲实实 行
48、自上而下的分析,文法不得含左行自上而下的分析,文法不得含左 递归递归 。令 G 是一个不含左是一个不含左 递归递归 的文法, 对对 G 的所有的非的所有的非 终结终结 符号的每个候符号的每个候 选选 定定 义义 它的它的 终结终结 首符集首符集 FIRST()为为 :FIRST()=a|*a,aVT特特 别别 是,若 *,则规则规 定定 FIRST()。换换 句句 话说话说 FIRST()是是 的所有可能推的所有可能推 导导的开的开 头终结头终结 符或可能的符或可能的 。如果非 终结终结 符符 A 的所有候的所有候 选选 首符集两两不相交,即首符集两两不相交,即 A25的任何两个不同的候的任何两个不同的候 选选 i 和和 j FIRST(i)FIRST(j) = 那么,当要求那么,当要求 A 匹配匹配 输输 入串入串 时