编译器与解释器

为什么80%的码农都做不了架构师?>>>   hot3.png

编译器和解释器都是可执行程序. 二者都需要输入.即文本代码文件.

编译器这样处理代码: 对代码进行词法分析,语法分析,语义制导,生成中间代码,中间代码优化,生成目标代码,目标代码优化.(目标代码可以是汇编代码,也可以是机器代码,这取决于编译器的实现,比如编译器中集成了汇编器) 代码的优化是反复进行的,穿插于整个过程中. 整个代码文件被编译成目标代码之后, 链接器程序将目标文件与相应的函数库链接,这样 原来的文本代码就成为了一个可执行程序,可以独立运行.

而解释器是这样处理: 解释器同样要对代码进行词法分析,语法分析,语义制导, 文本代码中某一段符合一定的语法规则,就会执行语法文件中定义好的动作.(想想,如果是编译器,与语法规则相对应的动作应该是构造中间代码).我们定义的动作可以是构造一棵语法树.比如遇到 a+b 匹配语法规则 expr '+' expr 对应的执行函数是{new treenode("+",$1,$3)} 当所有的文本代码都遍历完之后,就可以建立一棵完整的语法树,接下来,解释器程序可以遍历这棵语法树来实现想要完成的功能.比如说 我们要输出 文本文件代码表示的模型. 解释器就可以直接把这棵语法树输出给用户. 解释器也可以输出目标代码(比如汇编代码),只需把与语法规则相对应的动作改为输出函数,输出的汇编指令需要自己手写,这样产生的代码质量,完全取决于编写者的水平.一般没有编译器做的那么好. 如果再使用汇编器编译执行产生的汇编代码,解释器就变成了编译器. 解释器慢的原因之一是 同样的代码,下次执行,还是要从头来解释一遍,重新构造语法树.无法脱离解释器. 而编译器对文本文件代码编译一次,生成的程序可以独立运行,不再需要编译器.再执行一次,直接运行可执行程序.

 

  学过C/C++语言的同学都知道,写完的程序都要经过编译的过程,这其中就涉及到对编译器的理解,也许对于非计算机专业的人来说,没必要把其中的详细编译步骤了解清楚,但知其所以然似乎更好。

        Windows下比较主流的编译过程一般集成在集成开发环境VS中,在Linux下一般使用GNU(当然比较牛的人似乎都是用那种命令行的形式编译的,可惜我不是)。在VS中程序的执行过程包括:预处理(preprocessor)—编译(compiler)—汇编(assembler)—链接(linker)—加载(loader)。

         预处理的作用将分散在多个文件中的代码合并起来,#include语句就有此作用,在预处理中有可能用到宏(macros)。#include加入的头文件不能包含有定义语句,由于C++中变量和函数只能定义一次,而头文件是被加入到其他原文件中的,所以其中不能含有定义语句,否则会有重定义(redefinition)的错误,当然也有例外,类,const对象,inline函数可以定义在头文件中。

         编译的过程就是将源程序翻译成目标程序:源程序—编译器—目标程序,编译器还有报告源程序错误的作用。在生成了目标程序后,由我们的输入就可以生成相应的输出:输入—目标程序—输出,这也是诸多函数的调用形式。

        汇编就是将编译步骤生成的代码(在C/C++中.o格式文件),其一般是汇编语言代码,转化为计算机能够处理的机器代码,这个过程和上一步骤似乎很类似。

        链接是将分散在不同源文件中的代码组合起来,生成一个可以处理的大文件,例如,在VS中的多个源文件,通过单独编译后,可以链接成一个文件,然后通过加载器将其加载到计算机内存中,得到可执行文件(C/C++中的.exe文件)

        解释器是另外种形式的语言处理器,它相当于不生成上面的目标程序,直接将输入“放到”源程序中,然后经过解释器,就得到了输出。通常情况下,编译过程比解释过程更快,但解释器能够有更好的错误诊断,因为解释器是逐句进行解释的。学习过Python语言的同学都知道,Python是一种解释性语言,它的运行过程就用到了解释器。

        编译器和解释器可以结合起来进行处理,Java语言处理器就是其中的代表,其过程是源程序经过翻译器处理后得到中间程序,也被称作字节码(bytecode),然后和输入共同加入到虚拟机(virtual machine)的前端,得到输出,其前一部分用到编译器,后一部分用到解释器,这样做的好处是一个机器解释的代码可以应用在另外的机器上,甚至可以延伸到网络上。

转载于:https://my.oschina.net/wii01/blog/918822

你可能感兴趣的:(编译器与解释器)