什么是编译原理?
编译原理一般指的是把(编译型)高级语言(c/c++, rust, go) 转换(编译)为机器代码的过程.
java属于半编译型语言, 代码执行前被编译为字节码, 然后由java虚拟机运行
python, js属于解释型语言, 边执行边把代码编译为对应虚拟机的代码表示, 然后由虚拟机解释执行
类型
编译程序 | 把高级程序语言变为机器语言(汇编或机器码) |
汇编程序 | 把汇编语言变为机器码 |
还有交叉汇编, 交叉编译, 反汇编, 反编译, 可变目标编译程序….的分类. 我觉得这不重要
编译系统的组成
一般可以分为前端 和 后端
前端把高级语言变为中间代码。这个中间代码是一种与机器无关的表示形式,通常是三地址码或四元式。后端则负责将中间代码转换为目标机器代码,并进行代码优化。这种分层设计使得编译器的前端可以适用于多种高级语言,而后端则可以针对不同的目标机器进行优化。
前端又包括: 源代码 → 词法分析(记号流) → 语法分析(语法树) → 语义分析(类型检查) (→中间代码生成)
文法
文法G是一个四元组 G=(VN,VT,P,S)
- VN → variable 变量, 也成为非终结符
- P → production 产生式 表示语法规定的状态转移形式
Chromsky 四种文法
0型到3型父级关系, 也就是如果是1型则也需要满足0型的规则
0型
都是, 除了瞎写的, 或写错的
α→βα,β∈(VN∪VT)∗ 1型 上下文相关文法
α→β∣α∣≤∣β∣ 与0型相比, 多了产生式左部的模要≤右部的
2型 上下文无关文法
α→βα∈VN α只能是终结符
3型 正则文法
A→αB∣α右线性orA→Bα∣α左线性 最严格, 很少出现
LL(1)文法
判断
找到产生式中有 | 或的部分, 判断每个部分的 First 集无公共元素, 如果存在 ε(空串)
哪就要再判断右部的各部分的First集和左部的Follow集无公共元素
A→α∣β(...)First(α)∩First(β)∩.....=∅∀x∈α,β...,x=∅First(α)∩First(β)∩.....∩Follow(A)=∅∃x∈α,β...,x=∅
习题相关
消除左递归
消除左递归的目的在于, 消除文法推导的二义性(公共前缀), 把左递归变为右递归
A→Aα∣β⇒{A→βA′A′→αA′∣ε 
消除回溯
目的同上
A→δβ1∣δβ2∣δβ3∣β4∣...∣βnto{A→δA′∣β4∣...∣βnA′→β1∣β2∣β3