我正在尝试使用 TCL 程序来读取 TCL 模块文件并将它们翻译成另一种语言。到目前为止,这一直运作良好。由于解释过于复杂的原因,我必须在模块文件的不同部分以不同的方式处理“放置标准错误”。我正在寻求帮助,试图找出一种方法来做到这一点。
下面是一个极其缩写的模块文件,称为“modfile”。这个“modfile”由第二个 tcl 程序翻译或“获取”。
proc ModulesHelp { } {
puts stderr "(1) This is a help message"
}
puts stderr "(2) Here in modfile"
ModulesHelp 中的 puts 语句必须与第二个 puts 语句区别对待。请注意,任何解决方案都不能更改“modfile”。该文件不在我的控制之下。
这是我的解决方案尝试:
#!/usr/bin/env tclsh
proc myPuts { stream msg } {
global putMode
puts stdout "putMode: $putMode" # <====== HERE 1
puts stdout $msg
}
proc report { message } {
puts stderr "$message"
}
proc execute-modulefile { m } {
global MODFILE putMode
set putMode "normal"
set slave "__mod"
interp create $slave
interp alias $slave puts {} myPuts
interp alias $slave report {} report
interp eval $slave {global putMode }
interp eval $slave [list "set" "putMode" $putMode]
interp eval $slave [list "set" "m" $m]
set errorVal [interp eval $slave {
set sourceFailed [catch {source $m } errorMsg]
if {[info procs "ModulesHelp"] == "ModulesHelp" } {
set putMode "InHelp" # <======= HERE 2
ModulesHelp
}
if {$sourceFailed} {
report $errorMsg
return 1
}
}]
interp delete $slave
return $errorVal
}
eval execute-modulefile $argv
要运行它,我这样做: $ ./try.tcl modfile 其中显然上面的脚本是“try.tcl”,模块文件是“modfile”。我正在使用 tcl 8.4 的 linux 系统上运行它。
我想要发生的是,在标记为“HERE 2”的行中,我想以某种方式将“putMode”的全局变量从“正常”更改为“InHelp”,以便我可以更改标记为“HERE”的行的行为1"。无论我尝试做什么,我都无法通过在“HERE 2”处执行某些操作来更改“HERE 1”处的 putMode 值。“HERE1”处的 puts 语句总是说“正常”。
使用全局变量似乎是最简单的解决方案,但如果有人可以向我展示如何使用命名空间或其他一些技术,我也会对此感到满意。
感谢您的任何见解。
我非常感谢其他人看到我的问题的时间。我正在尝试使用建议的解决方案,但我不太明白。这是我对解决方案的新尝试(这根本不起作用)。有人可以建议我如何修改此代码以将“putMode”更改为“HERE 2”所在的 inHelp 吗?还有什么特别的东西需要去“HERE 1”所在的地方吗?
#!/usr/bin/env tclsh
proc myPuts { stream msg } {
global putMode
puts stdout "putMode: $putMode" # <=== HERE 1
puts stdout $msg
}
proc report { message } {
puts stderr "$message"
}
proc PutModeTrace {childInterp operation realPutMode} {
# Alias the main array element for the purposes of this procedure
upvar \#0 PutMode($childInterp) realPutMode
if {$operation eq "read"} {
interp eval $childInterp [list set putMode $realPutMode]
} elseif {$operation eq "write"} {
set realPutMode [interp eval $childInterp {set putMode}]
}
}
proc execute-modulefile { m } {
global MODFILE putMode
set putMode "normal"
set slave [interp create]
interp alias $slave puts {} myPuts
interp alias $slave report {} report
interp eval $slave {global putMode }
interp eval $slave [list "set" "putMode" $putMode]
interp eval $slave [list "set" "m" $m]
interp eval $slave [list "set" "slave" $slave]
interp eval $slave {trace add variable putMode {read write} PutModeTrace}
interp alias $slave PutModeTrace {} PutModeTrace $slave
set errorVal [interp eval $slave {
set sourceFailed [catch {source $m } errorMsg]
if {[info procs "ModulesHelp"] == "ModulesHelp" } {
set start "help(\[\["
set end "\]\])"
PutModeTrace $slave "write" "inHelp" # <=== HERE 2
puts stdout $start
ModulesHelp
puts stdout $end
}
if {$sourceFailed} {
report $errorMsg
return 1
}
}]
interp delete $slave
return $errorVal
}
eval execute-modulefile $argv