闻炳海 刘鹏 王利娥 张超英
[摘 要]《编译原理》是计算机专业本科教学的一个难点。从教学理念出发,深入分析了教材、教学对象、教学目标、教学过程、巩固与延伸等主题,提出编译原理的工程化的教学方法。实际结合“语法分析”一章具体部署实施过程。该方法在实际教学过程中取得了比较好的效果。
[关键词]编译原理 教学方法 工程化教学
[中图分类号] G642 [文献标识码] A [文章编号] 2095-3437(2015)02-0126-03
一、引言
编译所要完成的主要任务是将高级语言编写的程序翻译成计算机能够理解的机器语言。现代编译程序所要面对的经常是几十万、几百万行的大程序,在编译原理的研究过程中形成了大量的概念、理论和算法,这直接造成了编译原理这门课很难学。现在,编译原理课程是计算机专业的学生公认的本科阶段最难的课程之一,许多学生觉得编译原理难以掌握。本文将工程化的方法引入编译原理的教学过程中,通过一系列措施将编译原理的学习过程简单化、规范化,达到让学生学好编译原理的目标。
二、教学理念
所谓工程化教学是指在教学过程中引入工程的概念,使教学过程有明确的时间安排,有递进的阶段目标,有可以量化的指标,像管理工程项目一样对教学作全程控制。我们要打造工程化的教学过程,通过选择合适的教材、详细考察学生情况、精心组织教学内容、合理安排课后作业、设定逐步提高的开发目标,将学生引入一个可以量化的学习过程中。计算机科学有很强的理论背景,编译原理更以逻辑严密、算法枯燥著称。要求我们在教学过程中做到精简讲解、深入浅出,抓住理论的本质讲清楚。同时,计算机学科强调实践性教学,编译原理课程更是围绕着实际应用而展开的。要求我们在教学过程中激励学生动手,重视实验和课后锻炼,让学生掌握实际运用能力。我们提出了 “精简理论、加强实践”为中心思想的教学理念,掌握理论、动手实践是学好编译原理的不二法门。
三、教材和内容
我们选择的主讲教材是清华大学的张素琴教授主编的《编译原理》,这是目前国内应用最广泛的教材,发行量达到20余万册。我们选择的辅助教材是贝尔实验室的Alfred等编写的《编译原理技术与工具》,这是一本世界著名的编译原理教材,在编译原理领域有很高的声誉。因为封面画了一条龙,所以被大家亲切地称为“龙书”。主讲教材以理论分析为主,内容清晰,逻辑严谨;辅助教材有很好的实践内容,引导学生实际动手设计编译程序。两本教材风格互补,在章节编排上有很好的对应关系,便于在教学中结合使用。下面就以“语法分析”一章为例,介绍一下我们设计的工程化教学过程。教材上“语法分析”一章主要内容包括:LL(1)文法定义、文法判别算法、确定自顶向下分析、递归子程序法等。我们给出了一些补充内容,包括分析典型的源代码、自己开发的Yacc范例、自己开发的表达式语法分析程序等部分。通过这些案例的分析,让学生在理论学习的基础上学习如何将理论应用到实际开发,并熟悉流行的编译辅助工具软件的使用。
四、学生情况分析
编译原理这门课是为计算机专业本科三、四年级的学生开设的。学生在学习编译原理之前已经学过多种编程语言,如VB、VC、Java、Delphi、Html。但是一个普遍的情况是“多数学生没有认真思考过,编译程序的原理和开发方法”。学生不知道这些编译软件是如何设计出来的,更不知道不同编译程序背后的理论依据。学生会感觉到编译原理很神秘。而且编译原理“难”声在外,一些学生对编译原理有畏惧心理。这是学生学习《编译原理》的心理难点。我们要解决的问题是:如何为学生树立学好编译原理的信心?《编译原理》这门课程比较独立,理论自成体系,其他先修课程很少涉及编译方面的内容。教材内容定义多,概念抽象,形式化的描述难以理解;算法多,步骤复杂,计算量大,学生很容易陷入细节问题不能自拔,产生困难和厌学心理。这些情况造成学生不容易接受编译原理内容,上课时容易产生惰性心理。这是学生学习《编译原理》的理论难点。我们要解决的问题是:如何让学生把理论学明白、会运用?《编译原理》的理论学习尚且不易,设计编译程序更是一项非常复杂的工程,涉及多方面内容,学生的编程经验不足以开发一个简单的编译程序,经常会感觉不知从何入手。这是学生学习《编译原理》的技术难点。我们要解决的问题是:如何引导学生动手实践,给同学们找到一个很好的切入点?同时,我们观察到,学生主观上又想学好编译原理。因为著名的编译高手设计了学生每天使用的编译程序,比如设计了C语言的Ritchie &Thompson、设计了C++语言的Bjarne Stroustrup、设计了Java语言的James Gosling、设计了C#语言的Anders Hejlsberg等等,这些传奇式的编译高手受到学生们的广泛推崇。学生耳闻目染知道编译原理的重要性,对编译程序的开发感到好奇。这些都是我们引导学生学习的有利因素。在教学过程的设计当中,我们针对这些教学难点安排教学内容和教学方法,注意帮助学生克服困难,培养学生的学习兴趣。
五、教学目标和重点
结合这一章的内容,我们制定了四个递进的教学目标和三个教学重点。教学目标包括对教材内容的掌握和学习补充延伸的内容。第一,掌握教材上的基本原理。包括文法的FIRST集、FOLLOW集和SELECT集的定义和计算方法、LL(1)文法的定义和判别算法、确定自顶向下分析、递归子程序法等内容。这些基本理论学生必须要掌握。第二,学习使用语法分析自动生成工具。为学生介绍现在被广泛使用的工具软件Yacc。通过我们自己编写的Yacc程序范例,让学生掌握Yacc的结构和用法。第三,掌握经典的语法分析的源代码。通过分析PL / 0语言的语法分析源代码,让学生了解语法分析的经典实现。第四,引导学生动手实现语法分析器。引导学生对Yacc代码和PL / 0语法分析代码作个性化的修改和功能添加。通过这四个逐步深入的教学目标,引导学生不断深化学习。教学重点包括了这一章的三个重要的定义和理论。第一,LL(1)文法的定义。这个定义包括First集、Follow集和Select集三个前导定义,每个定义都是一段形式化的描述,要求讲课时要讲清楚形式化定义的本质。第二,LL(1)文法的判别算法。算法包括五个步骤:1.求出能推出ε的非终结符;2.计算First集;3.计算Follow集;4.计算Select集;5.判定是否是LL(1)文法。其中每个步骤又是一个独立的算法。整个算法比较冗长,教材上用了六页描述该算法。我们要用特别的方法让学生学习和掌握。第三,语法分析的递归子程序法。递归子程序法的思想是对LL(1)文法中每个非终结符编写一个递归过程,识别由该非终结符推出的符号串。PL / 0语法分析模块就是采用递归子程序算法实现的。在分析PL / 0语法分析模块的基础上,我们还引导学生动手开发自己的语法分析程序。
六、教学过程
下面详细介绍教学过程的安排,共分为六个步骤。第一步:提出问题,引发学生去思考。编译的任务是将高级语言编写的程序翻译成计算机能够直接理解的机器语言,这个翻译过程不是一步完成的。编译程序在进行真正的翻译和生成目标代码之前,首先要从结构上把握源程序。语法分析的任务就是从结构上分析程序,保证源程序语法结构正确并分析得到程序的各个语法成分。让我们考虑一个简单的例子,老师是如何判断小学生所造的句子语法结构上是否正确?比如,“我是学生”,我们说这个句子是语法结构正确的。那是因为我们可以将这个句子分为三部分,“我____是____学生”,每一部分正确的对应了“主语____谓语____宾语”三种语法成分,所以我们说这个句子是语法正确的。那么,编译程序是如何对源程序做语法分析的呢?比如,“if i<10 then n=0 else n=1”,这个简单的程序语句。编译程序首先从中分析出关键字“if、then、else”,然后分析出表达式“i<10、n=0、n=1”,表达式和关键字按正确的形式排列,所以这是一个语法结构正确的语句。实际应用的编译程序是能够处理几百万行代码的大程序,它的语法分析方法当然更复杂,比如这一章所涉及的LL(1)文法、递归子程序法、预测分析法等,都很复杂。但是,他们都是建立在这样一个简单的基本概念之上的,语法分析就是从“结构上分析程序”。在这里我们运用“先行组织者”原理,提出问题,举出范例,引导学生去思考语法分析方法。第二步:精简讲解,抓住理论的本质。例如教材上Follow集的定义为:设G=(VT,VN,S,P)是上下文无关文法,A∈VN,S是开始符号,#是输入串的结束符(输入串括号),FOLLOW(A)={a|S*→μAβ且a∈VT,a∈FIRST(β),μ∈VT*,β∈V+},若S *→μAβ且β→ε,则#∈FOLLOW(A)。学生很难从这样形式化的描述中看懂Follow集的到底是用来干什么的。我们在上课的时候就要讲清楚,Follow集就是用来考察“非终结符能够以哪些字符为后继”这样一个简单的本质。抓住本课程定义抽象,实际应用简单的特点,让学生认识到编译原理其实很简单。第三步:小题多练,采用搭积木的方式学习。教材上用了6页来讲解LL(1)文法的判别算法,如果直接将一道习题交给学生去完成,学生显然难以接受。在讲课的时候,我们先讲算法结构,然将一个大题分为几个阶段的小题,穿插演练,最后组成一个完整的解题过程。让学生体会到虽然整个算法十分冗长,但是每一步都很简单。第四步:互动教学,让学生积极参与。课堂教学过程中要鼓励学生提出想法和思路,尽可能对学生的发言给予肯定的评价,要密切注意学生的反馈信息,有针对性地讲解关键知识点。要让学生积极参与教学过程,跟上我们的讲解思路,尽量消除学生上课的惰性心理。第五步:分组作业,降低学生的困难感。将全班同学划分为几个小组,每组5至7名同学。对于同一个主题,不同小组可以选择不同方向。比如设计C语言文法,可以化为几个子集让不同小组实现,也可以不同小组完成不同任务,然后互相讨论学习。将理论基础好、动手能力强的同学分配到各个小组,以先学带动后学,降低学生的学习困难感,避免动手能力差的同学失去信心。第六步:实际运用,DIY自己的语法分析器。给学生布置一些递进的实践项目,比如“设计最简单的四则运算的语法分析器”、“学习用YACC设计C语言语法分析器”、“学习用C语言实现一个简单的语法分析器”等。由简单到复杂,把课堂讲授、实验课和课后锻炼有机地结合起来。以上就是我们教学方法的六个主题:提出问题、精简讲解、小题多练、互动教学、分组作业、实际运用。从理论学习到动手实践,有针对性地解决学生学习时所遇到的一系列问题,为学生打造一个循序渐进、深入浅出的完整学习过程。
接下来我们以语法分析为例,介绍一下如何引导学生动手实践语法分析理论。第一,一步一步教学生如何用Yacc创建语法分析项目,详细介绍每个步骤的含义。第二,一步一步教学生配置VC环境用于语法分析项目的编译,详细每个环境参数的作用。学生在实践的时候遇到的最主要的困难就是如何使用工具软件,我们通过详细的讲解帮助学生迈出语法分析的第一步。第三,用简单的例子讲解Yacc的结构和用法,让学生体会语法分析其实不神秘。第四,把我们自己写的文法范例在课堂上和同学们一起编写、调试、运行,实时展现不同文法分析的结果。第五,将我们自己用C语言开发的表达式语法分析程序作为补充练习,让学生去修改、添加功能,体会语法分析的思路。整个过程充分考虑了学生的能力培养,难度逐步加大,阶段目标明确,便于在教学过程中实施。
七、教学效果
在实际教学过程中,编译原理的工程化教学方法取得了较好的教学效果,学生保持较高的学习积极性,学生评教一直保持较高的分数。在课堂上,学生能够积极的参与教学过程,把握知识脉络并掌握知识点;在课余时间里,学生能够较好的完成作业并进行探索和学习。通过系统的学习编译原理,学生对软件开发有了深入认识,了解了程序优化和并行计算的方法和重要性,为编写高效、高质量的代码打下了基础。此外,本文第一作者以“编译原理的工程化教学”为主题参加广西师范大学第三届“青年教师说课比赛”,获得了理科组第一名的好成绩;并指导本科生以“基于泛型编程的编译器研究”为题目申请并获得广西师范大学创新性实验基金资助。
八、结语
在整个教学过程中,我们首先帮助学生端正学习态度,破除《编译原理》难学的迷信。然后采用精简讲解、小题多练等方式,让学生体会理论并不深奥。在理论学习的基础上,引导学生动手实践,设计由易到难的实践项目,在此过程中打造属于同学们自己的编译程序,培养学习成就感。最终达到懂得理论、学会设计、学好《编译原理》这个总目标。作为教学的巩固与延伸措施,我们会引导同学做更多的实践。比如C语言的语法分析、SQL语言的语法分析、尝试使用C++的Boost.Spirit开发包等等。同时,和学生一起参与开发过程,用电话、Emai等方式与同学保持密切联系,及时解答同学们学习过程中遇到的问题。不但要让学生学懂理论、学会运用,更要让学生记得牢固。
我们将整个教学过程看作是一个工程项目,将工程中目标明确、量化管理的特点引入到编译原理的教学过程中,收到了比较好的教学效果,也受到了学生的欢迎。
[ 参 考 文 献 ]
[1] 张素琴,吕映芝,蒋维杜,戴桂兰.编译原理[M].北京:清华大学出版社,2007.
[2] Alfred等著,李建中等译.编译原理技术与工具[M].北京:机械工业出版社,2003.
[责任编辑:黄紧德]