编译原理随笔资料

编译总过程

编译翻译汇编 翻译: 编译(翻译高级语言):将高级语言翻译成汇编语言,或将高级语言翻译成机器语言
汇编(翻译汇编语言):将汇编语言翻译成机器语言 转换(也被称为预处理):高级语言之间的翻译,如FORTRAN到ADA的转换
编译:高级语言可以直接翻译成机器语言,也可以翻译成汇编语言,这两个翻译过程称为编译 汇编:从汇编语言到机器语言的翻译被称为汇编
交叉汇编:将一个汇编语言程序汇编成为可在另一机器上运行的机器指令成为交叉汇编 反汇编:把机器语言翻译成汇编语言
反编译:把汇编语言翻译成高级语言
在这里插入图片描述

语言处理的主要工作流程: 源代码→ 预处理器→ 编译器 → 目标代码→ 链接器 → 可执行程序

1 处理器(预处理):作用是通过代入预定义等程序段将源程序补充完整。把存储在不同文件中的源程序聚合在一起,把被称为宏的缩写语句转换为原始语句。
2 编译器(前端语法语义分析形成抽象的语法树,后端优化中间代码生成目标代码)进行语法分析,也就是要把那些字符串分离出来。然后进行语义分析,就是把各个由语法分析分析出的语法单元的意义搞清楚。最后生成的是目标文件,也称为obj文件。
3 链接器(链接):一组目标文件,不必是同一编译器产生,但使用的编译器必需采用同样的输出格式,可以链接在一起并生成可以由用户直接执行的EXE,所以我们电脑上的文件都是经过编译后的文件
在这里插入图片描述

编译器流程
在这里插入图片描述
词法分析:把源代码分割成一个一个的词法记号
语法分析:识别程序结构,生成语法树
语义分析:给语法树添加信息,用于生成正确的目标代码
生成中间码:节省工作量,解放生产力,增加灵活性
优化:让程序跑得更快
语法和语义结合称为语法制导翻译
1> 词法分析:词法分析的输入是源程序,输出是识别出的记号流.目的是识别单词. 至少分以下几类:关键字(保留字)、标识符、字面量、特殊符号
2> 语法分析: 输入是词法分析器返回的记号流,输出是语法树.目的是得到语言结构并以树的形式表示.对于声明性语句,进行符号表的查填,对于可执行语句,检查结构合理的表达式运算是否有意义.
3> 语义分析:根据语义规则对语法树中的语法单元进行静态语义检查,如类型检查和转换等,目的在于保证语法正确的结构在语义分析上也是合法的.
4> 中间代码生成:生成一种既接近目标语言,又与具体机器无关的表示,便于代码优化与代码生成.
5> 中间代码优化:局部优化、循环优化、全局优化等;优化实际上是一个等价变换,变换前后的指令序列完成同样的功能,但在占用的空间上和程序执行的时间上都更省、更有效
6> 目标代码生成:不同形式的目标代码—汇编语言形式、可重定位二进制代码形式、内存形
在这里插入图片描述
在这里插入图片描述

