C ++重构:条件扩展和块消除 [英] C++ refactoring: conditional expansion and block elimination

查看:365
本文介绍了C ++重构:条件扩展和块消除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在重构大量的代码(大多数是C ++),以删除一些已永久设置为给定值的临时配置检查。例如,我将有以下代码:

I'm in the process of refactoring a very large amount of code, mostly C++, to remove a number of temporary configuration checks which have become permanantly set to given values. So for example, I would have the following code:

#include <value1.h>
#include <value2.h>
#include <value3.h>

...

if ( value1() )
{
    // do something
}

bool b = value2();

if ( b && anotherCondition )
{
    // do more stuff
}

if ( value3() < 10 )
{
    // more stuff again
}

其中对value的调用返回bool或int。由于我知道这些调用总是返回的值,我已经做了一些正则表达式替换来扩展调用到他们的正常值:

where the calls to value return either a bool or an int. Since I know the values that these calls always return, I've done some regex substitution to expand the calls to their normal values:

// where:
//   value1() == true
//   value2() == false
//   value3() == 4

// TODO: Remove expanded config (value1)
if ( true )
{
    // do something
}

// TODO: Remove expanded config (value2)
bool b = false;

if ( b && anotherCondition )
{
    // do more stuff
}

// TODO: Remove expanded config (value3)
if ( 4 < 10 )
{
    // more stuff again
}

请注意,尽管这些值是固定的,但是它们不是在编译时设置的,而是从共享内存中读取的,因此编译器目前不会对后台进行优化。

Note that although the values are fixed, they are not set at compile time but are read from shared memory so the compiler is not currently optimising anything away behind the scenes.

虽然结果代码看起来有点愚蠢,这个正则表达式方法实现了很多我想要的,因为它很容易应用和删除依赖的调用,而不改变行为代码,并且编译器可能会优化很多它知道一个块不能被调用或检查将总是返回true。它也使得它相当容易(特别是当与版本控制差异)看到什么已经改变,并采取清理它的最后一步,上面的代码最终看起来如下:

Although the resultant code looks a bit goofy, this regex approach achieves a lot of what I want since it's simple to apply and removes dependence on the calls, while not changing the behaviour of the code and it's also likely that the compiler may then optimise a lot of it out knowing that a block can never be called or a check will always return true. It also makes it reasonably easy (especially when diffing against version control) to see what has changed and take the final step of cleaning it up so the code above code eventually looks as follows:

// do something

// DONT do more stuff (b being false always prevented this)

// more stuff again

麻烦的是,我有数百(可能是数千)

The trouble is that I have hundreds (possibly thousands) of changes to make to get from the second, correct but goofy, stage to get to the final cleaned code.

我想知道是否有人知道一个重构工具可能会处理这个或任何我可以应用的技术。主要的问题是C ++语法使得完全扩展或消除相当难以实现,并且有许多排列上面的代码。我觉得我几乎需要一个编译器来处理我需要覆盖的语法的变化。

I wondered if anyone knew of a refactoring tool which might handle this or of any techniques I could apply. The main problem is that the C++ syntax makes full expansion or elimination quite difficult to achieve and there are many permutations to the code above. I feel I almost need a compiler to deal with the variation of syntax that I would need to cover.

我知道有类似的问题,但我找不到任何需要非常喜欢这个,也想知道自从问他们以后是否出现了任何工具或程序?

I know there have been similar questions but I can't find any requirement quite like this and also wondered if any tools or procedures had emerged since they were asked?

推荐答案

我称之为僵尸代码...在实践中死了,但仍然生活在编译器的关注。这是大多数系统的有组织的运行时配置变量的一个非常普遍的问题:最终一些配置变量到达永久固定的状态,但在运行时反复重新评估。

It sounds like you have what I call "zombie code"... dead in practice, but still live as far as the compiler is concerned. This is a pretty common issue with most systems of organized runtime configuration variables: eventually some configuration variables arrive at a permanent fixed state, yet are reevaluated at runtime repeatedly.

不是正则表达式,正如你已经注意到的,因为正则表达式不能可靠地解析C ++代码。
您需要的是计划转换系统。这是一个真正解析源代码的工具,可以将一组代码到代码重写规则应用于解析树,并可以从已更改的树中重新生成源文本。

The cure isn't regex, as you have noted, because regex doesn't parse C++ code reliably. What you need is a program transformation system. This is a tool that really parses source code, and can apply a set of code-to-code rewriting rules to the parse tree, and can regenerate source text from the changed tree.

我知道Clang在这里有一些能力;它可以解析C ++并构建一个树,但它没有源到源转换功能。你可以通过编写AST到AST转换来模拟这种能力,但这是一个更不方便的IMHO。我相信它可以重新生成C ++代码,但我不知道它是否会保留注释或预处理指令。

