编译原理-第一章 引论

1. 语言处理

一个编译器就是一个程序,它可以阅读某一种语言(源语言)编写的程序,并把该程序翻译成为一种等价的、用另一种语言(目标语言)编写的程序。

解释器(interpreter)是另一种语言处理器。它并不通过翻译的方式生成目标程序。解释器直接利用用户提供的输入执行源程序中指定的操作。

预处理器把那些称为宏的缩写形式转换为源语言的语句。将预处理的源程序作为输入传递给一个编译器。编译器可能产生一个汇编语言程序作为输出。这个汇编语言程序由称为汇编器的程序进行处理,并生成可重定位的机器代码。可重定位的机器代码和其他可重定位的目标文件以及库文件通过链接器连接到一起,形成真正在机器上运行的代码。加载器把所有的可执行目标文件放到内存中执行。

2. 一个编译器的结构

编译器有两个部分组成:分析部分和综合部分。分析部分(analysis)会把源程序分解为多个组成要素,生成一个中间表示和符号表(symbol table)并传送给综合部分。分析部分会检查源程序的语法结构和语义,出现错误后提供有用信息进行改正。综合部分(synthesis)根据中间表示和符号表中的信息来构造用户期待的目标程序。分析部分被称为编译器的前端(front end),综合部分被称为后端(back end)。

如下图所示,整个编译过程执行了一组步骤(phase)。每个步骤把源程序的一种表示方式转换成另一种表示方式,符号表可由编译器的各个步骤使用。

2.1 词法分析

编译器的第一个步骤被称为词法分析(lexical analysis)或扫描(scanning)。词法分析器读取组成源程序的字符流,并且将它们组成为有意义的词素的序列。对于每个词素,词法分析器产生如下形式的词法单元作为输出:<token-name, attribute-value>。第一个分量token-name是一个由语法分析步骤使用的抽象符号,第二个分量attribute-value指向符号表中关于这个词法单元的条目。

 

2.2 语法分析

编译器的第2个步骤被称为语法分析(syntax analysis)或解析(parsing)。语法分析器使用词法单元的一个分量来创建语法树(syntax tree)的中间表示。语法树的每个内部结点表示一个运算,而该结点的字子结点表示该运算的分量。

2.3 语义分析

语义分析器(semantic analyzer)使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。它同时也收集类型信息,并把这些类型信息存放在语法树或符号表中。语义分析的一个重要部分是类型检查(type checking),检查每个运算符是否具有匹配的运算分量。程序设计语言可能允许某些类型转换,这被称为自动类型转换coercion。

2.4 中间代码生成

一个编译器可能构造出一个或多个中间表示。语法树是其中一种表示形式。语法分析和语义分析完成后,很多编译器生成一个明确的低级的或类机器语言的中间表示,该中间表示有两个重要性质:它应该易于生成,且能够被轻松的翻译为目标机器上的语言。有一种被称为三地址代码(three-address code)的中间表示形式。这种中间表示由一组类似汇编语言的指令组成,每个指令具有三个运算分量。三地址代码右部最多只有一个运算符,编译器应该生成一个临时名字存放计算得到的值,有些指令的运算分量少于三个。

2.5 代码优化

机器无关的代码优化步骤试图改进中间代码,以便生成更好的目标代码。“更好”通常意味着更快,但是也有可能会有其他目标,如更短或能耗更低的目标代码。

2.6 代码生成

代码生成器以源程序的中间表示形式作为输入,并把它映射到目标语言。如果目标语言是机器代码,那么就必须为程序使用的每个变量选择寄存器或内存位置。代码生成的一个至关重要的方面是合理分配寄存器以存放变量的值。编译器在中间代码生成或代码生成阶段做出有关存储分配的决定。

2.7 符号表管理

符号表数据结构为每个变量名字创建了一个记录条目。记录的字段就是名字的各个属性。这些属性可以提供一个名字的存储分配、类型、作用域等信息。对于过程名字,还包括:参数数量和类型、参数的传递方法以及返回类型。

2.8 将多个步骤组合成趟

多个步骤的活动可以被组合成一趟(pass)。前端步骤的词法分析、语法分析、语义分析,以及中间代码生成可以被组合在一起成为一趟。代码优化可以作为一个可选的趟。然后可以有一个为特定目标机生成代码的后端趟。

2.9 编译器构造工具

