编译器原理学习笔记 一

来源:互联网 发布:奇葩的网络名字 编辑:程序博客网 时间:2024/05/21 09:19

语言处理器

Created with Raphaël 2.1.0源程序预处理器经过预处理的源程序编译器目标汇编程序汇编器可重定位机器代码链接器/加载器目标机器代码
  • 编译器 (compiler) : 将源语言翻译成目标语言。重要任务是在翻译过程中发现源语言中存在的错误。相比于解释器,目标语言执行的速度快。
  • 解释器 (interpreter) : 利用用户的输入执行源程序中指定的操作。相比于编译器,错误诊断效果好,解释器是逐个语句执行。
  • 预处理器 (preprocessor) : 把源程序聚合在一起,把宏的缩写转换为源语言的语句
  • 汇编器 (assembler) : 将汇编语言程序处理后生成可重定位的机器代码
  • 链接器 (linker) : 解决外部内存地址问题。将多个可重定位的目标文件以及库文件链接到一起,形成真正在机器上运行的代码
  • 加载器 (loader) : 把所有的可执行目标文件放到内存中执行

一个编译器的结构

Created with Raphaël 2.1.0字符流词法分析器符号流语法分析语法树语义分析语法树中间代码生成器中间表示形式机器无关代码优化器中间表示形式代码生成器目标机器语言机器相关代码优化器目标机器语言

编译过程: 分析部分,综合部分

  • 分析部分 (front end) : 检查源程序的语法和语义,出现错误时提供有用的信息;创建中间表示符号表 (symbol table) 传递给综合部分
  • 综合部分 (back end) :根据中间表示和符号表来构建目标程序
    这里写图片描述

词法分析 (lexical analysis)

  • 词法分析器:将源程序的字符流组织成为有意义的词素 (lexeme) 序列。对于每个词素,词法分析器产生如下形式的词法单元 (token) 作为输出:
    <token-name, attribute-value>
    token-name: 语法分析步骤使用的抽象符号。
    attribute-value: 指向符号表中关于这个词法单元的条目。一个标识符的符号表条目存放该标识符有关的信息,例如名字和类型。

  • 举例说明:
    position = initial + rate * 60
    分析如下:

词素 词法单元 position <id,1> = <=> initaial <id,2> + <+> rate <id,3> * <*> 60 <60>

语法分析 (syntax analysis)

语法分析器:使用词法单元的第一个分量来创建树形的中间表示,也就是根据抽象符号 (标识符、运算符 …)来构建语法结构。一个常用的表示方法语法树 (syntax tree),树中的每个内部结点表示一个运算,该结点子结点表示运算的分量。

语法树

语义分析 (semantic analysis)

  • 语义分析器 (semantic analyzer): 使用语法树和符号表中的信息来检查是否和语言定义的语义一致,并将类型信息存放在语法树或符号表中。
  • 语义分析的一个重要部分是类型检查 (type checking)。编译器检查到数组下标是浮点数就会报错;或者检查到一个二元运算符应用于一个浮点数和一个整数,则会把整数转换为一个浮点数,也就是自动类型转换 (coercion)
    这里写图片描述

中间代码生成

  1. 在语法分析和语义分析完成之后,很多编译器会生成一个类机器语言的中间表示。我们可以把这个中间表示看作是某个抽象机器的程序。该中间表示具有两个重要性质:易于生成;能够被轻松地翻译为目标机器上的语言
  2. 三地址代码 (three-address code): 类似于汇编语言的指令组成,每个指令具有三个运算分量。三地址赋值指令右部最多只有一个运算符;编译器生成临时名字存放一个三地址指令计算得到的值;有些三地址指令的运算分量少于三个

代码优化

  1. 机器无关的代码优化步骤视图改进中间代码来生成更好的目标代码。”更好” 意味着更快, 更短,能耗更低。。。。的目标代码。
  2. 使用一个简单的中间代码生成算法,然后再进行代码优化步骤是生成优质目标代码的一个合理方法。

