远程编译(共4篇)
远程编译 篇1
1 RPC概述
远程调用 (RPC) 是一种进程间通讯技术, 该技术允许一个程序调用执行处于另一地址空间中 (通常是网络中的另一台计算机) 的函数, 但无须显式编写远程交互代码, 即, 程序员可以编写基本相同的调用代码, 而无须考虑被调的函数处于本地还是远程服务器。当编写面向对象风格时程序时, RPC也常被指代为remote invocation或remote method invocation。已经存在很多用于实现RPC的技术, 比如ONC RPC和DCE/RPC, 它们之间是不兼容的。
RPC是一种典型的和流行的用于实现分布式计算之C/S模型的范式。一次远程调用由客户端发起, 它发送一个请求消息至一个已知的远程服务器, 请求使用其提供的参数执行一个指定的函数。而服务器将执行结果作为响应消息传回客户端, 客户端继续其执行。当服务器处理本次调用时, 客户端处于阻塞状态。由于不同的实现间存在很多细微变化, 造成了许多不兼容的RPC协议。
传统RPC实现只适合用来从零开始构建分布式系统, 对于存在大量遗留代码的情况, 会带来巨量的移植工作。为了刚好满足项目的需求, 笔者设计了一个专用的轻量级RPC系统, 该系统实现了最基本的RPC功能, 如本地过程语法调用、参数列集、散集、服务器并发访问、服务器端过程注册等 (剔除了多传输层支持、端口映射等项目不需要的功能) 。在该RPC系统初具雏形时, 笔者挑选了若干GIS服务过程 (均以标准C函数动态库导出的方式提供) , 开始通过调用RPC运行时函数, 为它们进行客户端代理与服务端存根代码的手工编写。经过仔细观察, 发现给定一个过程:
long foobar (Foo foo, Bar&bar) ;
其客户端代理入口
long CLNT_foobar (Foo foo, Bar&bar) ;
与服务器端存根入口
long SVR_foobar (DataStream&CallArgStrm, DataStream&RtnStrm) ;
实现代码由函数的声明信息唯一确定。即不同过程仅仅是参数和返回值的列集与散集代码不同, 剩下RPC运行时代码的调用完全类似。根据该规律, 笔者设计并实现了基于原始接口编译的远程调用代理存根生成器。
2 生成器的设计与实现
2.1 自定义RPC运行时框架的结构
由于代理存根生成器的实现与笔者设计的轻量级RPC运行时强相关, 在介绍生成器的设计之前有必要先对该RPC运行时库做简要的介绍。
运行时系统主要由3个动态库 (在linux下是3个共享对象) 组成。使用C++语言编写。
GisSocket.dll:提供跨平台的Socket5对象库。
GisSvcUtil.dll:提供客户端与服务器端的核心RPC API。包括消息传递、消息监听、调用转发和列集/散集库的动态加载管理。
BaseSerializer.dll:预定义结构的列集/散集函数库, 包含了笔者项目中涉及到的绝大多数数据结构。
CustomSerializer.dll:自定义结构的列集/散集函数库。所有预定义之外的都是自定义。
2.2 代理/存根的实现
客户端代理过程都通过类似的流程来实现, 如图2所示。
代理过程的签名 (signature) 与服务器端的实际过程完全一样。这样就为客户实现了本地调用的语义 (semantics) 。
再看服务器端存根过程的实现流程, 如图3所示。
代理与存根在使用上的不同在于:代理直接由客户端应用代码调用, 而代理自身是使用客户端RPC运行时实现的。而存根由服务器端RPC运行时调用, 运行时将列集后的调用参数流传递给它, 它将参数解析出来, 调用实际过程, 并将返回值列集返回给RPC运行时。
2.3 生成器的原理
生成器读取并分析已有服务过程的头文件声明, 解析出它的签名信息, 包括过程名、参数类型、参数名、参数数量并存于相应的数据结构。然后根据代理/存根代码的编写模式, 自动生成实现代码。
2.4 生成器的架构
使用标准的编译器架构, 由前端和后端构成。前端负责语法分析, 输入为经过标准化的动态库头文件 (前面已说明所有服务过程均以标准C函数动态库导出的方式提供) , 输出为经过解析的中间格式, 包括生成代理/存根代码所需要的所有过程定义的元数据。后端读取元数据, 根据内建规则 (规则即为代理/存根的实现方式) , 自动生成并输出代理/存根的实现代码。
2.5 生成器的实现
生成器前端的核心数据结构有:
(1) typedef vector
该结构存储初步解析后的过程声明信息。
(2) typedef struct directedparam有向参数。
有向参数的引入原因是:笔者已有的服务过程只通过返回值说明调用成功与否, 而逻辑上的返回值均是通过引用或指针的方式声明为函数的传出参数。定义了两个空宏:
#define IN;
#define OUT
用户标示参数为传入的实际参数还是为传出的实际返回值。这样生成器的前端就可以通过这两个宏来识别参数的方向, 并成功分辨和提取参数与返回值的元数据。并且可以不改变原有服务过程的声明。 (空宏不会引入任何改变) 。
(3) typedef vector
(4) typedef struct paramlist过程声明结构, 该结构保存了声明一个过程的完整元数据。
(5) typedef vector
后端没有数据结构, 而是将代码生成规则进行硬编码。以一个头文件的过程表结构为输入, 一次性产生所有的代理/存根源代码。由于生成规则与自定义RPC运行时的API强相关, 而这些API的设计与用法并非本文关注点, 所以对后端的实现不再赘述。
3 结束语
使用该生成器, 笔者在几乎没有对已有服务过程与客户端代码做任何改动的情况下, 成功将所有服务动态库以远程调用的形式部署到了Linux服务器上。基本实现了项目开发的需求。
但该生成器还具有很多不足与缺陷:
前端文本解析功能不完善。需要对过程的声明文件做一定的标准化修改, 比如去掉所有非过程声明类代码。
为了获得参数的方向, 必须在过程声明中使用空宏为每个参数标示方向。这样做虽然没有任何副作用, 但还是在一定程度上污染了已有的代码。
前端解析功能不完善。尚不支持复杂声明。比如多重指针、指针的引用等。
后端没有设计独立的代码生成规则表示。导致后端的实现与代码生成规则即自定义RPC运行时强相关, 如果修改自定义RPC运行时的实现, 则必须修改生成器后端。
这些问题的解决, 是笔者未来工作的重点方向。
参考文献
[1]RFC707A High-Level Framework for Network-Based Resource Sharing.
[2]RFC1050RPC:Remote Procedure Call Protocol Specification.
[3]RFC1094NFS:Network File System Protocol specification.
[4]ONC+Developer's Guide, Sun Microsystems, Inc, May2002.
[5][美]W.Richard Stevens.Unix网络编程Vol.1套接口API[M].杨继张, 译.北京:清华大学出版社, 2006.
远程编译 篇2
关键词:C语言,C编译器,——运算,编译
C语言是高校计算机课程的重要部分,同时也是全国计算机等级考试的一部分。目前C语言的学习者越来越多,对C语言的了解也越来越清楚。然而在C语言教学中发现很多学生对其中的自加自减运算符感到迷惑,特别是二者出现前置后置混合使用时。同时,C语言教学中常用的两个编译器,即Turbo C 2.0编译器和Visual C++6.0编译器,对自加自减运算的编译顺序有不同,更加重了学生对此部分内容的不解。因此,本文着重分析上述两种编译器如何对自减运算进行编译,对于自加运算读者可参考文中自减运算进行分析。
1 C语言自加和自减运算
C语言的自减运算符为--,有前置和后置两种用法。前置用法指将运算符放于变量的前面,其功能是在使用变量前,先使变量的值自减1,之后再使用变量的值。后置用法指将运算符放于变量的后面,其功能是先使用变量原来的值参加表达式运算,之后再使变量的值自减1。例如下面的C语句:
很显然,不管是前置用法还是后置用法,对变量本身的影响都是相同的即自减1,受影响的是所在表达式的值。表达式中仅包含单个自减运算时Turbo C 2.0编译器和Visual C++6.0编译器的解释相同,但当表达式中出现不止一个自减运算时,Turbo C 2.0编译器和Visual C++6.0编译器的解释就可能不同。
2 两种编译器中汇编代码的查看
计算机程序如何运行依赖于该语言的编译器,因此通过对编译器的编译结果进行分析是了解编译器如何对运算进行编译的有效方法。
Turbo C 2.0编译器提供有许多工具,其中的Tcc.exe就是一个C语言的编译器,可以将代码编译成目标文件,并能自动调用tlink链接生成可执行文件。Tcc.exe有多种命令行参数,其中使用-S可以生成汇编代码。例如Tcc.exe–S yourfilename.c将生成yourfilename.c源文件的汇编代码文件yourfilename.ASM,进而可对该文件进行汇编代码分析。
Visual C++6.0编译器有汇编窗口,可以以单步运行方式运行程序,之后选择View/Debug Window/Disassembly命令,进入汇编窗口查看对应于源程序的汇编代码。
3 自减运算的单一前置或后置
当出现多个单一前置或多个单一后置时,如何编译又分不同情况。例如下面的程序:
当以Turbo c 2.0编译器编译后运行结果为:12 9 3 6。其解释方式如下:
1)对运算1:因赋值表达式右式的均为自减后置,则先一次性取3个子表达式(a--)的值顺次进行加运算,即((4+4)+4)=12,之后再统一进行a的三次自减操作。则a最终为1,输出结果12。
2)对运算2:格式输出函数的实参为一个加运算表达式,求值时从左向右进行,因为是自减后置,每个子表达式在将a的原值作为子表达式值后直接进行自减操作,所以表达式的值为((4+3)+2)=9。则a最终仍为1,输出结果为9。
3)对运算3:因赋值表达式右式的均为自减前置,则先对a顺次进行3次自减操作变为1,之后再进行3个a的算术加。则a最终为1,输出结果为3。
4)对运算4:格式输出函数的实参为一个加运算表达式,求值时从左向右进行,因为是自减前置,每个子表达式在将a的进行自减操作后将其新值作为子表达式值,所以表达式的值为((3+2)+1)=6。则a最终仍为1,输出结果为9。
当以Visual C++6.0编译器编译后运行结果为:12 12 5 5。其解释方式如下:
1)对运算1:因赋值表达式右式的均为自减后置,则先一次性取3个子表达式(a--)的值顺次进行加运算,即((4+4)+4)=12,之后再统一进行a的三次自减操作。则a最终为1,输出结果12。
2)对运算2:格式输出函数的实参为一个加运算表达式,求值时从左向右进行,而编译器将算术加的优先级视为高于后置自减,所以仍先一次性取3个子表达式(a--)的值顺次进行加运算,即((4+4)+4)=12,之后再统一进行a的三次自减操作。则a最终仍为1,输出结果为12,运算过程与运算1类似。
3)对运算3:因赋值表达式右式的均为自减前置,而编译器将算术加的优先级视为低于前置自减,同时运算从左向右逐次进行,则先对a顺次进行2次自减操作变为2,之后求出前两个子表达式之和为4,之后再进行a的第3次自减变为1,之后再与之前的和相加得5,即((2+2)+1)=5。则a最终为1,输出结果为5。
4)对运算4:格式输出函数的实参为一个加运算表达式,求值时从左向右进行,因为是自减前置,同时运算从左向右逐次进行,则先对a顺次进行2次自减操作变为2,之后求出前两个子表达式之和为4,之后再进行a的第3次自减变为1,之后再与之前的和相加得5,即((2+2)+1)=5。则a最终为1,输出结果为5,运算过程与运算3类似。
4 自减的前置和后置混合使用
当同时出现前置和后置时,如何编译又分不同情况。例如下面的程序:
当以Turbo c 2.0编译器编译后运行结果为:6 7 4 3 3 4 10 19。其解释方式如下:
1)对运算5:对赋值表达式k=(a--)+(--a)+(--a),编译器按照自减前置优先级高于子表达式求值,子表达式求值高于自减后置的顺序进行。所以先进行两次a的自减操作使a的值变为2,之后将a的值分别作为三个子表达式的值进行求和并赋给k,则k的值为6,之后再进行一次a的后置自减使a的值变为1。则a最终为1,输出结果为6。
2)对运算6:格式输出函数的实参为一个加运算表达式,顺次将两两子表达式进行相加,即(((a--)+(--a))+(--a)),对每一个子表达式求值时其中包括的自减操作不论前置、后置均进行完才进行下一个子表达式的求值。所以先求子表达式(a--)的值为4并将a的值自减变为3,之后子表达式(--a)求值时先a自减变为2,再将新值2和上一个子表达式值4相加得6,之后进行第3个子表达式(--a)的求值,a先自减变为1,再将新值1和前两个子表达式之和6相加得7,即对应值为(((4)+(2))+(1))。则a最终为1,输出结果为7。
3)对运算7:此时格式输出函数的输出项列表有四个子表达式,Turbo c 2.0编译器按照从右至左的顺序进行求值,对每一个子表达式求值时其中包括的自减操作不论前置、后置均进行完才进行下一个子表达式的求值。所以先进行(a--)得第4个输出值为4并将a置为3,之后进行(a++)得第3个输出值为3并将a置为4,再之后进行(--a)将a置为3并求得第2个输出值为3,最后进行(++a)将a置为4并求得第1个输出值为4。则最终a为4,输出结果为4 3 3 4。
4)对运算8:此运算和运算9情况类似,两个子表达式((a--)+(--a)+(--a))求值时其中包括的自减操作不论前置、后置均进行完才进行下一个子表达式的求值,而每个子表达式求值和上述运算6一样。所以第2个输出项的对应值为((8)+(6)+(5))并将a置为5,第1个输出项的对应值为((5)+(3)+(2))并将a置为2。则最终a为2,输出结果为10 19。
当以Visual C++6.0编译器编译后运行结果为:8 8 4 3 4 4 14 20。其解释方式如下:
1)对运算5:对赋值表达式的右式,编译器首先从左到右两两子表达式进行加运算,每次运算中前置自减优先级高于子表达式求值,而后置自减则放于整体赋值之后统一进行,即k=(((a--)+(--a))+(--a))。对((a--)+(--a))先进行一次a的前置自减使a的值变为3,之后将a的新值分别作为两个子表达式的值进行加运算得和为6,此时不进行a的后置自减而是继续求下一个子表达式,第3个子表达式(--a)先进行a的前置自减使a变为2并将该值作为子表达式的值与前面两个子表达式之和6相加得8并赋给k,之后再进行a的后置自减使a的值变为1。即k对应值为(((3)+(3))+(2)),a最终为1,输出结果为8。
2)对运算6:格式输出函数的实参为一个加运算表达式,但Visual C++6.0编译器求值时和对运算5的求值相似,即总体按(((a--)+(--a))+(--a))进行。对((a--)+(--a))先进行一次a的前置自减使a的值变为3,之后将a的新值分别作为两个子表达式的值进行加运算得和为6,此时不进行a的后置自减而是继续求下一个子表达式,第3个子表达式(--a)先进行a的前置自减使a变为2并将该值作为子表达式的值与前面两个子表达式之和6相加得8并作为实参值输出,之后再进行a的后置自减使a的值变为1。即实参值为(((3)+(3))+(2)),a最终为1,输出结果为8。
3)对运算7:此时格式输出函数的输出项列表有四个子表达式,Visual C++6.0编译器按照从右至左的顺序进行求值,每次运算中前置自减优先级高于子表达式求值,而后置自减则放于各个输出项的值确定之后统一进行。所以先进行(a--)得第4个输出值为4而a不变,之后进行(a++)得第3个输出值为4而a仍保持原值,再之后进行(--a)将a置为3并求得第2个输出值为3,最后进行(++a)将a置为4并求得第1个输出值为4。则最终a为4,输出结果为4 3 4 4。
4)对运算8:此运算和运算9情况类似,两个子表达式((a--)+(--a)+(--a))求值时每次运算中前置自减优先级高于子表达式求值,而后置自减则放于各个输出项的值确定之后统一进行,而每个子表达式求值和上述运算6一样。所以第2个输出项的对应值为((7)+(7)+(6))并将a置为6,第1个输出项的对应值为((5)+(5)+(4)),之后统一进行两次(a--)置a值为2。则最终a为2,输出结果为1420。
5 结论
通过研究Turbo c 2.0编译器和Visual C++6.0编译器的汇编代码可以看到,两种编译器对自加自减运算的编译是不同的。所以对于C语言的学习者而言,在学习过程中应对所使用的编程环境加以区分,并掌握对这两种编译器的汇编代码的查看方法以帮助自己加深对编译器的理解。
参考文献
[1]刘克成.C语言程序设计[M].北京:中国铁道出版社,2007:42-50.
[2]谭浩强.C程序设计[M].北京:清华大学出版社,1998:30-35.
编译原理课程教学探讨 篇3
编译原理是高等院校计算机专业继“数据结构”、“计算机原理”等专业基础课之后的又一门重要的专业基础课, 以形式语言与自动机理论为基础, 讨论编译程序构造的基本原理[1]、基本设计方法和主要实现技术。通过本课程的学习, 能深化学生对计算机信息处理本质与计算机工作过程的认识, 加深对程序设计语言的理解, 为后继专业课程的学习奠定坚实的理论基础, 并将编译程序构造的基本原理和技术应用于一般软件的设计。因此, 努力提高这门课的教学效果, 使学生真正掌握这门课的精髓, 并应用到实践中去, 具有非常重要的现实意义。
1 编译原理课程现状与问题
编译原理课程由于理论性强, 具有严密的逻辑性, 应用其他课程的知识较多, 学生在学习过程中感到内容抽象、算法复杂、难于理解, 学习起来有一定的难度, 因此, 编译原理被普遍看做是计算机专业本科教学中最难讲解、最难学习的课程之一, 在教学上不同程度的存在以下几个问题。
1.1 理论知识抽象难懂, 学生有畏惧心理
这门课程主要讨论编译的基本理论和编译器构造的基本方法, 涉及的理论知识抽象、难懂, 如形式语言与自动机理论、语法制导翻译以及各种算法, 又综合运用到前面所学的相关课程的知识, 确实具有相当的难度, 使得学生产生了畏惧心理。此外, 不少学生认为学习这门课将来只能用于编译器的设计上, 而大多同学将来都不太可能去从事编译器的设计工作, 因此普遍认为这门课没有用, 学习热情不高。
1.2 理论课教学方式陈旧单一
目前, 编译原理的理论课大多以老师讲解为主, 很少辅之以其他形象生动的教学手段, 教学内容又大多是抽象的概念和复杂的算法, 老师和学生之间的互动很难形成, 学生觉得枯燥乏味, 慢慢就失去了学习的兴趣, 难以达到良好的教学效果[2]。
1.3 实验内容脱离实际, 不够合理
这门课程的实践环节大多要求实现一个小型语言的编译程序, 而实现一个编译程序不仅要有相关的理论知识, 更需要丰富的实践经验, 熟悉硬件系统和操作系统的功能, 对于大多数同学来说, 编程能力都相对欠缺, 实现编译程序基本是不可能完成的任务。因此, 大多同学在实验时碰到的困难太多, 无从下手, 干脆放弃努力, 也就失去了实验的意义。
2 教学探讨
2.1 帮助学生克服畏惧心理, 培养学习兴趣
根据这门课程抽象难懂的特点, 首先要帮助学生克服畏惧心理, 才能发挥他们的学习主动性。这门课的先行课程如“数据结构”、“离散数学”、“高级程序设计语言”等都是学生已经学习过的课程, 学生实际已经具有相应的能力, 老师需要的是帮助学生分析他们已经掌握的知识, 让学生对自己有足够的了解, 明白以他们已掌握的知识为基础, 有足够的能力学习掌握编译原理这门课程, 在学习之前首先消除畏惧心理。
编译程序涉及的算法、思想和实现技术除了设计编译器以外也可广泛应用于一般软件的设计实现[3], 如文本编辑器、信息检索系统、模式识别器等, 对提高学生程序设计能力和开发大型软件的能力是十分有益的。教师可以鼓励学生尝试将编译程序中的各种算法和技术应用到各个领域, 以培养学习兴趣, 激发学生的创造性思维, 培养学生的创新能力。
2.2 采用案例式教学, 把抽象问题具体化
编译原理中涉及的大量概念和算法都过于抽象, 学生理解起来非常困难, 要想获得良好的教学效果, 必须借助实例, 使抽象问题具体化。例如, 词法分析部分主要阐述词法分析器的工作原理和构造方法, 相关概念和算法较多, 可以通过一个具体的程序范例进行教学。通过编写一个读单词过程, 从输入的源程序中, 识别出各个具有独立意义的单词, 即基本保留字、标识符、常数、运算符、分隔符五大类, 并依次输出各个单词的内部编码及单词符号自身值。在课堂上通过程序的运行来展示词法分析器的工作过程。通过实例教学, 学生既加深了对理论知识的理解, 也提高了学习的积极性。
2.3 注重启发式教学, 培养学生独立思维能力
传统的教学注重教师的讲解, 学生被动的接受知识, 不利于学生思维能力的培养[4]。我们在教学中, 特别注重启发式教学, 引导学生去思考探讨。启发式教学需要教师有目的的设计问题, 有意义的提出问题, 通过问题把知识点引导出来, 学生通过思考回答问题, 寻找解决问题的途径和方法, 加深对知识点的理解。例如, LR分析法是语法分析中较难的部分, 其中包含了四种不同的分析表构造方法, 学生不好理解。在讲解时先给出LR (0) 分析表的构造方法, 引导学生发现其中的不足并进行改进, 从而引出SLR分析法, 再进一步引导学生发现SLR方法的不足, 引出LR (1) 分析法, 同样的方法引出LALR分析法。通过这样的启发式教学, 不仅破解了教学难点, 也引发了学生探究的兴趣。
通过启发式教学, 培养了学生独立思考问题、发现问题、解决问题的习惯和自主能力。学生也在这个过程中通过自己的学习活动获取知识, 发展能力。
2.4 现代化教学手段和板书相结合, 提高学习效果
编译原理课程内容抽象, 知识点多, 要想取得良好的教学效果, 必须借助形象化的教学手段, 构建多媒体环境下的教学环境。利用多媒体设施、电子教案、教学网站等多种途径把知识化静为动, 寓教于乐。为此, 我们精心编制了多媒体课件, 用Flash技术制作了动画, 可以生动形象的演示抽象概念和复杂算法。这样不仅激发了学生的学习兴趣, 也加深了学生对理论知识的理解。但是采用多媒体教学也不能完全抛弃板书, 因为板书灵活, 可以随时补充。所以在教学中应做到多媒体教学和传统的板书教学相结合。
2.5 精心设计课程实验, 加强学生实际应用能力
编译原理是一个理论和实践并重的课程, 但是如何组织实验内容始终是教学中的一个难题[5]。目前普遍的做法是实现一个小型语言的编译程序, 而这并非一件容易的事情, 对于编程能力都还欠缺的学生来说, 实现完整的编译程序基本是不可能完成的任务。因此, 大多同学在实验时碰到的困难太多, 无从下手。对此, 我们的做法是提供给学生程序源代码但是空出关键模块, 学生只需完成关键模块的编写, 大大降低了实验的难度, 也使学生可以集中精力解决关键问题。在实践环节中, 根据学生的能力、性别, 采用互补的搭配方式把学生分为若干小组, 每组设小组长负责实验的学习讨论并对各成员进行分工。每一次实验结束后, 各个小组以小组长为代表汇报自己的作业, 由其他小组自由提问, 实现各个小组之间的交流, 分享各组的实践成果, 互相借鉴, 很好的激发了大家的学习兴趣。
3 结语
编译原理课程作为计算机专业的一门重要专业基础课, 对于提高学生的计算机专业素养具有重要的作用。本文分析了目前教学中存在的问题, 并从教学实践出发, 对如何调动学生积极性从而真正提高教学效果总结出了一些有效的教学方法, 在实际教学中也取得了良好的效果。由于课程的复杂性和抽象性, 还需要不断地探索更合理的教学方法, 提高教学质量。
参考文献
[1]朱文华, 王荣波.基于建构主义的编译原理实践教学研究[J].杭州电子科技大学学报:社科版, 2008 (4) :67—70.
[2]舒忠梅, 李文军, 周晓聪.编译原理教学改革实践初探[J].中山大学学报:自然科学版, 2007 (S2) :101-104.
[3]莫雷.教育心理学[M].广州:广东高等教育出版社, 2003.
[4]何炎祥.现代教学理论指导下的“编译原理”教学综合改革[J].计算机教育, 2005 (03) .
《编译原理》教学改革初探 篇4
《编译原理》课程是计算机专业人员必修的一门主干课程, 虽然只有少数人从事编译方面的工作,但这门课程在理论、技术、方法上都对学生提供了系统而有效的训练,通过本课程的学习可以培养并提高学生的抽象思维、逻辑思维和编程能力。
《编译原理》一直是高年级专业课程中最难学习的课程之一。原因有四,第一:在学习本课程前,学生对它知之甚少,先入为主的认为该课程就是了解编译程序的构造,没有什么实际应用价值,学习没有积极性;第二:本课程具有一定的理论深度和难度,较一般课程学习过程的难度要大;第三:《编译原理》课程各章节间内容有密切的连贯性,学生在学习过程中,需要有较强的概括能力和逻辑能力,几个知识点掌握欠缺,可能会导致整章理解模糊,产生畏难心理;第四:实验题目较难,需要足够的理论基础和较强的编程能力为前提。因此,如何提升学习积极性、如何深入浅出讲授理论内容、如何合理安排实验过程显得尤为重要。本文就《编译原理》课程的授课方法和实验过程组织等问题进行探讨,以期改观本课程的教学效果,达到提高教学质量的目的。
1、课堂教学改革
1.1 兴趣教学
兴趣是人们力求认识某种事物或爱好某种活动的心理倾向,是推动学生学习活动的内在动力。要想让学生学得好,需不断的激发他们学习的兴趣,从而变被动学习为主动学习[1]。
1.1.1 兴趣入门,引发学习动力
兴趣的激发,应从入门开始。上课伊始,首先介绍《编译原理》课程的教学目标,并由此点出,整门课程讲解的就是一个编译程序的构造,可见该程序的庞大、复杂,提出在构造编译程序过程中用到了许多经典的技术和算法,利用学生猎新喜奇的心理,诱导学生学习的好奇心。其次,简单列举并演示编译技术在文本编辑器、网络协议、搜索引擎等方面的应用,激发兴趣的同时,消除学生对本课程无实际应用价值的理解误区。最后,指出包括《编译原理》课程在内,《软件工程》、《网络》等都是计算机专业独有的课程,在许多人把计算机只当作简单的应用工具,在许多非计算机专业也学习计算机课程的今天,进一步引导学生笃定学习目标为成为计算机专业人才。
1.1.2 兴趣教学贯穿整个教学过程
《编译原理》传统教学方式是以课堂教授为主的"灌输式"教学,而长时间以一种方法单调的进行教学,难免导致学生学习疲劳,因此需要根据具体教学内容,适当使用类比式、启发式、实例式等形式多样的的教学方法,来提升学习兴趣。
例如,从实现思想上来说,编译过程类似于英译汉,因此,可用类比式教育法由英译汉过程引入编译过程。大概如下,在对句子英译汉时,首先要识别出一个个单词(类似词法分析阶段),然后分析句子的语法结构是否合理(类似语法分析阶段),之后对英语句子进行初步的翻译(类似语义分析及中间代码生成阶段),接着对翻译进行润色(类似优化阶段),最后得到译文(目标代码生成阶段)。用这样的方法概述编译各阶段任务,学生更易理解。
又如,《编译原理》中算法非常多,对于一些雷同的算法,可采用启发式教育,教师提出问题,组织学生进行讨论并回答问题,教师做适当补充。例如在讲授算法优先分析方法的优先分析表构造时,需要求出所有非终结符的FIRSTVT集和LASTVT集,FIRSTVT集和LASTVT集的定义、求法是类似的,因此,教师可首先讲解FIRSTVT集的定义、求法及用其构造优先表的方法,然后使用启发式方法,让学生通过讨论,来写出LASTVT集的定义、求法及构造优先表的方法,教师做适当的纠正和补充。这样,学生对算符优先表的构造一定理解深刻。
又例,《编译原理》中多个理论可通过实例引入,采用实例法,激发学生的好奇心和求知欲。比如,对于算法优先分析法,可先通过如下文法G[E]及句子i1+i2*i3的归约,引入该法。
对句子i+i*i使用G[E]文法进行归约有两种方法,一种是:
i1+i2*i3归约为E+i2*i3归约为E+E*i3归约为E*i3归约为E*E归约为E。
另一种是:
i1+i2*i3归约为E+i2*i3归约为E+E*i3归约为E+E*E归约为E+E归约为E。
但显然第二种方法更符合我们的数学思维,因为从小学开始,我们就认为乘的优先级是高于加的。这就给出一种思路,能否设定运算符*的优先级高于+号,让i1+i2*i3归约的过程唯一,由此引入了算法优先分析法。
1.2 加深理论内涵的讲解
《编译原理》课程中包括有许多迷人的理论、精妙的算法,只有真正深刻理解到理论和算法的精髓,在日后才能将这些理论和算法应用于实际的问题解决中。对于课程中的非确定有限自动机的确定化、最小化、预测分析法、算符优先分析法、LR分析法等多个内容,笔者奉行理论-实例应用-理论-算法的讲解思路。即先了解理论的字面意思,然后通过实例非严格的对这些理论进行"证明",了解这些理论的使用,之后回到理论,通过基础知识点的逻辑推理,加深对这些理论的理解,最后由理论编写算法,解决问题。比如,讲授预测分析法的总控程序时,可首先描述三种可能动作的字面含义。然后,举例用这三种动作识别句子,熟悉三种动作的使用,了解总控过程。之后,从LL (1) 分析法思想及预测分析表的构造过程推导并深刻理解总控程序三个动作的内在含义,进一步了解预测分析法是LL (1) 分析法的一种具体。最后,依据三个动作及举例分析句子的过程,描述总控程序算法。
1.3 反复分析并强调知识点间逻辑关系
根据作者的经验和所作的调查显示,许多学生学习完《编译原理》后,并没有从宏观上掌握了编译程序构造的原理和基本设计方法,只是记住了各种算法的步骤,学会了做题,能基本应付考试。这就要求在授课过程中,要特别注意引导学生重视对编译的原理和技术的全面把握。具体在实施的时候,建议根据授课内容,由浅入深,从整体到局部,反复强调章和章之间、节和节之间逻辑关系,让学生在学习过程中,对每个知识点的意义和构造编译程序时其所处的位置有精准的把握。
比如,在讲授词法分析这章内容初始,可先行描述本章内容的组织。章节结构用图的形式来描述更加清楚,例词法分析这章内容可如图1.1所示。即本章第一个内容是了解词法分析的二元式输出形式。要通过词法分析程序获取二元式,需提前对源程序过滤无用的符号,因此,第二个内容是如何对源程序进行预处理。第三个内容为词法分析器的设计,从源程序获取二元式。讲授到词法分析器的设计时,又可通过图1.2来描述所用知识点及他们之间的关系。即首先通过正规式或正规文法描述出单词的词法规则,然后将正规式或正规文法等价转化为有穷自动机,对有穷自动机进行确定化和最小化,最后根据最小化的确定自动机编写词法分析器。学生了解了设计的总体思路后,在讲授到具体某个知识点还需要重复它在本图中的位置,及意义,如对确定有穷自动机的最小化,其目的为使有穷自动机的状态转换图达到最简形式,以便简化词法分析器的构造。经过验证,这样的叙述方式将词法分析器的实现思路,各知识点的逻辑关系阐述的更加清楚,加强了学生的整体把握。
2、实验教学改革
要很好地理解和掌握《编译原理》这门课,除了重视课堂教学的方法之外,还应该重视课程实验。设计一组与理论内容相适宜的课程实验,是整体上提高《编译原理》课程教学质量的重要保证。在实验内容组织上,我们在教学上采取如下策略:
2.1 针对知识点,增加小实验
传统实验课要求每个学生在规定学时内编写出词法分析器、语法分析器、语义分析及中间代码生成器。由于实验时间短,加之课堂教学刚刚结束,理论知识还没有完全消化,并且该课程实验的编程思路和以往一些编程实验的设计思想有很多的不同之处,所以,对于大多数学生来说,完成本实验困难较大,导致部分学生甚至不亲自编程,而是抄袭其他同学的实验报告应付了事,影响了实验教学的效果。因此,建议在各章授课结束后,先布置一些简单实验题目,加深学生对理论内容的理解,同时为最终完成各主要实验题目做好准备。可从两方面来考虑这些题目的选取。一方面,这些题目要与编译器的构造过程相关;另一方面,它们能够体现编译技术的应用。比如,词法分析章节结束后,可布置"一个人带着狼、羊、白菜过河"的题目。又如,在算符优先分析法章节后,可布置"简单计算器的设计与实现"题目。
2.2 简化基础语言文法,以理解编译理论和算法为目标。
实验的目的是加强对编译理论的理解和算法的应用,提高编程能力。若把构造编译器的源语言文法设计的非常复杂,学生则不得不将大量时间花费在用同样方法重复处理文法上,导致学生产生厌烦和畏难情绪,且对理解编译理论和算法没有大的益处。因此,可将源语言文法进行简化,这种做法看似降低了编译器构造的复杂性,为学生编程降低了难度,实则促进了学生对整个编译理论和技术的宏观掌握。
2.3 加强实验过程的组织与管理。
《编译原理》的语法分析、语义分析等实验比较庞大,务必要做完善的准备工作。教师最好提前一周布置实验,让学生有足够的时间准备。其次,在课堂上简要概括所需的理论知识、明确实验目的、实验内容、重点和难点,提醒学生使用软件工程的思想,来完成实验。并且,为防局限学生思路及抄袭现象,可改变传统的实验报告模式,教师不再硬性规定报告的格式和内容,而是要求学生将实验报告以科研论文的形式提交,让学生可完整叙述自己独到的思路和见解[2]。
2.4 根据实验实际情况,因材施教。
针对不同层次的学生,教师可在适当时候提供部分参考程序,让学生来完善。
3、总结
根据多年的教学经验,本文提出了几种课堂教学和实验教学的改进方法,事实证明切实可行。随着面向对象语言应用的日益广泛,学生素质的逐年提高,提升教师本身素质,根据需要增删教学内容,都是我们刻不容缓必须马上面对的问题。在解决这些问题的同时,我们应在该课程现有教学方法的基础上,合理运用各种教学辅助工具,对新的更合理的教学方法进行长期的不断的探索。
摘要:《编译原理》是计算机专业的一门主要的专业课程, 在计算机科学中有着重要的地位和作用。本文针对该课程的特点, 提出了几种改进课堂和实验教学的有效建议, 事实证明切实可行。
关键词:编译原理,教学改革
参考文献
[1]刘艳.计算机兴趣教学定位.黑龙江科技信息, 2008, 10:128