一些常用的的编译器构造工具包括:

1)语法分析器生成器

2)扫描器生成器

3)语法制导的翻译引擎

4)代码生成器的生成器

5)数据流分析引擎

6)编译器构造工具集

3. 程序设计语言的发展历程

20世纪50年代早期助记汇编语言的开发。20世纪50年度后五年开始走向高级程序设计语言,Fortran语言、Cobol语言、Lisp语言。第一代语言是机器语言,第二代语言是汇编语言,第三代语言是C、C++这样的高级程序设计语言,第四代语言是为特定应用设计的语言,第五代语言指的是基于逻辑和约束的语言。面向对象编程是指用一组相互作用的对象组成程序的编程风格。

4. 构建一个编译器的相关科学

如何使用抽象方法来解决问题:接受一个问题,写出抓住了问题的关键特性的数学抽象表示,并用数学技术来解决它。

4.1 编译器设计和实现中的建模

有穷状态的自动机描述程序的词法单位。上下文无关文法描述程序设计语言的语法结构。树形结构是表示程序结构以及程序到目标代码的翻译方法的重要模型。

4.2 代码优化的科学

编译器优化必须满足下面的设计目标:

1. 优化必须是正确的,也就是说,不能改变被编译程序的含义。

2. 优化必须能够改善很多程序的性能。

3. 优化所需的时间必须保持在合理的范围内。

4. 所需的工程方面的工作必须是可管理的。

5. 编译技术的应用

5.1 高级程序设计语言的出现

高级程序设计语言编程比较容易,但是比较低效。低级程序设计语言可以写出更加高效的代码,但是比较难编写而且移植性较差、容易出错、难以维护。

面向对象的主要思想是:数据抽象和特性的继承。

5.2 针对计算机体系结构的优化

几乎所有的高性能系统都利用了两种技术:并行(parallelism)和内存层次结构(memory hierarchy)。所有的现代微处理器都采用了指令级并行性。程序员可以为多处理器编写多线程代码,可以通过编译器从顺序程序自动生成并行代码。一个内存层次结构由几层具有不同速度和大小的存储器组成。离处理器最近的层速度最快但是容量最小。

5.3 新计算机体系结构的设计

 在计算机体系结构设计的早期,编译器是在机器建造好之后开发的。在现代计算机体系结构的开发中,编译器在处理器设计阶段就进行开发,然后编译得到的代码并运行于模拟器上。

5.4 程序翻译

我们通常把编译看作是从一个高级语言到机器语言的翻译过程。编译技术也可以应用到不同种类语言之间的翻译。

二进制翻译:编译器技术可以用于把一个机器的二进制代码翻译成另一个机器的二进制代码。

硬件合成:不仅仅大部分软件是用高级语言描述的,连大部分硬件设计也是使用高级硬件描述语言描述的,这些语言有Verilog和VHDL。

数据查询解释:除了描述软件和硬件,语言在很多应用中都是有用的。比如查询语言被用来搜索数据库。

编译然后模拟。

5.5 软件生产率工具

通过数据流分析技术静态地(即在程序运行之前)定位错误。

类型检查是一种有效的,且被充分研究的技术,它可以被用于捕捉程序中的不一致性。

边界检查。

内存管理工具。

6. 程序设计语言基础

6.1 静态和动态的区别

如果一个语言使用的策略支持编译器静态决定某个问题,那么我们说这个语言使用了一个静态(static)策略,或者说这个问题可以在编译时刻(compile time)决定。另一方面,一个只允许在运行程序的时候做出决定的策略被称为动态策略(dynamic policy),或者被认为需要在运行时刻(run time)做出决定。

如果仅通过阅读程序就可以确定一个声明的作用域,那么这个语言使用的是静态作用域(static scope),或者说词法作用域lexical scope。否则,这样语言使用的是动态作用域dynamic scope。

6.2 环境与状态

名字和内存(存储)位置的关联,及之后和值的关联可以用两个映射来描述。这两个映射随着程序的运行而改变。

1)环境(environment)是一个从名字到存储位置的映射。

2)状态(state)是一个从内存位置到它们值的映射。

 

6.3 静态作用域与块结构

6.4 显示访问控制

6.5 动态作用域

6.6 参数传递机制

6.7 别名

posted @ 2025-03-30 17:37  明er  阅读(255)  评论(0)    收藏  举报