建议你从百度上搜索"pl0"(Google搜的效果不太好),取一个pl0编译器的源码下来,在一个星期之内将程序读完,增长一些感性认识,再看教课书的内容,会好一些.我记得程序不长,当初我看的时候好象就1000多行.以前是在上完课后将它修改成pl1的,但是如果阅读程序的能力很强,可以先看.
编译原理很多地方都可以用得到随便举些例子 1. 当然如果你要写一个 compiler, 那是一定得用的, 这个 compiler 可能是 static compiler 或者是 dynamic compiler, 写 compiler 是很有趣的, 有机会可以试试看喔。我目前写过两个 dynamic compiler, 其中一个是为了我的模拟器 ARMware 写的, 有兴趣可以参考 http://www.csie.ntu.edu.tw/~r88052/ARMware/zh/index.php 这个网页. 通常撰写 dynamic compiler 的目的是加速 emulator 的执行. 在很多例子中都可以看到, 比方说 Sun Java Virtual Machine 里面通常都内建有 HotSpot compiler 来做一个加速的动作. 另外只要是以 interpret 模式来实做的语言, 里面都可以内建 dynamic compiler. 最近的 Microsoft C# Virtual machine 里也有类似的设计, 不过他是 ahead of time compiler, 比较偏向於 static compiler 了. 2. 在处理一些既定格式资料的情况下, 有机会使用到 syntax analysis 或 token analysis 这些观念跟 tool, 比方说 yacc, bision, yacc, bison 等等. 比方说一些简单的文字资料库等等就可以利用这些 tool 来简单的撰写一些 grammer 完成一个 program. 总括来说, 如果要学 compiler 的技术跟技巧, 大概就要搞懂一堆 algorithm, data structure 的处理, 比方说中介语言 (Intermediate Representation) 要怎麼设计才好, 才方便做哪些 optimization, DAG tree 的架构与设计, SSA form 的转入跟转出等等. 这中间都牵扯到很多的 algorithm 跟 data structure 的特性, 如果有兴趣的话, 可以看看有关 compiler 的书, algorithm 的书, 比方说 The Art of Computer Programming 这本, 虽然很多人觉得它是天书, 但我觉得要练基本功, 这本准没错, 如果没什麼时间或兴趣, 建议这本书的第二章可以拿来翻阅看看。
少走弯路:学习编译原理的相关建议
2005年04月13日 作者:hzzasdf 责任编辑:linjixiong
编译原理一般认为是较难的一门课.从网上的评论来看,有人说学了一年半软件理论,就一门编译看不懂;有人甚至说它是大本软件课程里最难的一门;有人抱怨国内的编译教材没有一本容易懂的。 从笔者学习实践来看,第一次学了一个多月,理论部分一知半解,第二次学了一星期,基本看懂词法分析的理论部分,语法分析就一知半解了,第三次学了一星期,才基本看懂词法分析和语法分析.由此看来,这门课确实有难度.网上有的帖子,把编译器的编写搞得高深莫测一般,似乎难度极大,非常人能及. 编译原理究竟难在哪里?笔者的体会,主要在这几点:
1.错误认识: 很多人以为编译原理只能应用在写程序语言的编译器上,觉得用处不大,学习兴趣不高.而且可能觉得写编译器就必须完全手工来写.
2.自动机理论: 象NFA,DFA之类,比较抽象,要费些脑子,特别如果学离散数学时没有学自动机理论的话,更是需要多花点时间.
3.集合论的推演: 主要是一些闭包运算之类,数学基础不好的话,学起来也会感到吃力.
4.LR文法: 主要是又引入了自动机
不管哪本编译教材,即使是绝对经典”龙书”也不例外,都要涉及到这几个难点.由于这些内容本身不好懂,作者有再大的本事,也很难把书写得象小说那么流畅好懂. 明确了难点,接着想对策.大致有这么几种:
1.端正认识: 编译原理在静态文本处理上有广泛的应用,举个简单的例子,把HTML文件转化为纯文本,利用编译原理来实现”非常”简单.理解了编译原理的实用性,大概可以提高学习兴趣.
2.反复看书: 这个办法看起来最笨,却是基本的方法.忘了是哪位名人说过,书只要多看,总能看得懂的.
3.结合源码来看: 这是经典教材Compiler Design in C的作者Allen Hollub建议的方法.这本教材的特色就是包含了大段yacc,lex的代码.这也是个好方法,而且,只有看懂了代码,才能说在根本上理解了理论.当然,要完全看懂yacc的代码,工作量是很大的,而且同样要先理解理论.
4.删繁就简,避重就轻.网上流传较广的一篇《编译原理学习导论》(作者四川大学唐良)就基本是这种思路,对于词法分析,作者避免了自动机理论和集合论推演的介绍,直接搬出源码来,大大降低了理解难度,对于语法分析,作者介绍了递归下降和LL文法及相应的源码,而对LR文法,只说”理解理论就可以了”.虽然这种方法回避了对于难点的学习,但是用这种方法学习,可以在较短时间内编写出一个能够运行的词法分析器和语法分析器,可以大大提高学习积极性.
笔者的思路大体上类似第4种方法,但也稍有不同.由于一个偶然的原因, 笔者需要编写一个词法分析器和语法分析器,用于程序源代码的静态分析.开始无从下手,硬着头皮看了点编译原理,觉得困难很大.后来偶然找到一个类似的开源程序,是利用一个叫做PCCTS的编译器自动生成工具开发的,大受启发.开源就是好!笔者找来了一个叫做ANTLR的工具(它是PCCTS的新版,支持生成java,c++和c#代码),又下载了一个c语言的语法文件(因为笔者需要处理c代码文件),然后自己编了少量动作(action)语句,界面代码,分析处理代码等,就这样,在对编译原理所知甚少(以前学过的因为理解不深都忘了,只记得正则表达式)的情况下,仅用一个星期就写出了程序. 这次实践使笔者对编译原理兴趣大增,重新又学了一遍编译原理,并归纳出笔者认为比较实用有效的编译原理学习步骤:
1.先利用ANTLR之类的编译器生成工具,做一个小程序(如上面提到的HTML文件转化成纯文本文件的程序),所需知识只是正则表达式的基本知识和生成工具本身的使用方法(可以看联机帮助和网上教程(tutorial)来掌握). 这样做的好处是: 1)可以体会到编译原理的实用性,提高学习兴趣 2)入门容易,消除编译原理学习的畏难情绪. 3)获得词法分析器和语法分析器的感性认识,有利于加深对理论的理解. 4)获得编译器自动生成工具(compiler compiler)的使用经验,提高解决实际问题的能力.(实际工作很多都不是手编而是利用工具的)
2.象ANTLR之类的工具是开源(open source)的,可研究其源码,以便必要时自己手编分析程序.
3.回过头来看编译原理教材. 这时大概会发现,很多理论很容易懂,剩下的只有上面说的几个难点,多看几遍,重点突破.
4.结合教材所附源码,进一步加深对教材的理解 这里顺便提一下,有的编译原理的教材,对于输入子系统不单立一章来讲,有的甚至完全忽略,笔者认为, 输入子系统相对于词法分析器和语法分析器来说当然简单地多,但也是两者的基础,故有必要看源码来理解.在这方面,ANTLR的实现机制和Lex是不同的(当然和java与c的差异有关),可对照着看.
笔者学习VC++时,深切体会到好教材的重要.笔者开始吃了劣质光盘版”教材”和”21天学VC++”的祸害,看了一个月还如入云雾之中,后来看了《VC++技术内幕》,方才豁然开朗.但是编译原理的教材却似乎质量相差不是特别大,关键还在于合适的方法.以上方法笔者也是误打误撞总结出来的,希望有所参考价值.
二、认清编译原理,明确学习意义,激发学生的热情
1.帮助学生认清编译原理的作用和地位
在教学过程中,很多学生都有这样的疑问:编译原理学的是什么?学习它有什么作用?
我们知道,目前的计算机能执行的都是非常低级的机器语言,一个用高级语言编写的源程序最终如何在计算机上执行呢?这就是编译原理要解决的问题。概括地说,编译原理课程介绍编译器构造的一般原理、基本设计方法和主要实现技术。编译原理课程通过编译器的各个组成部分来解释高级语言编写的源程序如何翻译成计算机能够执行的机器语言。这个翻译的过程涉及程序设计语言、机器结构、形式语言理论、类型论、算法和软件工程等方面的知识。例如,对软件工程来说,编译程序是一个很好的实例(基本设计、模块划分、基于事件驱动的编程等),编译原理课程所介绍的概念和技术可以用到一般的软件设计中。
事实上,通过编译原理的学习,有助于学生快速理解、定位和解决在程序编译、测试与运行中出现的问题。另外,编译原理的学习对熟悉编译过程、掌握计算机高级语言的生成机制、理解具体程序的运行状态起着关键作用。
2.帮助学生克服畏难心理,提高学生的兴趣
在教学的过程中,很多学生认为他们今后的工作不会涉及到编译原理的理论和技术,编译原理没有实际的用处,学习起来就非常的枯燥无味。其实这是对编译原理的一种错误认识。该课程中的原理除了可以用于分析编译器以外,还对诸如人工智能、并行处理技术等课程的学习具有指导作用。例如,利用编译原理的理论设计出“翻译风”这样的软件。与此同时编译原理课程可以帮助学生更进一步地理解和综合应用离散数学、高级语言、数据结构、汇编语言等专业基础课程的知识。例如,编译程序应用了多种数据结构,在词法分析阶段使用状态转换图来识别各种单词;在语法分析中使用语法树等来进行语法分析;在存储分配时使用栈式结构和堆式结构进行存储空间的分配。本门课程学习对其它课程的学习和今后很多领域的理论研究具有深远的意义,如计算机软件技术领域、计算机系统结构领域、人工智能系统的机器学习领域、并行处理技术等领域。
鉴于“编译原理”这门专业课程的特点,在教学过程中端正学生的认识,帮助学生克服畏难情绪,肯定学生所具有的能力,让学生明白以他们掌握的计算机知识,有足够的能力学好《编译原理》这门课程。鼓励他们同样可以利用学到的理论技术设计出类似“翻译风”这样的软件,帮助学生建立信心,发挥他们的才智,提高学习的热情。
三、把握课堂教学内容
1.整体把握一条主线,领会每个阶段的精髓,各个击破
编译器(编译程序)可以分为词法分析、语法分析、语义分析、中间代码生成,代码优化和目标代码生成这六个阶段,每个阶段还会伴有符号表管理和出错管理。在第一章编译器概述中就把编译器化分成这六个阶段,同时还简要的描述了这六个阶段各自的任务,这是贯穿整个课程的一个主线,整个课程就是按这六个阶段组织进行的。所以一开始让学生把握这条主线,对课程有一个总体的把握,理解编译的过程。
当学生从整体上理解编译器的结构之后,然后分章节对各个部分进行细致地教学。按照编译过程的划分,把课程分为六章内容,每章都有它的精髓所在,只要掌握了每章的精髓,就能掌握编译的整个过程。词法分析的精髓主要是词法分析的构造、有限自动机理论的应用;语法分析的精髓主要是语法分析的两种方法——自上而下分析法和自下而上分析法;语义分析主要是属性文法、语法制导定义以及翻译方案;中间代码主要描述了中间代码常见的几种表示形式、各种语法结构如何进行语法制导翻译形成中间代码;代码优化主要围绕如何从时间和空间上进行优化,尽可能提高执行的效率展开,分别讲述了局部优化和循环优化;目标代码生成主要是目标代码生成算法的实现及寄存器的分配。这六个部分相辅相成,互有联系,掌握每个阶段的精髓,各个击破,这样学生比较容易理解和接受。
2.课堂讨论式
在《编译原理》的教学过程中,课堂上不能采取“灌输式”教学,上面老师讲解的充满激情,下面学生听得昏昏欲睡,随着时间的积累,学生不理解的知识越来越多,就会慢慢失去学习的兴趣。所以,要注重与学生的交流,在课堂上可以采取集体讨论和分析的方法,让学生说出自己在学习的过程遇到的问题以及解决问题的方法。例如,数据对齐是由硬件特点造成的对存储分配的一点约束,这个概念有的教材并没有提到或者只是一带而过。针对数据对齐问题,有一个C语言的例子:
typedef struct a
{ char cl ;
long i;
char c2;
double f;
}a ;
typedef struct_b
{ char cl;
char c2;
long i;
double f;
)b ;
main ( )
{ printf( “Sizeof double,long,char= %d, %d , %d\\n”,sizeof(double) , siz eof( long),sizeof(char));
printf (“ Sizeof a ,b =%d, %d\\n,sizeof(a), sizeof(b)) ;
}
在X86/Linux机器上,该程序的运行的结果是:
Size of double,long,char= 8,4,1
Size of a, b = 20,16
在SPARC/Solaris工作站上,该程序的运行结果是:
Sizeof double,long,char=8,4 ,1
Sizeof a,b = 24,16
在这个例子中,结构体类型a和b的域名及类型都一样,仅次序不同,但是它们在同一机器上的存储分配字节数不一样,在不同机器上的情况也不一样。有的学生就会问为什么会要考虑数据对齐的问题?这时候,老师可以指导学生课后搜集相关资料,然后进行课堂讨论分析。
其实,数据对齐对用C语言编程、对构造编译器、对C程序的移植来说都是重要的。利用这样的例子考察实际编译器存储分配的对齐情况,让学生明白存储分配时要考虑到数据对齐以及数据对齐的作用。让学生自己去探索,不仅明白了概念的重要性,增强了学生的理解和应用能力,拓宽了知识面,而且培养了学生思考问题和解决问题的能力,培养了科学严谨的思维能力。 四、精心设计实验教学内容
《编译原理》对实践的要求比较高,所以实验课是培养学生实践能力的重要环节,是巩固和验证所学理论知识,培养学生分析问题、解决问题能力的重要环节。但是在教学的过程中,绝大部分学生无法完成编译原理的实验。即使告诉学生实验的思路和算法,有的还是不知如何入手,整个实验的效果很差。为了能达到好的实验效果,极大地促进学生对原理的理解,可以从以下几个方面思考:
1.认真设计合适的实验内容
编译技术中有很多经典的算法,由于课时有限,可以选择具有代表性的典型算法来实现。根据课程的特点和大纲的要求,可以设置三个实验内容:词法分析器的设计、递归下降分析器的设计、LR(0)分析器的设计。很多教材中都有相关的设计算法和程序代码片断,这样降低了《编译原理》实验课的难度。另外,根据老师可以根据的实验效果对实验内容再做适当调整。
2.采用适当的实验形式
根据课程的重难点和实验覆盖的知识点不同,将《编译原理》的实验内容分为两大部分:独立实验和分组实验。
在实验的过程中,将词法分析器的设计和递归下降分析器的设计作为独立的实验,由每一个学生自己独立完成,而将LR(0)分析器的设计作为分组实验。分组实验以学生自由组合的小组形式为单位进行,一般一个小组由3至4名学生组成,并推荐一人作为组长,负责师生之间的联系,采用分组实验的形式锻炼了团队分工协作的能力,培养了团队精神。
3.教师的耐心指导
教师在实验过程中的指导也很重要。教师对学生的指导要细心认真,让学生记录下每次实验的输入和输出形式,实现理论与实践的结合,注意调动学生的积极性,引导他们独立思考、独立完成;另外,更要加强实验结果的监督,提高实验教学质量。
五、结束语
以上结合自己的教学实际,在编译原理的课堂教学和实验教学中的一些思考。事实上学好编译原理课程需要老师和学生双方的共同努力,需要我们共同不断的思考、探索、实践和积累。
参考文献:
[1]张昱,陈意云,郑启龙.编译原理课程的教学方法和教材建设[J].中国大学教学,2005,(7):61-62.
[2]余玛俐,张海.《编译原理》教学方法探析[J].九江学院学报(自然科学版),2005,(4):114-118.
[3]陈意云,张昱.编译原理[M].高等教育出版社,2003.
[4]陈意云,张昱.编译原理习题精选[M].中国科学技术大学出版社,2002.
[5]侯惠芳.《编译原理》课程教改探讨[J].科技信息,2007,(17):152.193.