【编译器】电子书 - 自制编译器-后端电子书论坛-IT电子书-IT面试吧

【编译器】电子书 - 自制编译器

该帖子部分内容已隐藏
付费阅读
金币 3
此内容为付费阅读,请付费后查看

书籍封面

书籍目录

封面

书名

版权

前言

目录

第1章 开始制作编译器 

1.1 本书的概要 

本书的主题 

本书制作的编译器 

编译示例 

可执行文件 

编译 

程序运行环境 

1.2 编译过程 

编译的4 个阶段 

语法分析 

语义分析 

生成中间代码 

代码生成 

优化 

总结 

1.3 使用CЬ编译器进行编译 

CЬ编译器的必要环境 

安装CЬ编译器 

CЬ的Hello, World! 

第2章 CЬ和cbc 

2.1 CЬ语言的概要 

CЬ的Hello, World ! 

CЬ中删减的功能 

import 关键字 

导入文件的规范 

2.2 CЬ编译器cbc 的构成 

cbc 的代码树 

cbc 的包 

compiler 包中的类群 

main 函数的实现 

commandMain 函数的实现 

Java5 泛型 

build 函数的实现 

Java 5 的foreach 语句 

compile 函数的实现 

第1 部分 代码分析

第3章 语法分析的概要 

3.1 语法分析的方法 

代码分析中的问题点 

代码分析的一般规律 

词法分析、语法分析、语义分析 

扫描器的动作 

单词的种类和语义值 

token 

抽象语法树和节点 

3.2 解析器生成器 

什么是解析器生成器 

解析器生成器的种类 

解析器生成器的选择 

3.3 JavaCC 的概要 

什么是JavaCC 

语法描述文件 

语法描述文件的例子 

运行JavaCC 

启动JavaCC 所生成的解析器 

中文的处理 

第4章 词法分析 

4.1 基于JavaCC 的扫描器的描述 

本章的目的 

JavaCC 的正则表达式 

固定字符串 

连接 

字符组 

排除型字符组 

重复1 次或多次 

重复0 次或多次 

重复n 次到m 次 

正好重复n 次 

可以省略 

选择 

4.2 扫描没有结构的单词 

TOKEN 命令 

扫描标识符和保留字 

选择匹配规则 

扫描数值 

4.3 扫描不生成token 的单词 

SKIP 命令和SPECIAL_TOKEN 命令 

跳过空白符 

跳过行注释 

4.4 扫描具有结构的单词 

最长匹配原则和它的问题 

基于状态迁移的扫描 

MORE 命令 

跳过块注释 

扫描字符串字面量 

扫描字符字面量 

第5章 基于JavaCC 的解析器的描述 

5.1 基于EBNF 语法的描述 

本章的目的 

基于JavaCC 的语法描述 

终端符和非终端符 

JavaCC 的EBNF 表示法 

连接 

重复0 次或多次 

重复1 次或多次 

选择 

可以省略 

5.2 语法的二义性和token 的超前扫描 

语法的二义性 

JavaCC 的局限性 

提取左侧共通部分 

token 的超前扫描 

可以省略的规则和冲突 

重复和冲突 

更灵活的超前扫描 

超前扫描的相关注意事项 

第6章 语法分析 

6.1 定义的分析 

表示程序整体的符号 

语法的单位 

import 声明的语法 

各类定义的语法 

变量定义的语法 

函数定义的语法 

结构体定义和联合体定义的语法 

结构体成员和联合体成员的语法 

typedef 语句的语法 

类型的语法 

C 语言和CЬ在变量定义上的区别 

基本类型的语法 

6.2 语句的分析 

语句的语法 

if 语句的语法 

省略if 语句和大括号 

while 语句的语法 

for 语句的语法 

各类跳转语句的语法 

6.3 表达式的分析 

表达式的整体结构 

expr 的规则 

条件表达式 

二元运算符 

6.4 项的分析 

项的规则 

前置运算符的规则 

后置运算符的规则 

字面量的规则 

第2 部分 抽象语法树和中间代码

第7章 JavaCC 的action 和抽象语法树 

7.1 JavaCC 的action 

本章的目的 

简单的action 

执行action 的时间点 

返回语义值的action 

获取终端符号的语义值 

Token 类的属性 

获取非终端符号的语义值 

语法树的结构 

选择和action 

重复和action 

本节总结 

