2.2.2 编译程序基本原理

2025-06-07 18:39:05 更新

(一)编译过程

编译程序作用:把某高级语言的源程序翻译成与之等价的目标程序(汇编语言或机器语言形式)。

工作过程一般分为6个阶段(实际可能会将某些阶段合并处理)。


阶段

说明

备注

1

词法分析

源程序结构分析。对源程序从前到后(从左到右)逐字符扫描,识别出"单词”符号(基本语法单位)。如关键字(保留字)、标识符、常数、运算符和分隔符(如标点符号、左右括号)等。并以二元组方式输出,即类别和自身值。

int a,b,c; => int id1,id2,id3;(a、b、c类别是id用户标识符)

a:=b+c*2; => id1:=id2+id3*2;

源程序结构分析


2

语法分析

在词法分析基础上,根据语法规则将单词符号序列分解成各类语法单位,如“表达式”、“语句"、“程序"等。

语法错误Syntax Error:缺少分号、括号不匹配、关键字拼写错误、变量未声明、错误的缩进、遗漏括号引号、保留字冲突等

无语法错误→构造语法树

有语法错误→指出语法错误

3

语义分析

分析各语法结构含义,检查源程序是否包含静态语义错误,并收集类型信息供代码生成阶段使用。只有语法和语义都正确,才能翻译成正确的目标代码。

语义分析主要工作是类型分析和检查:类型载体和类型运算

如整除取余运算符只能针对整型数据(浮点数则报错)


语言的语义规则

4

中间代码生成

源代码与目标代码逻辑结构差别很大,翻译一次到位很困难。

根据语义分析的输出生成中间代码(特点与具体机器无关),提高编译程序的可移植性。

常用中间代码为采用四元式的三地址码。

(运算符,运算对象1,运算对象2,运算结果)

5

代码优化

默认生成的中间代码(机械、按固定模式)在时间和空间方面效率较差,必须进行优化。

优化过程可以在中间代码生成阶段进行,也可以在目标代码生成阶段进行。

中间代码不依赖于具体机器,优化一般建立在对程序的控制流和数据流分析的基础上,与具体机器无关。


6

目标代码生成

编译器工作的最后阶段。

任务:把中间代码变换成特定机器上的绝对指令代码、可重定位的指令代码或汇编指令代码,与具体的机器密切相关。


7

符号表管理

符号表作用:记录源程序中各符号的必要信息,以辅助语义的正确性检查和代码生成。

在编译过程中需对符号表进行快速有效地查找、插入、修改和删除等操作。

符号表建立可以始于词法分析阶段,也可以放到语法分析和语义分析阶段,但符号表的使用有时会延续到目标代码的运行阶段。


8

出错处理

源程序错误分为:静态错误和动态错误。

1)动态错误:称动态语义错误,发生在程序运行时,例如变量取零时作除数、引用数组元素下标错误等。

2)静态错误:编译阶段发现的程序错误

语法错误:单词拼写错误、标点符号错误、表达式中缺少操作数、括号不匹配等;

静态语义错误:语义分析时发现的运算符与运算对象类型不合法等错误。

在编译时发现错误后,编译程序应采用适当策略修复,使得分析过程能够继续下去,以便在一次编译过程中尽可能多地找出程序中的错误。


(二)编译器按逻辑分段

前端(与机器无关)

中间代码

后端(与机器有关)

从词法分析到中间代码

中间代码优化和目标代码的生成及优化

各种程序语言开发各自的编译器前端

针对指令系统和体系结构都不同的各种处理器开发相应的后端

各种语言在各种处理器上的编译器

语言有改动,修改编译器前端部分

处理器有改变,替换该语言编译器后端

(三)文法和语言形式描述

在编译中,文法是对语言结构的一种形式化描述,用于定义和生成一种语言的所有合法句子,是编译程序进行语法分析的基础。

1)基本概念

(1)终结符:是文法中不可再分的基本符号,通常对应于语言中的单词,如关键字、标识符、常量、运算符等。相当于单词,如“我”“你”“他”“吃”“苹果”“香蕉”等。

(2)非终结符:是可以由其他符号(终结符或非终结符)推导出的符号,用于表示语言中的语法结构或语法范畴,如表达式、语句、程序块等。可以是一些具有语法意义的成分,如“主语”“谓语”“宾语”等。

