邵 兵,杨海燕,张 莉
(1. 北京航空航天大学 软件学院,北京 100191; 2. 北京航空航天大学 计算机学院,北京 100191)
编译原理课程的教学改革与实践
邵 兵1,杨海燕2,张 莉1
(1. 北京航空航天大学 软件学院,北京 100191; 2. 北京航空航天大学 计算机学院,北京 100191)
编译原理的新概念、新算法和新理论比较多,被计算机及软件专业学生视为最难以掌握的专业基础课之一。针对课程教学中难点比较集中的问题,为了让学生能平缓地接受该课程的基础理论和知识,提出两遍教学法的思路,阐述如何将编译原理的实践环节和教学环节有机结合,对教学和实践的各个环节进行合理安排,并说明已取得的教学效果。
编译原理;课程实践;课程改革
编译原理课程作为本科计算机和软件专业的专业基础课,一直被学生公认为是大学期间最难掌握的课程之一。该课程之所以难,从学生的角度看,主要表现在其理论性比较强,新的概念和算法较多,具有很强的抽象性。从教师的角度看,主要表现在以下两个方面:一方面是编译原理课程的重点和难点较为集中;另一方面则是该课程的理论讲授和实践锻炼两部分之间的衔接关系不好处理。
1.1 编译原理知识体系的特点
编译原理课程的知识体系一般由词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生产以及符号表管理和错误处理几个章节组成。讲解该课程一般也是按照这一顺序递进展开,且差异多表现在后面几个章节的前后顺序上。这些章节中,最难理解的部分是词法分析和语法分析,学生一旦在该部分的学习与理解上出现问题,就会产生挫败感,将直接影响其后章节的学习兴趣。
各章节难度系数如图1所示,数据由我们对北京航空航天大学软件学院部分已修过该课程的学生进行问卷调查而来,共发放问卷60份,回收55份。问卷将每章内容的难度分为6档:非常难、较难、一般、容易、很容易和不知道,分别对应难度系数1.0、0.75、0.5、0.25、0.0和不计入。
从图1可以看出,语法分析和语义分析两章的难度明显高于其他章节的难度,在此形成一个顶峰,其次为代码优化。目标代码生成作为编译器最末端的一章内容,受不同目标机器指令体系的影响,因此内容变化较大,教师授课中可视学时数和教学目标而作取舍。编译器前端(分析部分)各章节依赖性很强,而后端(综合部分)各章节依赖性则较弱。如何在讲授中克服语法分析等章节的难度,让学生平缓地接受各部分知识,是授课教师在制订教学计划时必须考虑的一个问题。
图1 各章节难度系数示意图
1.2 编译原理实践环节
编译原理的理论性很强,因此,为了把书本上的理论知识转化为学生的实际技能,不少学校都为编译原理课程配备了一定学时的实验环节,包括课程中间的实验性作业或大作业形式的完整实验课程(权且称之为编译实践),以便学生亲自动手编程,实现一个小型编译器或者完成其中的某些部分,进一步巩固对理论知识的理解与掌握。
对于编译实践课程的安排,各院校基于各自的课程体系有自己的考量和安排。一些学校将编译原理和编译实践作为完全独立但有依赖关系的两门课程分开讲授;而有的学校则是将两门课程融合成一门课程,或者虽然作为两门课,但是同时安排在一个学期先后或交叉进行。这两种方法各有千秋,前者便于课程安排,但课程持续时间较长,理论部分和实践部分脱节;后者虽然解决了理论与实践脱节问题,但是在一定时期内如何合理地安排两部分内容,对课程组织来说构成了挑战。
在编译原理课程的所有内容中,最难的知识点莫过于自底向上方法中的LR分析法,学生尤其对如何构造识别规范句型活前缀的自动机较为困惑;其次可能是识别正则文法的有穷自动机的确定化及最小化问题。这两个难点恰恰是自动(机器)构造语法分析器和词法分析器的方法,对于手工编写程序以实现一个编译程序而言并没有影响。因此,编译原理的讲授可以分成两遍进行。
首先,讲授构造一个编译器的基础知识,在词法分析部分只讲授用状态图构造词法分析器的手工方法;然后,跳过有穷自动机的相关知识,直接进入语法分析部分;在语法分析一章,先给出一个语法分析器的总体概念,第一遍只讲授所有手工实现语法分析器的方法,包括自顶向下分析法中的递归子程序法和自底向上分析法中的算符优先分析法,跳过自顶向下的LL分析法和自底向上的LR分析法,所讲授的递归子程序法足以保证学生能够手工编写一个语法分析程序;此后,按正常的教学顺序依次讲授后面的内容。这种方法的具体过程和知识点组织如图2所示。
图2 编译过程和知识点组织
这种方法中,第一遍首先给学生介绍一个完整的最简单的编译过程,如图2中A列和B列对应的知识点。这些内容是构造一个编译器时必不可少的知识和技能,掌握了这些知识,就能保证学生可以做出一个可用的编译程序。
第一遍讲授结束时,所有手工编写编译程序的方法全部讲完,学生可以凭借这些知识开始编写自己的编译程序;此时,可以开始第二遍的讲授。第二遍讲授的内容包括编译程序的自动生成技术,包括词法分析部分的正则文法、自动机理论和LEX以及语法分析部分的LL分析法和LR分析法。代码优化和目标代码生成两部分的内容可以根据培养要求和课时长短选择性地讲授,可以放在第一遍讲授,也可以放到第二遍中。
在第一遍讲授过程中,每讲到一个知识点,教师就可以安排学生以作业的方式完成相应部分的编译程序,如讲完词法分析,可以让学生编写词法分析模块程序;讲完递归子程序法,让学生编写语法分析模块程序等。第一遍讲授全部结束后,学生基本上学习了编写一个简单编译程序的所有知识点,中间完成的各个编译程序子模块拼接起来实际上就构成一个内容基本完整的编译程序;也可以将上述作业仅仅作为课后练习,而在第一遍讲授结束后再布置一个大作业(或启动编译实践实验课程),让学生利用后半学期课程的时间编写一个编译器。与此同时,再进行第二遍讲授,并将第一遍讲授中剩下的所有内容全部补齐。这样做的好处在于等到最难的LL和LR分析法讲完时,正好赶上期末考试,学生可以趁热打铁,较好地理解和掌握自动化实现编译器的相关内容。
在编译大作业文法的选择上,教师可以考虑选择文献[1-2]提供的PL/0文法和文献[1]提供的Pascal-S文法或C0文法。
对于大作业,针对学有余力的学生,教师可以在他们完成一个完整的小型编译器所有内容的基础上,鼓励其对相应文法进行适当扩充或者是添加代码优化等选做内容,以期让学生从实践方法上得到更多的锻炼。针对学习能力一般的学生,教师可以采用为学生提供不完整的源代码,让其以填空方式完成其中一些模块;此类题目由于提供了大部分源程序,只是让学生参考教材或课堂上的示例,集中精力解决一些关键问题,以保证大多数学生能完成实践任务,真正达到通过课程实践加深对编译过程理解的目的。针对那些学习能力相对较弱的学生,教师则可以采用让他们分析现有编译器程序的做法;也就是说,并不要求他们自己设计开发一个具体的编译器,而是通过读懂现有的编译程序,了解其工作原理,哪怕让他们依葫芦画瓢地逐行输入并调试现有的程序,找出现有程序中的印刷错误和不合理之处,都将对提升其动手能力起到一定作用。总之,编译大作业的完成一定要因材施教,避免一刀切的教学模式[3]。
通过对比实施两遍教学法前后3年的教学效果发现,虽然学生的编译原理课程期末考试成绩并没有明显提高,这可能是试题不同所致,但是学生普遍反映对整个编译过程“有了更清晰地了解”。实施两遍教学法之前,学生对编译实践课程的学习兴趣不高,选修比例一直在低位徘徊,如2009级选修比例为22%、2010级无一人选修;而实施两遍教学法之后,学生选修比例持续高达90%以上。
在上述调查问卷中,针对“您认为编译实践课程(大作业)的作用”一问,有44%的学生认为很有帮助,有33%的学生选择“有帮助”,认为“一般”的占比13%,只有大约10%的学生认为帮助不大或完全没有帮助。由此可以看出,学生对实践环节的效果还是比较认同的。
笔者根据编译原理课程的特点和对学生接受能力的分析,提出将其整个编译原理课程知识体系的讲授过程分为编译器的手工编写和自动化生成两遍的教学方式;同时,通过合理安排编译实践环节,加深学生对相关知识的理解,培养学生的程序编写能力。该教学改革的尝试已在北京航空航天大学计算机学院和软件学院本科教学实践中试运行3年以上,取得了很好的教学效果。
将来,我们准备对编译实践环节进行深入探索,计划开发基于云平台的实验项目,为每位学生自动生成实验题目和内容。该平台在结果考查环节能够自动生成测试用例,从而减少教师的工作量;对学生而言,通过该平台能够及时获得相应的指导和帮助。
[1] 张莉, 杨海燕, 史晓华, 等. 编译原理及编译程序构造[M]. 北京: 清华大学出版社, 2011: 366-438.
[2] 陈英, 陈朔鹰, 王贵珍, 等. 编译原理[M]. 2版. 北京: 北京理工大学出版社, 2006: 286-304.
[3] 邵兵. 软件学院编译原理实践课程的教学探索[J]. 计算机教育, 2016(8): 115-117.
(编辑:宋文婷)
1672-5913(2017)02-0073-03
G642
邵兵,男,副教授,研究方向为编译技术和交互式设计,shaobing@buaa.edu.cn。