跳回不同的Tcl堆栈帧

跳回不同的Tcl堆栈帧,tcl,Tcl,有没有一种简单的方法可以在Tcl中展开堆栈? 我遇到了一个奇怪的问题,我必须回到一个特定的堆栈帧。我可以使用info命令获取所有帧信息,但要真正获取特定帧,我必须在每个过程中设置一些局部变量,并相应地检查它们。我想知道是否有更简单的方法。简单的回答是,您最好重新考虑您的设计 更长的答案是,唯一真正做到这一点的方法(我能想到)是抛出一个错误,并在您需要停止它的级别上重新捕获它。当然,除了在调用堆栈上检查变量的不太可靠的方法之外。然而,将错误用于控制流是。。。糟糕的形式。如果您愿意成为最前沿的,协同

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

简单的回答是,您最好重新考虑您的设计


更长的答案是,唯一真正做到这一点的方法(我能想到)是抛出一个错误,并在您需要停止它的级别上重新捕获它。当然,除了在调用堆栈上检查变量的不太可靠的方法之外。然而,将错误用于控制流是。。。糟糕的形式。

如果您愿意成为最前沿的,协同程序(在8.6中提供)可能会满足您的需求

否则,您可能会尝试记录在那里时需要达到的例程级别(即,将全局变量设置为[info level]),然后在更深的过程中,[uplevel]设置为绝对堆栈帧。差不多

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

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

(未测试)

如果您需要获取代码来执行非本地返回(即,跳过几个级别),您可以从8.5开始使用
-level
选项执行此操作,以
返回
。请参见此示例:

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或它们的脚本实现,也可以使用
try
throw
(请参阅8.6中讨论代码时使用的Tcl代码)


对于较旧的Tcl版本,最简单的机制是使用
return-code 42
,并将一些代码放入堆栈中,以捕获自定义异常,并确定它是否是神奇的值(这里是42;它将是
捕获的结果),并做出适当的响应。这可能相当有效,但也很混乱。这就是为什么8.5以后的版本为您提供了更易于使用的工具。

用于跑步。我需要从一个过程到另一个过程,在另一个层次上。虽然我认为Donal Fellows的答案是完美的,但这个主题最好重新表述,因为在大多数程序员的头脑中,“展开堆栈”是一个与异常处理/调试有着深刻联系的术语。你知道如何合理地重新措辞吗?同意。“在堆栈中移动”会更好吗?也许‘从一个堆栈帧移动到另一个堆栈帧’?我又尝试了一次改进标题;返回对你有效表明你在追求什么。真正的堆栈展开…唯一真正的答案是使用大于1的整数参数的
uplevel
,或者切换到8.6(这实际上是一个隐藏的无堆栈Tcl实现,这是一个巨大的变化,需要花费相当长的时间才能正常工作)。+1用于邪恶地使用
uplevel
。只是不要在我必须维护的任何代码中这样使用它!:-)