我有一些旧的软件(用一种不死的语言,但对我来说是死的;-)),它为源代码实现了一个基本的模式匹配和-rewriting系统。我正在考虑复制这段代码,将其翻译成现代语言,并将项目作为重构的动力工具开源。在我走得更远之前,我想知道是否已经存在这样的事情(今晚我的google-fu正在煽风点火)。
以下是它的工作原理:
软件在输入应用程序的抽象语法树(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格式。答案 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示例中显示的拆分案例,您可以为规则添加类似的警示。