虽然使用goto轻松实现所有操作(如f.ex. IL所证明),但我想知道是否还可以消除具有更高级别表达式和语句的all goto语句-例如-使用Java支持的所有功能。 或者,如果您喜欢:我正在寻找的是“重写规则”,它将始终有效,无论创建goto的方式如何。
主要是出于理论上的问题,纯粹是出于兴趣;并非好/坏做法。
我考虑过的显而易见的解决方案是使用这样的东西:
while (true)
{
switch (state) {
case [label]: // here's where all your goto's will be
state = [label];
continue;
default:
// here's the rest of the program.
}
}
虽然这可能会起作用并且确实适合我的“正式”问题,但我一点也不喜欢我的解决方案。对于一个,它是丑陋的,对于两个,它基本上将goto包装到一个开关中,该开关的功能与goto完全相同。
所以,有更好的解决方案吗?
更新1
由于许多人似乎认为这个问题过于笼统,所以我将进一步阐述……我提到Java的原因是因为Java没有'goto'语句。作为我的业余爱好项目之一,我试图将C#代码转换为Java,事实证明这非常具有挑战性(部分是由于Java中的这一限制)。这让我开始思考。如果您有外汇Open寻址中“删除”方法的实现(请参阅:http://en.wikipedia.org/wiki/Open_addressing-注1),在特殊情况下具有“转到”功能非常方便,尽管在这种特殊情况下,您可以通过引入“状态”来重写它'变量。请注意,这只是一个示例,我实现了连续的代码生成器,当您尝试对它们进行反编译时,它们会生成大量的goto。
我也不确定在此问题上的重写是否总是会消除'goto'语句,以及在每种情况下是否都允许使用该语句。尽管我不是要寻求正式的“证明”,但一些证据表明,在该问题上有可能消除。
关于“广泛性”,我向所有认为“答案太多”或“重写goto的方法很多”的人提出挑战,请他们提供重写一般情况的算法或方法,因为唯一的答案我到目前为止发现的是我发布的那个。
虽然使用goto实现一切都很容易(如f.ex. IL所证明的,但我想知道是否也可以消除所有具有更高级别的表达式和语句的goto语句-例如-...
] >> < [Stuff1();
if (cond) goto Label;
Stuff2();
Label:
Stuff3();
成为:
Stuff1(); if (!cond) { Stuff2(); } Stuff3();
案例2
Stuff1();
Label:
Stuff2();
Stuff3();
if (cond) goto Label;
成为:
Stuff1();
do
{
Stuff2();
Stuff3();
} while (cond);
并以此为基础来检查每个复杂的案例并应用导致这些琐碎案例的迭代转换。然后以最终的gotos / labels根除算法结束。
这是一个非常有趣的阅读。
UPDATE:关于该主题的其他一些有趣的论文(不容易掌握,因此在此复制直接链接以供参考):
A Formal Basis for Removing Goto Statements
A Goto-Elimination Method And Its Implementation For The McCat C Compiler从那天开始,我就使用Modula-2,C,Revelation Basic,三种VB和C#进行编码,但从未发现需要甚至建议使用GOTO作为解决方案的情况。但是,对于原始的BASIC,GOTO是不可避免的。
for(int i = 0; i < list.Count; i++)
{
// some code that initializes inner
for(int j = 0; j < inner.Count; j++)
{
// Some code.
if (condition) goto Finished;
}
}
Finished:
// Some more code.
为了避免转到,您应该执行以下操作:
for(int i = 0; i < list.Count; i++) { // some code that initializes inner bool conditon = false; for(int j = 0; j < inner.Count; j++) { // Some code that might change condition if (condition) break; } if (condition) break; } // Some more code.
我认为goto语句看起来要好得多。
如果内部循环使用其他方法,则第二种情况还可以。
void OuterLoop(list) { for(int i = 0; i < list.Count; i++) { // some code that initializes inner if (InnerLoop(inner)) break; } } bool InnerLoop(inner) { for(int j = 0; j < inner.Count; j++) { // Some code that might change condition if (condition) return true; } return false; }
由于您说的是理论问题,所以这里是理论答案。Java图灵当然是完整的,是的。您可以用Java表达任何C#程序。您也可以在Minecraft Redstone或Minesweeper中表达它。与这些替代方法相比,用Java表示它应该很容易。但是,帕特里斯给出了一个显然更实用的答案,即可以理解的算法来进行转换。
我一点都不喜欢我的解决方案。对于一个,它是丑陋的,对于两个,它基本上将goto包装到一个开关中,该开关的功能与goto完全相同。这是寻找可以替代goto用法的通用模式时总会得到的结果,它的功能与goto完全相同。还有什么呢? goto的不同用法应替换为最佳匹配的语言构造。这就是为什么首先要有构造为switch语句和for循环的构造,以使创建这样的程序流更容易且更不易出错。编译器仍然会生成goto的(或跳转),但在我们搞砸的地方会始终如一地进行。最重要的是,我们不必阅读编译器生成的内容,而是可以阅读(并编写)更容易理解的内容。[您会发现,存在大多数编译器构造以概括goto的特定用法,这些构造是根据之前存在的常见goto使用模式创建的。 Patrice Gahide的论文提到了某种相反的过程。如果在代码中找到goto,则可以查看其中一种模式,在这种情况下,应将其替换为匹配的语言结构。或者,您正在查看本质上是非结构化的代码,在这种情况下,您应该实际构造代码(或不理会它)。将其更改为非结构化但没有
goto
的内容只会使情况变得更糟。 (顺便说一下,相同的泛化过程仍在进行,请考虑如何将foreach
添加到编译器中以泛化for
的非常常见的用法...)
从那天开始,我就使用Modula-2,C,Revelation Basic,三种VB和C#进行编码,但从未发现需要甚至建议使用GOTO作为解决方案的情况。但是,对于原始的BASIC,GOTO是不可避免的。
for(int i = 0; i < list.Count; i++)
{
// some code that initializes inner
for(int j = 0; j < inner.Count; j++)
{
// Some code.
if (condition) goto Finished;
}
}
Finished:
// Some more code.
但是,帕特里斯给出了一个显然更实用的答案,即可以理解的算法来进行转换。
这是寻找可以替代goto用法的通用模式时总会得到的结果,它的功能与goto完全相同。还有什么呢? goto的不同用法应替换为最佳匹配的语言构造。这就是为什么首先要有构造为switch语句和for循环的构造,以使创建这样的程序流更容易且更不易出错。编译器仍然会生成goto的(或跳转),但在我们搞砸的地方会始终如一地进行。最重要的是,我们不必阅读编译器生成的内容,而是可以阅读(并编写)更容易理解的内容。