7.2 抽象语法树和节点 

Node 类群 

Node 类的定义 

抽象语法树的表示 

基于节点表示表达式的例子 

第8章 抽象语法树的生成 

8.1 表达式的抽象语法树 

字面量的抽象语法树 

类型的表示 

为什么需要TypeRef 类 

一元运算的抽象语法树 

二元运算的抽象语法树 

条件表达式的抽象语法树 

赋值表达式的抽象语法树 

8.2 语句的抽象语法树 

if 语句的抽象语法树 

while 语句的抽象语法树 

程序块的抽象语法树 

8.3 声明的抽象语法树 

变量声明列表的抽象语法树 

函数定义的抽象语法树 

表示声明列表的抽象语法树 

表示程序整体的抽象语法树 

外部符号的import 

总结 

8.4 cbc 的解析器的启动 

Parser 对象的生成 

文件的解析 

解析器的启动 

第9章 语义分析(1)引用的消解 

9.1 语义分析的概要 

本章目的 

抽象语法树的遍历 

不使用Visitor 模式的抽象语法树的处理 

基于Visitor 模式的抽象语法树的处理 

Vistor 模式的一般化 

cbc 中Visitor 模式的实现 

语义分析相关的cbc 的类 

9.2 变量引用的消解 

问题概要 

实现的概要 

Scope 树的结构 

LocalResolver 类的属性 

LocalResolver 类的启动 

变量定义的添加 

函数定义的处理 

pushScope 方法 

currentScope 方法 

popScope 方法 

添加临时作用域 

建立VariableNode 和变量定义的关联 

从作用域树取得变量定义 

9.3 类型名称的消解 

问题概要 

实现的概要 

TypeResolver 类的属性 

TypeResolver 类的启动 

类型的声明 

类型和抽象语法树的遍历 

变量定义的类型消解 

函数定义的类型消解 

第10章 语义分析(2)静态类型检查 

10.1 类型定义的检查 

问题概要 

实现的概要 

检测有向图中的闭环的算法 

结构体、联合体的循环定义检查 

10.2 表达式的有效性检查 

问题概要 

实现的概要 

DereferenceChecker 类的启动 

SemanticError 异常的捕获 

非指针类型取值操作的检查 

获取非左值表达式地址的检查 

隐式的指针生成 

10.3 静态类型检查 

问题概要 

实现的概要 

CЬ中操作数的类型 

隐式类型转换 

TyperChecker 类的启动 

二元运算符的类型检查 

隐式类型转换的实现 

第11章 中间代码的转换 

11.1 cbc 的中间代码 

组成中间代码的类 

中间代码节点类的属性 

中间代码的运算符和类型 

各类中间代码 

中间代码的意义 

11.2 IRGenerator 类的概要 

抽象语法树的遍历和返回值 

IRGenerator 类的启动 

函数本体的转换 

作为语句的表达式的判别 

11.3 流程控制语句的转换 

if 语句的转换(1 )概要 

if 语句的转换(2 )没有else 部分的情况 

if 语句的转换(3 )存在else 部分的情况 

while 语句的转换 

break 语句的转换(1 )问题的定义 

break 语句的转换(2 )实现的方针 

break 语句的转换(3 )实现 

11.4 没有副作用的表达式的转换 

UnaryOpNode 对象的转换 

BinaryOpNode 对象的转换 

指针加减运算的转换 

11.5 左值的转换 

左边和右边 

左值和右值 

cbc 中左值的表现 

结构体成员的偏移 

成员引用(expr.memb)的转换 

左值转换的例外:数组和函数 

成员引用的表达式(ptr-]memb)的转换 

11.6 存在副作用的表达式的转换 

表达式的副作用 

有副作用的表达式的转换方针 

简单赋值表达式的转换(1 )语句 

临时变量的引入 

简单赋值表达式的转换(2 )表达式 

后置自增的转换 

第3 部分 汇编代码

第12章 x86 架构的概要 

12.1 计算机的系统结构 

CPU 和存储器 

寄存器 

地址 

物理地址和虚拟地址 

各类设备 

缓存 

12.2 x86 系列CPU 的历史 

x86 系列CPU 

32 位CPU 

指令集 

IA-32 的变迁 

IA-32 的64 位扩展——AMD64 

12.3 IA-32 的概要 

IA-32 的寄存器 

通用寄存器 

机器栈 

