任何用于模式匹配和-rewriting源代码的软件?

时间:2009-01-06 04:27:24

标签: language-agnostic templates pattern-matching

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

以下是它的工作原理:

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

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

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

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格式。

5 个答案:

答案 0 :(得分:3)

  

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

我认为免费提供这样的工具真是太棒了。

但是有一种商业产品:DMS Software Reengineering Toolkit

  

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

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

  

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

Coccinelle对上述规则的实施将是:

@@
identifier cnt;
expression max,E;
@@

cnt = 0
... when != cnt=E
-while (cnt < max)
+for (cnt=0; cnt < max; cnt++)
{
  ...
-  cnt++;
}

对于C代码:

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

它给出了

int main(){   int i = 0;   printf(“hello \ n”);   for(i = 0; i&lt; arrlen; i ++){     printf(“element%d:%f \ n”,i,arr [i]);   } }

当!= cnt = E时,在cnt和while循环的初始化之间允许任意代码,但检查cnt是否未重新定义。如果在初始化和while循环之间没有使用cnt,那么更精细的规则也可以摆脱cnt的初始化。

答案 3 :(得分:1)

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

这是使用DMS的link that shows a complete, detailed example of pattern-matching/transformation

答案 4 :(得分: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示例中显示的拆分案例,您可以为规则添加类似的警示。