TCL培训教程全.docx
《TCL培训教程全.docx》由会员分享,可在线阅读,更多相关《TCL培训教程全.docx(104页珍藏版)》请在冰豆网上搜索。
TCL培训教程全
Tcl编程简介
(一)
简介
Tcl是一种很通用的脚本语言,它几乎在所有的平台上都可以解释运行,功能强大。
是toolcommandlanguage的缩写,发音为"tickle”,实际上包含了两个部分:
一个语言和一个库。
首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。
它有一个简单的语法和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。
其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充(定义新的过程)的库函数。
应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读取(按钮或菜单等)。
但Tcl库收到命令后将它分解并执行内建的命令,经常会产生递归的调用。
下面简单介绍以下tcl的语法规则:
解释器
在Tcl的数据结构中的核心是Tcl_Interp.一个解释器包含了一套命令,一组变量和一些用于描述状态的东西。
每一个Tcl命令是在特定的Tcl_Interp中运行的,基于Tcl的应用程序可以同时拥有几个Tcl_Interp。
Tcl_Interp是一个轻量级的结构,可以快速的新建和删除。
数据类型
Tcl只支持一种数据结构:
字符串(string)。
所有的命令,命令的所有的参数,命令的结果,所有的变量都是字符串。
请牢记这一点,所有的东西都是字符串。
这是它比较有特点的方面字符串有三种形式:
命令(command),表达式(expresion)和表(list)。
BasicCommandSyntax基本语法
Tcl有类似于shell和lisp的语法,当然也有许多的不同。
一条Tcl的命令串包含了一条或多条命令用换行符或分号来隔开,而每一条命令包含了一个域(field)的集合,域使用空白分开的,第一个域是一个命令的名字,其它的是作为参数来传给它。
例如:
seta22//相当于C中的a=22a是一个变量这条命令分为三个域:
1set2a322set使用于设置变量的值的命令,a、20作为参数来传给它,a使它要操作的变量名,22是要付给的a值。
Tcl的命令名可以是内置的命令也可以是用户建的新命令,如果是用户用户建的新命令应用程序中用函数Tcl_CreateCommand来创建。
所有的参数作为字符串来传递,命令自己会按其所需来解释的参数的。
命令的名字必须被打全,但Tcl解释器找不到一同名的命令时会用unknown命令来代替。
在很多场合下,unknown会在库目录中搜寻,找到一个的话,会自动生成一个Tcl命令并调用它。
unknown经常完成缩略的命令名的执行。
但最好不要使用。
注释
和shell很象,第一个字母是"#"的Tcl字符串是注释。
其他细节规则
Groupingargumentswithdouble-quotes用双引号来集群参数,目的在于使用有空白的参数。
例如:
seta"thisstringcontainswhitespace"
如够一个参数一双引号来开始,该参数会一直到下一个双引号才结束。
其中可以有换行符和分号。
Variablesubstitutionwith$用美元符进行变量替换说白了就是引用该变量。
如:
setahello
setb$a//b="hello"实际上传给set命令的参数
//是b,"hello"
setca//b="a"
Commandsubstitutionwithbrackets命令子替换(用方括号)
例如:
seta[setb"hello"]
实现执行setb"hello"并用其结果来替换源命令中的方括号部分,产生一条新命令
seta"hello"//"hello"为setb"hello"的返回值
最终的结果是b="hello"a="hello"
当命令的一个子域以方括号开始以方括号结束,表示要进行一个命令子替换。
并执行该子命令,用其结果来替换原命令中的方括号部分。
方括号中的部分都被视为Tcl命令。
如下一个复杂一点的例子:
setaxyz[setb"abc"].[setc"def"]
//returnxyzabcdef
Backslashsubstitution转移符替换
转移符时间不可打印字符或由它数意义的字符插入进来。
这一概念与C语言中的一样。
Backspace(0x8).
fFormfeed(0xc).
Newline(0xa).
Carriage-return(0xd).
Tab(0x9).
vVerticaltab(0xb).
{Leftbrace(`{").
}Rightbrace(`}").
[Openbracket(`[").
]Closebracket(`]").
$Dollarsign(`$").
spSpace(`"):
doesnotterminateargument.
;Semicolon:
doesnotterminatecommand.
"Double-quote.
Groupingargumentswithbraces用花扩括号来集群参数
用花扩括号来集群参数与用双引号来集群参数的区别在于:
用花扩括号来集群参数其中的三种上述的子替换不被执行。
而且可以嵌套。
例如:
seta{xyza{bcd}}//set收到俩个参数a"xyza{bcd}"
eval{
seta22
setb33
}//eval收到一个参数"seta22
setb33"
命令综述
1.一个命令就是一个字符串(string)。
2.命令是用换行符或分号来分隔的。
3.一个命令由许多的域组成。
第一个于是命令名,其它的域作为参数来传递。
4.域通常是有空白(Tab横向制表健Space空格)来分开的。
5.双引号可以使一个参数包括换行符或分号。
三种子替换仍然发生。
6.花括号类似于双引号,只是不进行三总体换。
7.系统只进行一层子替换,机制替换的结果不会再去做子替换。
而且子替换可以在任何一个域进行。
8.如果第一个非控字符是`#",这一行的所有东西都是注释。
表达式
对字符串的一种解释是表达式。
几个命令将其参数按表达式处理,如:
expr、for和if,并调用Tcl表达式处理器(Tcl_ExprLong,Tcl_ExprBoolean等)来处理它们。
其中的运算符与C语言的很相似。
逻辑非
*/%+-
<<>>
左移右移只能用于整数。
<><=>===!
=
逻辑比较
&^|
位运算和异或或
&&''
逻辑"和""或"
x?
y:
z
If-then-else与C的一样
Tcl中的逻辑真为1,逻辑假为0。
一些例子:
5/4.0
5/([stringlength"abcd"]+0.0)
计算字符串的长度转化为浮点数来计算
"0x03">"2"
"0y"<"0x12"
都返回1
seta1
expr$a+2
expr1+2
都返回3
窗体底端
窗体顶端
TCL语言
Tcl(最早称为“工具命令语言”"ToolCommandLanguage",但是目前已经不是这个含义,不过我们仍然称呼它为TCL)是一种脚本语言。
由JohnOusterhout创建。
TCL很好学,功能很强大。
TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。
TCL念作“踢叩”"tickle".Tcl的特性包括:
*任何东西都是一条命令,包括语法结构(for,if等)。
*任何事物都可以重新定义和重载。
*所有的数据类型都可以看作字符串。
*语法规则相当简单
*提供事件驱动给Socket和文件。
基于时间或者用户定义的事件也可以。
*动态的域定义。
*很容易用C,C++,或者Java扩展。
*解释语言,代码能够动态的改变。
*完全的Unicode支持。
*平台无关。
Win32,UNIX,Mac上都可以跑。
*和Windows的GUI紧密集成。
Tk
*代码紧凑,易于维护。
TCL本身不提供面向对象的支持。
但是语言本身很容易扩展到支持面向对象。
许多C语言扩展都提供面向对象能力,包括XOTcl,IncrTcl等。
另外SNIT扩展本身就是用TCL写的。
使用最广泛的TCL扩展是TK。
TK提供了各种OS平台下的图形用户界面GUI。
连强大的Python语言都不单独提供自己的GUI,而是提供接口适配到TK上。
另一个流行的扩展包是Expect.Expect提供了通过终端自动执行命令的能力,例如(passwd,ftp,telnet等命令驱动的外壳).
下面是TCL程序的例子:
#!
/bin/sh
#nextlinerestartsusingtclshinpath\
exectclsh${1+"$@"}
#echoserverthatcanhandlemultiple
#simultaneousconnections.
procnewConnection{sockaddrport}{
#clientconnectionswillbehandledin
#line-buffered,non-blockingmode
fconfigure$sock-blockingno-bufferingline
#callhandleDatawhensocketisreadable
fileevent$sockreadable[listhandleData$sock]
}
prochandleData{
puts$sock[gets$sock]
if{[eof$sock]}{
close$sock
}
}
#handleallconnectionstoportgiven
#asargumentwhenserverwasinvoked
#bycallingnewConnection
setport[lindex$argv0]
socket-servernewConnection$port
#entertheeventloopbywaiting
#onadummyvariablethatisotherwise
#unused.
vwaitforever
另外一个TK的例子(来自AsimpleA/Dclock)它使用了定时器时间,3行就显示了一个时钟。
procevery{msbody}{eval$body;after$ms[infolevel0]}
pack[label.clock-textvartime]
every1000{set:
:
time[clockformat[clocksec]-format%H:
%M:
%S]};#RS
解释:
第一行定义了过程every,每隔ms毫秒,就重新执行body代码。
第二行创建了标签起内容由time变量决定。
第3行中设置定时器,time变量从当前时间中每秒更新一次。
Tcl被广泛的用做script语言,大多数情况下,Tcl和Tk(“ToolKit”)库同时使用,Tk是一系列令Tcl易于编写图形用户接口的命令和过程
Tcl的一个重要特性是它的扩展性。
如果一个程序需要使用某些标准Tcl没有提供的功能,可以使用c语言创造一些新的Tcl命令,并很容易的融合进去。
正是由于Tcl易于扩展,很多人为它编写了扩展包,并在网上共享。
Tcl和其他编程语言例如c不同,它是一种解释语言而非编译语言。
Tcl程序由一系列Tcl命令组成,在运行时由Tcl解释器解释运行。
解释运行的一个优点是它可以自己为自己生成Tclscript。
变量和变量交换
不像c,Tcl的变量在使用前不需要声明。
Tcl的变量在它首次被赋值时产生,使用set命令。
变量可以用unset命令删除,虽然并不强制需要这样做。
变量的值通过$符号访问,也叫变量交换。
Tcl是一个典型的”弱类型定义”语言,这意味者任何类型可以存储在任何变量中。
例如,同一个变量可以存储数字,日期,字符串甚至另一段Tclscript.
Example1.1:
setfoo"john"
puts"Himynameis$foo"
Output:
Himynameisjohn
Example1.2:
setmonth2
setday3
setyear97
setdate"$month:
$day:
$year"
puts$date
Output:
2:
3:
97
Example1.3:
setfoo"putshi"
eval$foo
Output:
hi
在这个例子里,变量foo存储了另外一段Tclscript.
表达式
包括数学表达式,关系表达式,通常用expr命令。
Example2.1:
expr0==1
Output:
0
Example2.2:
expr1==1
Output:
1
两数比较,true则输出1,false输出0
Example2.3:
expr4+5
Output:
9
Example2.4:
exprsin
(2)
Output:
0.909297
命令传递
以运算结果替代Tcl命令中的部分
Example3.1:
puts"Iam[expr10*2]yearsold,andmyI.Q.is[expr100-25]"
Output:
Iam20yearsold,andmyI.Q.is75
方括号是命令传递的标志
Example3.2:
setmy_height6.0
puts"IfIwas2inchestaller,Iwouldbe[expr$my_height+(2.0/12.0)]feettall"
Output:
IfIwas2inchestaller,Iwouldbe6.16667feettall
命令流控制
Tcl有判断流转(if-else;switch)和循环控制(while;for;foreach)
Example4.1:
setmy_planet"earth"
if{$my_planet=="earth"}{
puts"Ifeelrightathome."
}elseif{$my_planet=="venus"}{
puts"Thisisnotmyhome."
}else{
puts"IamneitherfromEarth,norfromVenus."
}
settemp95
if{$temp<80}{
puts"It'salittlechilly."
}else{
puts"Warmenoughforme."
}
Output:
Ifeelrightathome.
Warmenoughforme.
Example4.2:
setnum_legs4
switch$num_legs{
2{puts"Itcouldbeahuman."}
4{puts"Itcouldbeacow."}
6{puts"Itcouldbeanant."}
8{puts"Itcouldbeaspider."}
default{puts"Itcouldbeanything."}
}
Output:
Itcouldbeacow.
Example4.3:
for{seti0}{$i<10}{incri1}{
puts"Intheforloop,andi==$i"
}
Output:
Intheforloop,andi==0
Intheforloop,andi==1
Intheforloop,andi==2
Intheforloop,andi==3
Intheforloop,andi==4
Intheforloop,andi==5
Intheforloop,andi==6
Intheforloop,andi==7
Intheforloop,andi==8
Intheforloop,andi==9
Example4.4:
seti0
while{$i<10}{
puts"Inthewhileloop,andi==$i"
incri1
}
Output:
Inthewhileloop,andi==0
Inthewhileloop,andi==1
Inthewhileloop,andi==2
Inthewhileloop,andi==3
Inthewhileloop,andi==4
Inthewhileloop,andi==5
Inthewhileloop,andi==6
Inthewhileloop,andi==7
Inthewhileloop,andi==8
Inthewhileloop,andi==9
Example4.5:
foreachvowel{aeiou}{
puts"$vowelisavowel"
}
Output:
aisavowel
eisavowel
iisavowel
oisavowel
uisavowel
Procedures
Tcl的Procedures和c的函数差不多.它们有参数,它们返回值。
基本定义方法是:
procnameargListbody
当一个procedure被定义,它就被看做是一个命令,如同Tcl的自带命令一样,通过名字来呼叫,名字后面跟上参数。
缺省的,procedure的返回值是它的最后一个命令结果。
但也可以通过return命令来返回其他值。
Return值可以在procedure的任何地方,一旦执行,procedure就此返回。
Example5.1:
procsum_proc{ab}{
return[expr$a+$b]
}
procmagnitude{
if{$num>0}{
return$num
}
setnum[expr$num*(-1)]
return$num
}
setnum112
setnum214
setsum[sum_proc$num1$num2]
puts"Thesumis$sum"
puts"Themagnitudeof3is[magnitude3]"
puts"Themagnitudeof-2is[magnitude-2]"
Output:
Thesumis26
Themagnitudeof3is3
Themagnitudeof-2is2
在procedure中可以通过set创造变量,但是变量只在procedure中有效,而且一旦procedure返回,这些变量就不可访问。
如果procedure需要访问主程序中的变量,就需要使用global关键字。
Example5.2:
procdumb_proc{}{
setmyvar4
puts"Thevalueofthelocalvariableis$myvar"
globalmyglobalvar
puts"Thevalueoftheglobalvariableis$myglobalvar"
}
setmyglobalvar79
dumb_proc
Output:
Thevalueofthelocalvariableis4
Thevalueoftheglobalvariableis79
Lists
Lists就好像是Tcl中的一种特殊的数组。
它把一堆东西放成一个集合,然后就像操作一个整体一样的操作它。
Example6.1:
setsimple_list"JohnJoeMarySusan"
puts[lindex$simple_list0]
puts[lindex$simple_list2]
Output:
John
Mary
注意list的index是从0开始的
Example6.2:
setsimple_list2"MikeSamHeatherJennifer"
setcompound_list[list$simple_list$simple_list2]
puts$compound_list
puts[llength$comp