编译原理学习笔记
课程内容: 介绍程序设计语言 编译程序构造 的 基本原理 和 基本实现技术 。
把某一种语言程序(称为 源语言程序
) 等价 的转换成另一种语言程序(称为 目标语言程序
) 的程序。
把某一种 高级语言程序
等价的转化成另一种 低级语言程序
(如汇编语言或机器语言程序)的程序。
编译程序可分为: 诊断编译程序
、优化编译程序
、交叉编译程序
、可变目标编译程序
。
把 源语言
写的源程序作为输入,但不产生目标 程序,而是 边解释边执行
源程序。
计算思维是运用计算集科学的基础概念去求解问题,设计系统和理解人类行为。
抽象、自动化、问题分解、递归、权衡、保护、冗余、容错、纠错、和恢复、启发式等等。
编译程序工作的五个阶段: 词法分析
、 语法分析
、 中间代码生成
、 优化
、 目标代码产生
。
构词规则
有限自动机
语法单位(语法范畴)
语法规则
上下文无关文法
语义规则
属性文法
三元式,四元式,树,...
程序的等价变换规则
目标代码三种形式
可以直接运行的目标代码是绝对指令代码。
遍: 对源程序或源程序的中间表示 从头到尾扫描一次
阶段与遍是不同的概念
编译后端
带来的好处
P1是一个可以在A机器上运行的编译程序(类似gcc.exe)即 L1ToA.A
,可以将一个L1语言的代码编译成一个可以在A上运行的程序
这时我们用L1语言写一个编译L2语言的编译器P2,即 L2ToA.L1
为了能够在A机器上运行,所以我们需要上面的编译器来编译这个代码,得到 L2ToA.A
这样就得到了一个L2语言的编译器(例如我们用C++语言编写一个Python的编译器python.cpp,然后用g++.exe 编译链接得到一个可以运行的Python的编译器 python.exe)
例如现在有一个在A平台(例如Windows)下的L语言(例如c++)的编译器,要移植这个编译器到B平台(Linux)下,我们拥有A平台下的一个L语言的编译器(例如g++.exe)即 LToA.A
,,
我们可以用L语言写一个针对B平台下的L语言的编译器(例如Linux中的g++.cpp)即 LToB.L
,
在A平台下编译即可得到一个在A平台下运行并可以编译出在B平台的下运行的L语言的编译器(P2: LToB.A
)
然后再用这个A平台下的编译器编译我们的代码( LToB.L
)就可以得到一个在B平台下运行的编译器 LToB.B
打个比方:
我们用c++ 编写一个 g++ForLinux.cpp
然后用 g++.exe
编译,得到 g++ForLinux.exe
然后用 g++ForLinux.exe
编译 g++ForLinux.cpp
就可以得到在Linux下运行的 g++ForLinux
c++编译器了。
就是编写L的编译器就用L的一小部分 L 1 L_1 L1 写一个编译器,然后编译 L 1 + L 2 L_1 + L_2 L1+L2 得到一个较大的编译器,这样不断的重复下去,利用语言自己来写完整的编译器。
编译程序-编译程序,编译程序产生器,编译程序书 写系统
LEX:词法分析程序产生器
YACC:语法分析程序产生器
相对机器语言或汇编语言,高级程序设计语言
标识符是语法概念,名字是语义概念
程序语言的定义: 语法 、语义 、语用
程序本质上是一定字符集上的字符串
语法:一组规则,用它可以形成和产生一个 合式(well-formed) 的程序。
词法规则 :单词符号的形成规则。
语法规则 :语法单位的形成规则。
语法规则 和 词法规则 定义了程序的形式结构。
定义语法单位的意义属于 语义 问题。
语义 :一组规则,用它可以定义一个程序的意义 。
描述方法 :
程序,本质上说是描述一定数据的处理过程 。
程序语言的基本功能 :描述数据 和 对数据的运算 。
数据类型 通常包括三要素:
初等数据类型 : 数值类型 、逻辑类型 、字符类型、指针类型。
标识符是语法概念,名字是语义概念
名字的意义和属性 :
名字的说明方式:
n维矩形结构、长度可变和不可变、存放方式:按行存放、案列存放
数组元素地址计算:
由已知类型的数据组合在一起的一种结构 (就是结构体。。。)
其中内部的元素也称为 域(field)
其内容包括:
程序设计语言对抽象数据类型的支持
一般的规定 :
注意:
语句的分类:
1.按功能:
2.按形式 :
文法 :描述语言的语法结构的形式规则。
以英文句子: He gave me a book
举例:
连接(积)
定义为: U V = { α β ∣ α ∈ U & β ∈ V } UV = \{\alpha \beta|\alpha \in U \& \beta \in V \} UV={αβ∣α∈U&β∈V} ( α β \alpha \beta αβ 的连接有顺序)闭包
: V ∗ = V 0 ⋃ V 1 ⋃ V 2 ⋃ V 3 ⋯ V^*= V^0 \bigcup V^1 \bigcup V^2 \bigcup V^3 \cdots V∗=V0⋃V1⋃V2⋃V3⋯正规(则)闭包
: V + = V V ∗ V^+=VV^* V+=VV∗eg: 设 U = { α , α α } U=\{\alpha , \alpha \alpha\} U={α,αα} ,显然 U ∗ = { ϵ , a , a a , a a a , a a a a , … } U^*= \{ \epsilon, a, aa, aaa, aaaa, \ldots \} U∗={ϵ,a,aa,aaa,aaaa,…}
U + = { a , a a , a a a , a a a a , … } U^+=\{ a, aa, aaa, aaaa, \ldots \} U+={a,aa,aaa,aaaa,…}
闭包与正规闭包的区别: V V V 若无空字, V ∗ V^* V∗ 中有空字、而 V + V^+ V+ 无空字。
上下文无关文法 G G G 是一个四元组 G = ( V T , V N , S , P ) G=(V_T,V_N,S,P) G=(VT,VN,S,P),其中:
终结符(Terminal)
集合(非空)非终结符(Noterminal)
集合(非空),且 V T ⋂ V N = ∅ V_T \bigcap V_N= \emptyset VT⋂VN=∅开始符号
, S ∈ V N S∈V_N S∈VN产生式
集合(有限),每个产生式形式为 P 定 义 为 → α , P ∈ V N , α ∈ ( V T ⋃ V N ) ∗ P \underrightarrow{定义为} \alpha , P \in V_N, \alpha \in (V_T \bigcup V_N)^* P定义为α,P∈VN,α∈(VT⋃VN)∗eg: 定义只含 + , ∗ +,* +,∗ 的算术表达式的文法 G = < { i , + , ∗ , ( , ) } , { E } , E , P > G=< \color{#F0A}{ \{i,+,*,(,)\} },\color{#0F5}{ \{E\} },\color{#08F}{E},\color{black}{P}> G=<{i,+,∗,(,)},{E},E,P>,其中,P 由下列产生式组成:
开始符号
和 产生式
:如图:G ( E ) G(E) G(E)里的 E E E 是指开始符号。
定义: 称 α A β \alpha A \beta αAβ直接推出 α γ β αγβ αγβ,即 α A β ⟹ α γ β α \color{#F08}{A} \color{black}{β} \implies α \color{#F08}{γ} \color{black}{β} αAβ⟹αγβ 仅当 A → γ \color{#F08}{A→γ} A→γ 是一个产生式,且 α , β ∈ ( V T ∪ V N ) ∗ α,β∈(V_T ∪V_N)^* α,β∈(VT∪VN)∗。
如果 α 1 ⟹ α 2 ⟹ ⋯ ⟹ α n α_1 \implies α_2 \implies \cdots \implies α_n α1⟹α2⟹⋯⟹αn,则我们称这个序列是 从α1到αn的一个 推导
。若存在一个从 α 1 α_1 α1 到 α n α_n αn 的 推导,则称 α 1 α_1 α1 可以 推导
出 α n α_n αn。
对文法 G ( E ) : E → i ∣ E + E ∣ E ∗ E ∣ ( E ) G(E):E →i| E+E | E*E | (E) G(E):E→i∣E+E∣E∗E∣(E)
E ⟹ ( E ) ⟹ ( E + E ) ⟹ ( i + E ) ⟹ E ( i + i ) E \implies (E) \implies (E+E) \implies(i+E) \implies E(i+i) E⟹(E)⟹(E+E)⟹(i+E)⟹E(i+i)
我们定义:
α 1 ⇒ ∗ α n \alpha_1 ⇒^* \alpha_n α1⇒∗αn 从 α 1 α_1 α1 出发,经过0步或若干步推出 α n α_n αn
α 1 ⇒ + α n \alpha_1 ⇒^+ \alpha_n α1⇒+αn 从 α 1 α_1 α1 出发,经过1步或若干步推出 α n α_n αn
因此, α ⇒ ∗ β \alpha ⇒^* \beta α⇒∗β 即为 α = β \alpha = \beta α=β 以及 α ⇒ + β \alpha ⇒^+ \beta α⇒+β
(这里的 + ∗ + * +∗ 都是在 ⇒ ⇒ ⇒ 的上面)
所以可以得到这样的关系,(理解一下即可):
< 句 子 > ⇒ ∗ He gave me a book < 句子>⇒^* \text{He gave me a book} <句子>⇒∗He gave me a book
< 句 子 > ⇒ + He gave me a book < 句子> ⇒^+ \text{He gave me a book} <句子>⇒+He gave me a book
He gave < 间接宾语><直接宾语> ⇒ + He gave me <冠词><名词> \text{He gave < 间接宾语><直接宾语>} ⇒^+ \text{He gave me <冠词><名词>} He gave < 间接宾语><直接宾语>⇒+He gave me <冠词><名词>
由以上定义可以得出句型、句子和语言的定义:
假定G是一个文法,S 是它的开始符号。
句型
句子
。语言
,记为 L ( G ) : L ( G ) = { α ∣ S ⇒ + α , α ∈ V T ∗ } L(G): L(G) = \{ \alpha | S ⇒^+ \alpha , \alpha \in V_T^* \} L(G):L(G)={α∣S⇒+α,α∈VT∗}(这里为了排版更加的整齐(其实是打公式太懒)就贴图片了):
请给出产生语言为 { a n b n ∣ n ≥ 1 } \{a^nb^n|n≥1\} {anbn∣n≥1} 的文法:
G 3 ( S ) : G3(S): G3(S):
从一个句型到另一个句型的推导往往不唯一,从推导的方向看有两种:
语法树
注意:
可以同名
文法的二义性
:如果一个 文法 存在 某个句子 对应 两棵不同的语法树 ,则说这个文法是二义的 G ( E ) : E → i ∣ E + E ∣ E ∗ E ∣ ( E ) G(E):E →i|E+E|E*E|(E) G(E):E→i∣E+E∣E∗E∣(E) 是二义文法语言的二义性
:一个语言是二义的,如果(那么) 对它不存在无二义的文法 。对于语言L,可能存在G和G’,使得 L ( G ) = L ( G ’ ) = L L(G)=L(G’)=L L(G)=L(G’)=L ,有可能其中一个文法为二义的, 另一个为无二义的二义性问题是 不可判定问题 ,即不存在一个算法,它能在有限步骤内,确切地判定一个文法
对于是否是二义的 ,可以找到一组无二义文法的充分条件
乔姆斯基于1956年建立形式语言体系,他把文 法分成四种类型:0,1,2,3型 。
程序设计语言不是上下文无关语言,甚至不是上下文有关语言,只能由0型语言产生,如:
(end)