退出命令后如何使tcl解释器不继续?

时间:2013-04-26 16:16:46

标签: c++ tcl exit

static int
MyReplacementExit(ClientData unused, Tcl_Interp *interp, int argc, const char *argv[])
{
 //     Tcl_DeleteInterp(interp);
 //     Tcl_Finalize();
        return TCL_OK;
}

int main() {
    Tcl_Interp *interp = Tcl_CreateInterp(); 
    Tcl_CreateCommand(interp, "exit", MyReplacementExit, NULL, NULL);

    Tcl_Eval(interp, "exit ; puts 11111111");
    std::cout << "22222222222" << std::endl;
    return 0;
}

我需要处理tcl解释器的exit命令评估。默认情况下,它会尝试删除自己,并调用关闭整个程序的std::exit。这不是我想要的,所以我试图用自定义proc替换它。我不需要在退出处理程序proc中删除解释器(我可以在以后执行),只需要它在exit命令后不继续评估命令。

在此代码中,我需要以某种方式更改MyReplacementExit proc,因此11111111不会被打印但是 22222222222打印出来。

可以通过从TCL_ERROR proc返回MyReplacementExit来实现,但是我无法区分其他错误情况。

1 个答案:

答案 0 :(得分:1)

替换exit删除解释器(停止执行更多命令,但实际上不会立即删除数据结构,因为它仍然在使用中),重要,通过调用Tcl_EvalTcl_Preserve来打电话给Tcl_Release。如果可以避免,请不要致电Tcl_Finalize;那就是当你即将从内存中卸载Tcl库时,这可能非常棘手(坦率地说,退出流程更容易)。

以下是如何使用您的代码(改编):

static int
MyReplacementExit(ClientData unused, Tcl_Interp *interp, int argc, const char *argv[])
{
    Tcl_DeleteInterp(interp);  // <------------------
    return TCL_OK;
}

int main() {
    Tcl_Interp *interp = Tcl_CreateInterp(); 
    Tcl_CreateCommand(interp, "exit", MyReplacementExit, NULL, NULL);

    Tcl_Preserve(interp);      // <------------------
    Tcl_Eval(interp, "exit ; puts 11111111");
    Tcl_Release(interp);       // <------------------
    std::cout << "22222222222" << std::endl;
    return 0;
}

请注意,Tcl_Release之后 ,因为它可能已被销毁(如同,内存已释放和在那一点上用随机的垃圾潦草地写下来。如果您需要检索结果并使用它们(例如,将它们打印出来),请事先这样做。

请注意,在这种特定情况下,您不需要保留/释放对;你的代码实际上并没有在Tcl_Eval之后触及解释器(它在内部自己保存/释放)。


如果您不希望解释器终止,那就太麻烦了。 8.4中最干净的方法可能是抛出一个自定义异常代码(即任何大于TCL_CONTINUE的代码),但不保证它可以用于任意代码,因为Tcl的catch命令仍然可以捕获它。如果您真的处于这种情况,实际上更容易创建一个解释器,在子interp中运行任意代码,并在脚本结束时将其拆除;然后,您可以放弃该解释器而不会丢失太多上下文。的确,你可以做到:

Tcl_Preserve(interp);
if (Tcl_Eval(interp, theScriptToEval) != TCL_OK)
    // Handle unexpected errors here
if (!Tcl_InterpDeleted(interp))
    Tcl_DeleteInterp(interp);
Tcl_Release(interp);

是的,这意味着您希望将设置解释器的工作量保持在相当小的水平;你可能不想尝试在中断时每隔一毫秒调用一次......