在WTL80中,AppWiz应用程序向导与AppWizMobile应用程序向导一个区别是在AppWizMobile中使用了SplitCode函数,目的是在编写WTL向导模板时只需要提供.h文件,使用SplitCode可以在需要时将类成员函数转换到.cpp文件中,而AppWiz应用程序向导则是编写了.h和.cpp文件,根据[!if WTL_USE_CPP_FILES]/[!endif]进行预处理,相比之下使用SplitCode对于向导模板的编写简单的多。
VisualFC当前版本(0.80.0601)内置的AppWizard和CodeWizard使用与WTL80的AppWiz同样的处理方式,即使用[!if WTL_USE_CPP_FILES]/[!endif]进行预处理。为简化VisualFC向导模板的编写,我们考虑在VisualFC以后版本中模仿WTL80的AppWizMobile向导提供SplitCode函数来进行处理。WTL80向导的SplitCode函数是用JScript完成的,在这里我们可以用boost::regex进行改写,以便在C++程序中直接使用。其中对于C++类及成员函数分析的正则表达式在两种语言中是完全一致的,具体代码如下:
WTL80的AppWizMobile的SplitCode代码
/******************************************************************************
Description: Add the function members body to a .cpp file and remove them
from the matching header. Do nothing if no matching .h file.
cppPath: Path name to a .cpp file
******************************************************************************/
function SplitCode(cppPath)
{
var fso = new ActiveXObject('Scripting.FileSystemObject');
var hPath = cppPath.replace(/.cpp$/, ".h");
if (!fso.FileExists(hPath))
return;
var cppFile = fso.GetFile(cppPath);
var hFile = fso.GetFile(hPath);
var tsh = hFile.OpenAsTextStream(1);
var hText = tsh.ReadAll();
tsh.Close();
var tscpp = cppFile.OpenAsTextStream(8);
var ClassPattern = /^[ /t]*class[ /t]+(/w+)[/s/S]+?(?:^[ /t]*/};$)/mg
var ClassInfo = hText.match(ClassPattern);
var numClass = ClassInfo.length;
for (nc = 0 ; nc < numClass; nc++)
{
var ClassText = ClassInfo[nc];
ClassText.match(ClassPattern);
var ClassName = RegExp.$1;
var FnPattern = /(^(?:[ /t]+/w+)*[ /t]+(/w+)/([^/)]*/))([/s]*/{([^/}]*/{[^/}]*/})*[^/}]*/}+?)/mg
var FnPatternIf = /(^(?:#if.+/s+)*(?:[ /t]+/w+)*[ /t]+(/w+)/([^/)]*/))([/s]*/{([^/}]*/{[^/}]*/})*[^/}]*/}+?(?:/s+#e(?:ndif|lif|lse)[^/r/n]*)*)/mg
var FnInfo = ClassText.match(FnPatternIf);
var numFn = FnInfo.length;
for (n = 0 ; n < numFn; n++)
{
var FnTextIf = FnInfo[n];
var FnTextIf = FnTextIf.match(FnPatternIf);
var FnDef = RegExp.$1;
var FnName = RegExp.$2;
var FnBody = RegExp.$3;
var FnFullName = ClassName + "::" + FnName;
FnDef = FnDef.replace(FnName, FnFullName);
FnDef = FnDef.replace(/^/t(?:/s*virtual/s+)*/, "");
FnBody = FnBody.replace(/^/t/mg, "");
tscpp.Write(FnDef);
tscpp.Write(FnBody);
tscpp.WriteBlankLines(2);
var FnText = FnTextIf.input.match(FnPattern);
var FnDecl = RegExp.$1 + ";";
ClassText = ClassText.replace(FnText, FnDecl);
}
hText = hText.replace(ClassInfo[nc], ClassText);
}
tscpp.Close();
tsh = hFile.OpenAsTextStream(2);
tsh.Write(hText);
tsh.Close();
}
使用boost::regex改写的代码,代码稍有不同,没有做文件的处理,直接处理字符串。
void process(const std::string & text)
{
std::string regstr = "^[ /t]*class[ /t]+(//w+)[//s//S]+?(?:^[ /t]*//};$)";
boost::regex expression(regstr,boost::regbase::JavaScript);
std::string::const_iterator start, end;
start = text.begin();
end = text.end();
boost::match_results<std::string::const_iterator> what;
boost::match_flag_type flags = boost::match_default;
std::string file_h = text;
std::string file_cpp;
while(boost::regex_search(start, end, what, expression, flags))
{
start = what[0].second;
std::string class_name = what[1];
std::string class_text = what[0];
std::string class_h, class_cpp;
process_class(class_name,class_text,class_h,class_cpp);
file_h = boost::regex_replace(file_h,boost::regex(class_text,boost::regbase::literal),class_h);
file_cpp += class_cpp;
}
}
void process_class(const std::string & class_name, const std::string & class_text, std::string & class_h, std::string & class_cpp)
{
std::string FnPattern = "(^(?:[ /t]+//w+)*[ /t]+(//w+)//([^//)]*//))([//s]*//{([^//}]*//{[^//}]*//})*[^//}]*//}+?)";
std::string FnPatternIf = "(^(?:#if.+//s+)*(?:[ /t]+//w+)*[ /t]+(//w+)//([^//)]*//))([//s]*//{([^//}]*//{[^//}]*//})*[^//}]*//}+?(?://s+#e(?:ndif|lif|lse)[^/r/n]*)*)";
std::string::const_iterator start, end;
start = class_text.begin();
end = class_text.end();
boost::match_results<std::string::const_iterator> what;
boost::match_flag_type flags = boost::match_default;
boost::regex expression(FnPatternIf,boost::regbase::JavaScript);
class_h = class_text;
class_cpp = "/r/n//class/t";
class_cpp += class_name;
class_cpp += _T("/r/n");
while(boost::regex_search(start, end, what, expression, flags))
{
start = what[0].second;
std::string func_buffer = what[0];
std::string func_def = what[1];
std::string func_name = what[2];
std::string func_body = what[3];
//write cpp function
std::string func_fullname = std::string(class_name) + "::" + func_name;
func_def = boost::regex_replace(func_def,boost::regex(func_name),func_fullname);
func_def = boost::regex_replace(func_def,boost::regex("^/t(?://s*virtual//s+)*"), "");
func_body= boost::regex_replace(func_body,boost::regex("^/t"), "");
class_cpp += _T("/r/n");
class_cpp += func_def;
class_cpp += func_body;
class_cpp += _T("/r/n/r/n");
boost::regex_search(func_buffer,what,boost::regex(FnPattern),flags);
//
std::string func_decl = (std::string)(what[1]) + ";";
boost::regex reg(std::string(what.base()),boost::regbase::literal);
class_h = boost::regex_replace(class_h,reg,func_decl);
}
}
通过对比,我们也可以看到,由于C++没有内置regex处理,所以代码要比JScript复杂一些
本文介绍了WTL80中AppWizMobile向导使用的SplitCode函数,该函数用于将类成员函数从头文件转移到对应的源文件中。文章对比了JScript版本与使用boost::regex重写的C++版本,并详细解释了其实现过程。
8691





