编译原理书籍推荐
⼤学课程为什么要开设原理呢?这门课程关注的是编译器⽅⾯的产⽣原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却⼀直作为⼤学本科的必修课程,同时也成为了研究⽣⼊学考试的必考内容。编译原理及技术从本质上来讲就是⼀个算法问题⽽已,当然由于这个问题⼗分复杂,其解决算法也相对复杂。我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,⽽编译原理这门课程讲的就是⽐较专注解决⼀种的算法了。在20世纪50年代,编译器的编写⼀直被认为是⼗分困难的事情,第⼀Fortran的编译器据说花了18年的时间才完成。在⼈们尝试编写编译器的同时,诞⽣了许多跟编译相关的理论和技术,⽽这些理论和技术⽐⼀个实际的编译器本⾝价值更⼤。就犹如数学家们在解决著名的哥德巴赫猜想⼀样,虽然没有最终解决问题,但是其间诞⽣不少名著的相关数论。
推荐参考书
虽然编译理论发展到今天,已经有了⽐较成熟的部分,但是作为⼀个⼤学⽣来说,要⾃⼰写出⼀个像Turboc C,Java那样的来说还是太难了。不仅写编译器困难,学习编译原理这门课程也⽐较困难。
正是因为编译原理学习相对困难,那么就要求有好的教师和好的教材。教师⽅⾯不是我们能⾃⼰更改的,⽽在教材⽅⾯我们却可以按⾃⼰的意愿来阅读。我下⾯推荐⼏本好的编译原理的教材。我推荐的书
籍都是国外的经典教材,因为在国内的教材中,确实还没发现什么让⼈满意的。
第⼀本书的原名叫《Compilers Principles,Techniques,and Tools》,另外⼀个响亮的名字就是龙书。原因是这本书的封⾯上有条红⾊的龙,也因为獗⾅樵诒嘁朐?砘?×煊蛉肥堤?忻所以很多国外的学者都直接取名为龙书。最近机械⼯业出版社已经出版了此书的中⽂版,名字就叫《编译原理》。该书出的⽐较早,⼤概是在85或86年编写完成的,作者之⼀还是著名的贝尔实验室的科学家。⾥⾯讲解的核⼼编译原理⾄今都没有变过,所以⼀直到今天,它的价值都⾮凡。这本书最⼤的特点就是⼀开始就通过⼀个实际的⼩例⼦,把编译原理的⼤致内容罗列出来,让很多编译原理的初学者很快⼼⾥有了个底,也知道为什么会有这些理论,怎么运⽤这些理论。⽽这⼀点是我感觉国内的教材缺乏的东西,所以国内的教材都不是写给愿意⾃学的读者,总之让⼈看了半天,却不知道⾥⾯的东西有什么⽤。
第⼆本书的原名叫《Modern Compiler Design》,中⽂名字叫做《现代编译程序设计》。该书由⼈民邮电出版社所出。此书⽐较关注的是编译原理的实践,书中给出了不少的实际程序代码,还有很多实际的编译技术问题等等。此书另外⼀个特点就是其“现代”⽽字。在传统的编译原理教材中,你是不可能看到如同Java中的“垃圾回收”等算法的。因为Java这样的解释执⾏语⾔是在近⼏年才流⾏起来的东西。如果你想深⼊学习编译原理的理论知识,那么你肯定得看前⾯那本龙书,如果你想⾃⼰动⼿做⼀个先进的编译器,那么你得看这本《现代编译程序设计》。
第三本书就是很多国内的编译原理学者都推荐的那本《编译原理及实践》。或许是这本书引⼊国内⽐较早吧,我记得我是在⾼中就买了这本书,不过也是在前段时间才把整本书看完。此书作为⼊门教程也的确是个不错的选择。书中给出的编译原理讲解也相当细致,虽然不如前⾯的龙书那么深⼊,但是很多地⽅都是点到为⽌,作为⼤学本科教学已经是⼗分深⼊了。该书的特点就是注重实践,不过感觉还不如前⾯那本《现代编译程序设计》的实践味道更重。此书的重点还是在原理上的实践,⽽⾮前⾯那本那样的技术实践。《编译原理及实践》在讲解编译原理的各个部分的同时,也在逐步实践⼀个现代的编译器Tiny C.等你把整本书看完,差不多⾃⼰也可以写⼀个Tiny C了。作者还对Lex和Yacc这两个常⽤的编译相关的⼯具进⾏了很详细的说明,这⼀点也是很难在国内的教材中看到的。
推荐了这三本教材,都有英⽂版和中⽂版的。很多英⽂好的同学只喜欢看原版的书,不我的感觉是这三本书的翻译都很不错,没有必要特别去买英⽂版的。理解理论的实质⽐理解表⾯的⽂字更为重要。
编译原理的实质
c语言入门书籍排行榜前⾯已经说过,学习编译原理其实也就是学习算法⽽已,没什么特别的。只不过这些算法的产⽣已经形成了⼀套理论。下⾯我来看看编译原理⾥⾯到底有什么⾼深的理论吧。
⼏乎每本编译原理的教材都是分成词法分析,语法分析(LL算法,递归下降算法,LR算法),语义分析,运⾏时环境,中间代码,代码⽣成,代码优化这些部分。其实现在很多编译原理的教材都是按照8
5,86出版的那本龙书来安排教学内容的,所以那本龙书的内容格式⼏乎成了现在编译原理教材的定式,包括国内的教材也是如此。⼀般来说,⼤学⾥⾯的本科教学是不可能把上⾯的所有部分都认真讲完的,⽽是⽐较偏重于前⾯⼏个部分。像代码优化那部分东西,就像个⽆底洞⼀样,如果要认真讲,就是单独开⼀个学期的课也不可能讲得清楚。所以,⼀般对于本科⽣,对词法分析和语法分析掌握要求就相对要⾼⼀点了。
词法分析相对来说⽐较简单。可能是词法分析程序本⾝实现起来很简单吧,很多没有学过编译原理的⼈也同样可以写出各种各样的词法分析程序。不过编译原理在讲解词法分析的时候,重点把正则表达式和⾃动机原理加了进来,然后以⼀种⼗分标准的⽅式来讲解词法分析程序的产⽣。这样的做法道理很明显,就是要让词法分析从程序上升到理论的地步。
语法分析部分就⽐较⿇烦⼀点了。现在⼀般有两种语法分析算法,LL⾃顶向下算法和LR⾃底向上算法。LL算法还好说,到了LR算法的时候,困难就来了。很多⾃学编译原理的都是遇到LR算法的理解成问题后就放弃了⾃学。其实这些东西都是只要⼤家理解就可以了,⼜不是像词法分析那样⾮得⾃⼰写出来才算真正的会。像LR算法的语法分析器,⼀般都是⽤⼯具Yacc来⽣成,实践中完全没有⽐较⾃⼰来实现。对于LL算法中特殊的递归下降算法,因为其实践⼗分简单,那么就应该要求每个学⽣都能⾃⼰写。当然,现在也有不少好的LL算法的语法分析器,不过要是换在⾮C平台,⽐如Java,Delphi,你不能运⽤YACC⼯具了,那么你就只有⾃⼰来写语法分析器。
等学到词法分析和语法分析时候,你可能会出现这样的疑问:“词法分析和语法分析到底有什么?”就从编译器的⾓度来讲,编译器需要把程序员写的源程序转换成⼀种⽅便处理的(抽象语法树或语法树),那么这个转换的过程就是通过词法分析和语法分析的。其实词法分析并⾮⼀开始就被列⼊编译器的必备部分,只是我们为了简化语法分析的过程,就把词法分析这种繁琐的⼯作单独提取出来,就成了现在的词法分析部分。除了编译器部分,在其它地⽅,词法分析和语法分析也是有⽤的。⽐如我们在DOS,Unix,Linux下输⼊命令的时候,程序如何分析你输⼊的命令形式,这也是简单的应⽤。总之,这两部分的⼯作就是把不“规则”的⽂本信息转换成⼀种⽐较好分析好处理的数据结构。那么为什么编译原理的教程都最终把要分析的源分析转换成“树”这种数据结构呢?数据结构中有Stack, Line,List…这么多数据结构,各⾃都有各⾃的特点。但是Tree这种结构有很强的递归性,也就是说我们可以把Tree的任何结点Node提取出来后,它依旧是⼀颗完整的Tree。这⼀点符合我们现在编译原理分析的形式语⾔,⽐如我们在函数⾥⾯使⽤函树,循环中使⽤循环,条件中使⽤条件等等,那么就可以很直观地表⽰在Tree这种数据结构上。同样,我们在执⾏形式语⾔的程序的时候也是如此的递归性。在编译原理后⾯的代码⽣成的部分,就会介绍⼀种堆栈式的中间代码,我们可以根据分析出来的抽象语法树,很容易,很机械地运⽤递归遍历抽象语法树就可以⽣成这种指令代码。⽽这种代码其实也被⼴泛运⽤在其它的解释型语⾔中。像现在流⾏的Java,.NET,其底层的字节码bytecode,可以说就是这中基于堆栈的指令代码的。
关于语义分析,语法制导翻译,类型检查等等部分,其实都是⼀种完善前⾯得到的抽象语法树的过程。⽐如说,我们写C语⾔程序的时候,都知道,如果把⼀个浮点数直接赋值给⼀个整数,就会出现类型不匹配,那么C语⾔的编译器是怎么知道的呢?就是通过这⼀步的类型检查。像C++语⾔这中⽀持多态函数的语⾔,这部分要处理的问题就更多更复杂了。⼤部编译原理的教材在这部分都是讲解⼀些⽐较好的处理策略⽽已。因为新的问题总是在发⽣,旧的办法不见得⾜够解决。
本来说,作为⼀个编译器,起作⽤的部分就是⽤户输⼊的源程序到最终的代码⽣成。但是在讲解最终代码⽣成的时候,⼜不得不讲解机器运⾏环境等内容。因为如果你不知道机器是怎么执⾏最终代码的,那么你当然⽆法知道如何⽣成合适的最终代码。这部分内容我⾃我感觉其意义甚⾄超过了编译原理本⾝。因为它会把⼀个计算机的程序的运⾏过程都通通排在你⾯前,你将来可能不会从事编译器的开发⼯作,但是只要是和计算机软件开发相关的领域,都会涉及到程序的执⾏过程。运⾏时环境的讲解会让你更清楚⼀个计算机程序是怎么存储,怎么装载,怎么执⾏的。关于部分的内容,我强烈建议⼤家看看龙书上的讲解,作者从最基本的存储组织,存储分配策略,⾮局部名字的访问,参数传递,符号表到动态存储分配(malloc,new)都作了⼗分详细的说明。这些东西都是我们编写平常程序的时候经常要做的事情,但是我们却少去探求其内部是如何完成。
关于中间代码⽣成,代码⽣成,代码优化部分的内容就实在不好说了。国内很多教材到了这部分都会很简单地⾛马观花讲过去,学⽣听了也只是作为了解,不知道如何运⽤。不过这部分内容的东西如果
要认真讲,单独开⼀学期的课程都讲不完。在《编译原理及实践》的书上,对于这部分的讲解就恰到好处。作者主要讲解的还是⼀种以堆栈为基础的指令代码,⼗分通俗易懂,让⼈看了后,很容易模仿,⾃⼰下来后就可以写⾃⼰的代码⽣成。当然,对于其它代码⽣成技术,代码优化技术的讲解就⼗分简单了。如果要仔细研究代码⽣成技术,其实另外还有本叫做《Advance Compiler Desgin and Implement》,那本书现在由机械⼯业出版社引进的,⼗分厚重,⽽且是英⽂原版。不过这本书我没有把它列为推荐书给⼤家,毕竟能把龙书的内容搞清楚,在中国已经就算很不错的⾼⼿了,到那个时候再看这本《Advance Compiler Desgin and Implement》也不迟。代码优化部分在⼤学本科教学中还是⼀个不太重要的部分,就是算是实践过程中,相信⼤家也不太运⽤得到。毕竟,⾃⼰做的编译器能正确⽣成执⾏代码已经很不错了,还谈什么优化呢?
关于实践
编译原理的课程毕竟还只是讲解原理的课程,不是专门的编译技术课程。这两门课程是有很⼤的区别的。编译技术更关注实际的编写编译器过程中运⽤到的技术,⽽原理的课关注讲解其基本理论。但是计算机科学本⾝就是⼀门实践性很强的课程,如果能够学以致⽤,那才叫真正的学会。李阳在讲解疯狂英语的时候就说到,只要当你会实际中运⽤⼀个单词⼀个词组的时候你才能叫学会了这个单词或者词组,⽽不是只是知道了它的拼写和意思。其实任何学习都是⼀样的,如果缺少了实践的结合,你不能算学会。
编译原理的课程主要就是讲解编译器产⽣的理论和原理,那么很简单,⾃⼰写个编译器就是最好的实践过程了。不过你得⼩⼼,编译系统可能是所有软件系统中最复杂的系统之⼀,不然为什么⼤学⾥⾯还会把编译器的编写开成⼀门叫做编译原理的课程来讲?我很佩服那些学了操作系统原理就开始⾃⼰写操作系统,学了编译原理就开始⾃⼰写编译器的⼈们,确实,在中国,敢这么做的学⽣太少了。且不管你这样做能不能做成功,⾄少有了这个尝试,会让你的程序设计,系统规划安排的功底增进不少。我下⾯给出⼀些关于实践过程中可能会遇到的困难,希望能够在你陷⼊困境的前帮你⼀把。
1. Lex和Yacc. 这两⼯具是作为词法分析很语法分析的⼯具。如果你⾃⼰写⼀个编译器,我⼗分不建议你连词法分析这种事情都亲⼿来写。Lex和Yacc应该是作为每本编译原理的教材的必备内容,可是在国内的教材中缺很少看到。这两个⼯具是Unix系统下的⼩东西,如果你要在Windows中运⽤,那么你最好去下在cygwin这个软件。它是个在Windows下模拟Unix的东东,⾥⾯就包含了和(yacc)这两个⼯具.这两个⼯具使⽤起来还挺⿇烦的(其实unix 下的很多⼗分有⽤的⼯具都是这样), 不过在《编译原理与实践》这本书上对于这两个⼯具的讲解⼗分详细,还列举了不少实际的例⼦。
2. 做解释型语⾔⽐做⽣成机器代码的编译器简单。虽然说,做解释型的编译器,像Java那样的,你还得⾃⼰去写解释器,不过这样你就不必去查机器代码的资料了。如果你做⽣成的最终机器代码编译器可能会遇到问题还有就是寄存器为基础的代码⽣成⽅法。前⾯说过,如果你⽣成的是以堆栈为基础
的代码,那么其代码⽣成过程⼗分简单,需要考虑的东西也不多,如果你考虑最终的机器代码⽣成的话,你必须考虑机器的寄存器如何分配等⿇烦的问题。
3. 考虑⽤别⼈已经⽣成的语法⽂件,尽量不要⾃⼰动⼿写词法⽂件和语法⽂件.以前⼀个朋友曾经说过,写出⼀个好的程序语⾔的语法定义,就⼏乎完成了⼀个编译器的⼀半.确实是这样,语法⽂件的编写是个很难的事情.现在⽹上到处都可以到⽐如C语⾔,C++,Java, Tiny C,Minus C 等语⾔的词法⽂件和语法⽂件,你完全可以⾃⼰下下来来⽤.
在《编译原理及实践》的书中,作者给出了⼀个Tiny C的全部代码.我⾃我感觉作者的这个编译器做得很不错,相对于其它php,perl等语⾔的源代码来说,简单得多,容易看懂,⽽且很清晰地展现了⼀个完成的编译系统的实现过程.其源代码可以在作者的⽹站上下载
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论