代码之家  ›  专栏  ›  技术社区  ›  tur1ng

C:转换A?b:c转换为if(a)b else c

  •  5
  • tur1ng  · 技术社区  · 14 年前

    我在找一个可以转换C代码表达式的工具:

    a = (A) ? B : C;
    

    在“default”语法中 if / else 声明:

    if (A)
      a = B
    else
      a = C
    

    有人知道一种工具可以实现这样的转换吗?

    我使用gcc 4.4.2并创建一个预处理文件 -E 但不想在里面有这样的结构。

    编辑: 还应转换以下代码:

    a = ((A) ? B : C)->b;
    
    5 回复  |  直到 14 年前
        1
  •  12
  •   LB40    14 年前

    Coccinelle 很容易做到。

    coccinelle是一个与 提供 语言smpl(语义补丁 语言)用于指定所需的 C代码中的匹配和转换。 coccinelle最初是目标 向履行抵押品 Linux中的演进。这样的演变 包含所需的更改 在客户端代码中响应 库api中的演进,以及 包括修改,如重命名 函数,添加函数参数 他的价值是 上下文相关,并重新组织 数据结构。抵押物以外 进化,coccinelle是成功的 (被我们和其他人)用来寻找 以及修复系统代码中的错误。

    编辑: 语义补丁示例:

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

    从文档中:

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

    你有一套很好的例子 here .

    邮件列表是非常活跃和有用的。

        2
  •  3
  •   Nico    14 年前

    下面的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;
    
        3
  •  1
  •   Ira Baxter    14 年前

    这个 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这样的工具的好处是,它可以显式地计算任意表达式的符号类型(因此是任何所需temp的类型声明),并且您可以相当直接地编写这么大的集合并应用它们。

    尽管如此,我不确定做三元条件表达式消除操作的真正价值。一旦编译器得到结果,您可能会得到类似的目标代码,就好像您根本没有完成转换一样。毕竟,编译器也可以应用保持等价性的转换。

    不过,在一般情况下进行定期更改显然是有价值的。

    (DMS可以将源到源程序转换应用到许多语言,包括C、C++、爪哇、C和P)。

        4
  •  0
  •   t0mm13b    14 年前

    我不知道三元运算符作为 if 逻辑…我能想到的唯一办法就是手动查找这些行并将其重写为 如果 被使用…作为普遍共识,三元运算符的工作方式如下

    expr_is_true ? exec_if_expr_is_TRUE : exec_if_expr_is_FALSE;
    

    如果表达式的计算结果为true,则执行 ? : ,否则执行 : ; . 如果表达式的计算结果为false,则相反

    expr_is_false ? exec_if_expr_is_FALSE : exec_if_expr_is_TRUE;
    
        5
  •  0
  •   Ian C.    14 年前

    如果语句非常规则,为什么不通过一个小的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
    

    当然,如果文本模式没有你发布的那样规则,它会变得越来越难。但是免费,快捷,容易尝试。