一切自动化是人类的一个梦想,人们为了实现这个梦想不断努力。人们利用计算机软件与硬件实现办公自动化、管理自动化的同时,也在考虑程序代码的自动生成。
在软件工程发展过程中,计算机科学家为了降低软件开发得强度,缩短开发周期,减少代码的重复书写,从而减轻程序员的编程负担,一直以来都致力于代码自动生成方面的研究。Lex/Yacc是最早用于自动化编写编译程序的工具。随着现代化信息环境日趋复杂,各种应用软件的开发难度随之加大,这需要更有技巧,更有方法地从事软件开发,开发团队之间也必须更无障碍地沟通,否则极可能无法在有限的开发时间中完成任务。由于时间上的压力,一般人只注重程序的编写速度,却忽略其完成后的实用性与维护性,加上大型程序多人共同参与开发,每个人都有各自的程序风格,容易造成严重的差异性,随着系统规模越来越大,这将造成系统完成后在测试及维护上沉重的负担,代码自动生成技术更显出了其显著的优越性。尽管这些应用没有代码生成工具也能开发完成,但利用代码生成技术可以大大加速软件的开发进度,提高软件的质量。
代码生成的优势与劣势分析
传统的代码开发调试工作流包括“编辑、编译、以及测试”。如图1所示。代码生成增加了一些新的工作流元素。传统的编辑、编译、以及测试阶段仍然适用。在代码生成的工作流中,首先编辑模版和定义文件(或者生成器本身),然后运行生成器创建输出文件。接着对输出文件进行编译测试(如果目标语言不是编译的语言,不考虑图1(右)中的编译阶段)。
![]()
图1 传统工作流与代码生成工作流的对比
代码生成技术是关于自动生成程序的程序的技术。与手工书写代码相比,代码生成器提供了下面的一些好处:
(1)所有软件实体的一致的代码质量,代码的质量依赖且只依赖于代码生成的模板、文件和模型。与此相比,手工经常采用的拷贝粘贴的方法为前后代码质量的一致性带来了隐患。
(2)提高了代码变更的能力,特别在需要大量更改代码的情况下,只需要更改模板并重新运行代码生成器即可。
(3)提高了修复软件Bug的能力,只需要修复模板的Bug然后重新运行生成器就可以修复所有的生成文件的Bug。
(4)提高了在不同框架之间的迁移能力,一个典型的情形是我们需要生成不同框架(如J2EE/.Net)的应用代码,代码生成技术将业务逻辑以语言无关的形式单独存放,通过为不同的框架提供代码模板可以基于同一逻辑生成不同框架的应用代码。
(5)灵活的同步机制,代码生成技术自动维护代码和数据模型的一致性,通过重新运行生成器,对模型的修改可以自动反映到代码中,这种同步机制对维护数据的一致性是非常必要的。
(6)大幅度提高了工作效率,运用代码生成技术可以将更多的时间花费在业务相关的设计和实现上,从而可以大大提高软件的开发效率和软件质量。
(7)是代码学习的导师,由于生成的代码具有良好的风格和100%的健壮性,程序开发者很容易模仿代码风格,从中学习。
当然,任何一种技术都有其缺点,代码生成器也不例外:
(1)代码生成器必须首先写好。
(2)只能适应指定的环境。
(3)不能100%生成想要得代码,还有一些代码需要手动修改。
(4)对于数据库代码,数据库必须涉及正确规范。生成器通常不能很好的应付有奇特设计特征的数据。
代码生成的分类
在技术领域一般我们可以将代码生成技术分为两大类:被动模式和主动模式(见图2)。在被动模式下,代码生成器产生一系列的代码,然后软件开发者可以自由的修改、编辑这些代码,但代码生成器不再承担对代码的维护工作。大多数软件集成开发环境(IDE)中的应用“向导”就是这种类型的代码生成器。被动模式的代码生成技术有其应用的范围,但是被动模式的生成系统有天生的局限性。生成器只运行一次,然后就不再承担对代码的维护工作。与此相反,主动模式下的代码生成器则对生成的代码“长期”负责,可以通过改变生成器的输入参数并重新运行生成器来改变输出的代码。如编译器生成器就是一种主动模式的代码生成器。
在技术领域一般我们可以将代码生成技术分为两大类:被动模式和主动模式(见图2)。在被动模式下,代码生成器产生一系列的代码,然后软件开发者可以自由的修改、编辑这些代码,但代码生成器不再承担对代码的维护工作。大多数软件集成开发环境(IDE)中的应用“向导”就是这种类型的代码生成器。被动模式的代码生成技术有其应用的范围,但是被动模式的生成系统有天生的局限性。生成器只运行一次,然后就不再承担对代码的维护工作。与此相反,主动模式下的代码生成器则对生成的代码“长期”负责,可以通过改变生成器的输入参数并重新运行生成器来改变输出的代码。如编译器生成器就是一种主动模式的代码生成器。
![]()
图2 被动模式与主动模式的对比
下面我们介绍几种常见的代码生成技术,这些技术对开发一个实用的代码生成器非常重要。可以依据代码生成技术的使用场合、复杂度等对这些生成技术进行分类,这里我们采用依据生成技术的输入、输出对它们进行分类。
(1)代码挑拣器,代码挑拣器的输入是源代码,通过拣取需要的信息可以生成各种文件,代码挑拣器的使用相当广泛,可以使用它来生成代码API文档(最著名的就是JavaDoc了)、获取常量和函数原型等。
(2)内联代码扩展器,内联代码扩展器的输入是带有特殊标记的源代码,这些特殊标记经过扩展器的处理后将被替换为相关的代码从而产生最终的生产源代码,内联代码扩展器的典型应用是将SQL语句嵌入到源代码中,其主要特点是使得底层结构和复杂的查询分开。
(3)混合代码生成器 混合代码生成器与内联代码扩展器很像,它也是处理源代码中的特殊注释但是与内联代码扩展器不同,它的结果将直接输出到输入的源代码中。这种方式的一个典型应用就是在对话框控件和它们代表的变量之间建立映射关系。
(4)部分类生成器 部分类生成器的输入是模板文件和包含特定类所需信息的定义文件,这些信息经过生成器将产生应用的基类。通过继承该基类可以完成剩余的工作。Velocity是一个源代码开放的Java模版引擎。
(5)层第生成器 层第生成器将生成一个多层应用的所有代码。模型驱动的开发是这种生成器的一个很好例子。通过UML模型输入和其余XML文件,生成器能够生成一个包含多个系统的完整应用,并且模型和代码之间可以单向乃至双向同步。
(6)完全领域语言 完全领域语言是一个图灵完全的语言,可以直接使用来进行领域相关的操作。一个典型的例子是Mathematica所使用的数学语言它可以简单的完成对矩阵运算的所有操作。
代码生成器几乎可以应用程序设计的每一个方面:
(1)编译与优化领域
编译与优化领域的代码生成主要是研究如何根据高级语言声称及其代码或字节码,以及生成的代码的可移植性问题。ANTLR, 语言识别的另类工具,是这样的一种语言工具。它为包括Java,C#和C++行为在内的语法描述提供了一种可以创建识别器,编译器和翻译器的框架。
(2)专用代码生成领域
专用代码生成器通常面向专用领域,生成小型的系统或程序,因此可以达到更高的代码生成率。例如有限元程序自动生成系统(FEPG)。FEPG采用元件化的程序设计方法和人工智能技术,根据有限元方法统一的数学原理及其内在规律,以类似于数学公式推理的方式,由微分方程表达式和算法表达式自动产生有限元源程序。
(3)通用代码生成领域
通用代码生成由于其应用开发的领域广泛,所以导致代码的生成效率不高,通常仅仅生成软件的框架代码,比如Rational Rose2002,它是Rational公司的旗舰产品,它使大型开发项目的分析、建模、设计规范化,它提供了许多框架,诸如J2EE等等,开发人员可以选择相应得框架将UML描述的设计转化为代码,但仅仅是框架,并没有具体得实现,需要开发人员在其中人工填入实现代码,以满足系统的功能需求,因而代码的生成率并不高。
AndroMDA 是一个前遵循模型驱动结构(MDA)范例的代码生成框架。它接受从CASE工具中获得的一个UML模型,生成类,为你的应用程序体系结构布署特定的组件(J2EE或其它)。JBuilder、EJB Maker、EJBGen、EJBCreator等都在一定程度上实现EJB代码的自动生成。Erwin是一个数据库设计工具﹐你可以设计﹑制作﹑快速维护高性能的应用数据库。通过ERwin的数据显示模型结构﹐你可以组织、管理﹑甚至减轻复杂的数据﹑数据库技术和开发环境。JaneBUILDER是一个可视化的PHP 编辑器,该软件并不是为了取代你现在所使用的文本编辑器和网页编辑软件。而是为用户在编写网页中的PHP代码时提供一个特殊的环境。PHP 是一种服务器端的跨平台的脚本语言,使用PHP语言可以创建出动态的网页。
代码生成机理
代码生成器的作用是读取工程的元数据,按照指定的设计模式,混合产生出规范的源代码。典型的代码生成器模型如图4所示。在图中,为自动生成程序代码,必需的三个关键要素是设计模式(所产生代码的模板文件)、领域元数据(在代码中需建模的拓扑结构,即定义文件,通常随开发折提供的特定数据增长)。
![]()
图4 典型代码生成器的模型图
构建自己的代码生成器有2种方法,一是综合利用流行的代码生成器。构建出适合自己的代码生成器;另一种方法是构造出一个全新的代码生成器。无论哪种方法,在构建代码生成器都应该注意下面几个方面:
(1)使用纯文字样版,使用纯文字样版的好处除了编辑方便外,也能将程序代码定义逻辑和格式化逻辑分隔开来,使实作上更有弹性。
(2)编写正规表达式(Regular Expression),正规表达式是一种字符串的表示方式,使用它不仅扩大了字符串的表达能力,让使用者很容易进行字符串判断,也可避免撰写程序进行复杂字符串解析的麻烦,也自然使得数据处理的过程变得更为迅速便利。
(3)编译器原理,在对于文本文件的处理上,先利用扫描器(Scanner)扫描出其中的字符,再实作解析器(Parser)解析出所对应的语法,然后转换成所要产生的程序语言。
(4)文档输出入的处理, 由于程序产生牵涉到大量的文档读写动作,需要定义合适的数据结构及缓冲区机制来提升文档存取的效率,另一方面来说,在编写样版文档时也需考量到对于存取效率上的负担。
总而言之,随着代码生成技术的发展以及各种生成工具的出现,程序人员将从高度脑力劳动和繁琐的体力劳动解脱出来,代码编写工作将可以像生成流水线一样简单。所产生的代码将非常健壮,是高品质、高一致性、高效率的统一体。当然,并不是从所有的代码生成技术中都可以获得上面列出的好处。在一个软件工具中采用和实现代码生成技术需要对具体需求的评估、对各种技术的综合考虑甚至还包括对“拿来”和自行开发的一种权衡。
1