少女祈祷中...

第一章 引论

什么是编译器?

:一个程序,读入以某一种语言(源语言)编写的程序,翻译为等价的,用另一种语言(目标语言)编写的程序

编译器:源程序-编译器-目标程序

编译器vs解释器:是否需要在某种虚拟机中运行,是否一行一行处理

编译器优点:

  • 效率高,一次编译多次运行
  • 通常目标程序是可执行的

Java:结合了编译器和解释器,使用Java虚拟机,而不是生成可执行文件,只要安装了JRE(Java运行时环境)就可以在不同平台上运行

C语言的编译:
预处理器(加了井号的东西,如#define)-编译器-汇编器-链接器-加载器

编译器的结构

  • 分析部分(Analysis):编译器前端,搜集源程序相关信息,放入符号表,定位错误信息(语法语义等),是与机器无关的部分
  • 综合部分(Synthesis):编译器后端,根据符号表和中间表示构造目标程序,与机器相关的部分

每个步骤把源程序的一种表述方式转换成另一种表示方式

符号表:

记录源程序中使用的变量的名字,收集各种属性,包括:

  • 名字的存储分配
  • 类型
  • 作用域
  • 过程名字的参数数量、参数类型等

可由编译器的各个步骤使用

词法分析:

读入字符流,输出有意义的词素(lexeme),产生词法单元

词法单元:<token-name,attribute-value>

  • token-name由语法分析步骤使用
  • attribute-value指向相应的符号表条目

例如:position=initial+rate*60

1
<id,1><=,><id,2><+,><id,3><*,><number,4>

语法分析

需要得到词素序列的语法结构

语法分析/解析:根据词法单元的第一个分量来创建树形中间表示形式,通常是语法树

指出词法单元流的语法结构

语义分析

得到语义,对于编译器来说比较难

使用语法树和符号表中的信息,检查源程序是否满足语言定义的语义约束

中间代码生成

根据语义分析的输出,生成类机器语言的中间表示(可以进行中间代码优化)

代码优化

通过对中间代码的分析,改进中间代码,得到更好的目标代码

代码生成

把中间表示形式映射到目标语言

编译器的趟(Pass)

以文件为输入输出单位的编译过程的个数,每趟可由一个或若干个步骤构成(要将源程序文件读入多少次)

程序设计语言

第一代:机器语言;第二代:汇编语言;第三代:高级语言;第四代:特定应用语言;第五代:基于逻辑和约束的语言

命令式语言:指明如何完成;声明式语言:指明要完成哪些计算

基础概念

1、静态/动态

  • 静态:不需要运行程序,只需要在编译时就可以获得状态(编译时就可以确定变量的数据类型,例如Java,C++)
  • 动态:需要运行这个程序才可以获得的状态(变量的类型在运行时确定,例如Python,JavaScript)

例如:Java类声明中的static指明了变量的位置可静态确定

2、作用域
变量有效的范围

  • 静态作用域:大部分都是静态作用域,通常可以根据源代码直接看出来它的作用域(块作用域)
  • 动态作用域:需要运行时才可以确定,取决于调用的函数或过程,已经被淘汰

3、参数传递机制
值传递:对实在参数求值/拷贝,再存放到被调用过程的形参的内存位置上

引用调用:实际传递的是实在参数的地址

名调用:基本废弃

4、别名
两个指针指向同一个位置的情况