🌈个人主页: 十二月的猫-CSDN博客
🔥 系列专栏: 🏀编译原理_十二月的猫的博客-CSDN博客
💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光
目录
[1. 前言](#1. 前言)
[2. 编译原理概述](#2. 编译原理概述)
[2.1 什么是编译器?](#2.1 什么是编译器?)
[2.2 与编译器有关的其他程序(不学习)](#2.2 与编译器有关的其他程序(不学习))
[2.3 编译程序的结构](#2.3 编译程序的结构)
[2.4 编译器结构分析](#2.4 编译器结构分析)
[2.5 为什么是汇编语言](#2.5 为什么是汇编语言)
[3. 文法](#3. 文法)
[3.1 词法](#3.1 词法)
[3.1.1 字母表与符号串](#3.1.1 字母表与符号串)
[3.1.2 构成符号串](#3.1.2 构成符号串)
[3.2 什么是文法?](#3.2 什么是文法?)
[3.2.1 推导与产生式](#3.2.1 推导与产生式)
[3.2.2 语法树](#3.2.2 语法树)
[3.2.3 文法的定义](#3.2.3 文法的定义)
[3.2.4 文法的分类](#3.2.4 文法的分类)
[4. 习题](#4. 习题)
[5. 总结](#5. 总结)
1. 前言
为什么打算开始这一系列的文章------编译原理🎄🎄
其实本学期开始就一直想持续更新,陆陆续续主要更新了实验部分。
正好趁着快要考试,便和大家一起花费几天的时间回顾编译原理的知识点。
目前,十二月猫的回顾计划如下🔞🔞:
日期计划 | 具体任务 | 完成进度 |
---|---|---|
第一天 | 概论与文法+词法分析 | ⏩ |
第二天 | 语法分析 | 📫︎ |
第三天 | 语义分析+代码生成 | 📫︎ |
第四天 | 按题型学习 | 📫︎ |
第五天 | 按题型学习 | 📫︎ |
第六天 | 往年题练习 | 📫︎ |
祝大家都能取得好成绩呀~~🥰🥰
参考书籍:
英文名:Compilers: Principles,Techniques,and Tools (龙书)🦖
作者:Alfred V.Aho,Ravi Sethi,Jeffrey D.Ullman
1.本课程介绍编译器构造的一般原理和基本实现方法,主要介绍编译器的各个阶段:词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成 。2.本课程在介绍命令式程序设计语言实现技术的同时,强调一些相关的理论知识,如形式语言和自动机理论、语法制导的定义和属性文法、类型论等。
3.本课程强调形式化描述技术,并以语法制导定义作为翻译的主要描述工具。
4.本课程强调对编译原理和技术在宏观上的理解,而不把读者的注意力分散到一些枝节的算法上,如计算开始符号集合和后继符号集合的算法,回填技术等。作为原理性的教材,本书介绍基本的理论和方法,而不偏向于某种源语言或目标机器。
2. 编译原理概述
2.1 什么是编译器?
- 编译器是将一种语言翻译为另一种语言的计算机程序。
- 编译器将编写的程序作为输入,而产生用目标语言编写的等价程序。
- 源程序→{编译器}→目标程序。
- 编译器与 翻译器、解释器的区别。
- 编译器是将便于人编写,阅读,维护的高级计算机语言翻译为计算机能解读、运行的低级机器语言 的程序。低级计算机语言是汇编语言或目标机器的目标代码,源代码一般为高阶语言。
**翻译器:**从一种语言变为等价的另一种语言(两个语言在同一个层级)。
**解释器:**边解释语言,边执行语言,并不产生中间代码。
**编译器:**将计算机高级语言 转为 等价的计算机低级语言。
2.2 与编译器有关的其他程序(不学习)
(1)解释程序
如同编译器的一种语言翻译程序。与编译器的不同在于:它立即执行源程序而不是在翻译完成之后才执行目标代码。
(2)汇编程序
用于特定计算机上的汇编语言的翻译程序
(3)连接程序
将分别在不同的目标文件中编译或汇编的代码收集到一个可直接执行的文件中
(4)装入程序
可处理所有与指定的基地址或起始地址有关的可重定位的地址
(5)预处理器
在真正的翻译开始之前由编译器调用的独立程序
(6)编辑器
编译器通常接受由任何生成标准文件 ( 例如 ASCII 文件 ) 的编辑器编写的源程序。编译器如今常与编辑器和其他程序捆绑进一个交互的开发环境--IDE中。
(7)调试程序
可在被编译了的程序中判定执行错误的程序。编译器必须为调试程序提供恰当的符号信息。
(8)描述器
在执行中搜集目标程序行为统计的程序
(9)项目管理程序
上面这些程序,我们都不学习,本课程只专注于 编译程序🤗🤗
2.3 编译程序的结构
大致结构:
解释如下:
- 词法分析器: 扫描源程序,将源程序的字符流进行扫描和分解,识别出单词。
- 语法分析器: 机器通过词法分析得到单词表 ,通过单词表将源程序分解为不同的语法短语 ,确定源程序输入能构成语法正确的程序。
- **语义分析器:**检查源程序有没有语义上的错误,例如上下文有关的错误,变量是否声明等。
- **中间代码生成器:**源程序经过前面的步骤生成了语法树,这里将源程序转变为一种内部表示,方便后续优化处理。
- **代码优化器:**根据前一阶段产生的中间代码,对其进行针对性的变换和改造,让代码更加高效,空间浪费更少。
- **代码生成器:**将前面优化后的代码转变为特定机器上的目标代码,例如汇编指令等。
带有输出输出的详细结构:
编译中涉及到的主要数据结构:
- 记号
- 语法树
- 符号表
- 常数表
- 中间代码
- 临时文件
2.4 编译器结构分析
分析与综合:
分析: 分析源程序以计算其特性的编译器操作
**综合:**生成翻译代码时所涉及到的操作
前端与后端:
- 通常认为,只依赖于源语言的的操作为前端,只依赖于目标语言的操作为后端。
- 如:扫描程序,分析程序,语义分析程序为前端。代码生成器为后端。
- 便于编译器的可移植性
什么是遍:
- 编译过程的几个阶段仅仅是逻辑功能上的一种划分,具体实现时,受不同源语言,设计要求,使用对象和计算机条件(如主存容量)的限制,往往将编译程序组织为若干遍。所谓"遍"就是对源程序或源程序的中间结果从头到尾扫描一次,并作有关的加工处理,生成新的中间结果或目标程序。
- 通常,每遍的工作由从外存上获得的前一遍的中间结果开始,完成它所含的有关工作之后,再把结果记录于外存,既可以将几个不同阶段合为一遍,也可以把一个阶段的工作分为若干遍。当一遍中包含若干阶段时,各阶段的工作是穿插进行的。
2.5 为什么是汇编语言
**两个问题:**1、为什么要转化为汇编语言;2、为什么不直接写汇编语言
答案:
- 优点:汇编语言大大提高了编程的速度和准确度
- 缺点:编写起来也不容易 , 阅读和理解很难;而且汇编语言的编写严格依赖于特定的机器,所以为一台计算机编写的代码在应用于另一台计算机时必须完全重写。
3. 词法与文法
3.1 词法
单词构成句子,有句子才有语法。
因此想要理解文法,我们只能先来看看词法------单词是如何由字母构成的。
3.1.1 字母表与符号串
字母表是也就是字母集合,字母就是构成单词的基本。
我们平常所说的单词例如:abandon、abuse🤓,本质都是符号串,因此这里就将研究扩展到符号串,而不仅仅是英语单词。
一句话理解:
- 字母表:字母构成的集合。
- 符号:字母表集合中的元素
- 符号串:符号构成的序列(可以为空)
3.1.2 构成符号串
**词法研究目的:**研究字母如何构成单词 抽象化后 研究符号如何构成符号串
**思考逻辑:**如果掌握符号构成符号串的规则,我们就能够知道每一个符号串是否满足构成规则,那么判断符号串是否正确也就不在话下了。
**构成符号串:**符号运算法则
到这里我们就不难将符号串和符号联系起来了------符号通过运算能够变为符号串
3.2 什么是文法?
想想我们是如何把汉语翻译成英语的😀
首先,我们要知道汉语的语法,然后知道英语的语法,这让我们翻译时句子是正确的。
然后,我们需要明白汉语的语义,然后明白英语的语义,这让我们翻译时句子内在含义是对应的。
编译器想要把一种语言转变为另一种语言,自然就需要明白前者的语法规则,然后再明白后者的语法规则。因此,明白语法一定是编译器的一个大工程。
而描述一门语言语法规则的工具就是------文法
下文开始,不再特别区分语法和文法
**浅表理解:**文法就是规范化、格式化后的语法。文法就是语法的抽象化定义。
举个语法的例子,假如有一句话叫"我是大学生",按照语法来说是"主谓语法"。
主谓语法的特点描述如下:
这说明描述语法规则可以用:产生式+推导
3.2.1 推导与产生式
上面的语法规则可以用产生式+推导来描述。
推导:
- 推导是在文法规则的右边进行选择的一个结构名字的替换序列。推导以一个结构名字开始并以记号符号串结束。
- 最左推导:它的每一步中最左的非终结符(可以理解为:还有其他产生式展开它的符号)都要被替换的推导。
- 最右推导:它的每一步中最右的非终结符都要被替换的推导。
- 最左推导和与其相关的分析树的内部节点的前序编号相对应;而最右推导则和后序编号相对应。
产生式:
- 文法规则也被称为产生式。
产生式+推导描述语法规则的具体过程如下:
这是对形式上句子结构的定义,并没有涉及语义问题。
语法: 仅仅考虑固定的语句结构,单词是否按照结构要求的去填写,另一种理解是上下文无关上是否合适。语义: 考虑填入语句结构中的单词本身是否合适(单词语义是否合适),另一种理解是上下文关系上是否合适。
3.2.2 语法树
看到前面用产生式,以及产生式之间的推导关系来描述语法规则,我们不难想到树结构。
产生式+推导 本质上 与树的层层展开 内在逻辑是一样的。
具体见下面VCR😳😳:
3.2.3 文法的定义
- 非终结符:在推导中必须被进一步替换的结构名(还能再展开的符号)。
- 终结符:终结推导的字母表中的符号(不能再展开的符号)。
- 产生式:文法规则也被称为产生式。
- 开始符号:定义就是Z,所有文法从它开始。
(什么,你问我为什么是Z!!!!!!)
你去问问我们的乔爷吧,他发明的☹️☹️
3.2.4 文法的分类
根据语言文法的难易程度分类(乔姆斯基分类结构):
4类:分为0型,1型,2型,3型文法😋
- 0型文法为:无限制文法
- 1型文法为:上下文有关文法
- 2型文法为:上下文无关文法
- 3型文法为:正则文法
4个文法的定义是逐渐增加限制的,也就是语法规则越来越简单 。
怎么理解呢?
- 乔老认为所有的语言(广义的,只要是描述工具都是语言)都是这四种文法中的一种。
- 不同类型的文法表达能力不同,复杂性也不同。
- 对于我们程序语言(java、c等)来说,2型文法已经是极限了,甚至3型的表达能力就够了。
- (不然,你以为为什么我们一个学期就学会了C语言,活了十来年了都没学会英语🥹🥹)
3.2.5 上下文无关文法
我们提过文法就是语法,是用来描述语言的语法规则的。
文法分为四种:
- 0型文法为:无限制文法
- 1型文法为:上下文有关文法
- 2型文法为:上下文无关文法
- 3型文法为:正则文法
同时,也提到越往下文法的表达能力越弱。
这里,猫猫直接说明:上下文无关文法在编译原理中很重要
显然不选择正则文法是因为表达能力太弱,不选择上下文有关文法是因为词法分析时压根不用考虑上下文(别给自己上强度了😅)
简单说说,正则文法 和 上下文无关文法的联系区别:
- 正则文法不允许产生式中有递归,上下文无关文法允许有递归。
- 正则文法和上下文无关文法的产生式都不用考虑其他的产生式怎么写,这不是他们的条件(无关性的体现)
递归:
正则定义与上下文无关文法的重要区别在于,在正则定义中是不允许递归定义的 ,例如A → aA|b不是一个正则定义,为其左边的A必须是一个新的符号,也就是说不能在其他地方定义过,但是其右边要求每一个符号都是定义过的,因此这个定义无法满足。而上下文无关文法则没有这个约束,因此A → aA|b是一个上下文无关文法的产生式,但不是正则定义的定义式。
正则文法又叫:线性文法。因为没有递归,文法的推导是一路向下的。
无关性:
上下文无关文法的特点:
上下文无关文法(CFG)示例:
S → (S)S | ε
解析:
S
是文法的开始符号,代表一个合法的平衡括号字符串。S → (S)S
表示一个合法的括号串可以由一个打开括号(
,接着是一个合法的括号串S
,再接着是一个闭合括号)
,最后再跟随一个合法的括号串S
。S → ε
表示空字符串也是一个合法的括号串,因为没有括号也符合平衡括号的要求。例子:
(())
:这是一个合法的平衡括号字符串。可以通过S → (S)S
规则推导得到:
S → (S)S
- 对第一个
S
继续应用S → (S)S
,直到得到S → ε
,从而形成空字符串。- 结果是
(())
。
()
:同样是合法的括号字符串,符合S → (S)S
规则,推导中直接应用S → ε
。
(()())
:同样是合法的,推导过程类似。为何它是上下文无关文法:
- 每条产生式的左侧是单个非终结符
S
,没有依赖于它所处的上下文。也就是说,无论S
出现在哪里,它的替代规则都不受上下文的影响。- 这种类型的文法只依赖于单一的非终结符来进行推导,符合上下文无关文法的定义。
上下文有关文法的特点:
- 规则的形式 :上下文有关文法的产生式规则通常形如
αAβ → αCβ
,其中:
A
是一个非终结符。α
和β
是任意的字符串(可以为空)。C
是一个终结符或非终结符。- 该规则意味着
A
可以被C
替换,但前提是A
前面是α
,后面是β
。上下文有关文法的示例:
假设我们要描述一个语言,该语言包括一些特定的字符,且要求某些字符只能在特定上下文中出现。例如,假设我们有如下要求:
- 字符
a
只能在b
后面出现,反之,字符b
只能在a
后面出现。我们可以设计如下的上下文有关文法:
S → aSb | ε bS → ab | ε
解释:
S → aSb
:表示在某些上下文下,a
后面可以跟着一个S
,然后是b
,并且这段串可以继续扩展。bS → ab
:表示在b
后面,S
可以被替换成ab
,这是一个更加具体的约束,保证了b
只能在a
后面出现。S → ε
:表示空字符串是一个合法的字符串。例子:
字符串
ab
:
S → aSb → ab
。S → ε
,因此ab
是合法的。字符串
ba
:
- 不能通过规则生成。因为没有规则允许
b
直接在a
前面。为什么这是上下文有关文法?
这个文法是上下文有关的,因为其产生式中的规则
bS → ab
依赖于符号b
出现在某个上下文中(即在S
前面)。这表明,S
被替换的规则不只是取决于单个符号,还需要考虑其前后文(即上下文)。上下文有关文法的替代规则通常不会像上下文无关文法那样简洁,而是需要依赖于符号的周围环境。
3.2.6 推导与语法树
在上一篇文章:【编译原理】编译原理知识点汇总·概论与文法-CSDN博客 中,我们提到了语法树的概念。说到 产生式+推导 的结构相当合适用树来描述,因此语法树很适合用于语法规则的描述。
3.2.6.1推导与树的生长
例如一个文法句型如下:
其推导过程可以转化为树的生长过程,如下:
由此可见:树的生长过程就是语法产生式的推导过程。
再例如一个文法如下:
文法G[E] :E->E+E | E*E | (E) | i ,字符串 i+i*i
构建相应的语法树(最左推导)为:
E->E+E->i+E->i+E*E->i+i*E->i+i*i
3.2.6.2 推导的类型
前面,我们一直没有涉及这个知识点:推导的类型
先给个定义:
我们讲语法,讲抽象后的文法,讲产生式与推导
其实,这里我们默认推导都是最左推导
但是推导不止有最左推导,还有最右推导,并且两者还存在一点点的区别。
最右推导见下图:
文法:
最右推导:
最左推导:
接续上面的文法,从最左推导转为最右推导为:
E->E+E->E+E*E->E+E*i->E+i*i->i+i*i
看到最左推导和最右推导的语法树是相同的。
事实确实如此,对于没有左递归等特性的文法,语法树就是相同的 。
3.2.6.3 归约与推导
定义:
3.2.6.4 语言与文法
任何一个文法(语法)都能够产生一个独属于这个文法的语言(广义上的语言)。
因此,语言的定义如下:
Z:文法开始符号
G(Z):一个文法
L(G【z】):文法所产生所有句子的总和
3.2.6.5 二义性文法
这里猫猫想要借 语法树 引入另一个概念 二义性文法。
首先,来回顾一下语法树:
然后,来看文法二义性的定义:
对于二义性的判断只能是必要而非充分的。
如果对一个文法测试后其没有二义性并不能说明其一定没有二义性。
例如文法如下:
该文法存在二义性:
上文说到:文法二义性不可判定😢😢(那可怎么办~~呜呜呜)
但是有一些充分性的方法可以使用:
给语法增加限制条件要求,只要语法满足这些要求,那么他一定是非二义性文法
比如上面这个语法树,只要限制好他的结合性(左结合还是右结合),就可以将语法树限制为一个,文法也就没有二义性了。
总结·消除二义性文法方法:
- 设置规则,即消除二义性规则(如优先级规则 和 结合性规则)
- 将文法改变成一个强制正确分析树构造的格式
4. 习题
1 编译是对()。
A. 机器语言的执行
B. 汇编语言的翻译
C. 高级语言的翻译
D. 高级语言程序的解释执行
2 用高级语言编写的程序经编译后产生的程序叫( ).
A. 源程序
B. 目标程序
C. 连接程序
D. 解释程序
3 ( )不是编译程序的组成部分。
A. 词法分析程序
B. 代码生成程序
C. 设备管理程序
D. 语法分析程序
4 源程序是句子的集合,( )可以较好地反映句子的结构。
A. 线性表
B. 树
C. 完全图
D. 堆栈
5 编译程序是一种( )。
A. 汇编程序
B. 翻译程序
C. 解释程序
D. 目标程序
- A. 汇编程序:汇编程序是一种将汇编语言代码翻译成机器语言的程序。它的功能比编译器要低级一些,因为汇编语言本身已经是接近机器代码的语言。
- B. 翻译程序:编译器是一种翻译程序,它的作用是将源代码翻译成目标代码。编译程序通常会对整个源代码进行分析并生成目标程序。
- C. 解释程序:解释程序(Interpreter)与编译程序不同,它不会将整个程序翻译成目标代码,而是逐行执行源代码。解释器通常不生成目标程序。
- D. 目标程序:目标程序是编译后的代码(机器语言),而不是程序本身,编译器的输出是目标程序。
6 按逻辑上划分,编译程序第三步工作是( )。
A. 语义分析
B. 词法分析
C. 语法分析
D. 代码生成
7 编译程序中语法分析器接收以( )为单位的输入。
A. 单词
B. 表达式
C. 产生式
D. 句子
8 编译过程中,语法分析器的任务就是( )。
A. 分析单词是怎样构成的
B. 分析单词串是如何构成语句和声明的
C. 分析语句和声明是如何构成程序的
D. 分析程序的结构
9 语法分析时所依据的是( )
A. 语法规则
B. 词法规则
C. 语义规则
D. 等价变换规则
10 通常一个编译程序中,不仅包含词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成等六个部分,还应包括( )。
A. 表格处理和出错处理
B. 解释器
C. 模拟执行器
D. 符号执行器
11 编译程序绝大多数时间花在( )上。
A. 词法分析
B. 目标代码生成
C. 出错处理
D. 表格管理
5. 总结
本文到这里就结束啦~~
本系列专栏将专注于【编译原理】知识。
内容包括:知识点讲解、习题练习、重点知识带练等
期待您的关注~~🥰🥰
猫猫陪你永远在路上💪💪
如果觉得对你有帮助,友友们可以点个赞,收个藏呀~