首先肯定的是先有的编程语言,哪怕这个语言简单到只有一个符号。先是设计好语言的规则,然后编写能够识别这套规则的编译器,否则若没有语言规则做为指导方向,编译器编写将无从下笔。第1个编译器是怎么产生的,这个问题我并没有求证,不过可以谈下自己的理解,请大伙儿辩证地看。这个问题属于哲学中鸡生蛋,蛋生鸡的问题,这种思维回旋性质的本源问题经常让人产生迷惑。可是现实生活中这样的例子太多了,如:1.英语老师教学生英语,学生成了英语老师后又可以教其他学生英语。2.写新的书需要参考其它旧书,新的书将来又会被更新的书参考,就像本书编写过程一样,要参考许多前辈的著作。3.用工具可以制造工具,被制造出来的工具将来又可以制造新的工具。4.编译器可以编译出新的编译器。这种自己创造自己的现象,称为自举。自举?是不是自己把自己举起来?是的,人是不能把自己举起来的,这个词很形象的描述了这类“后果必须有前因”的现象。以上前三个举的都是生活例子,似乎比第4个更容易接受。即使这样,对于前三个例子大家依然会有疑问:1.第一个会英语的人是谁教的?2.第一本书是怎样产生的?3.第一个工具是如何制造出来的?其实看到第2个例子大家就可能明白了,世界上的第一本书,它的知识来源肯定是人的记忆,通过向个人或群众打听,把大家都认同的知识记录到某个介质上,这样第一本书就出生了。此后再记录新的知识时,由于有了这本书的参考,不需要重新再向众人打听了原有知识了,从此以后便形成了书生书的因果循环。从书的例子可以证明,本源问题中的第一个,都是由其它事物创建出来的,不是自己创造的自己。就像先有鸡还是先有蛋一样,一定是先有的其它生命体,这个生命体不是今天所说的鸡。伴随这个生命体漫长的进化中,突然有一天具备了生蛋的能力(也许这个蛋在最初并不能孵化成鸡,这个生命体又经过漫长的进化,最终可以生出能够孵化成鸡的蛋),于是这个蛋可以生出鸡了。过了很久之后,才有的人类。人一开始便接触的便是现在的鸡而不知道那个生命体的存在,所以人只知道鸡是由蛋生出来的。很容易让人混淆的是编译c语言时,它先是被编译成汇编代码,再由汇编代码编译为机器码,这样很容易让人误以为一种语言是基于一种更底层的语言。似乎没有汇编语言,c语言就没有办法编译一样。拿gcc来说,其内部确实要调用汇编器来完成汇编语言到机器码的翻译工作。因为已经有了汇编语言编译器,那何必浪费这个资源不用,自己非要把c语言直接翻译成机器码呢,毕竟汇编器已经无比健壮了,将c直接变成机器码这个难度比将c语言翻译为汇编语言大多了,这属于重新造轮子的行为。曾经我就这样问过自己,php解释器是c语言写的,c编译器是汇编写的(这句话不正确),汇编是谁写的呢?后来才知到,编译器gcc其实是用c语言写的。咋一听,什么?用c语言写c编译器?自己创造自己,就像电影超验骇客一样。当时的思维似乎陷入了死循环一样,现在看来这不奇怪。其实编译器用什么语言写是无所谓的,关键是能编译出指令就行了。编译出的可执行文件是要写到磁盘上的,理论上,只要某个进程,无论其是不是编译器,只要其关于读写文件的功能足够强大,可以往磁盘上写任意内容,都可以生成可执行文件,直接让操作系统加载运行。相像一下,用python写一个脚本,功能是复制一个二进制可执行文件,新复制出来的文件肯定是可以执行的。那python脚本直接输出这样的一个二进制可执行文件,它自然就是可以直接执行的,完全脱离python解释器了。编译器其实就是语言,因为编译器在设计之初就是先要规划好某种语言,根据这个语言规则来写合适的编译器。所以说,要发明一种语言,关键是得写出与之配套的编译器,这两者是同时出来的。最初的编译器肯定是简单粗糙的,因为当时的编程语言肯定不完善,顶多是几个符号而已,所以难以称之为语言。只有功能完善且符合规范,有自己一套体系后才能称之为语言。不用说,这个最初的编译器肯定无法编译今天的c语言代码。编程语言只是文本,文本只是用来看的,没有执行能力。最初的编译器肯定是用机器码写出来的。这个编译器能识别文本,可以处理一些符号关键字。随着符号的越来越多,不断地去改进这个编译器就是了。以上的符号说的就是编程语言。后来这个编译器支持的关键字越来越多了,也就是这个编译器支持的编程语言越发强大了,可以写出一些复杂的功能的时候,干脆直接用这个语言写个新的编译器,这个新的编译器出生时,还是需要用老的编译器编译出来的。只要有了新的编译器,之后就可以和老的编译器说拜拜了。发明新的编译器实际上就是能够处理更多的符号关键字,也就是又有新的开发语言了,这个语言可以是全新的也可以是最初的语言,这取决于编译器的实现。这个过程不断持续,不断进化,逐渐才有了今天的各种语言解释器,这是个迭代的过程。这张图片在网络上非常火,它常常与励志类的文字相关。起初看到这个雕像在雕刻自己时,我着实被感动了,感受到的是一种成长之痛。今天把它贴过来的目的是想告诉大家,起初的编译器也是功能简单,不成规范,然而经过不断自我“雕刻”,它才有了今天功能的完善。下面的内容是我参考了别人的文章,由于找不到这位大师的署名,只好在此先献上我真挚的敬意,感谢他对求知者的奉献。要说到C编译器的发展,必须要提到这两位大神——C语言之父DennisRitchie和KenThompson。Dennis和Ken在编程语言和操作系统的深远贡献让他们获得了计算机科学的最高荣誉,Dennis和Ken于年赢得了ACM图灵奖。编译器是靠不断学习,不断积累才发展起来的,这是自我学习的过程,下面来看看他们是如何让编译器长大的。我们都知道转义字符,转义字符是以’’开头的多个字符,通常表示某些控制字符,它们通常是不可键入的,也就是这些字符无法在键盘上直接输入,比如’’表示回车换行,’ ’表示tab。由于以’’开头的字符表示转义,因此要想表示’’字符本身,就约定用’’来转义自己,即’\’表示字符’’。转义字符虽然表示的是单个字符的意义,在编译器眼里转义字符是多个字符组成的字符串,比如’’是字符’’和’n’组成的字符串,好啦,交待完毕。起初的c编译器中并没有处理转义字符,为叙述方便,我们现在称之为老编译器。如果待编译的代码文件中有字符串’\’,这在老编译器眼里就是’\’字符串,并不是转义后的单个字符’’。为了表明编译器与做为其输入的代码文件的关系,我们称做为输入的代码文件为应用程序文件,尽管被编译的代码文件是实现了一个编译器,而在编译器眼里,它只是一个应用程序级的角色。例如,gcc–ca.c中,a.c就是应用程序文件。现在想在编译器中添加对转义字符的支持,那就需要修改老编译器的源代码,假设老编译器的源代码文件名为
转载请注明:http://www.0431gb208.com/sjsbszl/7724.html