词法分析 :
(1) 记号、模式与单词
单词的分类:关键字(保留字)、标识符、字面量、特殊符号
模式 (pattern):产生/识别单词的规则
记号(token):按照某个模式(或规则)识别出的元素(一组)<种别码,属性值>
单词:被识别出的元素的值(字符串本身) ,也称为词值
(2)词法分析器的作用:
1> 识别记号并交给语法分析器(根据模式识别记号)
2> 滤掉源程序中的无用成分,如注释、空格和回车等
3> 处理与具体平台有关的输入(如文件结束符的不同表示等)
4> 调用符号表管理器和出错处理器,进行相关处理
举例:输入int a=123;(分词化->归类->输出已归类构成的字符的流)
处理后输出:(type1,int)(type2,a)(type3,=)(type4,123)(type5,;)
具体正确输出如图
有的一词一码,有的则需要除了种别码之外的属性值标识,例如123<INT,123>
在这里插入图片描述
词法分析器(扫描器)以字符流为输入,对其进行扫描和分解,产生多个 token(单词、符号),这个过程叫做 tokenize(分词化)。接着,这些 token 被归入对应的词类,最后再输出由已归类单词构成的流(形如(typeA,“str1”),(typeB,“str2”),(typeA,“str3”),(typeC,“str4”)…)
lex程序可以实现词法分析,它会按照用户之前扫描害的词法规则将输入的字符串分割成一个个记号。因为这样一个程序的存在,编译器开发者就无需为每一个编译器开发一个独立的词法扫描器,而是根据需要改变词法规则就可以了。
一段源代码进入编译器,被词法分析器接收,词法分析器将源代码分割成单个字符,根据字符表组合关键字,比如:它知道一个符号序列’i’、’f’是一个关键词”if”,而一个符号序列’1’、’2’、’3’、’4’是一个常量”1234”等等。但是,它不能知道他们之间的关系,例如:”int”、”x”、”=”、”1”、”;”,词法分析器不知道它是一个语句;它不能检测出它的语法错误。
编译器在扫描代码里的句子的时候,会过滤掉空格以及注释,将其中出现的字符一个个分割开来,并且将其分类,以便在后面构建语法树的时候能够对号入座。
记号一般分为如下几类:关键字、标识符、字面量(数字和字符串等)以及特殊符号(如+,= …)

语法分析 (生成语法分析树)
在经过词法分析之后,源文件的字符流变成了一个个可以被计算机识别的token,接下来就是用这些token构建出语法树,根据语法树和语法规则的对比,判断是否出现语法错误,并且一门语言的抽象程度,很大程度就是根据语法树的好坏和token的划分决定的
这两步的目的是检查代码里是否有出现比较明显的语法错误。比如说我们在初学c语言时最常出现的语法错误就是忘记在语句后面加上”;”符号,这一类错误将会在构建语法树的时候被检查出来。语法分析仅仅只是完成了对表达式的语法层面分析,但是它并不能确定这个语句是否真正有意义
在这里插入图片描述

语义分析:语义是指源程序及其组成部分所表述的含义,和语法不同,语法是关于程序及其组成部分的构成规则的描述,是上下文无关的;而语义是关于语法结构的含义及其使用规则的描述,是上下文有关的。语法上正确,其语义不一定正确。语义分析与中间代码生成器基于语义规则,对语法树进行语义分析(变量是否定义,类型是否正确)和中间代码生成(三元式、四元式等)。 主要功能包括建立符号表,进行静态语义检查,发现语义错误
编译器分析的语义都是静态语义,静态语义是指在编译器间可以确定的语义,与之对应的动态语义只能在运行期间才能被确定。
静态语义分析通常包括声明、类型匹配、类型转换等。经过语义分析之后,在语法分析生成的语法树的基础上进一步对表达式做一些标识。如:有些某些类型需要做隐式转化,语义分析器会在之前的语法树中插入相应的转换节点
在这里插入图片描述 2.语义描述
程序的语义,函数的语义,各种名字的声明和使用的语义, 各种语句的语义,表达式的语义
3.符号表
在编译程序工作的过程中,需要不断收集、记录和使用源程序中的各种名字及其属性等相关信息,以便检查语义是否正确,并辅助翻译为正确的代码。一般是建立表格的方式记录信息。
功能1)收集符号信息 2)进行语义的合法性检查
符号表应该包含常量表、变量表、函数表等等。
常见的语义错误主要有
在这里插入图片描述

中间代码生成
为什么不直接翻译成机器码呢,而多此一举生成中间代码再转换?
是为了提高编译器的可移植性,因为不同的cpu的指令集是不一样的,假如直接翻译成机器代码,那么当你换了一块cpu之后,可能你的编译器就完全不能运行了,所以为了鲁棒性,将代码先翻译成中间代码,然后在能在多个不同的cpu上做出相应的改变并且运行了。
使用中间代码的好处:
1)一是便于编译器程序的开发和移植
2)二是代码进行优化处理
常见的中间代码表示
后缀式、树、三地址码等
最基本的中间代码形式是树;
最常用的中间代码形式是三地址码,它的实现形式常采用四元式形式。在这里插入图片描述在这里插入图片描述