(3)产生式:是文法的核心组成部分,用于描述如何从一个或多个符号推导出另一个符号。如“句子→主语谓语宾语”“主语→我”“主语→你”“谓语→吃”“宾语→苹果”“宾语→香蕉”等。按照这些规则,可以生成“我吃苹果”“你吃香蕉”等句子,也可以判断“苹果吃我”的表述是不符合该文法规则的。

2)作用

(1)语法定义:精确描述了一种编程语言的语法规则,明确规定了什么样的字符序列是该语言的合法程序,为编译器提供了判断输入程序是否符合语法的依据。

(2)句子生成:可以根据文法的产生式规则,从起始符号开始,通过一系列的推导步骤生成该语言的所有句子,这有助于理解语言的结构和构造方式。

(3)语法分析基础:是编译程序中语法分析器的输入,语法分析器根据文法规则来分析源程序的语法结构,构建语法树,为后续的语义分析和代码生成等阶段提供基础。

3)分类

0型文法:无限制文法。

对产生式的限制最少,组合非常自由,只要左边至少有一个表示某种概念的卡片(非终结符),就可以按照一定的规则生成新的句子,类似于用不同的词语自由组合成有意义的句子。

1型文法:上下文有关文法。与上下文相关,就像游戏中角色的动作取决于其当前的状态和所拥有的道具,即只有在满足一定的上下文条件时,才能根据规则进行推导。

2型文法:上下文无关文法。 不依赖于上下文,只根据产生式规则进行替换。以文本生成为例,可以调整文法规则和参数,生成不同风格和主题的故事。再如消除单词和短语在特定语境中的语义,从而消除歧义。

3型文法:正规文法,是上下文无关文法的特殊形式。形式非常规则,就像自动售货机的投币规则一样严格,每个非终结符只能推出一个终结符加上一个非终结符或者只推出一个终结符,具有很强的确定性和规律性。如手机号码验证和身份证号码验证。

举例:设非终结符S表示电话号码,终结符为0到9的数字,其文法产生式可以写成:S→1A,A→3B|4B|5B|6B|7B|8B|9B,B→0C|1C|2C|3C|4C|5C|6C|7C|8C|9C,C→0D|1D|2D|3D|4D|5D|6D|7D|8D|9D,...H→0I|1I|2I|3I|4I|5I|6I|7I|8I|9I,I→0|1|2|3|4|5|6|7|8|9 。

(四)正规式

也叫正则表达式,是表示正规集的数学工具,是说明单词的模式的一种表示法,常用于在一个文件或字符里进行格式匹配。正则工作时以行为单位,一次处理一行。

(五)中间代码形式

1)后缀式(逆波兰式)

波兰逻辑学家卢卡西维奇发明的一种表示表达式的方法。

把运算符写在运算对象后面,如把 a+b写成 ab+。

优点:根据运算对象和算符出现次序进行计算,不需要使用括号,便于用栈实现求值。

对于表达式x:=(a+b)*(c+d),其后缀式为xab+cd+*:=

2)树形表示

表达式x:=(a+b)*(c+d)的树形表示

3)四元式

示例if x<y then while a<b do a:=a+b翻译成四元式

(六)代码生成主要问题


形式

说明

1

中间代码形式

中间代码有多种形式,其中树与后缀表示形式适用于解释器,而编译器多采用与机器指令格式较接近的四元式形式。

2

目标代码形式

目标代码分为两大类:

①汇编语言形式。

汇编语言作为中间输出形式,便于分析和测试。

②机器指令形式。

目标代码又可根据需求不同分为绝对机器指令代码和可再定位机器代码。

绝对机器代码优点:编译后立即执行,不形成保存在外存上的目标代码文件。

可再定位机器代码优点是目标代码可以被任意链接并装入内存的任意位置,是编译器采用较多的代码形式。

3

寄存器分配

访问寄存器速度远快于访问内存单元速度,应尽可能多地使用寄存器存储数据,而寄存器个数有限,需重点考虑分配及使用寄存器。

4

计算次序选择

代码执行效率会随计算次序的不同有较大差别。

在生成正确目标代码的前提下,适当地安排计算次序并优化代码序列。