TCL脚本语言的学习(一)
本文参考资料为《
TCL
语言教程》,感谢作者的分享,这里仅仅作为简单常用语法的入门,若有需要后期对本文进行添加补充。
前言(TCL综述)
TCL
(Tool Command Language)是一种解释执行的脚本语言(Scripting Language)。 它提供了 通用的编程能力:支持变量、过程和控制结构;同时 TCL
还拥有一个功能强大的固有的核心命令集。
由于TCL
的解释器是用一个C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL
看作一个C库,这个库中有丰富的用于扩展TCL
命令的C\C++过程和函数,可以很容易就在C\C++应用程序中嵌入TCL
,而且每个应用程序都可以根据自己的需要对TCL
语言进行扩展。我们可以针对某一特定应用领域对TCL
语言的核心命令集进行扩展,加入适合于自己的应用领域的扩展命令,如果需要,甚至可以加入新的控制结构,TCL
解释器将把扩展命令和扩展控制结构与固有命令和固有控制结构同等看待。扩展后的TCL
语言将可以继承TCL
核心部分的所有功能,包括核心命令、控制结构、数据类型、对过程的支持等。根据需要,我们甚至可以屏蔽掉TCL
的某些固有命令和固有控制结构。通过对TCL
的扩展、继承或屏蔽,用户用不着象平时定义一种计算机语言那样对词法、语法、语义、语用等各方面加以定义,就可以方便的为自己的应用领域提供一种功能完备的脚本语言。TCL
良好的可扩展性使得它能很好地适应产品测试的需要,测试任务常常会由于设计和需求的改变而迅速改变,往往让测试人员疲于应付。利用TCL
的可扩展性,测试人员就可以迅速继承多种新技术,并针对产品新特点迅速推出扩展TCL
命令集,以用于产品的测试中,可以较容易跟上设计需求的变化。
另外,因为TCL
是一种比C\C++ 语言有着更高抽象层次的语言,使用TCL
可以在一种更高的层次上编写程序,它屏蔽掉了编写C\C++程序时必须涉及到的一些较为烦琐的细节,可以大大地提高开发测试例的速度。而且, 使用TCL
语言写的测试例脚本,即使作了修改,也用不着重新编译就可以调用TCL
解释器直接执行。可以省却不少时间。TCL
目前已成为自动测试中事实上的标准。
(这里笔者对于TCL
脚本的用处目前还不是很明确,后期学习到了进行补充添加,此处作为EDA课程中的一部分进行学习)
附录(Tcl的安装)
直接打开终端(terminal),输入 sudo apt install tcl
即可进行安装,这里的截图是笔者安装成功后的实例。
之后输入tclsh
即可。
语法
脚本,命令和单词符号
一个TCL
脚本可以包含一个或多个命令。命令之间必须用换行符或分号隔开,下面的两个脚本都
是合法的:
set a 1 |
TCL
解释器对一个命令的求值过程分为两部分:分析和执行。在分析阶段,TCL
解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换(substitution); 在执行阶段,TCL
解释器会把第
一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。
置换(substitution)
TCL
解释器在分析命令时,把所有的命令参数都当作字符串看待,例如:
%set x 10 //定义变量x,并把x的值赋为10 |
上例的第二个命令中,x被看作字符串x+100的一部分,如果我们想使用x的值’10’ ,就必须告诉TCL
解释器:我们在这里期望的是变量x的值,而非字符’x’。怎么告诉TCL
解释器呢,这就要用到TCL
语言中提供的置换功能。置换功能分为三种.TCL
提供三种形式的置换:变量置换、命令置换和反斜杠置换。每种置换都会导致一个或多个单词本身被其他的值所代替。置换可以发生在包括命令名在内的每一个单词中,而且置换可以嵌套。
graph LR A[置换功能] --> B[变量置换variable subtitution] A[置换功能] --> C[命令置换command substitution] A -->D[反斜杠置换backslash substitution]
变量置换variable subtitution
变量置换由一个$
符号标记,变量置换会导致变量的值插入一个单词中。例如之前的一个例子
%set x 10 //定义变量x,并把x的值赋为10 |
命令置换command substitution
命令置换是由[]
括起来的TCL
命令及其参数,命令置换会导致某一个命令的所有或部分单词被另一个命令的结果所代替。例如:
%set y [expr $x+100] |
这里当TCL
解释器遇到字符’[‘时,它就会把随后的expr作为一个命令名,从而激活与expr
对应的C/C++过程,并把expr
和变量置换后得到的10+100
传递给该命令过程进行处理。
反斜杠置换backslash substitution
TCL
语言中的反斜杠置换类似于C语言中反斜杠的用法,主要用于在单词符号中插入诸如换行符、空格、[、$等被TCL
解释器当作特殊符号对待的字符。
%set msg money\ \$3333\ \nArray\ a\[2] |
双引号和花括号
除了使用反斜杠外,TCL
提供另外两种方法来使得解释器把分隔符和置换符等特殊字符当作普通字符,而不作特殊处理,这就要使用双引号和花括号({}
)。TCL
解释器对双引号中的各种分隔符将不作处理,但是对换行符 及$
和[]
两种置换符会照常处理。而在花括号中,所有特殊字符都将成为普通字符,失去其特殊意义,TCL
解释器不会对其作特殊处理。
%set y "$x ddd" |
注释
TCL
中的注释符是#
,#
和直到所在行结尾的所有字符都被TCL
看作注释,TCL
解释器对注释将不作任何处理。不过,要注意的是,#
必须出现在TCL
解释器期望命令的第一个字符出现的地方,才被当作注释。
%set a 100 # Not a comment |
变量
变量分为简单变量和数组
简单变量
一个 TCL
的简单变量包含两个部分:名字和值。名字和值都可以是任意字符串。
% set a 2 |
在最后一个命令行,我们希望把变量a.1的值付给b,但是TCL
解释器在分析时只把$符号之后直到第一个不是字母、数字或下划线的字符(这里是’.’)之间的单词符号(这里是’a’)当作要被置换的变量的名字,所以TCL
解释器把a置换成2,然后把字符串“2.1”付给变量b。这显然与我们的初衷不同。
当然,如果变量名中有不是字母、数字或下划线的字符,又要用置换,可以用花括号把变量名括起来。例如:
%set b ${a.1} |
数组
数组是一些元素的集合。TCL
的数组和普通计算机语言中的数组有很大的区别。在TCL
中,不能单独声明一个数组,数组只能和数组元素一起声明。数组中,数组元素的名字包含两部分:数组名和数组中元素的名字,TCL
中数组元素的名字(下标〕可以为任何字符串。 例如:
set day(monday) 1 |
数组元素的置换和简单变量类似。例:
set a monday |
其他命令
unset
% unset a b day(monday) |
上面的语句中删除了变量a、b和数组元素day(monday),但是数组day并没有删除,其他元素还存在,要删除整个数组,只需给出数组的名字。
append和incr
这两个命令提供了改变变量的值的简单手段。append
命令把文本加到一个变量的后面,例如:
% set txt hello |
incr
命令把一个变量值加上一个整数。incr要求变量原来的值和新加的值都必须是整数。
expr
可以进行基本的数学函数计算
%expr 1 + 2*3 |
List
list这个概念在TCL
中是用来表示集合的。TCL
中list是由一堆元素组成的有序集合,list可以嵌套定
义,list每个元素可以是任意字符串,也可以是list。下面都是TCL
中的合法的list:
{} //空list |
list是TCL
中比较重要的一种数据结构,对于编写复杂的脚本有很大的帮助
list
语法: list ? value value…?
这个命令生成一个list,list的元素就是所有的value。例: |
使用置换将其相结合
% set a {1 2 3 4 {1 2}} |
concat
语法:concat list ?list…?
这个命令把多个list合成一个list,每个list变成新list的一个元素。
% set a {1 2 3} |
lindex
语法:lindex list index
返回list的第index个(0-based)元素。例:
% lindex {1 2 {3 4}} 2 |
llength
语法:llength list
返回list的元素个数。例
% llength {1 2 {3 4}} |
% set a {1 2 3} |
linsert
语法:linsert list index value ?value…?
返回一个新串,新串是把所有的value参数值插入list的第index个(0-based)元素之前得到。例:
% linsert {1 2 {3 4}} 1 7 8 {9 10} |
% set a {1 2 3} |
lreplace
语法:lreplace list first last ?value value …?
返回一个新串,新串是把list的第firs (0-based)t到第last 个(0-based)元素用所有的value参数替换得到的。如果没有value参数,就表示删除第first到第last个元素。例:
% lreplace {1 7 8 {9 10} 2 {3 4}} 3 3 |
% set a {1 2 3} |
lrange
语法:lrange list first last
返回list的第first (0-based)到第last (0-based)元素组成的串,如果last的值是end。就是从第first个直到串的最后。
例:
% lrange {1 7 8 2 4 5 6} 3 end |
% set a {1 2 3} |
lappend
语法:lappend varname value ?value…?
把每个value的值作为一个元素附加到变量varname后面,并返回变量的新值,如果varname不存在,就生成这个变量。例:
% set a {1 2 3} |
lsearch
语法:lsearch ?-exact? ?-glob? ?-regexp? list pattern
返回list中第一个匹配模式pattern的元素的索引,如果找不到匹配就返回-1。-exact、-glob、 -regexp是三种模式匹配的技术。-exact表示精确匹配;-glob的匹配方式和string match命令的匹配方式相同;-regexp表示正规表达式匹配。缺省时使用-glob匹配。例:
% set a { how are you } |
-all 返回一个列表,返回的列表中的数值就是字符在列表中的位置
默认全局匹配,返回第一个字符在列表中的位置,其位缺省状态
% lsearch {a b c d e} c |
匹配不到返回-1
% lsearch {a b c d e} g |
更详细的点击 查看。
控制流
这里有之后学习的更加详细的笔记,主要是对于所有的控制流,包括 if、while、for、foreach、switch、break、continue 等以及过程,source的介绍总结
TCL脚本语言的学习(二)更为详细!!
if
语法: if test1 body1 ?elseif test2 body2 elseif…. ? ?else bodyn?TCL
先把test1当作一个表达式求值,如果值非0,则把body1当作一个脚本执行并返回所得值,否则把test2当作一个表达式求值,如果值非0,则把body2当作一个脚本执行并返回所得值……。例如:
if { $x>0 } { |
if { $x<0 } { |
循环命令:while 、for 、 foreach
while
语法为: while test body
参数test是一个表达式,body是一个脚本,如果表达式的值非0,就运行脚本,直到表达式为0才停止循环,此时while命令中断并返回一个空字符串。
例如:假设变量 a 是一个链表,下面的脚本把a 的值复制到b:
% #首先生成一个集合 |
for
语法为: for init test reinit body
参数init是一个初始化脚本,第二个参数test是一个表达式,用来决定循环什么时候中断,第三个参数reinit是一个重新初始化的脚本,第四个参数body也是脚本,代表循环体。下例与上例作用相同:(注意这里复制打印顺序的不同)
% set a {1 2 3 4} |
例
% for {set i 0} {$i<4} {incr i} { |
foreach
这个命令有两种语法形式
1, foreach varName list body
第一个参数varName是一个变量,第二个参数list 是一个表(有序集合),第三个参数body是循环体。每次取得链表的一个元素,都会执行循环体一次。 下例与上例作用相同:
% set a {1 2 3 4} |
例子:
% foreach var {a b c d e f} { |
2, foreach varlist1 list1 ?varlist2 list2 ...? Body
这种形式包含了第一种形式。第一个参数varlist1是一个循环变量列表,第二个参数是一个列表list1,varlist1中的变量会分别取list1中的值。body参数是循环体。 ?varlist2 list2 …?表示可以有多个变量列表和列表对出现。例如:
set x {} |
例子:
% foreach i {a b c} j {d e f g} { |
这时总共有三次循环,x的值为”b a d c f e”。
set x {} |
这时总共有四次循环, x的值为”a d b e c f {} g” 。
set x {} |
这时总共有三次循环,x的值为”a d e b f g c {} {}”。
例子: