1.1 编译器 VS 解释器
编译器和解释器是什么?有什么特点?(根据理解言之有理即可)
- 编译器将源程序编译成机器语言,执行机器语言程序速度更快。
- 解释器逐个语句地解释并执行源程序,因此效率低,但错误诊断效果更好。
1.1.1 编译器
读入以某种语言 (源语言) 编写的程序
输出等价的用另一种语言 (目标语言) 编写的程序
通常目标程序是可执行的
1.1.2 解释器
直接利用用户提供的输入,执行源程序中指定的操作
不生成目标程序,而是根据源程序的语义直接运行
Java语言的处理结合了编译和解释
编译器可以分为分析部分和综合部分
分析部分 (前端/Front end)
- 把源程序分解成单词元素,以及相应的语法结构
- 使用这个结构创建源程序的中间表示
- 同时收集和源程序相关的信息,存放到符号表
综合部分 (后端/Back end)
- 根据中间表示和符号表信息构造目标程序
1.2 编译过程
以 position = initial + rate * 60 为例,理解编译器结构和流程
阶段 | 输入 | 输出 | 描述体系 |
词法分析 | 源程序符号串 | 词法单元序列 | 正则表达式 |
语法分析 | 词法单元序列 | 语法分析树 | 上下文无关文法 |
1.2.1 词法分析(Lexical Analysis)/扫描(Scanning)
词法分析器读入源程序的字符流,将其组织成有意义的词素(Lexeme)序列,产生如下的词法单元作为输出:
<token-name, attribute-value>
1.2.2 语法分析(Syntax Analysis)/解析(Parsing)
分析语法结构,并使用各个词法单元的第一个分量来创建中间表示形式,如语法树(Syntax Tree)
树中的每个内部结点表示一个运算,而该结点的子结点表示该结点的分量
1.2.3 语义分析(Semantic Analysis)
使用语法树和符号表来检查源程序是否和语言定义一致
执行类型检查、自动类型转换等
1.2.4 中间代码生成
生成等价的低级或类机器语言的中间表示
该中间表示应易于生成,且容易译为目标机器上的语言
一般使用三地址代码作为中间表示形式
1.2.5 中间代码优化
对中间代码进行改进,以生成“更好”的目标代码。
编译器优化必须满足以下目标:
- 优化必须是正确的,不改变被编译程序的含义。
- 优化必须能够改善很多程序的性能。
- 优化所需的时间必须保持在合理的范围内。
- 所需要的工程方面的工作必须是可管理的
对中间代码进行改进,以生成“更好”的目标代码。
更快、更短、能耗更低
1.2.6 代码生成
将中间代码映射到目标语言指令。
需要合理分配寄存器以存放变量的值。
1.3 其他概念
- 符号表管理
记录源程序中使用的变量的名字,收集各种属性
- 趟 (Pass)
每趟读入一个输入文件,产生一个输出文件
“步骤” (Phase) 是逻辑组织方式
“趟”和具体的实现相关
- 编译器构造工具
扫描器 (Lex/Flex)、语法分析器 (Yacc/Bison)、语法制导的翻译引擎、…
- 出错管理
- 语法错误:不符合语法或词法规则的错误,通常在词法分析和语法分析时检测出来。 非法字符、括号不匹配、缺少
- 语义错误:不符合语义规则的错误,通常在语义分析时检测出来。 说明错误、作用域错误、类型不一致