当前位置:首页 > 民俗文化

编译程序 人人都能读懂的编译器原理

了解编译器的内部原理可以让你更高效地使用它。根据编译的工作顺序,深入研究编程语言和编译器是如何工作的。本文有很多链接、示例代码和图表来帮助您理解编译器。

作者备注:

这是我第二篇关于媒介的文章的转载。上一版有21000多名读者。很高兴能帮到你的学习,所以我完全按照上一版的评论重新写了一遍。

我选择了Rust作为本文的主要语言。它详细、高效、现代,似乎让设计编译器变得很容易。我很喜欢用。https://www.rust-lang.org/

写这篇文章的主要目的是吸引读者的注意力,而不是提供20多页让人头皮发麻的阅读材料。对于那些你感兴趣的更深层次的主题,文章中有许多链接可以引导你找到相关信息。维基百科的大部分链接。

谢谢大家的关注。我花了20多个小时写的这些文章,希望你会喜欢。请在文章底部的评论部分留下任何问题或建议。

简单介绍一下什么是编译器?

你口中的编程语言本质上只是一个软件。这个软件叫做编译器。编译器读取一个文本文件,经过大量处理,最终生成一个二进制文件。编译器的语言部分是它处理的文本样式。因为计算机只能读取1和0,而且人们编写Rust程序比直接编写二进制程序简单得多,所以使用编译器将人类可读的文本转换成计算机可以识别的机器码。

编译器可以是任何可以将文本文件转换成其他文件的程序。例如,有一个用Rust语言编写的编译器,可以将0转换为1,将1转换为0:

一个

2

10

11

12

13

14

//将0转换为1,将1转换为0的示例编译器。

