寻找可以简化的过于复杂的布尔表达式的工具?

时间:2011-09-11 14:51:21

标签: c++ boolean simplification

是否有任何C ++代码解析器可以查找可以使用布尔代数进行简化的布尔表达式?

我知道编译器已经这样做了,但是有一个工具可以提供这样的东西,以便人们可以真正提高代码的可读性。

6 个答案:

答案 0 :(得分:3)

人类

你想要提高可读性,并且由于可读性主要是人类的事情,它应该由人类教授。

请更有经验的开发人员查看您的表达并提供提示。

例如,请在此处查看我的回答:What is the best way (performance-wise) to test whether a value falls within a threshold?

答案 1 :(得分:0)

虽然它不能直接在C / C ++布尔表达式上工作,但我发现一个简化复杂布尔逻辑非常有用的工具是Logic Friday。不幸的是它仅限Windows,但幸运的是它是免费的。

答案 2 :(得分:0)

您可以通过减少需要检查的“if”数量来提高代码效率。但是更加简化和更好的可读性无法自动完成。

答案 3 :(得分:0)

http://www.freewarepalm.com/educational/booleanfunctionsimplificationtool.shtml

可能值得一试。

然而,通常最好自己做 - 因为可读性和可理解性更重要 - 让编译器进行简化。

答案 4 :(得分:0)

这是个坏主意!程序员编写反映其思维过程的代码。因此,人类编写的布尔表达式已经自动优化以供人类理解。任何以编程方式改进的尝试都注定要失败。它可能有意义的唯一上下文是工具生成的源代码的后处理。

答案 5 :(得分:0)

你需要的是一个工具,它可以解析C ++,确定其符号的含义,选择布尔方程,并对它们应用不违反语义的布尔简化规则。

可以执行此操作的工具是我们的DMS Software Reengineering Toolkit及其C++ Front End。 DMS旨在对代码执行程序分析和源到源转换。使用C ++前端,它可以将C ++解析为AST,构建符号表,并推断表达式的类型,并应用重写规则。

可以编写这样的重写规则:

domain Cpp.  -- tell DMS to use the C++ front end

rule factor_common_and_term(e1: condition, e2:condition, e3: condition):
        disjunctive_expression -> disjunctive_expression =
 " \e1 && \e2 ||  \e1 && \e3 " ->  " \e1 && ( \e2 || \e3 ) "
 if no_side_effects(e1) /\ no_side_effects(e2);

分解出一个常见的情况。该规则具有名称“factor_common_and_term”以将其与通常可能编写的数百个其他规则(例如,“distribute_term”等)区分开。 e1,e2,e3是表示任意子表达式的元变量(根据语法规则的“条件”类型)。重写仅在disjunction_expressions上运行;你可以使它成为“只是表达式”但是你不会得到嵌套在其他条件表达式中的析取。重写有一个模式(左)和一个替换(右),两者都用元引号包装,以区分模式中的C ++代码和围绕它的规则语言语法。 \ e1 是C ++语法的转义,并指出元变量可以匹配的位置。元变量匹配相应类别的任何语法,因此看到 \ e1 可能是一个任意复杂的“条件” e1在模式中被提及两次的事实迫使出现的事件是相同的。

可以编写一组重写规则来编码有关简化任意复杂布尔方程的知识;几十个规则就是这样做的。我们已将这些应用于具有数十万个术语的非C ++布尔方程组,以及C和C ++预处理器条件。

对于C ++,你需要检查重写是否安全,如果e1有副作用,或者e2有副作用。使用辅助函数调用进行此检查,该调用必须以保守的方式确定此答案。事实上,确定没有副作用对C ++来说非常复杂:你必须知道表达式的所有元素是什么,并且它们都没有副作用。

可以使用DMS的属性语法(有组织的树爬行)检查所有表达式元素。简单的常量和变量(需要一个符号表)不。函数调用(包括构造函数等)可以;必须找到它们的定义(同样需要符号表),并进行类似处理。表达式元素可能会调用单独编译的函数;在这种情况下保守的答案是“不知道”,因此“假设有副作用”。 DMS实际上可以同时读取多个编译单元,因此如果你想要那么远,可以找到一个单独编译的函数,解析/符号解析和爬行。

因此布尔重写部分非常简单;副作用分析不是。

我们使用DMS对C ++代码进行了大量更改;我们经常通过对这样的复杂分析做出假设来作弊。通常我们会对程序员感到惊讶的方式感到惊讶(“你是什么意思, 有副作用?”)。它大部分效果都很好。我们对2500万行的C系统进行了详细的副作用分析;还没有完全适合C ++。

副作用分析仅在某些子表达式可能被评估多次时才有意义。 OP的例子,在评论中给出,不需要它们,可以通过以下规则来处理:

rule not_on_disjunction(e1:condition, e2:condition):
    condition -> condition =
  " ! (\e1 || \e2) " ->  " !\e1 && !\e2";

rule double_not(e:condition):
    condition -> condition =
  " ! ! \e " -->  " \e ";

一个包含更详细说明的完整但简单的工作示例是this example of algebraic simplification of conventional algebra and some calculus

关于特定代码转换是否会使代码更具可读性,显然存在争议。恕我直言,那是因为代码的形状往往是一种艺术判断,我们似乎都对艺术持不同意见。这与让别人修改你的代码没什么不同。