如何在Groovy中使用GOTO语句?

时间:2011-01-05 10:00:09

标签: groovy dsl transformation goto continuations

我看到这个nice blog post about a Scala continuations“模仿”Scala语言中的GOTO语句。 (阅读更多关于Continuations here

的信息

我想在编程语言Groovy中使用相同的东西。我认为这可能在Groovy compiler phase transformation内。

我正在研究领域特定语言(DSL),并且首选嵌入在Groovy中。我想要GOTO语句,因为DSL是一种非结构化语言(并且是从工作流程图生成的)。我需要一个'标记'的goto语句,而不是行号。

DSL是工作流定义的语言,由于节点之间的箭头没有限制,因此需要goto。 (或while等不可读的代码)

作为Groovy和Scala的初学者我不知道如果我可以将Scala解决方案转换为Groovy,但我不认为Groovy中有延续。

我正在寻找一种算法/代码,用于在Groovy中模拟标记的goto。我想到的一种算法是反复使用eval;当您在eval时执行goto。 DSL已经使用eval评估。

我不是在寻找'while'循环或其他东西,而是翻译这段代码以便它可以工作(其他一些语法没问题)

label1: 
a();
b();
goto label1; 

PS: 如果我真的应该/想要GOTO声明,我不喜欢讨论。 DSL是一种规范语言,可能无法应对变量,效率等。

PS2:可以使用其他关键字GOTO

4 个答案:

答案 0 :(得分:5)

您可能想要更多地了解您正在尝试构建的语言,也许这很简单,处理转换将会过度工程化。
使用AST是人们多年来一直在做的事情,它真的很强大 spock框架人员重写你用标签创建注释代码的测试。 http://code.google.com/p/spock/

哈姆雷特·德·艾西已经就此事发表了几次演讲。他的博客上也可以找到几个帖子。 http://hamletdarcy.blogspot.com/
Cedric Champeau描述了他建立的一个有趣的转变及其演变http://www.jroller.com/melix/

可能会遗漏很多其他人,但我记得那些人 您可能已经知道但可能非常有用的起点。 http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations
http://groovy.codehaus.org/Building+AST+Guide

长话短说,我说它很可能

答案 1 :(得分:1)

由于gotoreserved word in Groovy(就像在Java中一样),因此您无法在任何地方尝试此操作,因此在DSL中使用它会有问题。

这不是reserved word in Scala,所以这不是问题

答案 2 :(得分:1)

您可以使用if循环模拟gotowhile。它不会很漂亮,它会引入许多不必要的代码块,但它应该适用于任何函数。有一些证据表明,总是可以重写这样的代码,但当然可能并不意味着它很好或很容易。

基本上,您将所有局部变量移动到函数的开头并添加bool takeJump局部变量。然后为任何goto +标签对添加while(takeJump){ + }对,并将while之前和之前的标志设置为所需的值。

但说实话,我不推荐这种做法。我宁愿使用一个库,它允许我使用标签和gotos构建一个AST,然后将其直接转换为字节码。

或者使用支持goto的java vm上构建的其他语言。我确信有这样的语言。

答案 3 :(得分:1)

把它扔到那里,也许你可以有一个范围的开关案例

所以,如果您的DSL说明了这一点:

def foo() {
   def x = x()
   def y
   def z
   label a:
     y = y(x)
   if(y < someConst) goto a
   label b: 
    z = y(z)
    if(z > someConst) goto c
    x = y(y(z+x))
    z = y(x)
   label c:
    return z; 
}

你的“编译器”可以把它变成这个:

def foo() {
    String currentLABEL = "NO_LABEL"
    while(SCOPED_INTO_BLOCK_0143) {
       def x
       def y
       def z
       def retval
       switch(currentLABEL) {
       case "NO_LABEL":
          x = x()
       case "LABEL_A"
          y = y(x)

          if(y < someConst) {
            currentLABEL = "LABEL_A"
           break
          }
       case "LABEL_B"
          z = y(z)

          if(z > someConst) {
            currentLabel = "LABEL_C"
            break
          }
          x = y(y(z+x))
          z = y(x)
       case "LABEL_C"
          SCOPED_INTO_BLOCK_0143 = false
          retval = z
       }
    }
    return retval
}