分享
 
 
 

开发代码产生器的经验

王朝other·作者佚名  2006-08-31
窄屏简体版  字體: |||超大  

开发代码产生器的经验

转载时请注明出处:http://blog.csdn.net/absurd/

提到代码产生器,很容易让人联想到Rrose之类的工具,它们根据UML图产生相应的代码,同时还可以从代码反向生成UML图。Rrose是一个庞大的系统,自然让人觉得代码产生器也是一个复杂的东西,所以不少人对代码产生器抱着敬而远之的态度。其实,代码产生器可大可小,小则几行代码,大则数万行代码。大小本身不是问题,重要的是它能提高我们的工作效率。

产生式编程已经不是什么新概念了,早在好几年前,国外一些专家都曾预言,产生式编程将在软件开发中占据重要地位。事实也是如些,产生式编程已经是软件开发中不可或缺的方法之一了。根据《产生式编程—方法、工具与应用》一书中的描述,泛型编程、面向方面的编程、面向意图的编程和代码产生器都属于产生式编程。

本文重点在代码产生器上,当然我们的目标是研究代码产生器本身的开发,而不是某个特定代码产生器的使用方法。说来很惭愧,我从来没有去研究过某些经典的代码产生器,它们的实现方法是非常值得学习的。本文讲述的仅仅一些个人经验,但我相信这些的经验仍然有些实用价值的。

代码产生器的基本模型为:

代码产生器要根据一些规则才能产生代码,即使这个规则蕴涵在代码产生器之中,从逻辑上讲,它仍然是存在的,我们把这些规则称为元代码。元数据就是用来描述数据的数据,比如DTD是用来描述XML文件的,XML文件本身也是数据,所以可以把DTD称为元数据。元代码有类似的含义,它是对将要产生的代码描述,从某种意义上讲,它本身也是一段代码。

代码产生器的目标是要产生代码,我们把产生出来的代码称为目标代码。所谓目标代码是针对代码产生器而言的,这里的目标代码通常会成为编译器的源代码。至于这些目标代码的具体语言,要视的情况而定,实际上可以为任何语言,甚至是自然语言。

代码产生器有点像编译器,把一种语言转换成另外一种语言。从更广泛的角度来看,很多应用程序本身就是一个代码产生器,比如用CGI/ASP/PHP等开发的WEB程序,接收用户输入的参数,输出HTML文件,把这样的应用程序当作代码产生器也是可以的。这里不讨论广义的代码产生器,而专注于程序员所用的代码产生器。这类代码产生器有一定特殊之处,下面我们看看开发代码产生器所要考虑的问题。

1. 是否有必要开发代码产生器。

这是我们要考虑的第一问题,有人说代码产生器是个好东西,为什么不要呢?问题在于任何好东西都是有代价的,开发代码产生器也是一样,至少要耗费我们的时间和精力。如果开发代码产生器本身的代价远大于直接编写代码本身,开发这样代码产生器意义就不大了。可以参考下面的公式:

(编写代码的工作量 - 编写规则的工作量 ) * 重用次数 大于 开发代码产生器的工作量

从功利上讲,只有上述公式成立时才考虑使用代码产生器。当然有例外,比如出于兴趣或者研究的目的去开发也是可以的。

比如在决定开发gclassfactory时所考虑的,如果只是编写一个gobject子类,开发代码产生器要花数几倍的时间,那我会选择手工去编写那些宏、安装属性、创建信号和重载函数,忍一忍也就过去了。但是我们整个平台是基于glib/gtk+的,以后有很多这样的子类要写,若利用代码产生器,累积起来的工作量非常可观了。同时我也希望练习一下用glib写程序,所以最终决定glib来开发gclassfactory了。

2. 是否能够使用代码产生器。

代码产生器的适用范围是有限的,它不是万能的,否则程序员这个职业就消失了。工具是愚蠢的,好的工匠应该了解工具的长处和短处,充分利用它们的特长。代码产生器只适用于那些规则性比较强的情况。因为规则是抽象的,以少量的规则可以产生大量的代码,也就是说代码产生器的输出一定要大于输入(根据工作量来衡量),否则花了很长时间开发工具,结果只是让事情复杂化了。

比如对于gclassfactory来说,输入可以用标准idl或者xml格式描述gobject子类,这些描述几乎没有什么冗余信息,输出gobject子类代码则有很多类似又有差异的代码,比如函数原型、函数外包装、实现函数的原型、实现函数的框架、大量的宏、安装属性和创建信号等等。输出的代码量是输入的代码量的三倍以上,而且编写输入规则时根本不用思考。

