编译原理(第2版)笔记
目录[隐藏] |
[编辑]一个简单的语法制导翻译器
[编辑]右结合文法
如对赋值a=b=c,有:
right := left=right | letter left := letter letter := a | b | c
[编辑]运算符优先级
创建2个非终结符expr、term分别对应这两个优先级(+-和*/),并引进另一个factor代表运算基本单元,并考虑两者都是左结合,则有:
term := term * factor | term / factor | factor expr := expr + term | expr - term | term factor:= DIGIT | ( expr )
请注意这里对非终结符命名的技巧。
[编辑]二义文法的消除:注意这里分号在不是stmt的后面
stmt := ID = expr ; | if( expr ) stmt | if( expr ) stmt else stmt | while( expr ) stmt | do stmt while ( expr ) ; | { stmts } stmts := stmts stmt | e
[编辑]递归下降:左递归修改为右递归,增加e
之前:
A := Aa | b
之后:
A := bR R := aR | e
[编辑]AST:抽象语法树
[编辑]为每个作用域设置一个符号表
[编辑]静态检查
- 左值、右值
- 类型一致
-
- 自动类型转换
- 重载
-
[编辑]词法分析
- 缓冲区:eof(-1)标记
- 正则表达式
- Aho和Corasick对KMP算法进行了推广,使得可识别一个关键字集合中的任何关键字(字符串处理领域4个算法/数据结构:KMP、BM、后缀树(数组)、AC自动机)
- Lex
- 在Fortran和其他一些语言中,关键字并不是保留字,。。。(查看其后缀)
- FA
-
- NFA到DFA的转换:e-Closure的构造
- NFA的on-the-fly模拟(也就是说,‘即时使用’)
- DFA中的死状态(不可达)
- 从re直接构造DFA:nullable、firstpos、lastpos、followpos
- DFA最小化(最小的是不是唯一的??)
-
- DFA存储
int nextState(s,a){ if( check[ base[s]+a ] == s ) return next[ base[s]+a ]; else return nextState( default[s],a ); }
[编辑]语法分析
[编辑]CFG
[编辑]递归下降语法分析:求FIRST、FOLLOW集(其实就是一个传递闭包)
[编辑]LL(1)文法
[编辑]自底向上语法分析
[编辑]移进-归约
[编辑]LR分析器
[编辑]LR(0)
[编辑]SLR
- ACTION
- GOTO
[编辑]规范LR(1)
- LR(1)项
[编辑]LALR
- 合并具有相同core的LR(1)项
[编辑]二义文法
[编辑]YACC
[编辑]语法制导的翻译
[编辑]SDD:语法制导定义
[编辑]继承属性与综合属性
[编辑]依赖图
[编辑]SDD1:`S属性`
- 所有属性都是综合的
[编辑]SDD2:`L属性`
- 继承属性:只能够依赖parent节点的继承属性,和左兄弟的(任意)属性
-
- 实际上,这保证了能够在一趟深度遍历中处理完所有工作。。。
-
[编辑]中间代码生成
[编辑]DAG
[编辑]类型推导:合一
[编辑]运行时环境
[编辑]‘调用-返回’序列
[编辑]活动记录栈
[编辑]访问链(access link)
[编辑]代码生成
[编辑]目标代码
- 指令集
- 地址空间:Code、Static、Heap、Stack
[编辑]基本块
[编辑]流图
[编辑]局部优化
- 窥孔优化
- 寄存器分配
- 树重写
[编辑]机器无关优化(全局优化)
- 公共子表达式
- 复制传播
[编辑]数据流分析
- 到达定值
- 活跃变量分析
- 可用表达式
[编辑]常量传播
[编辑]流图中的循环
[编辑]支配节点
[编辑]深度优先排序
[编辑]回边
[编辑]图的深度
[编辑]可归约性
[编辑]区域分析
[编辑]指令级并行
[编辑]并行性和局部优化
[编辑]源代码转换:7个基本仿射变换
- 融合(fusion)
- 裂变(fission)
- 重新索引
- 缩放
- 反置(reversal)——反向循环
- 交换(permutation)——交换内外循环
- 倾斜(skewing)