fn main(){

let input = " 1 0 1 A 1 0 1 3

//迭代输入中的每个字符` c '

让输出:String= input.chars()。地图(|c|

ifc = = ' 1 ' { ' 0 '

elseifc = = ' 0 ' { ' 1 '

else{c}//如果不是0或1,就不要管它

).collect();

普林。(" {} ",输出);// 0 1 0 A 0 1 0 3

}

编译器是做什么的?

简而言之,编译器获取源代码并生成一个二进制文件。因为将复杂的、人类可读的代码直接转换成0/1二进制非常复杂,所以编译器在生成可运行的程序之前有几个步骤:

从你给定的源代码中读取单个词。把这些词按照单词、数字、符号、运算符进行分类。通过模式匹配从分好类的单词中找出运算符,明确这些运算符想进行的运算,然后产生一个运算符的树(表达式树)。最后一步遍历表达式树中的所有运算符,产生相应的二进制数据。

虽然我说编译器直接从表达式树转换成二进制,但实际上它会生成汇编代码,然后汇编代码会被汇编/编译成二进制数据。汇编程序就像一种高级的、人类可读的二进制系统。这里有更多关于汇编语言的阅读材料。

什么是翻译?

解释器很像编译器。他们还阅读编程语言的代码,然后进行处理。但是,解释器跳过代码生成,然后立即编译并执行AST。解释器的最大优点是在调试过程中运行程序所需的时间。编译器可能在一秒到几分钟内编译一个程序,但是解释器可以不编译而立即开始执行程序。解释器最大的缺点是必须安装在用户的计算机上才能执行程序。

虽然本文主要是关于编译器的,但是需要明确编译器和解释器的区别,以及与编译器相关的内容。

1.词汇分析

第一步是逐字拆分输入。这一步叫做词法分析,或者分词。这一步的关键是我们把字符组合成单词、标识符、符号等等。词法分析大多不需要处理逻辑运算,比如计算2+2——其实这个表达式只有三个标签:一个数字:2,一个加号,另一个数字:2。

让我们假设您正在解析像12+3这样的字符串:它读入字符1、2、+和3。我们已经分裂了这些人物,但现在必须把他们结合起来;这是分词器的主要任务之一。例如,我们得到两个独立的字符1和2,但是我们需要将它们放在一起,并将其解析为一个整数。至于+,也需要识别为加号而不是它的字符值——字符值为43。

如果你能看懂上面的代码并理解这么做的意义,那么下一个Rust单词分隔符会把数字组合成32位整数,加号最后会标记出值Plus。

铁锈操场

您可以点击Rust playgroud左上角的“运行”按钮,在您的浏览器中编译并执行代码。

在编程语言的编译器中,词法分析器可能需要许多不同类型的标记。例如:符号、数字、标识符、字符串、运算符等。从源文件中提取什么标签完全取决于编程语言本身。

一个

2

10

intmain(){

inta

intb

a = b = 4;

返回-b;

}

扫描仪生产:

【关键字(Int),Id(“main”),符号(LParen),符号(RParen),符号(LBrace),关键字(Int),Id(“a”),符号(分号),关键字(Int),Id(“b”),符号(分号),Id(“a”),运算符(赋值),Id(“b”),

运算符(赋值)、整数(4)、符号(分号)、关键字(返回)、标识(“a”)、运算符(减)、标识(“b”)、符号(分号)、符号(跑道)]

对C语言的样例代码进行了词法分析,并输出了其标记

2.分析

解析器真的是语法解析的核心。解析器提取词法分析器生成的标记,试图判断它们是否符合特定的模式,然后将这些模式与表达式(如函数调用、变量调用和数学运算)相关联。解析器逐字定义编程语言的语法。

int a = 3和a: int = 3的区别在于解析器处理。语法分析器决定语法的外部形式。它确保括号和花括号的数量是平衡的,每个语句以分号结束,每个函数都有一个名称。当标签不符合预期模式时,解析器将知道标签的顺序不正确。

您可以编写几种不同类型的解析器。最常见的解析器之一是自顶向下、递归降级的解析器。递归退化解析器是最简单最容易理解的。我写的所有解析器示例都是基于递归降级的。

解析器解析的语法可以用语法来表示。像EBNF这样的语法可以描述解析简单数学运算的解析器,例如12+3:

一个

2

expr = additive _ expr

additive_expr= term,('+'| '-'),term;

术语=数字;

简单加减表达式的EBNF语法

请记住,语法文件不是解析器,而是解析器的表达式。您可以围绕上面的语法创建一个解析器。语法文件可供人们使用,比直接阅读和理解解析器代码简单得多。

该语法的解析器应该是expr解析器,因为它与所有内容的顶层直接相关。唯一有效的输入必须是任何数字,加号或减号,任何数字。Expr需要一个加法_expr,主要出现在加减表达式中。Additive_expr首先需要一个项(一个数),然后是一个加号或减号,最后是另一个项。

分析12+3产生的样品AST

解析器生成的树结构称为抽象语法树,简称AST。Ast包含要执行所有操作。解析器不计算这些操作,它只是以正确的顺序收集标签。

我之前补充了我们的词法分析器代码,让它和我们的语法匹配,可以像图形一样产生AST。我用//BEgin PARSOR//和//END PARSOR//的注释标记了新解析器代码的开始和结束。

铁锈操场

我们可以更进一步。假设我们要支持无运算符的数字输入,或者加除法和乘法,甚至加优先级。可以简单地修改语法文件,任何调整都会直接反映在我们的解析器代码中。

一个

2

expr = additive _ expr

加法_expr=乘法_expr,{('+'| '-'),乘法_ expr };

乘法_expr= term,{("*"| "/"),term };

术语=数字;

新语法

https://play.rust-lang.org/? gist = 1587 a5dd 6109 f 70 cafe 68818 A8 C1 a 883 & amp;版本=夜间& amp模式=调试& ampedition=2018

为C语言语法编写的解析器(也称为词法分析器)和样本解析器。" if(net >:0.0)total+= net(1.0+税/100.0);"扫描仪形成一系列标签并对它们进行分类,如标识符、保留字、数字或运算符。后一个序列由解析器转换成语法树,然后由其他编译器分阶段处理。扫描器和解析器分别处理规则和独立于上下文的C语法部分。引自:Jochen Burghardt。来源。

3. 生成代码

代码生成器接收一个AST,然后生成相应的代码或汇编代码。代码生成器必须以递归降序遍历AST中的所有内容——就像解析器工作一样——然后生成相应的内容,只是这里生成的不再是语法树,而是代码。

https://godbolt.org/z/K8416_

如果您复制并打开上面的链接,您可以在左侧看到示例代码生成的程序集代码。汇编代码的第三和第四行显示了编译器在AST中遇到常量时如何为常量生成相应的代码。

Godbolt编译器Explorer是一个很棒的工具,可以让你用高级语言写代码,查看它生成的汇编代码。您可能会有点困惑,想知道生成了什么样的代码,但不要忘记在您的编程语言编译器中添加优化选项,看看它有多智能。(-0代表生锈)

如果您对编译器如何用汇编语言在内存中保存局部变量感兴趣,本文(“代码生成”)将详细解释堆栈。大多数情况下,当变量不是局部变量时,高级编译器会在堆区为变量分配空,并保存在堆区而不是栈区。你可以从这个StackOverflow的回答中读到更多关于变量存储的内容。

因为编译是一个完全不同的复杂学科,这里就不多讨论了。我只想强调代码生成器的重要性和它的作用。另外,代码生成器不仅可以生成汇编代码。Haxe编译器有一个后端,可以生成六种以上不同的编程语言,包括C++、Java和Python。

后端指编译器的代码生成器或表达式解析器;所以前端是词法分析器和解析器。还有一个中间端,通常和优化和IR有关,后面会解释。后端通常独立于前端,只关心接收到的AST。这意味着相同的后端可以被多个不同的前端或语言重用。著名的GNU编译器集合就是这种情况。

找不到比我的C编译器后端更好的代码生成器例子;你可以在这里查看。

汇编代码生成后,会写入一个新的汇编文件(。s或。asm)。然后文件会传递给汇编器,汇编器是汇编语言的编译器,它会生成相应的二进制代码。之后,这些二进制代码将被写入新的目标文件(。o)。

目标文件是机器码,但不能执行。为了使它们成为可执行文件,目标文件需要链接在一起。链接器读取通用机器代码,然后将其转换为可执行文件、共享库或静态库。更多关于linkers的知识在这里。

链接器是根据操作系统而不同的应用程序。任何第三方链接器都应该能够编译后端生成的目标代码。所以写编译器的时候不需要自己创建链接器。

编译器可能有中间表示,简称IR。IR主要是在优化或翻译成另一种语言时,无损地表示原始指令。IR不再是原码;红外是无损简化,在代码中寻找潜在的优化。循环展开和矢量化都是通过红外完成的。更多关于IR相关优化可以在此PDF中找到。

总结

当你理解了编译器,你就可以更有效地使用你的编程语言。也许有一天你会对创造自己的编程语言感兴趣?希望这对你有帮助。

∑编辑|双子

来源|博乐在线

1.《编译程序 人人都能读懂的编译器原理》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《编译程序 人人都能读懂的编译器原理》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/guoji/1601113.html

上一篇

怎么治疗脸部疤痕 脸上有疤痕要怎么办?六种祛疤的方法你要知道!

下一篇

加加米 平成假面骑士扮演者如今怎样了,逼王成为奶爸,老司机充满哲学气息?

strength的动词 高中英语语法知识点总结:名词、主谓一致和冠词

高中知识搜索小程序 易错点1。看单词创造意义 同义词、近义词甚至近义词的含义和适用场合不同,要特别注意在具体语境中准确运用词汇和语法知识的能力。平时要尽量扩大词汇量,深入理解语境,整体把握,根据句子意思做出最佳选择。 名词词义辨析是高考的一个热点,主要考察考生结合语境辨别词义的能力。因此,在记忆一...

unusual前用a还是an 高中英语语法知识点总结:名词、主谓一致和冠词

高中知识搜索小程序 易错点1。看单词创造意义 同义词、近义词甚至近义词的含义和适用场合不同,要特别注意在具体语境中准确运用词汇和语法知识的能力。平时要尽量扩大词汇量,深入理解语境,整体把握,根据句子意思做出最佳选择。 名词词义辨析是高考的一个热点,主要考察考生结合语境辨别词义的能力。因此,在记忆一...

阿里云code 官方回应阿里云代码托管平台“泄露”客户代码一事:用户注意访问权限

阿里云code 官方回应阿里云代码托管平台“泄露”客户代码一事:用户注意访问权限

2月22日上午,有媒体报道阿里巴巴云平台源代码泄露,阿里巴巴云码托管平台项目权限设置模糊导致开发商操作失误,导致万科集团、米谷音乐、51信用卡51足迹、百度无人车合作伙伴ecarx等至少40家企业200多个项目代码泄露,至今未彻底解决。 文章称,2018年8月下旬,爆料的张发现,多家公司的...

表语是什么意思通俗点 八下英语短语/句型/语法,学霸们都在提前看

第一单元。怎么了? 关键词归纳 1.脚-脚:牙齿-牙齿: 2.感冒了 3.胃痛 4.背痛 5.喉咙痛 6.发烧 7.躺下休息一下躺下休息一下 8.蜂蜜加蜂蜜的热茶 9.看牙医看医生看医生看医生看医生 多喝水多喝水 11 .很多很多很多 很多=很多,可以修饰可数名词和不可数名词,一般用在肯定...

数词思维导图 超全英语思维导图50张,包含中学阶段所有语法,推荐收藏

  • 数词思维导图 超全英语思维导图50张,包含中学阶段所有语法,推荐收藏
  • 数词思维导图 超全英语思维导图50张,包含中学阶段所有语法,推荐收藏
  • 数词思维导图 超全英语思维导图50张,包含中学阶段所有语法,推荐收藏

sit现在分词 英语语法 分词的种类和用法

  • sit现在分词 英语语法 分词的种类和用法
  • sit现在分词 英语语法 分词的种类和用法
  • sit现在分词 英语语法 分词的种类和用法
数词的用法 英语语法解析之数词知识点汇总

数词的用法 英语语法解析之数词知识点汇总

基数 表示数字或顺序的单词叫做数字。1.基本词汇的构成: 1-101,2,3,4,5,6,7,8,9,10; 11-1911、十二、十三、十四、十五、十六、十七、十八、十九; 20-90岁,三十,四十,五十,六十,七十,八十,九十; ≥100100 a/一百;1000 a/千;100万a/百万;1...

代码表白 程序员表白代码,用过的人都找到了对象...