《编译原理绪论》PPT课件.ppt
第1章 绪论,1.1 编译程序概述 1.2 编译程序的工作过程与结构 1.3 编译程序的开发 1.4 构造编译程序所应掌握的内容,1.1 编译程序概述,为了处理和解决实际问题,每一种计算机都具有其特定的功能,而这些功能是通过计算机执行一系列相应的操作来实现的。计算机所能执行的每一种操作称为一条指令,计算机能够执行的全部指令集合就是该计算机的指令系统。由于计算机硬件的器件特性,决定了计算机本身只能直接接受由0和1编码的二进制指令和数据,这种二进制形式的指令集合称为该计算机的机器语言,它是计算机惟一能够直接识别并接受的语言。,用机器语言编写程序很不方便且容易出错,编写出来的程序也难以调试、阅读和交流。为此,出现了用助记符代替机器语言二进制编码的另外一种语言,这就是汇编语言。汇编语言是建立在机器语言之上的,因为它是机器语言的符号化形式,所以较机器语言直观;但是计算机并不能直接识别这种符号化语言,用汇编语言编写的程序必须翻译成机器语言之后才能执行,这种“翻译”是通过专门的软件汇编程序实现的。,尽管汇编语言与机器语言相比在阅读和理解上有了长足的进步,但其依赖具体机器的特性是无法改变的,这给程序设计增加了难度。随着计算机应用需求的不断增长,出现了更加接近人类自然语言的功能更强、抽象级别更高的面向各种应用的高级语言。高级语言已经从具体机器中抽象出来,摆脱了依赖具体机器的问题。用高级语言编制的程序几乎能够在不改动的情况下在不同种类的计算机上运行且不易出错,这是汇编语言难以做到的,但高级语言程序翻译(编译)成最终能够直接执行的机器语言程序的难度却大大增加了。,由于汇编语言和机器语言一样都是面向机器的,故相对于面向用户的高级语言来说,它们都称之为低级语言,而FORTRAN、PASCAL、C、ADA、Java这类面向应用的语言则称之为高级语言。因此,编译程序就是指这样一种程序,通过它能够将用高级语言编写的源程序转换成与之在逻辑上等价的低级语言形式的目标程序,见图11。,图1-1 编译程序的功能,一个高级语言程序的执行通常分为两个阶段,即编译阶段和运行阶段,如图12所示。编译阶段将源程序变换成目标程序;运行阶段则由所生成的目标程序连同运行系统(数据空间分配子程序、标准函数程序等)接受程序的初始数据作为输入,运行后输出计算结果。如果编译生成的目标程序是汇编语言形式,那么在编译与运行阶段之间还要添加一个汇编阶段,它将编译生成的汇编语言目标程序再经过汇编程序变换成机器语言目标程序,如图13所示。,图1-2 源程序的编译和运行阶段,图13 源程序的编译、汇编和运行阶段,用高级语言编写的程序也可通过解释程序来执行。解释程序也是一种翻译程序,它将源程序作为输入,一条语句一条语句地读入并解释执行,如图14所示。解释程序与编译程序的主要区别是:编译程序是将源程序翻译成目标程序后再执行该目标程序,而解释程序则是逐条读出源程序中的语句并解释执行,即在解释程序的执行过程中并不产生目标程序。典型的解释型高级语言是BASIC语言。,图1-4 解释程序解释执行过程的示意,1.2 编译程序的工作过程与结构,编译程序的工作过程是指从输入源程序开始到输出目标程序为止的整个过程,此过程是非常复杂的。一般来说,整个编译过程可以划分成五个阶段:词法分析阶段、语法分析阶段、语义分析和中间代码生成阶段、优化阶段和目标代码生成阶段。,1词法分析 词法分析的任务是输入源程序,对构成源程序的字符串进行扫描和分解,识别出一个个单词符号,如基本字(if、for、begin等)、标识符、常数、运算符和界符(如“()”、=”、“;”)等,将所识别出的单词用统一长度的标准形式(也称内部码)来表示,以便于后继语法工作的进行。因此,词法分析工作是将源程序中字符串变换成单词符号流的过程,词法分析阶段工作遵循的是语言的构词规则。,2语法分析 语法分析的任务是在词法分析的基础上,根据语言的语法规则(文法规则)把单词符号流分解成各类语法单位(语法范畴),如“短语”、“子句”、“句子(语句)”、“程序段”和“程序”。通过语法分析可以确定整个输入串是否构成一个语法上正确的“程序”。语法分析所遵循的是语言的语法规则,语法规则通常用上下文无关文法描述。,3语义分析和中间代码生成 这一阶段的任务是对各类不同语法范畴按语言的语义进行初步翻译,包含两个方面的工作:一是对每种语法范畴进行静态语义检查,如变量是否定义、类型是否正确等;二是在语义检查正确的情况下进行中间代码的翻译。注意,中间代码是介于高级语言的语句和低级语言的指令之间的一种独立于具体硬件的记号系统,它既有一定程度的抽象,又与低级语言的指令十分接近,因此转换为目标代码比较容易。把语法范畴翻译成中间代码所遵循的是语言的语义规则,常见的中间代码有四元式、三元式、间接三元式和逆波兰记号等。,4优化 优化的任务是对前阶段产生的中间代码进行等价变换或改造,以期获得更为高效(节省时间和空间)的目标代码。常用的优化措施有删除冗余运算、删除无用赋值、合并已知量、循环优化等。例如,其值并不随循环而发生变化的运算可提到进入循环前计算一次,而不必在循环中每次循环都进行计算。优化所遵循的原则是程序的等价变换规则。,5目标代码生成 这一阶段的任务是把中间代码(或经优化处理之后)变换成特定机器上的机器语言程序或汇编语言程序,实现最终的翻译工作。最后阶段的工作因为目标语言的关系而十分依赖硬件系统,即如何充分利用机器现有的寄存器,合理地选择指令,生成尽可能短且有效的目标代码,这些都与目标机器的硬件结构有关。上述编译过程的五个阶段是编译程序工作时的动态特征,编译程序的结构可以按照这五个阶段的任务分模块进行设计。编译程序的结构示意如图15所示。,图15 编译程序结构示意,编译过程中源程序的各种信息被保留在不同的表格里,编译各阶段的工作都涉及到构造、查找或更新有关的表格,编译过程的绝大部分时间是用在造表、查表和更新表格的事务上,因此,编译程序中还应包括一个表格管理程序。出错处理与编译的各个阶段都有联系,与前三个阶段的联系尤为密切。出错处理程序应在发现错误后,将错误的有关信息如错误类型、出错地点等向用户报告。此外,为了尽可能多地发现错误,应在发现错误后还能继续编译下去,以便发现更多的错误。,一个编译过程可分为一遍、两遍或多遍完成,每一遍完成所规定的任务。例如,第一遍只完成词法分析的任务,第二遍完成语法分析和语义加工工作并生成中间代码,第三遍再实现代码优化和目标代码生成。当然,也可一遍即完成整个翻译工作。至于一个编译程序究竟应分成几遍,如何划分,这和源程序语言的结构与目标机器的特征有关。分多遍完成编译过程可以使整个编译程序的逻辑结构更清晰一点,但遍数多势必增加读写中间文件的次数,从而消耗过多的时间。,1.3 编译程序的开发,由于计算机语言功能的完善、硬件结构的发展、环境界面的友好要求等都对编译程序提出更多、更高的要求,因而构造一个编译系统并非易事。虽然编译理论和编译技术的不断发展已使编译程序的生产周期不断缩短,但是要研制完成一个编译程序仍需相当长的时间,工作也相当艰巨。因此,如何高效、高质量地生成一个编译程序一直是计算机系统设计人员追求的目标。,编译程序的任务是把源程序翻译成某台计算机上的目标程序,因此,开发人员首先要熟悉这种源程序语言,对源程序语言的语法和语义要有准确无误的理解。此外,开发人员还需确定编译程序的开发方案及方法,这是编译开发过程中最关键的一步,其作用是使编译程序具有易读性和易改性,以便将来对编译程序的功能进行更新和扩充。选择合适的语言编写编译程序也是非常重要的,语言选择不当会使开发出来的编译程序可靠性较差,难以维护且质量也无法保证。目前大部分编译程序都是用PASCAL、C和ADA这类高级语言编写的,不仅减少了开发的工作量,也缩短了开发周期。最后,开发人员对目标机要有深入的研究,这样才能充分利用目标机的硬件资源和特点,产生质量较高的目标程序。,1自编译 用某种高级语言书写自己的编译程序称为自编译。例如,假定A机器上已有一个PASCAL语言可以运行,则可以用PASCAL语言编写出一个功能更强的PASCAL语言编译程序,然后借助于原有的PASCAL编译程序对新编写的PASCAL编译程序进行编译,从而在编译后即得到一个能在A机器上运行的功能更强的PASCAL编译程序。,2交叉编译 交叉编译是指用A机器上的编译程序来产生可在B机器上运行的目标代码。例如,若A机器上已有C语言可以运行,则可用A机器中的C语言书写一个编译程序,它的源程序是C语言程序,而产生的目标程序则是基于B机器的,即能够在B机器上执行的低级语言程序。以上两种方法都假定已经有了一个系统程序设计语言可以使用,若没有可使用的系统程序设计语言,则可采用自展或移植的办法来开发编译程序。,3自展 自展的方法是:首先确定一个非常简单的核心语言L0,然后用机器语言或汇编语言书写出它的编译程序T0;再把语言L0扩充到L1,此时有L0 L1,并用L0编写L1的编译程序T1(即自编译);然后再把语言L1扩充为L2,此时有L1 L2,并用L1编写L2的编译程序T2;这样不断扩展下去,直到完成所要求的编译程序为止。,4移植 移植是指A机器上的某种高级语言的编译程序稍加改动后能够在B机器上运行。一个程序若能较容易地从A机器上搬到B机器上运行,则称该程序是可移植的,移植具有一定的局限性。用系统程序设计语言来书写编译程序虽然缩短了开发周期并提高了编译程序的质量,但实现的自动化程序不高。实现编译程序的最高境界是能够有一个自动生成编译程序的软件工具,只要把源程序的定义以及机器语言的描述输入到该软件中,就能自动生成这个语言的编译程序,如图16所示。,图16 编译程序自动生成示意,计算机科学家和软件工作者为了实现编译程序的自动生成进行了大量研究工作,随着形式语言学研究的发展和编译程序自动生成工作的进展,已经出现了一些编译程序的自动生成系统,如UNIX操作系统下的软件工具LEX和YACC等。,1.4 构造编译程序所应掌握的内容,要在某一台机器上为某种语言构造一个编译程序,必须掌握下述三方面的内容:(1)对被编译的源语言(如C、PASCAL等),要深刻理解其结构(语法)和含义。例如,下面的for循环语句:for(i=1;i=10+i;i+)x=x+1;,就存在对循环终值的理解问题:一种理解是以第一次进入for循环的i值计算出循环终值,此循环终值在循环中不再改变,也即循环终值为11;而另一种理解则是循环终值表达式10+i中的i值随循环在不断地改变,此时for语句将出现死循环。如TURBO PASCAL就是按第一种语义进行翻译的,而TURBO C则是按第二种语义翻译的。此外,如果出了循环后还要引用i值,那么这个i值究竟是循环终值还是循环终值加1?因此,对语义的不同理解可以得到不同的编译程序。,(2)必须对目标机器的硬件和指令系统有深刻的了解。例如,产生两个数相加的指令在8086/8088汇编中假定用下面两种指令实现:ADD AX,06或ADD BX,06 粗略看来,这两条加法指令除了寄存器不同外没有本质上的差别,其实不然。由于AX是累加器,因此,从机器指令的代码长度来说(见附录1),第一条指令比第二条指令节省一个字节。此外,从PC机硬件结构来看,,AX本身就是累加器且相加的结果也在累加器中,这就节省了传送的时间;而第二条指令则先要将BX中的值送到累加器中,相加后又要由累加器取出结果再送回寄存器BX中。显然,第二条指令要比第一条指令费时,因此,在可能的情况下,应尽量生成像第一条指令这样的目标代码。,(3)必须熟练掌握编译方法,编译方法掌握的如何将直接影响到编译程序的成败,一个好的编译方法可能得到事半功倍的效果。由于编译程序是一个极其复杂的系统,故在讨论中只好把它分解开来,一部分一部分地进行研究。在学习编译程序过程中,应注意前后联系,切忌用静止的、孤立的观点看待问题;作为一门技术课程,学习时还必须注意理论联系实际,多练习、多实践。,