这个问题背后的动机是学习......
我已经完成了一些TCL编程,但我确实有一个正常工作的代码,但我不明白为什么有些语法有效,而另一种语法没有。
问题描述: 我正在编写一个需要设置电源和接地网电压的代码。 在我输入VDD网络后,
set POWER_NETS "vdd=1.1 vdda=1.2 vref=1.1"
然后一个简单的TCL代码应该构造并执行以下命令:
set_vdd vdd 1.1
set_vdd vdda 1.2
set_vdd vref 1.1
就是这样。这似乎微不足道,但我在执行它时遇到了一些困难。我仍然不明白为什么有时我的代码不起作用,虽然这对我来说似乎是正确的。
工作解决方案:我提出的唯一可行的解决方案是:
foreach ITEM [split $POWER_NETS] {
set NET [lindex [split $ITEM =] 0]
set VOLTAGE [lindex [split $ITEM =] 1]
set_vdd $NET $VOLTAGE
}
这么简单的操作有很多代码。当以更精简的形式书写时,它仍然有效:
foreach ITEM [split $POWER_NETS] {
set_vdd [lindex [split $ITEM =] 0] [lindex [split $ITEM =] 1]
}
但我仍然觉得这里有改进的余地。
学习目标:我想以此解决方案作为最佳代码解决(它既简短又全面)
foreach ITEM [split $POWER_NETS] {
set_vdd [split $ITEM =]
}
不幸的是,这不起作用。解释set_vdd命令的工具会抱怨
no value given for parameter "voltage" (use -help for full usage) :
我不明白为什么这不起作用。有什么区别?
当我用set_vdd
替换puts
时,它会打印所有值。所有信息都在那里。不是吗?
nlv12345@acc3081 CHAR_OUT_LOGS $ tclsh
% set POWER_NETS "vdd=1.1 vdda=1.2 vref=1.1"
vdd=1.1 vdda=1.2 vref=1.1
% foreach ITEM [split $POWER_NETS] {
puts [split $ITEM =]
}
vdd 1.1
vdda 1.2
vref 1.1
%
答案 0 :(得分:4)
错误消息不是最佳的,但问题是您将split
中的两个单词作为单个参数传递给set_vdd
。
如果您的Tcl解释器是任何当前支持的版本,您可以改为执行此操作:
foreach ITEM [split $POWER_NETS] {
set_vdd {*}[split $ITEM =]
}
{*}
是一个标记,表示“取这个列表 - 这个词的其余部分 - 并将其拆分为单独的参数”。虽然它正式不是运营商而是Tcl语言的语法部分,但称其为“扩展运算符”并不会让您感到困惑。
较旧的,不受支持的Tcl版本(8.4及之前版本)需要使用eval
来执行此操作。你可能还可以:
foreach ITEM [split $POWER_NETS] {
eval set_vdd [split $ITEM =]
}
但实际上这样做会更安全:
foreach ITEM [split $POWER_NETS] {
eval [linsert [split $ITEM =] 0 set_vdd]
}
如您所见,{*}
简化了一些事情。
但是,我实际上是这样做的:
foreach {ITEM KEY VALUE} [regexp -all -inline {(\w+)=([\d.]+)} $POWER_NETS] {
set_vdd $KEY $VALUE
}
就像那样,POWER_NETS
价值中出人意料的事情不会造成太大麻烦。 OTOH,如果你不习惯正则表达式,那么现在可能不是时候开始regexp
......
答案 1 :(得分:2)
另外两个简单的解决方案,用于启发和进一步学习:
set POWER_NETS "vdd=1.1 vdda=1.2 vref=1.1"
foreach ITEM [split $POWER_NETS] {
lassign [split $ITEM =] NET VOLTAGE
set_vdd $NET $VOLTAGE
}
这个使用lassign
分配ITEM
的部分,而不是将它们拆分为无名参数。
set POWER_NETS [string map {= { }} "vdd=1.1 vdda=1.2 vref=1.1"]
foreach {NET VOLTAGE} [split $POWER_NETS] {
set_vdd $NET $VOLTAGE
}
这个用空格替换等号,然后让foreach
成对地提取两个值。