Tcl中表达式的替换规则
在TCL中表达式操作数的替换方式有两种,第一种是普通的TCL解析器机制,例如下面的命令:
% set x 0.5236
0.5236
% expr 2*sin($x)
1.0000021207252057
这里TCL解析器会在执行命令前替换变量x的值,传递给expr的第一个参数的值类似于2*sin(0.5236)。
第二种方式则是通过表达式处理,在处理表达式时会再进行一轮变量替换和命令替换。例如:
expr {2*sin($x)}
这里大括号阻止了TCL解析器替换x的值,因此传给expr的参数是2*sin($x),当表达式处理器遇到$符号时,它自己会进行一次变量替换,把变量x的值作为参数传给sin。当表达式处理器执行变量或命令替换时,替换的值必须是整数、实数或者字符串。这里替换的值不能是任意的表达式。
有这样两层替换对expr命令的操作来说通常不会造成什么不同,但是对于 while这样会反复处理一个表达式,而各次处理所得的值不同的命令就有很大的影响了。例如下面这个脚本,该脚本寻找比指定的数大的、最小的2的幂。
set pow 1
while {$pow<$num} {
set pow [expr $pow*2]
}
表达式$pow<$num在每次迭代开始之前都要处理一次,判断是否终止循环。该表达式在每次处理的时候都必须替换进pow的新值。如果没有这个大括号,那这个替换就会在解析 while命时进行,那样 while的第一个参数应该是常量表达式,这个循环要么不进行,要么就会进入死循环。
最好总是把表达式用大括号括起来,即使是在使用expr命令的时候,TCL处理括起来的表达式的效率大大高于处理没有括起来的表达式的效率。把表达式用大括号括起来还能避免在代码中出现一些难以捉摸的安全漏洞。考虑以下情况,程序提示用户给出一个值,用户输入了一个表达式,例如
set x [expr $input +2]
如果一个恶意用户在 Windows系统中输入[ format C:\],那么TCL解释器会把这个字符串作为input变量,而表达式处理器会执行其中的命令一一格式化C盘。如果把这个表达式用括号括起来,表达式处理器会把它的值作为 input的值替换进来,这个值并不是一个有效的数学表达式,于是会产生一个错误。