斯坦福大学CS143编译原理课程笔记:2.编译器结构
目录
编译器的五个阶段
五个阶段的作用
1.概念
2.词法分析
3.语法分析
4.语义分析
5.代码与内存优化
6.代码生成
编译器的五个阶段
1.词法分析
2.语法分析
3.语义分析
4.代码与内存优化
5.代码生成
五个阶段的作用
1.概念
如有如下句子
这句话里共有四个单词,想要表达的意思是这是一个句子,用我们让的话一眼就能看清楚这个句子有几个单词,并且能够理解这些单词组合成句子是什么意思,This is a sentence翻译过来就是这是一个句子。
我们人在看这个句子时是以空格作为分隔单词的分隔符,同时把单词连起来组成一个句子,就知道这段英文想要表达什么意思。
程序也一样,程序在分析这段英文句子时也要通过分隔符来识别出这句话里有几个英文单词,然后在将英文单词按顺序连接起来,组成一个句子,然后在理解这段话的意思。
首先程序会先通过分隔符取出四个单词:
取出后在以从左往右打顺序理解这四个单词:
1.This 这
2.is 是
3.a 一个
4.sentence 句子
然后把每个句子组成起来就是:这是一个句子
程序就理解了这段话的意思,程序就知道了:噢!这段话是想告诉我这是一个句子
程序会先把This is a看成关键字,sentence看成名称或者其它目标语句。
This is a作为关键字的功能是描述一个东西,后面跟着的单词就是要描述的东西,那么程序就知道这句话是在描述一个物品或者东西。
那么程序是怎样知道这句话已经到达末尾了呢?因为我们可能会输入多个物品,不光sentence也可能有book,注意这句话
This is a sentence. 末尾有一个.
这个.代表这个语句的结束,和我们人一样,程序是人设计的,它带着设计者的思想。
当然如果你给程序一个单词:This is a
程序就蒙了,因为程序是让设计的,它所认知的一切都是人给的,This is a程序就会思考你是不是没有输入目标语,就会报错给你,因为关键字后面没有跟着单词,程序会问你是不是没有输入完?然后给你提示几个你可能想要输入得单词:如 pig、sentence等!
当然如果你给它:This is a dog,如果程序的设计者没有告诉它dog是什么的话,那么它就会报出不认得dog,这就是根据错误类型来报错。
当出现了设计者没有告知的错误类型时,则会报出通用的未知错误。
但是当我们遇到了一些比较奇怪的句子:
这个字母顺序完全打乱了,我们如也需要时间和好好的梳理一下仔细看下这个句子,才能能够梳理出这句话中的所有单词:
This is a sentence.
但是对于程序我们人都很难梳理出的句子,那么程序就更难了,所以程序的设计者一般不会让你这么胡乱去输入一段句子。
2.词法分析
词法分析的目标就是我们输入的代码文本按照编译器的方式进行分词,也就是按照编译器的
词汇表进行分词。
如这段代码
可以看到有:if、then、else这样很明显的词法单元,词法单元也叫关键字。
除此之外也可以看到有变量名:x、y、z
同时也有一些常量1、2
还有双等号以及赋值运算符
不光如此,分号以及其它标点符号都属于词法单元。
至于其它标点符号在词法单元中属于什么作用,看编译器的设计者,如常见的c语言里分号“;”代表一行语句的结束,而“,”逗号代表多个参数,或者多个定义,在或者函数的参数分割符。
如空格这段代码中使用了大量的空格来将关键字与变量以及常量和运算符分开,从而能让编译器更好的识别出这段代码中的词法单元。
3.语法分析
与人一样,当从发现这段句子中的所有单词后就需要去理解这些单词组成这段句子是什么意思,就是去理解这段句子的结构。
编译器也一样,当把一行代码中的关键字以及变量和所有的可能出现的运算符分析完成之后,会交给语法分析系统,那么语法分析系统就会开始对这段代码进行理解。
如开头是if,那么语法分析会认为这是一个条件判断的代码,那么就会开始寻找剩下的关键字里是否是then else,或者只有then没有else,没有else的情况下就是我们不需要否则的条件,从而确定条语句是想要干什么,每个关键字的作用以及变量在这段语句中起到怎样的作用。
这和图解句子结构一样。
语法分析久是去每个单词在句子中担任的角色
每个单词分析后就有了名词,动词,以及形容词
在语法分析每个单词的作用之后,就会将它们组成更高级的结构
如上图所示,包含了主语,动词,以及宾语
This line 就是主语,代表主题,longer sentence代表的就是obect,物体
组成更高级的结构后就是关键字是:描述,既然是描述,那么对象就是:sentence
其次还有一些名词以及动词用来辅助这段句子,形容词用来形容这个物体,
如longer形容比较长的,代表这个物体比较长,而sentence代表物体,它的含义是句子, a是冠词,用来帮助说明名词所指的人/物,以及该名词的具体含义。
而This line代表主语的这行,而后面的is动词是用来描述人与事务的,语法分析会将它们分割开,将其组成主语,动词和目标,通过主语(this line)确定这个句子想要描述的行为,通过动词(is)来确定要描述的是事务或者人,在通过对象(a longer sentence)来确定要描述的是什么物体以及物体的特征行为。
这样就组成了一个树
从树根(sentence)以及向上从左往右子节点以及展开分析,从而确定这个语句想要表达的意思。
从理论上来说,其实词法分析和语法分析是一样的。
如:
还是这段代码,语法分析结果是它是一个if-then-else语句,会将它分解成如下树节点
if-then-else代表根
if-then-else有三个子节点
1.predicate条件判断语句
2.then条件成立语句
3.else条件不成立语句
除此之外predicate也会生成子节点,字节点里包含了条件表达式
x == y就组合在一起就成了一个逻辑表达式,它是predicate的子节点,子节点代表predicate想要对什么进行判断。
而then-stmt也会生成一个子节点,子节点中包含了当relation成立时的语句
一个简单的z = 1的赋值运算
同时在else-stmt中也会生成子节点,包含了relation不成立时的语句
z = 2的赋值运算
if-then-else这句语句经过语法分析后就会生成这样的树节点
语法分析的作用就是将词法分析的结果,在分析为一个结构,然后在根据数据结构的定义将这句话以主语,对象等这样的结构方式打包成一个树结构,这样后面理解这段代码时可以轻松的从结构中得知这句话的行为以及要产生这样行为的目标。
4.语义分析
当我们有了语法分析的结构后,我们就要去理解这个结构想要干什么,也就是去理解这段话的意思。
相比人类,程序要理解一段话的意思更难,它能做的语义分析是非常有限的,它只能去找出一段话中矛盾的地方,并告知这些矛盾点。
编译器不会知道程序真正想要做什么,比如上面的if-then-else语句,编译器只知道你要进行条件判断,但不知道你条件判断是为什么,但是现在许多现代编译器已经具有理解上下文的功能,并且能帮你推到出最优写法,并且能告知你一些写法的风险。
最简单的例子是如下:
jack said jerry left his assignment at home(杰克说杰瑞把作业忘在家里了)
这里的his是指他,这里的他是指向谁?
可以指jerry,如果是指jerry,那么这句话的意思就是jack说杰瑞把作业忘在家里了。
但是也可以指向jack,也可以说jack说jerry把他(jack)的作业落家里了。
在没有更多的信息下,我们不知道这里的his是指谁,那怕是在做英语作业有这样的题,即便是人也会不知道如何去翻译。
甚至更糟糕的情况是如下这个句子:
jack said jack left his assignment at home(杰克说杰克把作业忘在家里了)
这句话中总共有多少人?最多可能会有三个,因为可能有两个不同的人都叫jack,his指向别人,这个名字没有在句子里出现的。
也可能只有一个人,这里的jack和his都指向同一个人
在语义分析中这种歧义是确实存在的。
类似的在编程语言中就是变量绑定的问题
如上面有两个jack变量,都是int,理论上来说编译器会严格指定规则去防止开发者们去编写之前那样句子里难以理解的歧义问题。
打印结果是4
因为下面的jack被作用域词法单元分割开了,这是编程语言的一个规范,但是仅限于带有作用域词法单元的编程语言,如c语言,c语言会优先选择在同一作用域下的变量。
其次类型检查也一样,这里有一个句子
jack let her homework at home(杰克让她在家做作业)
基于命名规范我们可以知道jack是指男名,男生,而her是指女性的意思,所以我们可以确定这段谈话中是指两个人,这里的her肯定不是指jack,这里就出现了类型不匹配,这就是语义分析也要做的工作,类型检查
就像函数参数一样
int add(int a,int b);
你在输入时输入
char类型的作为参数,那么编译器通过语义分析就会报出类型不匹配。
很明显add要求的是int,你输入的是char,这里语义分析就知道了,参数里你输入的char不匹配规则。
语义分析的作用就是去理解结构的含义同时也要去做变量类型检查,但是语义分析只会去理解语句的含义,不会去理解程序想要干什么,它只管语句的含义,比如if-then-else,它只理解这句话想要做条件判断,不会去管为什么做条件判断这样的问题。
5.代码与内存优化
这个步骤很像编辑工作,将一段长长的文章删减成一个非常短小的文章,但是文章内容意思不变。
如这句话:
But a little bit like editing(但有点像编辑)
这句话非常长,我们其实看用akin to来替代中间的四个单词
But akin to editing(但类似于编辑)
很明显词汇量变少了,且意思不变,阅读起来更加快速了。
程序优化和上面一样,目标就是修改代码使之使用更少的资源
程序优化可以有许多目标
1.更快的运行时间
2.减少内存使用,让我们能存储更多的数据
3.移动设备的耗电量
4.如果我们是网络设备则减少发送数据的大小,降低流量消耗
5.数据库程序则减少对数据库的访问提升程序性能
这里通过一个简单的粒子来表示一个程序可能要进行的优化
很明显,x=y*0,最终结果是0,我们编译器可以将它优化为x=0,这样可以省去计算工作,节省更多的运行步骤。
但很不幸这不是一个正确的优化
我们需要理解编译器的一个规则,那就是针对浮点数的运算,以上结果只针对integer类型,因为整数乘上0,结果就是0,针对浮点数是不行的
这里要设计到IEEE标准化的一些规定,一个特殊的number(数字)不能被称为number,特殊的数字被称为nan
任何nan*0都等于nan,所对于浮点数来说我们不能这样优化,这样会破坏IEEE标准的算法逻辑,
当nan是字符时是不能做运算的,所以返回结果是nan,对于nan的描述如下:
NaN 属性代表一个“不是数字”的值。这个特殊的值是因为运算不能执行而导致的,不能执行的原因要么是因为其中的运算对象之一非数字(例如, "abc" / 4),要么是因为运算的结果非数字(例如,除数为零)。
针对浮点数时,当浮点数小数为0时,则是number否则是nan
6.代码生成
这个阶段通常被成为Code Gen
总的来说就是将目标语言翻译成汇编代码,正如人工将英语翻译成法语一样,编译器会将高级程序转换为低级语言汇编代码,这里得高级语言是指开发效率快,能够被人快速认知得程序,越是接近人类容易理解得语言如接近数学表达式的编程语言都是高级语音,越是接近机器码,或者助记符这样的机器指令都不被人类容易理解的称为低级语言。
相较于较早的编译器FORTRAN它的阶段如下:
较为复杂的词法分析(L)和语法分析(P)系统,非常小的语义分析系统(6),一个相当复杂的优化阶段(o),一个相当复杂的代码生成阶段(cg)早期的编译器各个阶段复杂性相当平均,除了语义分析很弱之外。
但是现代编译器的变化比较大,它们的阶段复杂度如下:
词法分析和语法分析变得较小了,语义分析复杂的还算中等偏下,因为词法分析和语法分析现在使用工具代替了,现在核心放在优化上,然后还有一个小小的汇编代码生成。
斯坦福大学CS143编译原理课程笔记:2.编译器结构相关推荐
- 斯坦福大学CS143编译原理课程笔记:1.编译器与解释器简介
目录 前言 第一节课:编译器与解释器简介 线上与线下的概念 线上 线下 编译器与解释器的区别 编译器 解释器 FORTRAN 1结构 它包含五个阶段 1.词法 分析 2.语法解析 3.语义分析 4.优 ...
- 斯坦福大学CS143编译原理课程笔记:3.编译器的性价比
目录 编译器性价比的三个问题 为什么会有那么多编程语言? 科学计算 并行处理 商业领域 系统编程 为什么会有新编程语言的诞生? 1.广泛使用的编程语言会改变的很慢 2.很容易产生一门新的语言 3.使用 ...
- 斯坦福大学CS143编译原理课程笔记:4. Cool语言概述
目录 什么是Cool语言? 开始前的准备 COOL项目的五个步骤 COOL编程语言基本教程 文件属性 基本组成 如何运行 输入输出 变量定义 让我们来编译它 COOL语言换行符 COOL方法体续说 C ...
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记
最近开了一个新坑--[CS231n]斯坦福大学李飞飞视觉识别课程,准备认真学习并记录自己的学习历程. 文章目录 [CS231n]斯坦福大学李飞飞视觉识别课程笔记 课程笔记 学习安排 Week 1 We ...
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记(四):图像分类笔记(上)
[CS231n]斯坦福大学李飞飞视觉识别课程笔记 由官方授权的CS231n课程笔记翻译知乎专栏--智能单元,比较详细地翻译了课程笔记,我这里就是参考和总结. [CS231n]斯坦福大学李飞飞视觉识别课 ...
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记(六):线性分类笔记(上)
[CS231n]斯坦福大学李飞飞视觉识别课程笔记 由官方授权的CS231n课程笔记翻译知乎专栏--智能单元,比较详细地翻译了课程笔记,我这里就是参考和总结. [CS231n]斯坦福大学李飞飞视觉识别课 ...
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记(五):图像分类笔记(下)
[CS231n]斯坦福大学李飞飞视觉识别课程笔记 由官方授权的CS231n课程笔记翻译知乎专栏--智能单元,比较详细地翻译了课程笔记,我这里就是参考和总结. [CS231n]斯坦福大学李飞飞视觉识别课 ...
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记(十九):卷积神经网络笔记(下)
[CS231n]斯坦福大学李飞飞视觉识别课程笔记 由官方授权的CS231n课程笔记翻译知乎专栏--智能单元,比较详细地翻译了课程笔记,我这里就是参考和总结. [CS231n]斯坦福大学李飞飞视觉识别课 ...
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记(十一):反向传播笔记
[CS231n]斯坦福大学李飞飞视觉识别课程笔记 由官方授权的CS231n课程笔记翻译知乎专栏--智能单元,比较详细地翻译了课程笔记,我这里就是参考和总结. [CS231n]斯坦福大学李飞飞视觉识别课 ...
最新文章
- motan源码分析二:使用spi机制进行类加载
- andorid 开发笔记 -- 问题与解决
- java字面量 方法区_(一)java的内存模型
- 密码学系列之:IDEA
- SAP UI5 dialog style max-height
- 统计字符串每个字符出现的次数
- linux之睡眠函数(my_sleep)
- 最优化学习笔记(二)一维搜索
- Linux学习笔记014---文件及文件夹权限设置_以及文件、文件夹的删除_移动_复制操作
- IDEA+SpringBoot+Dubbo在webapp下创建前端页面
- 【干货】无人机如何进行倾斜摄影的航线规划
- 重置单例对象Singleton Swift
- 搜索RaySource资源的8大方法
- 【老骥伏枥-原创】制作黑威联通启动盘:进阶篇
- 老司机的HCIE战报
- APS生产计划排程(Production Planning and Scheduling)
- Win8下IE10安装Flex调试flashpalyer控件失败的解决办法
- word在试图打开文件时遇到错误,解决办法
- 手机怎么把照片转JPG格式?这三种手机小技巧需要知道
- 2023年全国最新工会考试精选真题及答案53
热门文章
- python编程心得体会-python核心编程____学习心得____part1
- html怎么用div从左到右,单独使用CSS,你怎么能有一个从右到左的边框底部渐变?...
- 开源私有云盘python_用Seafile不花钱搭建高安全性局域网私有云盘
- linux使用shell脚本利用expect工具实现SCP传输文件到多台服务器
- centos8 开启ftp服务
- 计算机网络考试卷2014B答案,计算机网络考试卷2014B
- apache camel 相关配置_Web基础配置篇(二): Maven配置及使用
- 电脑上玩和平精英_和平精英奇幻之旅怎么玩-和平精英奇幻之旅玩法攻略
- 人体轮廓_速写人体轮廓的处理有哪些技法?
- typora 语法教程