【第一章】编译原理基础
编译器的结构
主要分为2个部分:分析(analysis)部分和综合(synthesis)部分
- 分析部分:源程序分解为多个组成要素,并再要素上加上语法结构,创建一个中间表示,相关信息存入符号表。
- 综合部分:根据中间表示和符号表构造目标程序。
1.词法分析
词法分析器读入字节流,将他们组成有意义的词素(lexeme)序列,以词法单元(token)的形式输出:
<token-name,attribute-value>
例子:
position = initial + rate * 60
词法分析后为一个词法单元序列
<id,1><=><id,2><+><id,3><*><60>
2.语法分析
语法分线器使用词法分析器生成的各个词法单元 创建树形的中间表示,累似一颗二叉树表的中间表示。
3.语义分析
使用语法树和符号表中的信息检查源程序是否和语言定义的语义一致。
- 类型检查 (如数组下表必须为整数)
- 类型和运算合法性检查
- 自动类型转换 (如一个float*int)
4.中间代码生成
完成语法分析和语义分析,编译器生成一个类机器语言的中间表示。
意义:易于生成,容易被翻译成目标机器上的语言
常见的有 三地址代码(three-address code的中间表示。这种中间表示累死汇编语言的指令,每个指令有三个运算分量,每个运算分量像一个寄存器。
5.代码优化
机器无关的代码优化,可以改进中间代码,以便生成更好的目标代码(更短更快)
//三地址代码序列
t1 = inttofloat(60)
t2 = id3 * t1
t3 = id2 + t2
id1 = t3
//优化后
t1= id3 * 60.0
id1 = id2 + t1
6.代码生成
以源程序的中间表示作为输入,映射到目标语言(机器代码)。须要为程序中的变量选择寄存器或内存位置。合理分配寄存器以存放变量的值至关重要。
如使用寄存器R1和R2,完成中间代码翻译的机器代码:
LDF R2, id3
MULF R2, R2, #60.0
LDF R1, id2
ADDF R1, R1, R2
STF id1, R1
7.符号表管理
符号表为每一个变量名字创建了一个记录条目,包括类型,作用域。对于过程名字,包括参数数量和类型,参数的传递方式,反回类型。
8.将多个步骤组合趟
在特定的实现中,多个步骤的活动被组合成一趟(pass)。每趟读入一个输入文件并产生一个输出文件。词法语法,语义分析组成一个pass,代码优化作为一个可选的pass,为特定目标机生成代码为一个pass。
通过把前端和不同的目标机后端结合,建立针对不同目标机的编译器。
9.编译器结构工具
实现一个完整的软件开发环境,包含语言编辑器,调试器,版本控制,程序秒暑期,测试管理等工具。
程序设计语言的发展
- 第一代:机器语言
- 第二代:汇编语言
- 第三代:Fortran、C、C++、Java高级程序设计语言
- 第四代:为特定应用设计的语言,如SQL,markdown
名词解释
- 强制式语言:指名如何完成一个计算任务的语言(c,java)
- 声明式语言:指名要进行哪些计算的语言(ML,Haskell等函数式语言)
针对计算机体系结构的优化
几乎所有的高性能计算系统都用到了两种技术:并行(Parallelism)和内存层次结构(memory hierarchy)。
并行性
- 现代微处理器都采用了指令集并行。
- 在指令集层次,多个运算可以被同时执行。
- 处理器层次,同一个应用的多个不同线程再不同的处理器上运行。
内存层次结构
- 几百字节的寄存器
- 几K到几M的高速缓存
- 几M到几G的物体寄存器
- 几G的外部寄存器