《编译原理》教案.docx
《《编译原理》教案.docx》由会员分享,可在线阅读,更多相关《《编译原理》教案.docx(58页珍藏版)》请在冰豆网上搜索。
《编译原理》教案
《编译原理》教案
授课题目(教学章、节或主题):
第一章引论
课时安排
2
授课时间
第1周第1、2节
教学目的、要求(分掌握、熟悉、了解三个层次):
简单介绍学习此课程的目的和要求
初步了解编译技术的基本原理和方法
熟悉piler的基本概念
掌握piler的结构和功能
教学重点和难点:
编译程序的基本结构和功能
授课类型(请打√):
理论课☑讨论课□实验课□练习课□其他□
教学方式(请打√):
讲授☑讨论□示教□指导☑其他□
教学资源(请打√):
多媒体☑模型□实物□挂图□音像□其他□
讨论、思考题、作业:
编译程序的基本结构如何?
各部分功能?
教学内容
0课程学习的要求及任务,学习方法介绍,成绩考核标准。
第一章引论
1.1什么叫编译程序?
通常所说的翻译程序是指这样的一个程序,它能够把某一种语言程序(称为源语言程序)转换成另一种语言程序(称为目标语言程序),而后者与前者在逻辑上是等价的。
如果源语言是诸如FORTRAN、Pascal、C、Ada、Smalltalk或Java这样的“高级语言”,而目标语言是诸如汇编语言或机器语言之类的“低级语言”,这样的一个翻译程序就称为编译程序。
高级语言程序除了像上面所说的先编译后执行外,有时也可“解释”执行。
一个源语言的解释程序是这样的程序,它以该语言写的源程序作为输入,但不产生目标程序,而是边解释边执行源程序本身。
本书将不对解释程序作专门的讨论。
实际上,许多编译程序的构造与实现技术同样适用于解释程序。
根据不同的用途和侧重,编译程序还可进一步分类。
专门用于帮助程序开发和调试的编译程序称为诊断编译程序(Diagnosticpiler),着重于提高目标代码效率的编译程序叫优化编译程序(Optimizingpiler)。
现在很多编译程序同时提供了调试、优化等多种功能,用户可以通过“开关”进行选择。
运行编译程序的计算机称宿主机,运行编译程序所产生目标代码的计算机称目标机。
如果一个编译程序产生不同于其宿主机的机器代码,则称它为交叉编译程序(CrOSSpiler)。
如果不需重写编译程序中与机器无关的部分就能改变目标机,则称该编译程序为可变目标编译程序(Retargetablepiler)。
1.2编译过程概述
编译程序过程:
从输入源程序开始到输出目标程序为止的整个编译过程可分为以下五个阶段:
词法分析,语法分析,语义分析,中间代码产生,优化和目标代码生成.
1.3编译程序的结构
编译程序的结构可以按照从输入源程序开始到输出目标程序为止的整个编译过程可分为以下五个阶段:
词法分析,语法分析,语义分析,中间代码产生,优化和目标代码生成。
1.3.1编译程序总框
编译程序的结构可以按照这五个阶段的任务分模块进行设计。
下图给出了编译程序的总框。
1.3.2表格与表格管理
编译程序在工作过程中需要保持一系列的表格,以登记源程序的各类信息和编译各阶段的进展状况。
在编译程序使用的表格中,最合理的是符号表。
编译程序在工作过程中需要保持一系列的表格,以登记源程序的各类信息和编译各阶段的进展状况。
合理地设计和使用表格是编译程序构造的一个重要问题。
在编译程序使用的表格中,最重要的是符号表。
它用来登记源程序中出现的每个名字以及名字的各种属性。
例如,一个名字是常量名、变量名,还是过程名等等;如果是变量名,它的类型是什么、所占内存是多大、地址是什么等等。
通常,编译程序在处理到名字的定义性出现时,要把名字的各种属性填人到符号表中;当处理到名字的使用性出现时,要对名字的属性进行查证。
当扫描器识别出一个名字(标识符)后,它把该名字填人到符号表中。
但这时不能完全确定名字的属性,它的各种属性要在后续的各阶段才能填人。
例如,名字的类型等要在语义分析时才能确定,而名字的地址可能要到目标代码生成才能确定。
由此可见,编译各阶段都涉及到构造、查找或更新有关的表格。
1.3.3出错处理
遍:
是对源程序或源程序的中间结果从头到尾扫描一次,并作有关的加工处理,生产新的中间结果或目标程序。
一个编译程序不仅应能对书写正确的程序进行翻译,而且应能对出现在源程序中的错误进行处理。
如果源程序有错误,编译程序应设法发现错误,把有关错误信息报告给用户。
这部分工作是由专门的一组程序(叫做出错处理程序)完成的。
一个好的编译程序应能最大限度地发现源程序中的各种错误,准确地指出错误的性质和发生错误的地点,并且能将错误所造成的影响限制在尽可能小的X围内,使得源程序的其余部分能继续被编译下去,以便进一步发现其它可能的错误。
如果不仅能够发现错误,而且还能自动校正错、误,那当然就更好了。
但是,自动校正错误的代价是非常高的。
编译过程的每一阶段都可能检测出错误,其中,绝大多数错误可以在编译的前三阶段检测出来。
源程序中的错误通常分为语法错误和语义错误两大类。
语法错误是指源程序中不符合语法(或词法)规则的错误,它们可在词法分析或语法分析时检测出来。
例如,词法分析阶段能够检测出“非法字符”之类的错误;语法分析阶段能够检测出诸如“括号不匹配”、“缺少;”之类的错误。
语义错误是指源程序中不符合语义规则的错误,这些错误一般在语义分析时检测出来,有的语义错误要在运行时才能检测出来。
语义错误通常包括:
说明错误、作用域错误、类型不一致等等。
1.3.4遍
遍:
是对源程序或源程序的中间结果从头到尾扫描一次,并作有关的加工处理,生产新的中间结果或目标程序。
通常,每遍的工作由从外存上获得的前一遍的中间结果开始(对于第一遍而言,从外存上获得源程序),完成它所含的有关工作之后,再把结果记录于外存。
既可以将几个不同阶段合为一遍,也可以把一个阶段的工作分为若干遍。
例如,词法分析这一阶段可以单独作为一遍,但更多的时候是把它与语法分析合并为一遍;为了便于处理,语法分析和语义分析与中间代码产生又常常合为一遍。
在优化要求很高时,往往还可把优化阶段分为若干遍来实现。
当一遍中包含若干阶段时,各阶段的工作是穿插进行的。
例如,我们可以把词法分析、语法分析及语义分析与中间代码产生这三阶段安排成一遍。
这时,语法分析器处于核心位置,当它在识别语法结构而需要下一单词符号时,它就调用词法分析器,一旦识别出一个语法单位时,它就调用中间代码产生器,完成相应的语义分析并产生相应的中间代码。
一个编译程序究竟应分成几遍,如何划分,是与源语言、设计要求、硬件设备等诸因素有关的,因此难于统一划定。
遍数多一点有个好处,即整个编译程序的逻辑结构可能清晰一点。
但遍数多势必增加输入/输出所消耗的时间。
因此,在主存可能的前提下,一般还是遍数尽可能少一点为好。
应当注意的是,并不是每种语言都可以用单遍编译程序实现。
1.3.5编译前端与后端
概念上,我们有时把编译程序划分为编译前端和编译后端。
前端主要由与源语言有关但与目标机无关的那些部分组成。
这些部分通常包括词法分析、语法分析、语义分析与中间代码产生,有的代码优化工作也可包括在前端。
后端包括编译程序中与目标机有关的那些部分,如与目标机有关的代码优化和目标代码生成等。
通常,后端不依赖于源语言而仅仅依赖于中间语言。
可以取编译程序的前端,改写其后端以生成不同目标机上的相同语言的编译程序。
如果后端的设计是经过精心考虑的,那么后端的改写将用不了太大工作量,这样就可实现编译程序的目标机改变。
也可以设想将几种源语言编译成相同的中间语言,然后为不同的前端配上相同的后端,这样就可为同一台机器生成不同语言的编译程序。
然而,由于不同语言存在某些微妙的区别,因此在这方面所取得的成果还非常有限。
为了实现编译程序可改变目标机,通常需要有一种定义良好的中间语言支持。
例如.在著名的Ada程序设计环境APSE中,使用的是一种称为Diana的树形结构的中间语言一个Ada源程序通过前编译转换为Diana中间代码,由编译后端把Diana中间代码转换为目标代码。
编译前端与不同的编译后端以Diana为界面,实现编译程序的目标机改变。
又如,在Java语言环境中,为了使编译后的程序从一个平台移到另一个平台,Java定义一种虚拟机代码--Bytecode。
只要实际使用的操作平台上实现了的Java解释器,这个操作平台就可以执行各种Java程序。
这就是所谓Java语言操作平台无关性。
1.4编译程序与程序设计环境
开发通常还需要一些其它的工具;如编辑程序、连接程序,调试工具等等。
编译程序与这些程序设计工具一起构成所谓的程序设计环境。
在高级语言发展的早期,这些程序设计工具往往是独立的,缺乏整体性,而且也缺乏对软件开发全生命周期的支持。
随着软件技术的不断发展,现在人们越来越倾向于构造集成化的程序设计环境。
一个集成化的程序设计环境的特点是,它将相互独立的程序设计工具集成起来,以便为程序员提供完整的、一体化的支持,从而进一步提高程序开发效率,改善程序质量。
在一个好的集成化程序设计环境中,不仅包含丰富的程序设计工具,而且还支持程序设计方法学,支持程序开发的全生命周期。
有代表性的集成化程序设计环境有Ada语言程序设计环境APSE、LISP语言程序设计环境INTERLISP等。
广大读者所熟悉的Pascal、TurboC、VisualC++等语言环境也都可认为是集成化的程序设计环境。
1.5编译程序的生成
以前人们构造编译程序大多是用机器语言或汇编语言做工具的。
为了发挥各种不同硬件系统的效率,为了满足各种不同的具体要求,现在许多人仍然采用这种工具来构造编译程序。
但是,越来越多的人倾向于使用高级语言作为工具来构造编译程序。
因为,这样可以节省大量的程序设计时间,而且所构造出来的编译程序也易于阅读、修改和移植。
人们已经建立了多种编制部分编译程序或整个编译程序的有效工具。
有些能用于自动产生扫描器,有些可用于自动产生语法分析器,有些甚至可用来自动产生整个的编译程序。
如:
编译程序-编译程序、编译程序产生器、翻译程序书写系统等,它们是按照对源语言和目标语言(或机器)的形式描述(作为输入数据)而自动产生编译程序的。
本课程将把自动产生器作为一个重要课题来讨论。
近些年来,有些人主X采用“自编译方式”产生编译程序。
意思是,先对语言的核心部分构造一个小小的编译程序(可用手编实现),再以它为工具构造一个能够编译更多语言成分的较大编译程序。
如此扩展下去,就象滚雪球一样,越滚越大,最后形成人们所期望的整个编译程序。
这种通过一系列自展途径而形成编译程序的过程叫作自编译过程。
现在,有些编译程序是通过“移植”得到的。
即把某一机器上的编译程序移植到另一机器上。
着需要寻求某种适当的“中间语言”。
但是,由于建立通用中间语言实际上办不到,因此,移植也只能在几种语言和几种机器之间进行。
授课题目(教学章、节或主题):
第二章词法分析
课时安排
12
授课时间
第1周第3-6节
第2周第1-6节
第3周第1、2节
教学目的、要求(分掌握、熟悉、了解三个层次):
了解词法分析器的构造方法
熟悉词法分析的任务和过程
掌握正规式和有限自动机的基本概念
教学重点和难点:
词法分析器的设计、正规表达式和有限自动机、正规表达式和有限自动机的等价性、正规文法和有限自动机间的转换
授课类型(请打√):
理论课☑讨论课□实验课☑练习课☑其他□
教学方式(请打√):
讲授☑讨论□示教□指导☑其他□
教学资源(请打√):
多媒体☑模型□实物□挂图□音像□其他□
讨论、思考题、作业:
P63:
3,6,7,8,12,14
教学内容
第二章词法分析
2.1对于词法分析器的要求
首先讨论词法分析器输出的单词符号的一般形式,然后研究词法分析器应如何和语法分析器相衔接。
2.1.1词法分析器的功能和输出形式
词法分析器的功能是输入源程序,输出单词符号。
单词符号是一个程序语言的基本语法符号,程序语言的单词符号一般可分为下列五种:
1基本字如FORTRAN中的DIMENSION、IF和DO等等;
2标识符用来表示各种名字,如变量名、数组名和过程名等等;
3常数各种类型的常数,如125,0.718、TRUE等等;
4运算符如+、-、*、/等等;
5界符如逗号、括号、分号等等。
标识符一般统归为一种。
常数则宜按类型(整、实、复或布尔)分种。
基本字可将其全体视为一种,也可以一字一种。
运算符可采用一符一种的分法,但也可以把具有一定共性的算符(如所有关系符)视为一种。
界符一般用一符一种的分法。
如果一个种别只含一个单词符号,那么,对于这个单词符号,种别编码就完全代表它自身了。
若一个种别含有许多个单词符号,那么对于它的每个单词符号,除了给出种别编码之外,还应给出自身的值。
2.1.2词法分析器作为一个独立子程序
可以使整个编译程序的结构更简洁、清晰和条例化。
2.2词法分析器的设计
我们将按照词法分析的任务和作为一个独立子程序的要求来考虑词法分析器的设计。
2.2.1输入、预处理
词法分析器工作的第一步是输入源程序文本。
输入串一般是放在一个缓冲区中,这个缓冲区称为输入缓冲区。
词法分析的工作(单词符号的识别)可以直接在这个缓冲区中进行。
但在许多情况下,把输入串预处理一下,对单词符号的识别工作将是比较方便的。
预处理的工作包括:
剔除无用的空白、跳格、回车和换行符等编辑性字符;预处理工作还可以包括源程序和出错信息的列表打印。
2.2.2单词符号的识别:
超前搜索
词法分析器的结构如下图所示:
当词法分析器调用预处理子程序处理出一串输入字符放进扫描缓冲区之后,扫描器就从此缓冲区中逐一识别单词符号。
当缓冲区里的字符串被处理完之后,它又调用预处理程序装入新串。
图3.1词法分析器
下面我们来介绍一下单词符号识别的一个简单方法——超前搜索。
基本字的识别有些语言的基本字的输入表示有特殊标志,如加双引号(如“BEGIN”),在这种情况下,基本字的识别是很直接的,不存在什么困难。
象FORTRAN这样的语言,基本字不加特殊保护,基本字和用户自定义的标识符或标号之间没有特殊的界符作间隔,这就使得基本字的识别甚为麻烦。
这里就需要用到超前搜索。
2.2.3状态转换图
使用状态转换图是设计词法分析程序(扫描器)的一种好途径。
转换图是一X有限方向图。
在状态转换图中,结点代表状态,用圆圈表示。
状态之间用箭弧连结。
箭弧上的标记(字符)代表在射出结(即箭弧始节)状态下可能出现的输入字符或字符类。
如下图3.2(a)所示。
在状态1下,若输入字符X,则读进X,并转换到状态2。
若输入字符Y,则读进Y,并转换到状态3。
一X转换图只包含有限个状态(即有限个结点),其中有一个被认为是初态,而且实际上至少要有一个终态(用双圈表示)。
图3.2(a)状态转换图示例
2.2.4状态转换图的实现
一个状态转换图可用于识别(或接受)一定的字符。
大多数程序语言的单词符号都可以用转换图予以识别。
转换图非常易于用程序实现,最简单的办法是让每个状态结点对应一小段程序。
下面我们将引进一组全局变量和过程,把它们作为实现转换图的基本成分。
这些变量和过程是:
1.CHAR字符变量,存放最新读进的源程序字符。
2.TOKEN字符数组,存放构成单词符号的字符串。
3.GETCHAR子程序过程,把下一个输入字符读到CHAR中,把搜索指示器前移一字节位置。
4.GETBC子程序过程,检查CHAR中的字符是否为空白.若是,则GETCHAR直到CHAR中进入一个非空白符。
5.CONCAT子程序过程,把CHAR中的字符连接TOKEN之后。
例如,TOKEN原来的值为‘AB',而CHAR中存放着'C',经调用CONCAT后,TOKEN的值就变为'ABC'。
6.LETTER和DIGIT布尔函数过程,它们分别CHAR中的字符是否为字母和数字,从尔给出真值TRUE或假值FALSE。
7.RESERVE整型函数过程,对TOKEN中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回0值(假定0不是保留字的编码)。
8.RETRACT子程序过程,把搜索指示器回调一个字节位置,把CHAR中的字符置为空白。
2.3正规表达式与有限自动机
2.3.1正规式与正规集
设Σ是一个有穷字母表,它的每个元素称为一个字符。
Σ上的一个字(也叫字符串)是指由Σ中的字符所构成的一个有穷序列。
不包含任何字符的序列称为空字,记为ε。
用Σ*表示Σ上的所有字的全体,空字ε也包括在其中。
例如,若Σ={a,b},则Σ*={ε,a,b,aa,ab,ba,bb,aaa}下面是正规式和正规集的递归定义:
1.和Φ都是上的正规式,它们所表示的正规集分别为{ε}和Φ;
2.任何α∈Σ,是Σ上的一个正规式,它所表示的正规集为{α};
3.假定U和V都是上的正规式,它们所表示的正规集分别记为L(U)和L(V),那么,(UV)、(U|V)和(U)*也都是正规式,它们所表示的正规集分别为L(U)⋃L(V)、L(U).L(V)(连接积)和(L(U))*(闭包)。
仅由有限次使用上述三步骤而定义的表达式才是Σ上的正规式,仅由这些正规式所表示的字集才是Σ上的正规集。
算符的优先顺序为:
先"*",次".",最后"|"。
例如,令Σ={a,b},下面是Σ上的正规式和相应的正规集:
ba*:
Σ上所有以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.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.S0∈S,是唯一的一个初态;
5.Z⊆S,是一个终态集(可空)。
一个DFA可用一个矩阵表示,该矩阵的行表示状态,列表示输入字符,矩阵元素表示f(s,a)的值,这个矩阵称为状态转换矩阵。
例如,有DFAM=({0,1,2,3,{a,b,f,0,{3}其中f为:
f(0,a)=1f(0,b)=2
f(1,a)=3f(4,b)=2
f(2,a)=1f(2,b)=3
f(3,a)=3f(3,b)=3
则对应的状态转换矩阵如下表3.2所示:
表3.2状态转换矩阵
状态
a
b
0
1
2
1
3
2
2
1
3
3
3
3
一个DFA也可以表示成一X(确定的)状态转换图。
对于Σ*中的任何字α,若存在一条从初态结到某一条终态结的道路,且这条路上所有弧的标记符连接成的字等于α,则称α可为DFAM所识别(读出或接受)。
若M的初态结同时又是终态结,则空字ε可为M所识别(或接受)。
上例所定义的DFAM相应的状态转换图如下所示:
它能识别Σ上所有含有相继两个a或相继两个b的字。
图3.5状态转换图
2.3.3非确定有限自动机(NFA)
设一个确定的有限自动机(DFA)M是一个五元式M=(S,Σ,f,S0,Z)其中
1.S是一个有限集,它的每个元素称为一个状态;
2.Σ是一个有穷字母表,它的每个元素称为一个输入字符;
3.f是一个从S×Σ*到S的子集的映照,即f:
S×Σ*→2S
4.S0⊆S,是非空初态集;
5.Z⊆S,是一个终态集(可空)。
2.3.4正规文法与有限自动机的等价性
对于正规文法G和有限自动机M,如果L(G)=L(M),则称G和M是等价的。
关于正规文法和有限自动机的等价性,有以下结论:
(1)对每一个右线性正规文法G或左线性正规文法G,都存在一个有限自动机(FA)M,使得L(M)=L(G)。
(2)对每一个FAM,都存在一个右线性正规文法GR或左线性正规文法GL,使得L(M)=L(GR)=L(GL)
2.3.5正规式与有限自动机的等价性
我们可以证明:
(1)对任何FAM,都存在一个正规式r,使得L(r)=L(M)。
(2)对任何的正规式r,都存在一个FAM,使得L(M)=L(r)。
上述结论加上前面章节所证明的结论,说明正规文法、正规式、确定有限自动机和非确定有限自动机在接收语言的能力上是互相等价的。
2.3.6确定有限自动机的化简
等价状态;最少化。
2.4词法分析器的自动产生
教学目的:
使用状态转换图构造词法分析程序;上机实践LEX的实现。
2.4.1语言LEX的一般描述
一个LEX源程序主要包括两部分。
一部分是正规定义式,另一个是识别规则。
产生式(也称产生规则或简称规则)是定义语法X畴的一种书写规则。
一个产生式的形式是A→a其中,箭头(有时也用:
:
=)左边的A是一个非终结符,称为产生式的左部符号;箭头右边的a是由终结符号或非终结符号组成的符号串,称为产生式的右部。
我们有时也说,产生式A→a是关于A的一条产生规则。
产生式是用来定义语法X畴的。
例如,令i代表已定义的X畴“变量”,那么,产生式算术表达式→i意味着把“算术表达式”这个X畴定义为“变量”。
在有的书上,“→”也用“:
:
=”表示:
这种表示方法也称巴科斯X式。
2.4.2超前搜索
在某些语言中,要识别一个单词符号必须超前看若干字符。
2.4.3LEX的实现
LEX的编译程序旨在将一个LEX源程序改造为一个词法分析器L,这个词法分析器L将像有限自动机那样工作。
相关介绍:
人们已建立了多种编制部分编译程序或整个编译程序的有效工具。
有些能用于自动产生扫描器(如LEX),有些可用于自动产生语法分析器(如YACC),有些甚至可用来自动产生整个的编译程序。
这些构造编译程序的工具称为编译程序——编译程序、编译程序产生器或翻译程序书写系统,它们是按对源程序和目标语言(或机器)的形式描述(作为输入数据)而自动产生编译程序的。
授课题目(教学章、节或主题):
第三章语法分析-上下文无关文法、形式语言和文法
课时安排
6
授课时间
第3周第3-6节
第4周第1、2节
教学目的、要求(分掌握、熟悉、了解三个层次):
理解和定义上下文无关文法,为学习和构造编译程序打下良好基础。
理解语言和文法的定义
掌握文法的等价变换及语法描述方法
了解文法的分类
教学重点和难点:
文法的直观概念、文法和语言的形式定义、文法的类型、语法树和二义性、文法中的实用限制、句型的分析
授课类型(请打√):
理论课☑讨论课□实验课□练习课☑其他□
教学方式(请打√):
讲授☑讨论□示教□指导☑其他□
教学资源(请打√):
多媒体☑模型□实物□挂图□音像□其他□
讨论、思考题、作业:
P36:
6,8