代码优化
并且在中间代码到目标代码的过程中,许多数据科学家发明了很多可以提高代码运行效率的算法,这个就是编译原理中重要的代码优化部分
优化的分类:
机器无关优化 :针对中间代码
机器相关优化 :针对目标代码
局部代码优化 :单个基本块范围内的优化
全局代码优化 :面向多项基本块的优化
优化和变形的目的:
减少代码的长度,提高内存,缓存的使用率,减少读写磁盘 。
常见的优化方法有:函数内嵌,无用代码删除,标准化循环结构,循环体展开,循环体合并 ,删除公共子表达式 ,删除无用代码,代码移动
在这里插入图片描述

目标代码生成:以源程序的中间表示形式作为输入,并把它映射到目标语言
代码生成器:将此前的中间代码转换成特定机器上的机器语言或汇编语言
在这里插入图片描述

补充编译器

编译器、解释器定义(将高级语言或汇编语言的代码转换成机器认识的代码)机器不能理解我们用高级语言编写的代码,所以要在程序执行前将高级语言“翻译”为机器语言。这是一个将源语言程序转化为目标语言程序的过程,它依靠翻译程序来完成。

编译器:将编译型语言(C++,Go)翻译为机器语言。(工作效率高,即时间快、空间省;交互性与动态性差,可移植性差)
在这里插入图片描述解释器:将解释型语言(JavaScript、Python)翻译为机器语言。(工作效率低,即时间慢、空间费;交互性与动态性好,可移植性好)

编译与解释的比较
(1)编译程序会产生目标程序;而解释程序不产生目标程序;
(2)编译程序实现起来比较复杂;而解释程序本身实现起来比较简单;
(3)编译程序效率比较高;而解释程序运行效率比较低,需对语法、词法、语义等进行检测;
编译是将源代码经过分析后生成语法树,再优化生成中间代码,最后生成机器码。编译的结果是生成一个可执行的二进制文件;
而解释也是将源代码经过分析后生成语法树,只不过此后它是基于语法树生成字节码,再根据字节码去执行程序。它并不会生成目标文件,更多的是一个结果。在这里插入图片描述
在这里插入图片描述

解释型语言和编译型语言
相同之处:都需要转换成二进制才能执行。
不同之处:
1、运行的时候是否需要编译器
编译型语言运行的是最终的二进制代码了,所以不再需要编译器;但是解释型语言边解释、边运行,所以运行时候还有部分代码没有解释好举个例子:在浏览器里,要看 html 效果,要通过带有内置编译工具的软件去查看(如:浏览器或者模拟浏览器的工具)。
2、执行速度
毫无疑问边翻译边执行的解释型语言的速度会比编译型语言运行速度要慢。但是CPU的运行速度如果很快,你可能看不出来,偶尔会看到“有点卡”的效果。
3、可移植性对比
编译型语言运行二进制内容,一旦 CPU 指令改变,之前的二进制文件可能运行不了了。即在其他硬件平台上运行,可能出错,如果想在其他平台运行就需要编译出新的二进制文件,所以编译型语言可移植性差;解释型语言在需要的时候才开始编译、运行,所以具有可移植性,在很多平台都能运行起来。
4、升级上对比
编译型语言的二进制文件如果要升级,需要重新下载一个新的二进制文件了。如QQ的升级,就是要重新下载、安装、覆盖;
而解释型的语言,只要重新写好源代码即可。如网站平台升级,用户只要重新刷新即可。
5、 应用领域
编译型语言应用领域通常是安装软件,如:桌面或手机上安装软件;
解释型的语言的应用领域通常是互联网,网站等,刷新就可以看到最新效果。

词法分析
在这里插入图片描述编译原理之文法篇

前几天搜了一些编译相关知识点做成一个word文档,今天想在博客上整理一下,但由于当时没有标明出处,若有侵权,请联系我删除相关博客

某手写笔记https://blog.csdn.net/qq_40237865/article/details/94764491

发布了142 篇原创文章 · 获赞 0 · 访问量 2613

猜你喜欢

转载自blog.csdn.net/yunxiu988622/article/details/105021880
今日推荐