编译原理
编译器的工作流程
词法分析
-
识别出正确的单词,转换成统一格式,备用。
-
转换
-
对基本字、运算符、界线符的转换
-
标识符的转换
-
常数的转换
-
转换完成后的格式:(类号、内码)
-
-
描述此法分析的有效工具:正规式、有限自动机
语法分析
在词法分析的基础上根据语法规则将单词分解成各种语法短语,一般表示为语法树。
语法规则:又称为文法;规定单词如何构成短语、语句、过程和程序。
语法规则的表示:
BNF: A::=B|C
巴科斯范式(Backus–Naur form)
课本上的 BNF 的构成规则
-
() ———— 提因子
例如:
U -> ax|ay|az改写成U -> a(x|y|z) -
{} ———— 重复指定次数
例如:
<标识符> -> <字母>{<字母>|<数字>$}_0^5$ 表示标识符由 0-6个字符或数字构成, 也可以不指定上下限定表示不限长度重复 -
[] ———— 任选符号
例如:
[+|-]<数字>{<数字>} -
-> ———— 有什么组成
-
| ———— 或者
维基百科上的 BNF 也是常用编程语言中的 BNF 表示方式
<symbol> ::= __expression__
其中:
<symbol> 是非终结符(nonterminal variable aka. $V_n$)并且总是由尖括号包围.
::= 表示位于该运算符左边的符号总是被右边的表达式替代
__expression__ 表示一个或多个终结符($V_t$)或者非终结符($V_n$)构成的串
语法分析的方法:
- 推导(derive)
eg. 判断 x=a+b*50 是否是合法语句
语法规则:
A::=V=E
E::=T|E+T
T::=F|T*F
F::=V|(E)|C
V::=Label
C::=Const
A
-> V=E -> V=E+T -> v=E+T*F -> V=E+T*C -> V=E+T*50
-> V=E+F*50 -> V=E+V*50 -> V=E+b*50 -> V=T+b*50
-> V=F+b*50 -> V=V+b*50 -> V=a+b*50
- 规约(reduce)
最右推导逆过程就是最左规约,规约与推导互为逆操作。
语义分析
中间代码生成
-
任务 对语法分析识别出的各类语法范畴,分析其含义, 进行初步翻译,产生介于源代码与目标代码之间的一种代码。
-
分为两个阶段
-
对每种语义范畴进行静态语义检查
-
若语义正确,就进行中间代码生成
-
-
中间代码的形式 四元式、三元式、逆波兰式
四元式:算符、左操作数、右操作数、结果 三元式: 逆波兰式:
优化
对前一阶段产生的中间代码进行变换或进行改造,目的是 使生成的目标代码更为高效。
原则:等价变换
主要方面:公共子表达式的提取、合并已知量、删除无用语句、循环优化等。
目标代码生成
任务:把经过优化中间代码转换成特定机器上的低级语言代码
目标代码的形式:
-
绝对指令代码:可以直接执行的目标代码
-
汇编指令代码:汇编语言程序,需要汇编器汇编后才能运行
-
可重定位指令代码:先将各个目标模块连接起来, 确定变量、常量在主存中的位置,装入主存后才能成为可以运行的 绝对指令代码
一些需要了解的概念
遍 or 趟 (pass)
指对源程序或源程序的中间结果从头到尾扫描一次, 并做有关的加工处理,生成新的中间结果或目标代码。
前端、后端
现代编译器一般把编译的过程分为前端(front end)和后端(back end):
前端主要依赖于语言而与机器码无关。 前端通常包含词法分析、语法、语义分析和中间代码生成以及某些前端可以 做的优化以及错误处理工作。
后端依赖于目标机器而不依赖于源语言,只与中间代码有关的阶段的工作, 即目标代码生成及相关的错误处理和符号表操作。