机器栈的操作 

机器栈的用途 

栈帧 

指令指针 

标志寄存器 

12.4 数据的表现形式和格式 

无符号整数的表现形式 

有符号整数的表现形式 

负整数的表现形式和二进制补码 

字节序 

对齐 

结构体的表现形式 

第13章 x86 汇编器编程 

13.1 基于GNU 汇编器的编程 

GNU 汇编器 

汇编语言的Hello, World! 

基于GNU 汇编器的汇编代码 

13.2 GNU 汇编器的语法 

汇编版的Hello, World! 

指令 

汇编伪操作 

标签 

注释 

助记符后缀 

各种各样的操作数 

间接内存引用 

x86 指令集的概要 

13.3 传输指令 

mov 指令 

push 指令和pop 指令 

lea 指令 

movsx 指令和movzx 指令 

符号扩展和零扩展 

13.4 算术运算指令 

add 指令 

进位标志 

sub 指令 

imul 指令 

idiv 指令和div 指令 

inc 指令 

dec 指令 

neg 指令 

13.5 位运算指令 

and 指令 

or 指令 

xor 指令 

not 指令 

sal 指令 

sar 指令 

shr 指令 

13.6 流程的控制 

jmp 指令 

条件跳转指令(jz、jnz、je、jne、……) 

cmp 指令 

test 指令 

标志位获取指令(SETcc) 

call 指令 

ret 指令 

第14章 函数和变量 

14.1 程序调用约定 

什么是程序调用约定 

Linux/x86 下的程序调用约定 

14.2 Linux/x86 下的函数调用 

到函数调用完成为止 

到函数开始执行为止 

到返回原处理流程为止 

到清理操作完成为止 

函数调用总结 

14.3 Linux/x86 下函数调用的细节 

寄存器的保存和复原 

caller-save 寄存器和callee-save 寄存器 

caller-save 寄存器和callee-save 寄存器的灵活应用 

大数值和浮点数的返回方法 

其他平台的程序调用约定 

第15章 编译表达式和语句 

15.1 确认编译结果 

利用cbc 进行确认的方法 

利用gcc 进行确认的方法 

15.2 x86 汇编的对象与DSL 

表示汇编的类 

表示汇编对象 

15.3 cbc 的x86 汇编DSL 

利用DSL 生成汇编对象 

表示寄存器 

表示立即数和内存引用 

表示指令 

表示汇编伪操作、标签和注释 

15.4 CodeGenerator 类的概要 

CodeGenerator 类的字段 

CodeGenerator 类的处理概述 

实现compileStmts 方法 

cbc 的编译策略 

15.5 编译单纯的表达式 

编译Int 节点 

编译Str 节点 

编译Uni 节点(1 ) 按位取反 

编译Uni 节点(2 ) 逻辑非 

15.6 编译二元运算 

编译Bin 节点 

实现compileBinaryOp 方法 

实现除法和余数 

实现比较运算 

15.7 引用变量和赋值 

编译Var 节点 

编译Addr 节点 

编译Mem 节点 

编译Assign 节点 

15.8 编译jump 语句 

编译LabelStmt 节点 

编译Jump 节点 

编译CJump 节点 

编译Call 节点 

编译Return 节点 

第16章 分配栈帧 

16.1 操作栈 

cbc 中的栈帧 

栈指针操作原则 

函数体编译顺序 

16.2 参数和局部变量的内存分配 

本节概述 

参数的内存分配 

局部变量的内存分配:原则 

局部变量的内存分配 

处理作用域内的局部变量 

对齐的计算 

子作用域变量的内存分配 

16.3 利用虚拟栈分配临时变量 

虚拟栈的作用 

虚拟栈的接口 

虚拟栈的结构 

virtualPush 方法的实现 

VirtualStack#extend 方法的实现 

VirtualStack#top 方法的实现 

virtualPop 方法的实现 

VirtualStack#rewind 方法的实现 

虚拟栈的运作 

16.4 调整栈访问的偏移量 

本节概要 

StackFrameInfo 类 

计算正在使用的callee-save 寄存器 

计算临时变量区域的大小 

调整局部变量的偏移量 

调整临时变量的偏移量 

16.5 生成函数序言和尾声 

本节概要 

生成函数序言 

生成函数尾声 

16.6 alloca 函数的实现 

什么是alloca 函数 

实现原则 

