您的位置:首页 > 数据库

有关语法数据库Clone的设计方案

2008-12-27 20:49 253 查看
最近有这样的需求:需要为自己设计的语法数据库GDB( Grammar DataBase)提供Clone机制的支

持,具体来说,就是给定一个GDB语法树TreeA,希望能够复制出一份跟TreeA内容一模一样的语法树

TreeB,TreeB除了内容跟TreeA一模一样外,跟TreeA不存在任何依赖关系,即使删除了TreeA,也可以

正常访问TreeB中的内容。

这样的一个功能,说起来比较简单,实现起来还有一点讲究,也遇到了一些问题。

第一个问题就是,选择什么样的策略来实现对GDB的Clone支持?第一眼看见这个需求,映射入我脑海

中的是Prototype模式。但是细想起来,Prototype并不完全适合我这里的需求。

在GDB里边,类的层次关系比较复杂,为了便于描述,让我们将GDB的类层次结构视为一个树形结

,其中叶子结点对应具体的语法类,可以据以创建出一个语法结点,非叶子节点对应的是抽象类或基

类,不能据以创建出语法结点(但是出于程序设计的弹性方面的考虑,在GDB中存在大量的通过基类,

抽象类指针,指向一个具体的语法类对象的场景)。在这个树形结构中,有出现在第一层的叶子结点,

也有出现在第二层,第三层的叶子结点。而引用这些叶子结点类的地方,既有通过具体类型指针的,也有

通过基类指针的。比如说:

class GDBCompilerDirective : GDBNode {

......

};

class GDBStmt : GDBNode {

......

};

class GDBMainProg {

public:

GDBCompilerDirective * directive_;

vector< GDBStmt* > stmts_;

};

GDBStmt就是一个抽象语句类,从它会派生出具体语句对应的语法类,比如

GDBForStmt,GDBWhileStmt,。。。

GDBCompilerDirective则是一个具体的语法类,用来存放编译制导控制的相关信息。

那么想要实现Clone一个GDBMainProg对象的操作,就需要对它内部的directive_stmts_区分处

理了。

对stmts_的Clone可以通过为GDBStmt增加clone()虚方法的接口在GDBStmt的具体派生类中

增加相应的clone()方法实现
来完成。

为GDBStmt增加的clone()接口描述如下:

virtual GDBStmt * clone();

这样的接口,符合GDBMainProg的需求,即GDBMainProg关心的只是GDBStmt基类指针

下面再来看一下对directive_的Clone操作的实现。directive_是用一个具体语法类的指针来指向的。所

以Clone的结果也需要返回一个具体语法类的指针。但是怎样为GDBCompilerDirective定义一个

clone()方法就有些为难了。将clone()方法定义为这样的形式;

形式1:

virtual GDBNode * clone()

或是这样的形式;

形式2:

GDBCompilerDirective * clone();

感觉都不是太好。

定义成形式1的话,需要对clone()的结果进行一个类型cast的动作以后才能供GDBMainProg使用,增

加了类型不安全的风险。

定义成形式2的话,clone()内部只会包括一个干巴巴的copy constructor的调用,又有些多余,颇有

杀鸡用牛刀的感觉。

最后我的方案是作了一个折衷,对于会以基类指针形式访问的语法类,为其增加一个copy

constructor及一个clone()接口
,该接口在基类中定义为一个纯虚方法,在具体类中给出实现内容,

该方法返回的是基类的指针;对于以具体类指针形式访问的语法类,只为其增加一个copy

constructor


第二个问题就是关于copy constructor的实现。如上所述,在GDB中,有些语法类提供了clone()接

,对其的Clone操作直接通过调用clone()接口即可;有些语法类则没有提供clone()接口,仅提供

了copy constructor的实现;还有些特殊的语法类,设计时出于效率的考虑,该类型的指针指向的

具体内容是由一个全局容器管理的, 为其执行Clone操作也只是进行指针级别的复制


所以对不同的语法类,执行Clone操作所需调用的具体动作也是有所区别,如果只是手工编写代码来处

理这种差异是肯定可以的,但是考虑到需要增加Clone操作的类很多,纯手工处理是一件既耗时

也容易出错的力气活
。所以,引入了一些GP的小技巧来协助处理。细节就不说了,大致的思想就是

义一个泛型函数g_clone_t(),在需要执行Clone动作的地方调用泛型函数g_clone_t,由

g_clone_t根据当前的上下文信息
包括具体需要Clone的语法类的类型以及该语法类的Clone动

作类型
来执行相应的具体动作

g_clone_t的伪码描述如下:

<template class cloneType>

cloneType* g_clone_t( cloneType* obj )

{

// Type1: obj提供了clone()接口

return obj->clone();

// Type2: obj未提供clone()接口,仅实现了copy constructor

return new cloneType( *obj );

// Type3: obj指向的内容是通过全局容器管理的

return obj;

}

g_clone_t具体的实现运用到了一些template specialization, traits的技巧,在这里不再多述。

第三个问题就是GDB对应的类比较多,粗略统计了一下,需要增加Clone()方法及相关的copy

constructor的类大概有40个之多,clone()方法的内容并不多,copy constructor的实现也不算复杂,

但是要为这么多类增加支持,工作量上可不小。我没有选择纯手工完成这些工作,而是借助了宏处理

来简化工作量


1)。定义了一组宏来简化clone()接口的定义

#define CLONE_HOOK_1( classType ) virtual classType * clone() const = 0;

#define CLONE_HOOK_2( returnClassType, realClassType ) virtual returnClassType * clone() { /

return new realClassType( *this ); /

}

2). 定义了一组宏来简化copy constructor的实现

#define CLONE_FIELD( srcObj, field ) clone_t( field, srcObj.field )

#define CLONE_FIELDS_2( srcObj, field1, field2 ) do { /

CLONE_FIELD( srcObj, field1 ); /

CLONE_FIELD( srcObj, field2 ); /

} while ( 0 )

#define CLONE_FIELDS_3( srcObj, field1, field2, field3 ) do { /

CLONE_FIELDS_2( srcObj, field1, field2 );

CLONE_FIELD( srcObj, field3 );

} while ( 0 )

#define CLONE_FIELDS_4 ...

有了这些宏以后,在为一个语法类增加clone()接口的时候,只需要调用宏CLONE_HOOK_1

CLONE_HOOK_2即可,为一个语法类实现copy constructor的时候,只需要调用

CLONE_FIELD/_1/_2/_3/_4/...
即可,具体的重复的事情,就由预处理器替我们完成了

注:文中提到的以大写C开头的Clone表示Clone操作,以小写c开头的clone则表示的是具体实现的

clone()方法,为一个语法类实现Clone操作可能会需要定义并实现相应的clone()方法,也可以不为该

语法类定义clone方法,而是通过别的方式来完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: