Language agnostic 有用于模式匹配和重写源代码的软件吗?

Language agnostic 有用于模式匹配和重写源代码的软件吗?,language-agnostic,templates,pattern-matching,Language Agnostic,Templates,Pattern Matching,我有一些旧的软件(用一种对我来说还没有死但已经死了的语言;-)为源代码实现了一个基本的模式匹配和重写系统。我正在考虑重新编写这段代码,将其翻译成一种现代语言,并将该项目作为重构工具进行开源。在我进一步讨论之前,我想知道这样的事情是否已经存在(我的google fu今晚正在播放) 下面是它的工作原理: 模式匹配部分使用带有绑定变量的模板匹配跨多行代码的源代码模式 模式重写部分使用模板重写匹配的代码,插入匹配模板中绑定变量的内容 匹配和重写模板通过简单(无条件)重写规则关联(1:1) 该软件对输

我有一些旧的软件(用一种对我来说还没有死但已经死了的语言;-)为源代码实现了一个基本的模式匹配和重写系统。我正在考虑重新编写这段代码,将其翻译成一种现代语言,并将该项目作为重构工具进行开源。在我进一步讨论之前,我想知道这样的事情是否已经存在(我的google fu今晚正在播放)

下面是它的工作原理:

  • 模式匹配部分使用带有绑定变量的模板匹配跨多行代码的源代码模式
  • 模式重写部分使用模板重写匹配的代码,插入匹配模板中绑定变量的内容
  • 匹配和重写模板通过简单(无条件)重写规则关联(1:1)
该软件对输入应用程序的抽象语法树(AST)进行操作,并输出修改后的AST,该AST可重新生成新的源代码

例如,假设我们找到一堆while循环,它们实际上应该是for循环。以下模板将与while循环模式匹配:

Template oldLoopPtrn
    int @cnt@ = 0;
    while (@cnt@ < @max@)
    {
        … @body@
        ++@cnt@;
    }
End_Template
所以代码看起来像这样

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]);
}
inti=0;
而(i是基于规则的,而不是基于模式的,因此它有更多的功能,但可能有更陡峭的学习曲线

我正在考虑重新编写这段代码,将其翻译成一种现代语言,并将该项目作为重构工具进行开源

我认为免费提供这样一个工具是非常好的

但有一种商业产品可用:

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

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

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


上述规则的最终实施将是:

@@ identifier cnt; expression max,E; @@ cnt = 0 ... when != cnt=E -while (cnt < max) +for (cnt=0; cnt < max; cnt++) { ... - cnt++; } @@ 标识符cnt; 表达式max,E; @@ cnt=0 …当!=cnt=E时 -而(cnt 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”); 而(我 int main(){ int i=0; printf(“hello\n”); 对于(i=0;i
当!=cnt=E允许在cnt初始化和while循环之间使用任意代码,但检查cnt是否未重新定义。如果在初始化和while循环之间未使用更详细的规则,则也可以取消cnt初始化。

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


这是一个使用DMS的示例。

在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
包括“c.grm”
主要规则
替换[声明或声明*]
int cnt[id]=0;
而(cnt
对于此输入:

int main () {
  int i=0;
  while(i < arrlen) {
    printf("element %d: %f\n",i,arr[i]);
    ++i;
  }
}
int main(){
int i=0;
而(我
它产生了以下结果:

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

对于上面的Coccinelle示例中显示的拆分案例,您为规则添加了一个类似的保护。

感谢链接,这看起来非常有趣……但远不是直观的!;-)程序转换系统中的规则往往只是成对的模式,第一个用于匹配,第二个用于重新生成,很像Lowe的建议。这个想法并不新鲜。重要的是该工具的健壮实现,以及将其应用于实际源代码的能力。TXL(和Stratego/XT)可以做到这一点,但并不擅长处理符号表类型信息(尽管可以伪造它)。DMS(在另一个答案中提到)可以做到这一点,但也提供/使用符号表数据以及控制/数据流、分析点和调用图。如果您决定发布此版本的开源版本,请务必随时通知我们,谢谢!
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;
    }
}