当前位置:
文档之家› TCL脚本语言-3-置换:TCL的灵魂
TCL脚本语言-3-置换:TCL的灵魂
}
三行代码,三个换行符只有最后一个是 if 命令的分隔符;而前两个相对于 if 命令而言, 只是其第二个参数中的字符而已。初学者往往会把上面的代码写成下面两种形式:
if {$a>100}{ puts “a = $a ”
}
;#条件判断的}后面没有空格,直接跟着{
if {$a>100} {
puts “a = $a ” }
for {set sum 0;set i 0;#初始化} {$i<=100} {incr i;#递增} { incr sum $i
}
puts $sum
第三行注释不正确,因为这里#以及后面的字符都被解释成了 set 命令的参数,所以会报 错:
作者:雷雨后
Email: leiyuhou010@
用双引号括起来的单词中,所有的置换类型都可以发生。具体我们后面在置换一节中详 细解释。
花括号
如果一个单词以字符“{”开始,那么它必须以相对应的反括号字符“}”作为结束。单
作者:雷雨后
Email: leiyuhou010@
TCL、Python 和软件测试自动化
16
词内部的花括号可以嵌套,但是它们必须配对出现;如果某一个花括号前面是反斜线,那么 TCL 解释器在寻找配对括号的时候该括号不计算在内。该单词是所有出现在花括号在内的原 始字符,但是不包含开始和结束的花括号。例如下面的代码:
把脚本解析成命令序列
Yes
全部命令执行?
No
取下一条命令
该命令分解成单词 必要的置换操作
执行该命令
执行结束
理解了上面的脚本执行过程,就可以理解上一节所说的“一定程度”是什么意思了:执 行器在执行一条命令的之前,首先把命令划分成单词,然后根据单词的写法来进行置换。
在上一节左边的代码中,代码被划分成三个单词,但是后面两个单词都是用花括号括着 的,所以没有不会发生置换,直接把它们作为参数调自动化
18
set a 100 set i 0 set sum 0
while "$i <= $a" { incr sum $i incr i
}
;#如果换成{$i<=$a},就不会死循环了。
puts $sum
需要指出的是,上面解释执行过程中的第三步是可以嵌套的,也就是说,在执行一个过 程的时候,在这个过程内部也可以通过这个过程来执行另外一块脚本代码。就比如上面的 while 循环,它的第一个参数是条件表达式”$i<=$a”,第二个参数是一段代码;在执行 while 命令的过程中,首先计算条件表达式,根据表达式的值确定是否执行下面的代码,如果条件 满足,那么就执行。执行这一段代码的过程和执行 while 的类似:先划分成命令序列,再顺 序执行每一条命令。这一段代码如何执行,是由 while 命令来控制,而不是 TCL 解释器所控 制的。所以,while 不过是一个命令!
而右边的代码中,同样是三个单词,只不过后面的两个单词被双引号括着,所以在执行 if 命令之前,解释器会先对这两个单词进行置换,把里面的$a 用 a 的值替代,然后把替换后 的单词作为参数传递给 if 命令。
下面的代码会进入死循环,为什么?大家自行分析。
作者:雷雨后
Email: leiyuhou010@
set a 100 ”set” “a” “100” set b “First Second” set b First Second set c “The first line
The second line”
;#命令 1 ;#命令 2 ;#命令 3 ;#命令 4,错误
上面代码中,前面两个命令是完全等价的,虽然命令 2 中三个单词都用双引号括起来, 但是三个单词和命令 1 中的三个单词完全一样。执行后变量 a 的值都为 100;命令 3 中第三 个单词用引号括起来,其中包含了空格,如果没有引号,象命令 4 中所示,那么就会出现错 误。因为 set 命令不能够接受三个参数。最后一个命令中也包含三个单词,最后一个单词是 用引号括起来的跨行字符串,里面包含了换行符号。
没有 do...while?自己实现
TCL 中没有 do...while 循环,但是我们明白了上面的道理之后,完全可以自己实现一个 do 命令,作为我们自己的一种控制结构。这在其他的 Python、Pascal 等语言中是很难想象的: python 里面没有 switch,你试着在 python 实现一个 switch,看能否实现?
;#第一条命令 class 及其两个参数 ;#成员变量,保护类型,可以被继承
constructor {name sex} { set m_name $name set m_sex $sex
}
;#构造函数
public method PrintInfo {} { puts "CPerson [GetInfo]"
TCL、Python 和软件测试自动化
19
wrong # args: should be "set varName ?newValue?"
while executing
"set a 100
#创建变量 a,不合法的注释"
上面的错误,是我们经常犯的错误。 上面例子中,for 循环命令中的注释,似乎和前面介绍的 TCL 注释规则相违背,注释并 没有从“#”直到一行结束,而是只到花括号结束。仔细分析,实际上并不违背:例如 for 的第一个参数,包括里面的注释,是整个作为一个单词被传递给 for 命令来解释的,for 命令 执行这个单词的时候,就会正确的解释其中的注释。
脚本注释
理解了脚本的执行过程,就不难理解 TCL 中的注释规则: 当 TCL 解释器在解释执行脚本的时候,如果期望下一个单词是一个命令,但是这个单 词的第一个字符是“#”,那么从这个“#”开始直到这一行的结束,都被 TCL 当作注释而忽 略过去。 下面是几个例子:
#这是一行合法的注释 set a 100 ;#创建变量 a,合法的注释 set a 100 #创建变量 a,不合法的注释;
通过上面的分析,可以看到,下面的两块代码在“一定程度上”是等价的:
if {$a>100} { puts “a = $a”
}
if “$a>100” “ puts \“a = $a\”
”
为什么说是“一定程度”呢,我们有必要了解 TCL 解释执行脚本的过程。
解释执行过程
TCL 解释器执行脚本的过程就是: 1. 根据前面介绍的命令分隔规则和单词划分规则,将脚本文件内容解析成多个命令的
"if {$a>100}"
第一种情况,{$a>100}和后面的{之间没有空格,那么就会报错:因为不符合单词的语 法。第二种情况,{直接拿到了 if 命令的第二行,那么 TCL 认为这里的 if 命令在本行就结束, 那么 if 命令就只有一个参数,显然也会报错。
作者:雷雨后
Email: leiyuhou010@
;#条件判断的后面直接回车,把执行体的{放到下一行
两种写法都是错误的。错误代码分别如下:
extra characters after close-brace while executing
"if {$a>100}{ puts "a = $a "
}
wrong # args: no script following "$a>100" argument while executing
;#第二条命令 ;#第三条命令
作者:雷雨后
Email: leiyuhou010@
TCL、Python 和软件测试自动化
14
上面代码很长,但是实际上只有三个命令:第一个是 class 命令,带有两个参数,第一 个是类名,第二个是类的定义体;第二个命令是 CPerson 命令,实际上刚才的 class 命令在 执行之后就定义了一个新的 TCL 命令,命令名就是我们声明的类名;第三个命令的命令字 是 a,这是我们刚才创建的对象,实际上 CPerson 命令在执行的时候又创建了一个 TCL 命令, 其名字就是我们给出的对象名。
while executing "set b { \{ Sat "Hello" } }"
最后一行代码出错了,因为 set 第三个单词内,嵌套的花括号不能匹配上。如果一个单 词是用花括号括起来的,那么里面所有的置换都不会发生。我们回归头来看看前面 CPerson 类的定义,类的定义部分就是一个用花括号括起来的,包含多行字符创的单词。
下面就是一个 do 命令的简单实现,使用 TCL 写成:
#定义 do 命令 proc do { body while_key cond} {
if { $while_key != "while" } { error "the second parameter must be \"while\"."
TCL、Python 和软件测试自动化
15
什么时候回车字符作为命令结束符,什么时候又不是?为什么会出现第一种错误?回答 这些问题之前,我们必须弄清楚另外一个重要概念:单词!
单词、引号、括号
一个脚本是由多个命令顺序排列而成;而一个命令则是由多个单词组成。单词是由空格 来进行分隔的一个字符串,例如下面的命令中:
分号分隔;TCL 中的一切都是命令及其参数。 2. 一个命令语句包括一个命令字以及零个或多个该命令的参数;命令和参数以及参数
之间用空格或者 Tab 分隔; 3. 如果任何地方出现可以进行置换的操作,那么就会按照规则进行置换; 例如下面的一段代码实际上是由三个命令组成的:
class CPerson { protected variable m_name protected variable m_sex