开放编译器OpenC++工作原理及对其局限的改进
2010-09-19汤发俊江文柴晓前
汤发俊,江文,柴晓前
(1,2无锡商业职业技术学院,江苏无锡214063;3华为技术有限公司,广东深州518129)
开放编译器OpenC++工作原理及对其局限的改进
汤发俊,江文,柴晓前
(1,2无锡商业职业技术学院,江苏无锡214063;3华为技术有限公司,广东深州518129)
本文详细分析了OpenC++工作原理和OpenC++MOP,并在研究实践的基础上指出了OpenC++的局限,最后针对这些局限分别提出了改进的方法,给出了改进后的OpenC++的工作流程。
开放编译器;工作原理;局限;改进
一、O penC++概览
OpenC++2.5/2.7(以下简称OpenC++)是一个典型的开放编译器,它将元对象协议(Meta-object Protocol,MOP)[1]引入到C++语言的编译过程中,是一种面向C++的源代码转换工具。OpenC++可被用来实现对C++语言的各种扩充,如添加新的文法、新的符号、新的对象行为等[2]。所谓开放编译,就是指通过元对象协议将编译过程向用户开放,用户可以通过元对象协议提供的接口,干预编译过程。
OpenC++的扩展特征由元程序(Meta-Level Program)在编译时指定。元程序由编程人员按照OpenC++MOP编写。这个接口把编译器的内部结构(经过面向对象的抽象)呈现给编程人员。与普通的C++程序一样,元程序其实也是一个C++程序。为了有所区别,我们把普通C++程序称为基级程序(Base-Level Program)。元程序经OpenC++编译器编译后被(动态或静态地)链接到OpenC++编译器上。链接后得到的OpenC++编译器按照元程序指明的方式对基级程序进行转换或分析。如果没有给出元程序,OpenC++与普通的C++一样。基级程序被OpenC++根据元程序转换后,再与运行时支持代码链接(用于提供基级程序使用的类和函数),最终得到可执行程序。参见图1。
图1 O penC++概览
OpenC++是一个用于对C++程序进行分析与转换的工具包。如果使用OpenC++来开发C++程序的转换器(Translator)和分析器(Analyzer),用户无需考虑解析器和类型系统这样的细节。OpenC++还可以为许多其他工具的开发提供支持,例如用户可以利用OpenC++实现C++程序类层次关系的源代码分析器。
二、O penC++工作原理
OpenC++编译器的工作过程由三个阶段组成:预处理,从OpenC++到C++的源到源(Source-to-Source)转换,以及标准C++编译器的编译和链接[3]。OpenC++MOP是在第二阶段控制转换的接口,指明OpenC++的扩展特征如何转换成普通的C++代码,参见图2。
图2 O penC++的工作原理
C++预处理器处理后的基级程序,在OpenC++中被分割成许多代码片断。这些代码片断由元对象转换后,再重新组合成一个完整的C++程序。最后OpenC++将转换后的C++程序传递给标准C++编译器,比如GNU C++。
在OpenC++中,代码片断由Ptree元对象以分析树的形式表示。虽然元对象与C++中的对象类似,但它们只存在于编译器中,并且代表着基级程序的元状态,因此称它们为元对象,而不能简单的称为对象。从在系统中所起的作用看,对象用于满足系统功能性方面的需求,而元对象则用于满足系统非功能性方面的需求。通过绑定到合适的元对象上,对象可以具备非功能性方面的能力。
三、O penC++M O P分析
OpenC++MOP属于编译时MOP的一种[3]。也就是说OpenC++中的元对象不是在运行时按照某种指定的方式去解释基级程序,而是在编译时转换基级程序,实现定制行为。因此OpenC++MOP只需在编译时提供对C++中一些关键特性的控制能力即可。针对对象的每一个基本动作,例如方法调用、数据读写、对象创建等,元对象都有对应的方法,用于定制对象的这一种行为。
OpenC++MOP之所以要按照编译时MOP的原则进行设计,是因为编译时MOP具有高性能与充分自定制的特点:不会带来运行时代价;提供了为标准C++语言添加扩展特性的能力。
类似于其他MOP,在OpenC++MOP中也存在元环[1][4](Meta-Circular)的概念。从本质上说,元类和类没有差别,元类只不过是一个可以实例化出类的类(即元对象对应于类)。类与元类的关系等价于对象与类的关系。因此,如果程序中包含元类的定义,MOP也会为这些元类构建元对象,以用于控制这些元类的编译过程。这样就必然会出现“类-元类-元类的元类-……”无限延续的现象:为了编译一个类,其元类必须先被编译;为了编译这个元类,这个元类的元类必须先被编译……
在OpenC++中,Metaclass是Class的元类,同时Class子类的元类也必须是Metaclass(Class的子类从Class继承元类,因此程序员无需显式的为Class的子类声明元类)。由于Metaclass是Class的子类,因此Metaclass的元类就是其自身(参见图3),这样就解决了元环的问题。
图3 实例化关系
OpenC++主要提供了五种元对象:Ptree元对象、Environment元对象、TypeInfo元对象、Class元对象和Member元对象[4]。这些元对象呈现了在C++中不能访问的几个方面。大部分的元对象提供的是内省(Introspection)的能力,但也有一些元对象表现了程序行为方面的特征,并使源到源的转换成为可能。
四、O penC++的局限及改进
(一)O penC++的局限
经多次研究并实际应用后发现,OpenC++对源文件的转换有四个比较大的局限:
(1)OpenC++首先调用标准C++的预处理器对源文件进行预处理,然后对预处理生成的文件进行分析。标准预处理器在预处理时,会导入所有必需的头文件,不仅包括用户编写的头文件,还包括许多系统头文件,如stdio.h。因此预处理生成的文件会比源文件大很多。对这些文件的转换,将耗费非常多的时间与空间,可能会出现耗尽内存而无法继续的现象。
(2)OpenC++一次只能对一个文件进行转换。当目标系统包含多个源文件时,就不得不多次调用OpenC++以实现对预处理后的所有文件进行转换。
(3)需要用户为待转换的类编写元类,并加入加入元类声明。即使有辅助工具自动完成这一工作,也可能给基极程序的维护人员造成困惑。
(4)OpenC++提供的MOP并不包含对全局函数的处理接口。
(二)O penC++的改进
针对以上OpenC++对源文件转换的四个局限,经过多次实践后提出如下方法进行改进:
(1)对于局限1来说,可以通过重新编写一个支持只导入用户头文件的预处理器来解决。
(2)对于局限2来说,通过添加一个记录所有头文件和源文件的列表文件来解决,这个列表文件可由辅助工具根据make文件或VC工程文件自动生成。
(3)对于局限3来说,由于OpenC++在解析源码时如果发现没有自定义的元类时,它会指派缺省元类Class。所以可以通过修改默认元类的缺省实现来实现转换功能。
(4)对于局限4来说,可以在OpenC++对全局函数进行转换的关键点进行处理实现对全局函数的处理。改进后的OpenC++的工作流程如图4所示,其中灰色为改进的部分。
图4 改进后的O penC++的工作流程
总之,OpenC++是解析和分析C++源代码的一种软件工具,它使用一个源对象协议(MOP)来为语言扩展提供服务。而在实际使用中需要我们不断加以改进才能发挥其最大效用。
[1]ShigeruChiba.AMetaobjectProtocolforC++. Proceedings of ACM Conference on OOPSLA.1995,10.
[2]Shigeru Chiba.A Study of Compile-time Metaobject Protocol.PhD thesis.Graduate School of Science,The University of Tokyo.1996,3.
[3]Shigeru Chiba.OpenC++Tutorial.1998.
[4]Shigeru Chiba.OpenC++2.5 Reference Manual.1999.
TP312
A
1671-5993(2010)04-0057-03
2010-06-22
汤发俊(1977-),男,江苏建湖人,硕士,无锡商业职业技术学院讲师、工程师。
江文(1979-),女,江苏连云港人,本科,无锡商业职业技术学院实验师。
柴晓前(1976-),男,甘肃静宁人,硕士,华为技术有限公司工程师。