规模与 OP 代码库的大小一样,需要的是program transformation system (PTS)。这是一个将目标语言源文件解析为编译器数据结构(通常是 AST)的工具,允许您对 AST 应用转换,然后可以重新生成有效的源代码,包括修改后的程序的原始 cmets。将 PST 视为大规模重构的工具。
一个好的 PTS 会让你写出 source-to-source transforms 的形式:
when you see *this*, replace it by *that* if *condition*
其中 this 和 that 以目标语言语法表示,其中 this 仅在源代码与显式语法匹配时才匹配。 [这些不是字符串匹配;他们在 AST 上工作,因此布局不会影响他们的匹配能力]。
你需要一个看起来像这样的关键规则:
rule move_to_initializer(constructor_name:IDENTIFIER,
arguments: argument_list,
initializer_list: initializer,
member_name:IDENTIFIER,
initializer_expression: expression,
statements: statement_list
): constructor -> constructor =
" \constructor_name(\arguments): \initializer_list
{ \member_name = \initializer_expression ;
\statements } "
-> " \constructor_name(\arguments): \initializer_list, \member_name(\initializer_expression)
{ \statements } ";
The syntax of these rules/patterns for our DMS Software Reengineering Toolkit is explained here。 DMS 是我所知道的唯一可以处理 C++ 的源到源 PTS;它甚至可以处理 MSVS 方言]。
我遗漏了一个可能必要的“if 条件”检查成员名称确实是类的成员,假设您的构造函数没有滥用。
因为你的构造函数可能没有任何初始化列表,你需要一个辅助规则来在必要时引入一个:
rule move_to_initializer(constructor_name:IDENTIFIER,
arguments: argument_list,
member_name:IDENTIFIER,
initializer_expression: expression,
statements: statement_list
): constructor -> constructor =
" \constructor_name(\arguments)
{ \member_name = \initializer_expression ;
\statements } "
-> " \constructor_name(\arguments): \member_name(\initializer_expression)
{ \statements } ";
{ \member_name = \e ; } "
您总是需要额外的规则来涵盖其他特殊情况,但不应该超过几个。
关于检查初始化顺序,您可以使用 (DMS) 模式触发此类检查:
pattern check_initializer_order(constructor_name:IDENTIFIER,
initializer_list: initializer,
statements: statement_list
): constructor =
" \constructor_name(): \initializer_list,
{ \statements } "
if complain_if_not_ordered(constructor_name,initializer_list);
这需要一个辅助元谓词来检查顺序,如果它们被错误排序就会抱怨。您需要 constructor_name 来使谓词能够查找相应的类并检查成员的顺序。 [DMS 向means to access a symbol table 提供此信息]。
或者,您可以简单地使用不同的重写规则重新排序它们:
rule order_initializers(constructor_name:IDENTIFIER,
arguments: argument_list,
initializer_list_prefix: initializer,
initializer_list_suffix: initializer,
member1_name:IDENTIFIER,
initializer1_expression: expression,
member2_name:IDENTIFIER,
initializer2_expression:expression,
statements: statement_list
): constructor -> constructor =
" \constructor_name(\arguments):
\initializer_list_prefix,
\member1_name(\initializer1),
\member2_name(\initializer2),
\initialize_list_suffix
{ \statements } "
->
" \constructor_name(\arguments):
\initializer_list_prefix,
\member2_name(\initializer2),
\member1_name(\initializer1),
\initialize_list_suffix
{ \statements } "
if is_wrong_order(constructor_name,member1_name,member2_name);
这个规则本质上是对初始化器进行排序。 [注意这是一个冒泡排序:但初始化器列表往往不会很长,而且无论如何你只会对每个构造器运行一次。] 在你将所有初始化器从构造器主体中取出后运行这个规则前面显示的规则。