代码生成

  1. 代码生成器:将源程序的中间表示形式映射成目标语言。如果目标语言是机器代码,就必须为程序使用的每个变量选择寄存器或内存位置,然后中间指令被翻译成能够完成相同任务的机器指令序列。
  2. 代码生成的一个至关重要的方面是合理分配寄存器以存放变量的值。

符号表管理

  1. 符号表数据结构:为每个变量名字创建一个记录条目。变量名字:存储分配,类型,作用域等。过程名字:存储分配,类型,作用域,参数数量和类型,参数的传递方法,返回类型等等。。

将多个步骤组合成趟

  1. 前端趟:将词法分析,语法分析,语义分析,中间代码生成组合在一起
  2. 代码优化作为一个可选的趟。
  3. 后端趟:为特定目标机生成代码。
  4. 不同的前端趟和某个目标机的后端趟结合起来,可以为不同的源语言建立该目标机上的编译器;把一个前端趟和不同的目标机后端趟结合起来,建立针对不同目标机的编译器。

编译器构造工具

一些常用的编译器构造工具:
1. 语法分析器的生成器:可以根据一个程序设计语言的语法描述自动生成语法分析器。
2. 扫描器的生成器:可以根据一个语言的语法单元的正则表达式描述生成词法分析器。
3. 语法制导的翻译引擎:可以生成一组用于遍历分析数并生成中间代码的例程。
4. 代码生成器的生成器:依据一组关于如何把中间语言的每个运算翻译成为目标机上的机器语言的规则生成一个代码生成器。
5. 数据流分析引擎:可以帮助收集数据流信息,即程序中的值如何从程序的一个部分传递到另一个部分。数据流分析是代码优化的一个重要部分。
6. 编译器构造工具集:提供了可用于构造编译器的不同阶段的例程的完整集合。

程序设计语言的发展历程

第一台电子计算机出现在 20 世纪 40 年代。

走向高级程序设计语言

  • 第一步是 20 世纪 50 年代早期人们对助记汇编语言的开发。
  • 重大一步发生在 20 世纪 50 年代的后五年。设计高层次的表示方法,例如用于科学计算的 Fortran 语言,用于商业数据处理的 Cobol 语言和用于符号计算的 Lisp 语言被开发出来
  • 语言分类
    1. 根据语言的代:第一代是机器语言;第二代是汇编语言;第三代是Fortran,Cobol,Lisp,C,C++,C# 及 Java 这样的高级程序设计语言;第四代语言是为特定应用设计的语言,例如,用于生成报告的 NOMAD, 用于数据库查询的 SQL 和用于文本排版的 Postscript。第五代语言指的是基于逻辑和约束的语言,比如 Prolog 和 OPS5。
    2. 程序中指明如何完成一个计算任务的语言称为强制式 (imperative) 语言,例如C,C++,C# 和 Java;程序中指明要进行哪些计算的语言称为声明式 (declarative) 语言,例如 ML,Haskell,Prolog。
    3. 冯 · 诺依曼语言 (von Neumann language) 是指以冯 · 诺依曼计算机体系结构为计算模型的程序设计语言,例如 Fortran 和 C;面向对象语言 (object-oriented language) 是指支持面向对象编程的语言,面向对象编程是指用一组相互作用的对象组成程序,Simula 67 和 Smalltalk 是早期的主流面向对象语言, C++,C#,Java 和 Ruby 是现在常用的面向对象语言;脚本语言 (scripting language) 是指具有高层次运算符的解释型语言,通常用于把多个计算过程粘合在一起,例如 Awk,JavaScript,Perl,PHP,Python,Ruby 和 Tcl。

构造一个编译器的相关学科

  • 编译器优化必须满足:
    1. 优化必须是正确的,也就是说,不能改变被编译程序的含义。
    2. 优化必须能够改善很多程序的性能。
    3. 优化所需的时间必须保持在合理的范围内。
    4. 所需要的工程方面的工作必须是可管理的。
原创粉丝点击