alloca 函数的影响 

alloca 函数的实现 

第17章 优化的方法

17.1 什么是优化 

各种各样的优化 

优化的案例 

常量折叠 

代数简化 

降低运算强度 

削除共同子表达式 

消除无效语句 

函数内联 

17.2 优化的分类 

基于方法的优化分类 

基于作用范围的优化分类 

基于作用阶段的优化分类 

17.3 cbc 中的优化 

cbc 中的优化原则 

cbc 中实现的优化 

cbc 中优化的实现 

17.4 更深层的优化 

基于模式匹配选择指令 

分配寄存器 

控制流分析 

大规模的数据流分析和SSA 形式 

总结 

第4 部分 链接和加载

第18章 生成目标文件

18.1 ELF 文件的结构 

ELF 的目的 

ELF 的节和段 

目标文件的主要ELF 节 

使用readelf 命令输出节头 

使用readelf 命令输出程序头 

使用readelf 命令输出符号表 

readelf 命令的选项 

什么是DWARF 格式 

18.2 全局变量及其在ELF 文件中的表示 

分配给任意ELF 节 

分配给通用ELF 节 

分配.bss 节 

通用符号 

记录全局变量对应的符号 

记录符号的附加信息 

记录通用符号的附加信息 

总结 

18.3 编译全局变量 

generate 方法的实现 

generateAssemblyCode 方法的实现 

编译全局变量 

编译立即数 

编译通用符号 

编译字符串字面量 

生成函数头 

计算函数的代码大小 

总结 

18.4 生成目标文件 

as 命令调用的概要 

引用GNUAssembler 类 

调用as 命令 

第19章 链接和库 

19.1 链接的概要 

链接的执行示例 

gcc 和GNU ld 

链接器处理的文件 

常用库 

链接器的输入和输出 

19.2 什么是链接 

链接时进行的处理 

合并节 

重定位 

符号消解 

19.3 动态链接和静态链接 

两种链接方法 

动态链接的优点 

动态链接的缺点 

动态链接示例 

静态链接示例 

库的检索规则 

19.4 生成库 

生成静态库 

Linux 中共享库的管理 

生成共享库 

链接生成的共享库 

第20章 加载程序 

20.1 加载ELF 段 

利用mmap 系统调用进行文件映射 

进程的内存镜像 

内存空间的属性 

ELF 段对应的内存空间 

和ELF 文件不对应的内存空间 

ELF 文件加载的实现 

20.2 动态链接过程 

动态链接加载器 

程序从启动到终止的过程 

启动ld.so 

系统内核传递的信息 

AUX 矢量 

读入共享库 

符号消解和重定位 

运行初始化代码 

执行主程序 

执行终止处理 

ld.so 解析的环境变量 

20.3 动态加载 

所谓动态加载 

Linux 下的动态加载 

动态加载的架构 

20.4 GNU ld 的链接 

用于cbc 的ld 选项的结构 

C 运行时 

生成可执行文件 

生成共享库 

第21章 生成地址无关代码 

21.1 地址无关代码 

什么是地址无关代码 

全局偏移表(GOT) 

获取GOT 地址 

使用GOT 地址访问全局变量 

访问使用GOT 地址的文件内部的全局变量 

过程链接表(PLT) 

调用PLT 入口 

地址无关的可执行文件:PIE 

21.2 全局变量引用的实现 

获取GOT 地址 

PICThunk 函数的实现 

删除重复函数并设置不可见属性 

加载GOT 地址 

locateSymbols 函数的实现 

全局变量的引用 

访问全局变量:地址无关代码的情况下 

函数的符号 

字符串常量的引用 

21.3 链接器调用的实现 

生成可执行文件 

generateSharedLibrary 方法 

21.4 从程序解析到执行 

build 和加载的过程 

词法分析 

语法分析 

生成中间代码 

生成代码 

汇编 

生成共享库 

生成可执行文件 

加载 

第22章 扩展阅读 

22.1 参考书推荐 

编译器相关 

语法分析相关 

汇编语言相关 

22.2 链接、加载相关 

22.3 各种编程语言的功能 

异常封装相关的图书 

垃圾回收 

垃圾回收相关的图书 

面向对象编程语言的实现 

函数式语言 

附 录 

A.1 参考文献 

A.2 在线资料 

A.3 源代码 

下载地址

请登录后发表评论

    没有回复内容