7

我有一些旧软件(使用的语言还没有死,但对我来说已经死了;-))为源代码实现了基本的模式匹配和重写系统。我正在考虑恢复这段代码,将其翻译成现代语言,并将项目作为重构动力工具开源。在我走得更远之前,我想知道这样的事情是否已经存在(我的 google-fu 今晚正在宣传这件事)。

以下是它的工作原理:

  • 模式匹配部分使用具有绑定变量的模板匹配跨越多行代码的源代码模式,
  • 模式重写部分使用模板重写匹配的代码,从匹配的模板插入绑定变量的内容
  • 匹配和重写模板通过一个简单的(无条件的)重写规则关联(1:1)

该软件对输入应用程序的抽象语法树 (AST) 进行操作,并输出修改后的 AST,然后可以将其重新生成为新的源代码

例如,假设我们发现一堆真正应该是 for 循环的 while 循环。以下模板将匹配 while-loop 模式:

Template oldLoopPtrn
    int @cnt@ = 0;
    while (@cnt@ < @max@)
    {
        … @body@
        ++@cnt@;
    }
End_Template

而以下模板将指定输出重写模式:

Template newLoopPtrn
    for(int @cnt@ = 0; @cnt@ < @max@; @cnt@++)
    {
        @body@
    }
End_Template

和一个简单的规则来关联它们

Rule oldLoopPtrn --> newLoopPtrn

所以看起来像这样的代码

int i=0;
while(i<arrlen)
{
    printf("element %d: %f\n",i,arr[i]);
    ++i;
}

自动改写成这样

for(int i = 0; i < arrlen; i++)
{
    printf("element %d: %f\n",i,arr[i]);
}

我见过的最接近这样的东西是一些代码重构工具,但它们似乎是针对选定片段的交互式重写,而不是大规模的自动更改。

我相信这种工具可以增强重构,并且可以在多种语言(甚至 HTML/CSS)上工作。我也相信转换和完善代码库将是一个巨大的项目,我根本无法在任何合理的时间内单独完成。

那么,已经有类似的东西了吗?如果没有,是否需要考虑任何明显的特征(除了重写规则条件)?

编辑:我非常喜欢这个系统的一个特点是模板模式相当明显且易于阅读,因为它们是用与目标源代码相同的语言编写的,而不是一些深奥的变异正则表达式/BNF 格式。

4

5 回答 5

3

我正在考虑恢复这段代码,将其翻译成现代语言,并将项目作为重构动力工具开源。

我认为免费提供这样一个工具真是太好了。

但是有一个商业产品可用:DMS Software Reengineering Toolkit

DMS Software Reengineering Toolkit 是一套工具,用于自动化定制的源程序分析、修改或翻译或软件系统的生成,包含任意混合语言(“域”)。DMS 的“软件”一词​​非常广泛,涵盖任何形式符号,包括编程语言、标记语言、硬件描述语言、设计符号、数据描述等。该工具包是实现 The Design Maintenance System™ 的第一步,一个雄心勃勃的 21 世纪软件工程环境愿景,支持由语义和捕获的设计驱动的大型应用程序系统的增量构建和维护。

此外,对于 C 源代码,还有coccinelle工具:

Coccinelle 是一个程序匹配和转换引擎,它提供语言 SmPL(语义补丁语言)用于在 C 代码中指定所需的匹配和转换。Coccinelle 最初的目标是在 Linux 中执行附带演变。这种演变包括客户端代码中响应库 API 演变所需的更改,并且可能包括修改,例如重命名函数、添加其值在某种程度上依赖于上下文的函数参数以及重新组织数据结构。除了附带演变之外,Coccinelle 还成功地用于(我们和其他人)查找和修复系统代码中的错误。

于 2010-03-21T21:00:19.100 回答
1

在 TXL 中,它看起来像这样:

include "c.grm"

rule main
    replace [declaration_or_statement*]
        int cnt [id] = 0;
        while (cnt < max [shift_expression] )
        {
                body [declaration_or_statement*]
        }
    deconstruct * body
        ++cnt;
    by
        for (int cnt = 0; cnt < max; cnt++)
        {
                body
        }
end rule

对于此输入:

int main () {
  int i=0;
  while(i < arrlen) {
    printf("element %d: %f\n",i,arr[i]);
    ++i;
  }
}

它产生了这个:

int main () {
    for (int i = 0; i < arrlen; i++) {
        printf ("element %d: %f\n", i, arr [i]);
        ++i;
    }
}

对于上面 Coccinelle 示例中显示的拆分案例,您可以在规则中添加类似的保护。

于 2012-06-03T08:12:33.120 回答
1

TXL是基于规则而不是基于模式的,因此它具有更多功能,但学习曲线可能更陡峭。

于 2009-01-06T04:38:14.373 回答
1

上述规则的 Coccinelle 实现将是:

@@
标识符cnt;
表达式最大值,E;
@@

cnt = 0
... 当 != cnt=E
-while (cnt < 最大值)
+for (cnt=0;cnt < 最大值;cnt++)
{
  ...
-cnt++;
}

对于 C 代码:

诠释主要(){
  诠释我=0;
  printf ("你好\n");
  而(我<阿伦){
    printf("元素 %d: %f\n",i,arr[i]);
    ++i;
  }
}

它给

int main () { int i=0; printf ("你好\n"); for (i = 0; i < arrlen; i++) { printf("元素 %d: %f\n",i,arr[i]); } }

... when != cnt=E 允许在 cnt 的初始化和 while 循环之间执行任意代码,但会检查 cnt 是否未重新定义。如果在初始化和 while 循环之间不使用 cnt 的初始化,则更详细的规则也可以消除它。

于 2010-05-15T17:03:15.760 回答
1

我们的 DMS 已经被提及。正如 OP 所说,它具有转换规则,“易于阅读,因为它们是用与目标源代码相同的语言编写的”。

这是一个链接,显示了使用 DMS 进行模式匹配/转换的完整详细示例。

于 2010-05-18T18:19:15.070 回答