3. 选择开发语言。

个人认为每个程序员至少熟练掌握一门脚本语言和一门编译语言,我用过不少语言,比如汇编(ARM/Z80/x86)、PB、VB、Autolisp和C/C++等,但真正熟练的只有bash+awk系列和C/C++。脚本语言的好处在于方便,不需要编译; 也更高级,用少量的代码可以实现很强大的功能。但脚本在规模变大时,极难维护,变得很复杂,也就失去了优势。

通常情况下,如果代码产生器的规则简单,用脚本来写比较有利。当规则比较复杂,这些规则本身就是一种微型语言或者用XML之类的语言来描述时,使用编译语言更方便一点。当然像python和ruby这样功能强大的语言,集脚本语言和编译语言两者之所长,因为我不懂,就不讨论它们了。

前几天遇到一个问题,要定义一组宏,它的格式是这样的:

KEYMAP(GDK_Op_Left, GDK_F12, DIKS_F12)

KEYMAP(GDK_Op_Right, GDK_F13, DIKS_F13)

大约有30多行,第一列的Op_Left之类是自定义的按键,是我们讨论的结果,放在一个表格中,手工把这份表格转换成以上的宏,不难也要不了多少时间,但这样单调的事很容易出错,特别对于我这样粗心大意的人来说。于是决定用awk来做:

awk 'BEGIN{i = 4} {print "KEYMAP(GDK_" $1 ", GDK_F" i ", DIKS_F" i ")"; i++}' keys.txt

这就是代码产生器!就一行代码。简单吧,它却产生了30多行代码。其实我经常在用这样的代码产生器,给我节省了不少时间,减少了出错的可能。所以能用脚本就用脚本,脚本实现困难时才考虑用C/C++等编译语言。

4. 分离规则读入与代码产生两个部分。

如果代码产生器比较复杂,应该规划一下代码产生器的架构。代码产生器架构是一个典型的管道--过滤器模型,所以应该把读取规则的部分和代码产生的部分独立开来,两者互不影响。如果与编译器对应起来,读取规则的部分就对应于编译器的前端,代码产生的部分对应于编译器的后端。

为什么要这样做呢?原因在于隔离变化和代码重用。

规则的格式是可以变化的,只要语义不变,它的变化不会影响到代码产生器,这为支持多种规则格式提供了方便。比如在开发gclassfactroy的时候,想到描述接口的通常采用IDL,为了简单我采用了XML,但我把规则读取部分抽象成一个loader,不同的loader动态的加载进来,要支持IDL只需要编写一个IDL的loader即可,不需要对gclassfactory做一点改动。

同样的,把代码产生部分抽象成一个coder,也是动态加载的。现在支持产生C语言代码,若要支持产生C++代码,就编写一个产生C++代码的coder,也不需要对gclassfactory做任何改动。甚至用它来产生测试程序,来产生RPC的程序,理想情况下也不需要对gclassfactory做任何修改,只要编写新的coder即可。

5. 选择中间语言。

中间语言是个好东西,它本身就是一种抽象,即对规则的抽象。抽象后的规则不再依赖于特定的loader,比如就接口描述而言,不管你用IDL描述的还是用XML描述的,到了中间语言这里,这些差异已经泯灭了,都表示成同样的东西。

分离规则读入和代码产生两个部分,中间语言起了非常重要的作用,把两者联系起来了,但耦合很松散,两者仍然可以独立变化。中间语言几乎在任何与格式转换相关的程序中,都广泛的使用着,特别是在编译器和文档格式转换等系统中。

中间语言可以是一种实际的语言,有自己特定的格式,也可以只是一种内存中的数据结构。因此到中间语言的转换也有两种方式,对于前者,可以先把原始输入转换成中间语言,保存在文件中,再由中间语言的loader加载进来。对于后者,每种loader都是独立,直接转换成中间语言。

比如,在gclassfactory(参考[open source] gclassfactory)中,它的中间语言是一个内存中的数据结构,每个loader是独立的,直接转换成中间语言,然后交给代码产生组件处理。而在cilc (参考[open source] cilc) 中,它的中间语言是XML格式的,要先把其它格式转换成XML后,才能用cilc处理。

一个典型的代码产生器的结构如下:

有的代码产生器还带有图形用户界面,但是对于良好的设计,图形用户界面是可以独立存在的,其核心部分应该与上图大同小异。比如拿Rrose来说,它一定有一个中间语言,先把UML的图形表示转换成中间语言,再根据中间语言来产生代码,而不会直接通过界面元素产生代码。

~~end~~

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有