我一直在寻找一种可以转换表格的C代码表达式的工具:
a = (A) ? B : C;
使用if
/ else
语句进入'默认'语法:
if (A)
a = B
else
a = C
有人知道能够进行此类转换的工具吗?
我使用GCC 4.4.2并使用-E
创建一个预处理文件,但不希望这样的结构。
编辑: 以下代码也应该转换:
a = ((A) ? B : C)->b;
答案 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
当然,如果文本模式不如您发布的文本模式那么规则,那就越来越难了。但是免费,快速和容易尝试。