第一章
编译程序的各个逻辑阶段及各阶段的意义
- 词法分析
从左到右读入源程序的每个字符,对构成源程序的字符流进行扫描和分解,从而辨识出一个个的单词(也叫单词符合或者符合)。 - 语法分析
依据语言的语法规则,确定源程序的输入串是否构成一个语法上正确的程序。
最终将单词序列分解为各类语法短语(也叫语法单位),如“程序”、“语句”、“表达式”等。 - 语义分析
审查源程序有无语义错误,为代码生成阶段收集类型信息。 - 中间代码生成
在语法分析和语义分析之后,将源程序变成一种“内部表示形式”。 - 代码优化
对中间代码进行变换或者改造,使之更为高效(时间、空间)。 - 目标代码生成
把中间代码变换成特定机器上的绝对指令代码或者可重定位的机器指令代码或者汇编指令代码。
遍的概念
一个编译过程可由一遍、两遍或多遍完成。所谓"遍",也称作"趟",是对源程序或其等价的中间语言程序从头到尾扫视并完成规定任务的过程。每一遍扫视可完成上述一个阶段或多个阶段的工作。例如一遍可以只完成词法分析工作;一遍完成词法分析和语法分析工作;甚至一遍完成整个编译工作。对于多遍的编译程序,第一遍的输入是用户书写的源程序,最后一遍的输出是目标语言程序,其余是上一遍的输出为下一遍的输入。
在实际的编译系统的设计中,编译的几个阶段的工作究竟应该怎样组合,即编译程序究竟分成几遍,参考的因素主要是源语言和机器(目标机)的特征。比如源语言的结构直接影响编译的遍的划分;像PL/1或ALGOL 68 那样的语言,允许名字的说明出现在名字的使用之后,那么在看到名字之前是不便为包含该名字的表达式生成代码的,这种语言的编译程序至少分成两遍才容易生成代码。另外机器的情况,即编译程序工作的环境也影响编译程序的遍数的划分。遍数多一点,整个编译程序的逻辑结构可能清晰些,但遍数多即意味着增加读写中间文件的次数,势必消耗较多时间,一般会比一遍的编译要慢。
第二章
词法分析器的相关概念
词法分析器的输出结果为:单词的种别编码和自身值。
状态转换图、NFA、DFA、NFA与DFA的转换、DFA的化简
由正则式构造NFA
正规式与正规集
正规式M1和M2等价是指:M1和M2所识别的语言集相等。
第三章
优先集、结合性;名字、标识符;左值和右值
- 优先集、结合性
优先级与结合性是指运算符与操作数的“紧密程度”; 结合性表明了同一优先级的运算符对同一操作数的紧密程度。简单理解就是:各种运算符的计算顺序;可以使用优先集和结合性解决部分二义性文法的问题。 - 名字、标识符
标识符(identifier)是一个字符串,通常由字母和数字组成。它用来指向(标记)一个实体,比如一个数据对象、过程、类,或者类型。所有的标识符都是名字,但并不是所有的名字都是标识符。名字也可以是一个表达式。比如名字x.y可以表示x所指的一个结构中的字段y。这里,x和y是标识符,而x.y是一个名字。像x.y这样的复合名字称为受限名字(qualified name)。 - 左值和右值
通俗的讲,左值就是能够出现在赋值符号左面的东西,而右值就是那些可以出现在赋值符号右面的东西了。
符号串和符号串集合的相关概念以及相关运算
上下文无关文法、推导与归约、语法分析树、二义性
规范推导:最右推导
规范规约:最左规约
形式语言鸟瞰,即四种类型的文法
LL(1)
LR(0)
SLR
LALR
语法分析器的相关概念
在自底向上的语法分析中,其关键是寻找句柄。
在自顶向下的语法分析中,其关键是选择候选式。
自上而下分析面临的问
左递归、回溯 、二义性
左递归的消除,公共左因子的提取
first集 follow集
不断应用下列规则,直到没有新的终结符或ε可以被加入到任何FIRST集合中为止
- 如果X是一个终结符,那么FIRST ( X ) = { X }
- 如果X是一个非终结符,且 X→Y1…Yk∈P(k≥1),那么如果对于某个i,a在FIRST (Yi ) 中且ε 在所有的FIRST(Y1) , … ,FIRST(Yi-1)中(即Y1…Yi-1 * ε ),就把a加入到FIRST( X )中。如果对于所有的 j = 1,2, . . . , k,ε在FIRST(Yj)中,那么将ε加入到FIRST( X )
- 如果 X→ε∈P,那么将ε加入到FIRST( X )中
LL(1)文法的条件
消除回溯、消除左递归
条件1:如果α 和β均不能推导出ε ,则对应的这两个产生式的SELECT集就分别是α 和β的FIRST集。
既然FIRST集不相交,那么SELECT集也不相交。
条件2:如果α 和β均能推导出ε ,则对应的这两个产生式的SELECT集就都包含FOLLOW(A)中的元素,那么, 两个SELECT集就会有交集。所以α 和β不能都推导出ε ,至多只能有一个能推导出ε
条件3:如果β能推导出ε ,则β对应的产生式的SELECT集就都包含FOLLOW(A)中的元素,那么,FIRST(α)中就不能再包含FOLLOW(A)中的元素。否则,这两个产生式的SELECT集就会有交集
LL(1)分析表的构造及预测分析过程
预测分析表:
由Select集构建
概念的掌握,如短语、直接短语、句柄
LR分析步骤
掌握LR(0)分析表、SLR分析表、规范LR分析表、LALR分析表的画法
LR(0)分析表
SLR分析表
规范LR分析表(LR(1))
LALR分析表:LR(1)合并同心项目集就可以得到
第四章
综合属性、继承属性
综合属性用于自下而上传递信息;继承属性用于自上而下传递信息。
S-属性文法 和 L-属性文法
语法制导定义
翻译模式
第六章
局部存储分配策略
静态分配策略、堆式分配策略、栈式分配策略
静态分配策略
在静态存储分配中,编译器为每个过程确定其活动记录在目标程序中的位置。
这样,过程中每个名字的存储位置就确定了。
因此,这些名字的存储地址可以被编译到目标代码中,过程每次执行时,它的名字都绑定到同样的存储单元。
限制条件
- 数组上下界必须是常数
- 不允许过程的递归调用
- 不允许动态建立数据实体
常用存储分配方法
顺序分配法、层次分配法。
顺序分配法
- 按照过程出现的先后顺序逐段分配存储空间
- 各过程的活动记录占用互不相交的存储空间
层次分配法
通过对过程间的调用关系进行分析,凡属无相互调用关系的并列过程,尽量使其局部数据共享存储空间。
堆式分配策略
堆式存储分配是把连续存储区域分成块,当活动记录或其它对象需要时就分配。
块的释放可以按任意次序进行,所以经过一段时间后,堆可能包含交错的正在使用和已经释放的区域。
栈式分配策略
运行时刻存储以栈的形式进行管理,称为栈式存储分配.
活动记录、活动树和运行栈、调用序列
活动记录
使用过程(或函数、方法)作为用户自定义动作的单元的语言,其编译器通常以过程为单位分配存储空间。
过程体的每次执行称为该过程的一个活动(activation)。
过程每执行一次,就为它分配一块连续存储区,用来管理过程一次执行所需的信息,这块连续存储区称为活动记录( activation record )。
活动树
用来描述程序运行期间控制进入和离开各个活动的情况的树称为活动树。
树中的每个结点对应于一个活动。根结点是启动程序执行的main过程的活动。
在表示过程p的某个活动的结点上,其子结点对应于被p的这次活动调用的各个过程的活动。按照这些活动被调用的顺序,自左向右地显示它们。一个子结点必须在其右兄弟结点的活动开始之前结束。
参数传递:值调用、引用调用、换名调用
第七章
中间语言的表示形式
三元式
四元式
逆波兰式