我听说理论上已经证明可以使用结构化编程结构(条件,循环和循环中断,以及子程序调用)在图灵完备语言中表达任何控制流,而不是任意的 GOTO
声明。有没有办法使用该理论自动重构包含的代码 GOTO
s代码没有?
假设我在一个简单的命令式语言中有一个任意的单个子例程,比如C或Pascal。我还有一个解析器可以验证这个子例程是否有效,并从中生成一个抽象语法树。但代码包含 GOTO
s和标签,可以向前或向后跳转到任意点,包括进入或退出条件或循环块,但不在子程序本身之外。
是否有一种算法可以使用此AST并将其重新编写为新代码,该代码在语义上相同,但不包含任何标签或 GOTO
声明?
我想你想读 驯服控制流程 由Erosa和Hendren撰写,1994年。(早先的链接 谷歌学术)。
顺便说一句,循环中断也很容易消除。有一个简单的机械过程,包括创建一个布尔状态变量和重组嵌套条件以创建直线控制流。它不会产生漂亮的代码:)
如果您的目标语言具有尾部调用优化(并且理想情况下,内联),则可以通过将循环转换为尾递归函数来机械地删除中断和继续。 (如果索引变量被循环体修改,你需要更加努力。我将只展示最简单的情况。)这是一个简单循环的转换:
for (Type Index = Start; function loop(Index: Type):
Condition(Index); if (Condition)
Index = Advance(Index)){ return // break
Body Body
} return loop(Advance(Index)) // continue
loop(Start)
该 return
标有“继续”和“休息”的陈述恰恰是转型 continue
和 break
。实际上,该过程的第一步可能是将循环重写为原始语言中的等效形式:
{
Type Index = Start;
while (true) {
if (!Condition(Index))
break;
Body;
continue;
}
}
原则上,总是可以这样做,虽然结果可能不是很好。
始终消除gotos的一种方法是以下列方式转换程序。首先编写原始程序中的所有指令。例如,给定此程序:
start:
while (true) {
if (x < 5) goto start;
x++
}
您可以对这些语句进行编号:
0 start:
1 while (x < 3) {
2 if (x < 5) goto start;
3 x++
}
为了消除所有的getos,你可以通过使用while循环,一个包含程序计数器的显式变量和一堆if语句来模拟通过这个函数的控制流。例如,您可以像这样翻译上面的代码:
int PC = 0;
while (PC <= 3) {
if (PC == 0) {
PC = 1; // Label has no effect
} else if (PC == 1) {
if (x < 3) PC = 4; // Skip loop, which ends this function.
else PC = 2; // Enter loop.
} else if (PC == 2) {
if (x < 5) PC = 0; // Simulate goto
else PC = 3; // Simulate if-statement fall-through
} else if (PC == 3) {
x++;
PC = 1; // Simulate jump back up to the top of the loop.
}
}
这是一种非常非常糟糕的翻译方式,但它表明理论上总是可以做到这一点。实际上实现这一点会非常麻烦 - 你可能会对函数的基本块进行编号,然后生成将基本块放入循环的代码,跟踪当前正在执行的基本块,然后模拟运行基本块的效果和从该基本块到适当的下一个基本块的转换。
希望这可以帮助!
我使用/和Polyhedron的spag和大量的77to90开始重构fortran的过程,然后将其转换为matlab源。但是,这些工具总是留下程序中goto的1/4到1/2。
我写了一个goto卸妆程序,它完成了与你所描述的类似的东西:它需要fortran代码并重构所有剩余的goto来自程序并用条件替换它们并执行/循环/退出然后可以转换为其他语言,如matlab 。您可以在此处阅读有关我使用的流程的更多信息:
http://engineering.dartmouth.edu/~d30574x/consulting/consulting_gotorefactor.html
这个程序可以适应其他语言,但我还没有达到目的。