2012-04-04 43 views
3

有没有简单的方法在Tcl中展开堆栈? 我有这个奇怪的问题,我必须回到特定的堆栈框架,从字面上。我可以使用info命令获取所有帧信息,但要真正到达特定帧,我必须在每个过程中设置一些局部变量并相应地检查它们。我想知道是否有更简单的方法。跳回不同的Tcl堆栈框架

+0

用于调试或...? – 2012-04-04 23:43:34

+0

用于跑步。我需要从一个程序到另一个程序。 – ilya1725 2012-04-04 23:49:49

+0

虽然我认为Donal Fellows的答案是完美的,但是这个主题应该更好地转述,因为“展开堆栈”是一个与大多数程序员头脑中的异常处理/调试密切相关的术语。有关如何合理地改述的想法? – kostix 2012-04-05 14:18:33

回答

4

如果你需要得到代码做一个非本地回报(即跳过后面几个级别),你可以从8.5起与-level选项return做到这一点。看到这个例子:

proc foo-a {} { 
    puts a-in 
    foo-b 
    puts a-out 
} 
proc foo-b {} { 
    puts b-in 
    foo-c 
    puts b-out 
} 
proc foo-c {} { 
    puts c-in 
    foo-d 
    puts c-out 
} 
proc foo-d {} { 
    puts d-in 
    bar 
    puts d-out 
} 
proc bar {} { 
    puts bar-in 
    return -level 3 
    puts bar-out 
} 
foo-a 

这是通过抛出一种特殊的异常;细节相当隐蔽。或者,如果您已经获得8.6或其脚本实现,则还可以使用trythrow(有关讨论8.6中的代码时使用的Tcl代码,请参阅Tcler's Wiki)。

对于旧的Tcl版本,最简单的机制是使用return -code 42,并将一些代码放在最上层到catch自定义异常,并确定它是否为魔术值(42这里;它将是catch)并做出适当回应。这可能相当有效,但也很麻烦。这就是为什么8.5以后会为您提供易于使用的工具的原因。

3

简短的回答是,你可能会更好地重新考虑你的设计。

较长的答案是,唯一真正的方法(我能想到)做到这一点是抛出一个错误,并在需要停止它的级别捕获它。当然,除了在调用堆栈中检查变量的方式之外,还有一些不太有用的方法。然而,使用控制流的错误是......糟糕的形式。

1

如果你愿意成为先锋,协程(8.6版本)可能会满足你的需求。

否则,你可能会尝试的是注意当你在那里时需要到达的例程的级别(即设置一个全局变量为[info level]),然后在更深的proc中[ uplevel]到该绝对堆栈帧。喜欢的东西

proc need-to-be-here {} { 
    set ::myframe [info level] 
    deeper-calls 
} 

proc deepest-call {} { 
    uplevel #$::myframe {what I need to do} 
} 

(未经测试)

+0

邪恶使用'uplevel'+1。只是不要在任何我必须维护的代码中使用它! :-) – 2012-04-06 06:12:07