I understand that Clang has some capability here; it can parse C++ and build a tree, but it does not have source-to-source transformation capability. You can simulate that capability by writing AST-to-AST transformations but that's a lot more inconvenient IMHO. I believe it can regenerate C++ code but I don't know if it will preserve comments or preprocessor directives.

我们 DMS软件重组工具包及其 C ++(11)前端可以(并且已经用于)对C ++源代码执行大规模变换,并具有源到源变换。 AFAIK,它是唯一可以做到这一点的生产工具。你所需要的是一组转换,表示你对感兴趣的配置变量的最终状态的了解,以及一些简单的代码简化规则。以下DMS规则接近您可能想要的规则:

Our DMS Software Reengineering Toolkit with its C++(11) front end can (and has been used to) carry out massive transformations on C++ source code, and has source-to-source transformations. AFAIK, it is the only production tool that can do this. What you need is a set of transformations that represent your knowledge of the final state of the configuration variables of interest, and some straightforward code simplification rules. The following DMS rules are close to what you likely want:

  rule fix_value1():expression->expression
    "value1()" -> "true";
  rule fix_value2():expression->expression
    "value2()" -> "false";
  rule fix_value3():expression->expression
    "value3()" -> "4";

  rule simplify_boolean_and_true(r:relation):condition->condition
     "r && true" -> "r".
  rule simplify_boolean_or_ture(r:relation):condition->condition
     "r || true" -> "true".
  rule simplify_boolean_and_false(r:relation):condition->condition
     "r && false" -> "false".
  ...
  rule simplify_boolean_not_true(r:relation):condition->condition
     "!true" -> "false".
  ...

  rule simplify_if_then_false(s:statement): statement->statement
      " if (false) \s" -> ";";
  rule simplify_if_then_true(s:statement): statement->statement
      " if (true) \s" -> "\s";
  rule simplify_if_then_else_false(s1:statement, s2:statement): statement->statement
      " if (false) \s1 else \s2" -> "\s2";
  rule simplify_if_then_else_true(s1:statement, s2: statement): statement->statement
      " if (true) \s1 else \s2" -> "\s2";

您还需要规则来简化(折叠)涉及算术的常数表达式, strong>开关。要查看整数常数折叠的DMS规则,请参阅代数作为DMS域

You also need rules to simplify ("fold") constant expressions involving arithmetic, and rules to handle switch on expressions that are now constant. To see what DMS rules look like for integer constant folding see Algebra as a DMS domain.

与regexes不同,DMS重写规则不能不匹配代码;它们表示相应的AST,并且是匹配的AST。因为它是AST匹配,他们没有空格,换行符或注释的问题。你可能会认为他们可能有操作数的顺序的麻烦(遇到假&& x如果怎么办?它们不会,因为&& || 的语法规则在DMS C ++解析器中标记为关联和交换,并且匹配过程会自动将其纳入考虑。

Unlike regexes, DMS rewrite rules cannot "mismatch" code; they represent the corresponding ASTs and it is that ASTs that are matched. Because it is AST matching, they have no problems with whitespace, line breaks or comments. You might think they could have trouble with order of operands ('what if "false && x" is encountered?'); they do not, as the grammar rules for && and || are marked in the DMS C++ parser as associative and commutative and the matching process automatically takes that into account.

这些规则本身不能做的是在分配之间传播的值(在你的情况下,常量)。为此,您需要流分析,以便您可以跟踪此类分配(到达定义)。显然,如果你没有这样的作业或很少,你可以手动补丁。如果你这样做,你需要流分析;唉,DMS的C ++前台不在那里,但我们正在努力;我们有控制流分析到位。 (DMS的C前端具有全流分析)。

What these rules cannot do by themselves is value (in your case, constant) propagation across assignments. For this you need flow analysis so that you can trace such assignments ("reaching definitions"). Obviously, if you don't have such assignments or very few, you can hand patch those. If you do, you'll need the flow analysis; alas, DMS's C++ front isn't quite there but we are working on it; we have control flow analysis in place. (DMS's C front end has full flow analysis).

(编辑2015年2月:现在完整的C ++ 14;功能/方法中的流分析)。

(EDIT February 2015: Now does full C++14; flow analysis within functions/methods).

我们实际上将这种技术应用于IBM Tivoli大约十年前的1.5M SLOC混合C和C ++代码应用程序,并获得了极大的成功;我们不需要流分析: - }

We actually applied this technique to 1.5M SLOC application of mixed C and C++ code from IBM Tivoli almost a decade ago with excellent success; we didn't need the flow analysis :-}

这篇关于C ++重构:条件扩展和块消除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