当你启动一个tcl脚本时,会发生什么后台进程。 (类似于c编译)?
当您开始期望时,脚本过程如何工作?
答案 0 :(得分:1)
假设您已经有一个正在运行的Tcl解释器并且只运行了source
脚本(这避免了描述整个解释器启动序列和初始化),那么在最近的(8.x)Tcl解释器中会发生以下情况:
这基本上调用了一些像Tcl_EvalFile()
这样的C代码,它将脚本加载到内存中,并将实际执行的工作交给内部TclEvalEx()
,这是{{{}}的私有版本。 1}},如此处所述(https://www.tcl.tk/man/tcl/TclLib/Eval.htm)。
这解释了没有字节码编译的顶级脚本,例如解析脚本,一旦找到命令,就直接执行。这是非常缓慢的,旧的Tcl 7.x一直在运行。
但是如果执行命令,则检查命令是否可以字节编译为更有效的形式。这是通过Tcl_EvalEx()
定义的命令的情况,因此如果第一次执行命令,proc
会在内部调用Tcl_EvalObjEx()
以获取命令的字节码表示,该命令缓存在已解析命令的TclCompileObj()
。
如果命令无法编译,则直接执行,例如调用Tcl_Obj
中的一个函数,例如,处理命令generic/tclCmd*.c
,concat
中的命令为Tcl_ConcatObjCmd()
。此函数也可能来自加载到解释器中的某个C扩展,并且以完全相同的方式处理。可用命令在内部注册在某个哈希表中,这就是generic/tclCmdAH.c
所做的事情。
但是如果可以编译命令,就会发生不同的事情。在这种情况下,命令变为字节码表示。例如,对于这样一个简单的过程:Tcl_CreateObjCmd()
这将变成四个字节码。您实际上可以通过proc c {a b} {concat $a $b}
命令检查生成的字节码,看看这个Tkcon会话和Tcl 8.6.3:
::tcl::unsupported::disassemble
此字节码(底部的四行)由Tcl解释器内的虚拟机执行。它目前是基于堆栈的VM。您可以在() 69 % proc c {a b} {concat $a $b}
() 70 % ::tcl::unsupported::disassemble proc c
ByteCode 0x00000000045A2660, refCt 1, epoch 16, interp 0x0000000002E26120 (epoch 16)
Source "concat $a $b"
Cmds 1, src 12, inst 10, litObjs 0, aux 0, stkDepth 2, code/src 0.00
Proc 0x0000000002EB32A0, refCt 1, args 2, compiled locals 2
slot 0, scalar, arg, "a"
slot 1, scalar, arg, "b"
Commands 1:
1: pc 0-8, src 0-11
Command 1: "concat $a $b"
(0) loadScalar1 %v0 # var "a"
(2) loadScalar1 %v1 # var "b"
(4) concatStk 2
(9) done
文件中找到它的实现。
并非所有命令都可以进行字节编码,如果命令没有匹配的字节码,则生成对普通函数的调用,例如,提到直接执行的generic/tclExecute.c
事之一。
对于大多数情况,字节码更快(几乎每次重复使用命令时)。这是建议将所有代码放在过程中的一个原因(它们以这种方式进行字节编译),并支持你的表达式。
希望这能说明一下这个过程。我遗漏了一些更复杂的细节,如编译epoches和协同例程的问题,非递归引擎等。
Expect与普通的Tcl完全相同,它只是通过Tcl_*ObjCmd
添加了一些额外的命令。