编译原理-引言


编译原理-引言

大概是在开始学习编写程序的时候购入了一系列的计算机基础书籍,由于自己的原因导致很多书都只是寥寥翻开几页,就匆匆放下了.
近来这两年,随着年纪的增大忽然有了一个念头就是自己的程序生涯已经快要结束,但是还有那么多书未看未读,有一些惋惜和不舍.不舍的既有对知识的向往也有对年轻的奢望,惋惜的是荒废了大好年华.不如把既有的书籍看完,也是完成当初对自己的期待和结束吧.

碎碎念了很久,让我们接下来开始吧,笔记按照书籍的章节进行记录

第一章

程序设计语言是向人以及计算机描述计算过程的记号

这是这本书的第一句话,我觉得很好.程序/代码是由人编写给人阅读,拿给机器进行执行的,因此在编写的时候既要考虑到程序的可阅读性也要考虑到机器执行的效率.
但是机器是看不懂人类编写的语言,就需要一个’翻译家’将我们需要的计算过程转义后告诉计算机进行执行,这个’翻译家’就是我们的编译器
研究这些编译原理,也许究其一生我们也不会使用到一次相关的知识,但是可以学习前人在处理复杂问题时候的解决思路,没有灵活的思维就只能通过经验来模仿大师的行为

语言处理器

编译器泛指语言处理器,通常由两部分组成编译器解释器

  1. 编译器
    编译器指的是将某一种语言翻译成为行为相同的另外一种语言(目标语言)

  2. 解释器
    解释器指的是直接执行输入过来的语言

    java语言的处理器就融合了这两个语言处理器,向通过编译器将源代码编译成为中间语言代码,在通过JVM解释执行中间语言代码

  • 编译器结构
    1. 分析部分(analysis)

      分析部分又被称为前端,指的是将源程序分解为多个组成要素,并在这些要素根据语法结构来创建出一个’中间输出’,提供给下一阶段作为输入,并且生成’符号表’

      以上是书上对前端编译器的定义,目前认为前端编译器就是执行语法规则/约束来将源代码翻译成为’中间代码’

    2. 综合部分(synthesis)

      综合部分是根据前端输入的中间代码和符号表来构造用户期望的目标代码

      对于这个的理解是从中间代码转换为目标代码的过程,例如生成目标代码为java的某A语言以及A-j的中间代码,最后才能生成java语言
      前端编译器是与机器无关的,后端编译器是与机器相关的

编译器的步骤

编译器执行的步骤大致分为七个步骤,置顶向下分别是

  1. 词法分析器
  2. 语法分析器
  3. 语义分析器
  4. 中间代码生成器
  5. 机器无关代码优化器
  6. 代码生成器
  7. 机器相关代码优化器

下图所示:
编译器步骤图

下面就对这7个步骤进行分析

1.词法分析器

词法分析器指的是将源代码的词素(lexeme)转义成为由词法单元(token)组成的词法单元序列

这里涉及到两个知识点:
以java代码为示例

String name = "hello";
  1. 词素(lexeme)
    词素(lexeme)在语言领域等同与词汇,在这里指的是组成源代码的单个符号.
    示例的源代码中的词素为’String’、‘name’、‘=’、‘"’、‘hello’、‘"’

  2. 词法单元
    词法单元指的是编译器对词素的抽象承载对象,通过两部分组成<token-name,attribute-value>
    token-name:语法分析步骤中使用到的抽象符号
    attribute-value:指向符号表中关于这个词法单元的条目(可选)

  3. 符号表
    符号表指的是用于记录源代码程序中使用到的变量名字,用于存储各种属性

通过步骤1语法分析器可以将源代码转换成为词法单元序列,后续的操作是建立在词法单元序列的基础上的

2.语法分析

编译器的第二个步骤是语法分析解析.语法分析器使用上一步词法分析器的输出词法单元序列作为输入,通过使用词法单元来构建语法树结构。
语法树结构是由树中的每一个内部节点表示一个运算组成,叶子节点表示该运算的分量 ,如下图所示中的第二个步骤,通过这个步骤将将’操作’和’分量’分离,以便下一步语义分析器使用

编译器工作示例

3. 语义分析器

语义分析器是根据语法树符号表中的信息来检查输入的源代码是否符合语言的定义,同时收集类型信息存放到语法树和符号表中,以便在随后生成中间代码的过程中进行使用

在语义分析的过程中主要是做两方面的事情:
第一: 根据语言语义和符号表对语法树中的节点进行分析语义的正确性
第二:进行类型检查和自动类型转换

4. 中间代码的生成

通过以上三个步骤(词法分析/语法分析/语义分析)得到正确的语法树,通过这个语法树生成需要的中间代码
中间代码指的是是一种易于生成并且可以与目标代码进行转换的一种语言,生成一种伪指令的代码表述

5. 代码优化

这一步进行对中间代码的一个与机器无关的优化,由于在上一步中生成中间代码是完全按照源代码的逻辑,因此可以按照逻辑规则进行一些优化处理,由于是对逻辑的优化因此是与机器无关的

6. 代码生成

代码生成是根据上一步中优化后的中间代码作为输入,然后根据不同的计算平台来生成操作具体的寄存器/内存地址的机器代码

编译器处理过程小结

编译器处理过程的过程划分为以上6个步骤(词法/语法/语义/中间代码生成/代码优化/机器代码生成)这几个步骤,在实现时可以将这几个步骤合并成为“一趟”

程序设计语言的历史

我很喜欢了解这种技术的发展过程,虽然这段历史离我们很遥远,但是在阅读的过程中好像在历史的长流中一样,按照时间顺序

  • 机器指令

  • 汇编语言

    • 宏指令
  • 高级程序语言

    • lisp
    • C/C++
    • JAVA
  • 特定应用程序设计语言

    • SQL
  • 基于逻辑和约束的语言

    • prolog
    • ops5

语言的发展变化也在一定程度上到了编译器的方向,编译器的演化也会影响到语言的发展,两者是相辅相成的。

编译器也会对机器指令集的发展产生影响,例如编译器更喜欢RISC(精简指令集)因为RISC上的可以做更好的指令优化

参考资料

编译原理讲义-南京大学


  TOC