C:转换A? B:C进入if(A)B else C

时间:2010-03-11 18:24:44

标签: c if-statement transformation

我一直在寻找一种可以转换表格的C代码表达式的工具:

a = (A) ? B : C;

使用if / else语句进入'默认'语法:

if (A)
  a = B
else
  a = C

有人知道能够进行此类转换的工具吗?

我使用GCC 4.4.2并使用-E创建一个预处理文件,但不希望这样的结构。

编辑: 以下代码也应该转换:

a = ((A) ? B : C)->b;

5 个答案:

答案 0 :(得分:12)

Coccinelle可以很容易地做到这一点。

  

Coccinelle是一个程序匹配和   提供的转换引擎   语言SmPL(Semantic Patch   语言)用于指定所需的   C代码中的匹配和转换。   Coccinelle最初是针对性的   执行抵押品   Linux中的演变。这样的演变   包含所需的更改   在客户端代码中响应   图书馆API的演变,可能   包括重命名等修改   一个函数,添加一个函数参数   其价值以某种方式   依赖于上下文,并重组一个   数据结构。抵押品   进化,Coccinelle成功   用(由我们和其他人)进行查找   并修复系统代码中的错误。

修改 语义补丁的一个例子:

@@ expression E; constant C; @@
(
  !E & !C
|
- !E & C
+ !(E & C)
)

来自文档:

  

模式!x& y。这种形式的表达式几乎总是毫无意义,因为它将布尔运算符与位运算符组合在一起。特别是,如果y的最右边的位是0,则结果将始终为0.此语义补丁关注于y是常量的情况。

你有一套很好的例子here

邮件列表非常活跃且乐于助人。

答案 1 :(得分:3)

Coccinelle的以下语义补丁将进行转换。

@@
expression E1, E2, E3, E4;
@@

- E1 = E2 ? E3 : E4;
+ if (E2)
+   E1 = E3;
+ else
+   E1 = E4;

@@
type T;
identifier E5;
T *E3;
T *E4;
expression E1, E2;
@@

- E1 = ((E2) ? (E3) : (E4))->E5;
+ if (E2)
+   E1 = E3->E5;
+ else
+   E1 = E4->E5;


@@
type T;
identifier E5;
T E3;
T E4;
expression E1, E2;
@@

- E1 = ((E2) ? (E3) : (E4)).E5;
+ if (E2)
+   E1 = (E3).E5;
+ else
+   E1 = (E4).E5;

答案 2 :(得分:1)

DMS Software Reengineering Toolkit可以通过应用程序转换来完成此任务。

特定的DMS转换以匹配您的特定示例:

domain C.

rule ifthenelseize_conditional_expression(a:lvalue,A:condition,B:term,C:term):
stmt -> stmt
=  " \a = \A ? \B : \C; "
-> " if (\A) \a = \B;  else \a=\C ; ".

您需要另一条规则来处理您的其他案件,但同样容易表达。

转换对源代码结构而不是文本进行操作,因此布局和注释不会影响识别或应用。规则中的引号不是传统的字符串引号,而是金属语言引用,它将规则语法语言与用于指定要更改的具体语法的模式语言分开。

如果您打算保留预处理指令,则会出现一些问题。由于您可能愿意使用预处理器扩展代码,因此您可以要求DMS在转换步骤中执行预处理;它内置了完整的GCC4和GCC4兼容预处理器。

正如其他人所观察到的,这是一个相当容易的案例,因为您指定它在完整语句的级别上工作。如果你想要删除看起来类似于这个语句的任何赋值的代码,在各种上下文(初始化器等)中嵌入这样的赋值,你可能需要一组更大的变换来处理各种特殊情况,你可以需要制造其他代码结构(例如,适当类型的临时变量)。像DMS这样的工具的好处是,它可以显式计算任意表达式的符号类型(因此任何所需临时值的类型声明),并且您可以相当直接地编写这样一个更大的集合并应用它们。

所有这一切,我不确定进行三元条件表达式消除操作的真正价值。一旦编译器获得结果,您可能会获得类似的对象代码,就好像您根本没有完成转换一样。毕竟,编译器也可以应用等价保留转换。

尽管如此,定期更改显然是有价值的。

(DMS可以将源到源程序转换应用于许多语言,包括C,C ++,Java,C#和PHP)。

答案 3 :(得分:0)

我不知道这样的事情,因为三元运算符作为if逻辑的快捷方式内置于语言规范中...我能想到这样做的唯一方法是手动查找这些行并将其重写为使用if的形式...作为一般共识,三元运算符就像这样工作

expr_is_true ? exec_if_expr_is_TRUE : exec_if_expr_is_FALSE;

如果表达式被评估为真,则执行?:之间的部分,否则执行:;之间的最后一部分。如果表达式被评估为假,那将是相反的

expr_is_false ? exec_if_expr_is_FALSE : exec_if_expr_is_TRUE;

答案 4 :(得分:0)

如果这些语句非常规则,为什么不通过一个小的Perl脚本运行你的文件呢?对于您的示例行,执行查找和转换的核心逻辑很简单。这是一个简单的方法:

use strict;
while(<>) {
    my $line = $_;
    chomp($line);
    if ( $line =~ m/(\S+)\s*=\s*\((\s*\S+\s*)\)\s*\?\s*(\S+)\s*:\s*(\S+)\s*;/ ) {
        print "if(" . $2 . ")\n\t" . $1 . " = " . $3 . "\nelse\n\t" . $1 . " = " . $4 . "\n";
    } else {
        print $line . "\n";
    }
}
exit(0);

你会这样运行:

perl transformer.pl < foo.c > foo.c.new

当然,如果文本模式不如您发布的文本模式那么规则,那就越来越难了。但是免费,快速和容易尝试。