您的位置:首页 > 其它

Tcl脚本初步学习

2018-03-09 20:37 183 查看


1.命令

Tcl是一门基于命令的脚本语言,每个命令通过换行符或分好隔开。每条命令都包含一个或多个单词,第一个单词是命令名,其他单词是命令的参数,如:

命令
命令名
参数
set a 15
set
a、15
proc power {base p} {
set result 1
while {$p > 0} {
set result [expr $result*$base]
set p [expr $p-1]
}
return $result
}
proc
power、{base p}、
{
set result 1
while {$p > 0} {
set result [expr $result*$base]
set p [expr $p-1]
}
return $result
}
set result [expr $result*$base]
 
set
result、 [expr $result*$base]
power 2 6
power
2、6
有些命令是Tcl语言内建的命令,由proc定义的过程也可以当做一个命令来用,用户还可以通过API来自定义命令,使用接口Tcl_CreateObjCommand()
在命令中,每个参数用空格隔开,要注意双引号、中括号和大括号里的内容整体作为一个参数。
在Tcl执行过程中,先解析命令,然后把参数作为这个命令的输入,执行命令时再由命令进一步解析参数。


2.替换

    Tcl解析时会把命令分解为单词,然后根据相应的规则对这些单词执行替换操作。Tcl提供了3种形式的替换:变量替换、命令替换和反斜杠替换。

 

符号

举例

替换

变量替换

$

set a 15

expr $a*2.2

把$a替换为15

命令替换

[]

set b [expr 13*13]

方括号内的单词必须构成有效的Tcl脚本,里面的内容会替换为执行脚本后的返回值

反斜杠替换

\

set a bbb\ \$aa\x31

把“\ ”“\$”“\x31”

替换成字符空格、$、1。空格和$有特殊意义,所有要使用该字符要进行替换,\x31是把ascii码替换为字符


3.引用

        Tcl提供了引用的方法,来阻止解释器对一些特殊字符做特殊处理。引用的方法有2种,分别是双引号引用和大括号引用。

● 双引号引用

在双引号引用中,空格、制表符、换行以及分号都做普通字符处理,如:

set msg "Eggs: \$2.18/dozen

Gasoline: \$1.49/gallon"

此时输出为:

Eggs: $2.18/dozen

Gasoline: $1.49/gallon

这里面的空格和换行符做为普通字符处理,但是仍然执行替换操作。

● 大括号引用

大括号提供了更彻底的引用形式,它会取消其中所有特殊字符的特殊意义。在大括号里的所有内容都表现为最原始的字符串,不会有任何替换,如:

set a 15

set b {$a}

此时第二行输出是$a而不是15


4.对象


4.1对象的定义

Tcl里没有专门的变量定义,变量的外在表现形式为
e7c4
$替换操作,内在表现形式为对象。

由set命令来定义一个对象,在Tcl里所有的对象都当作字符串来处理,以下举一些例子来理解Tcl中的对象:

set 123 abc

这里123是一个对象,它的值是abc

set abc 123

这里abc是一个对象,它的值是字符串“123”,不是数字123

特别要指出的是Tcl里的字符串一般都是指的是普通字符串(以\0结尾的),但是有时候还可以是二进制字符串,如

set a“abc\000123”,它的值是abc
123而不是abc

虽然所有的对象都是基于字符串,但是当把对象作为参数传给命令时,命令可以对其做出其他解释,比如

set a 111

set b 222

expr $a+$b

这里expr命令把对象a和对象b被解释为了数字。

命令执行后会返回一个对象

set c [expr $a+$b]

这里expr $a+$执行完后返回一个对象,这个对象的值是333,并把对象c的值设为333


4.1对象的结构

对象的结构体定义如下

typedef struct Tcl_Obj {
int refCount;		/* When 0 the object will be freed. */
char *bytes;		/* This points to the first byte of the
* object's string representation. The array
* must be followed by a null byte (i.e., at
* offset length) but may also contain
* embedded null characters. The array's
* storage is allocated by ckalloc. NULL means
* the string rep is invalid and must be
* regenerated from the internal rep.  Clients
* should use Tcl_GetStringFromObj or
* Tcl_GetString to get a pointer to the byte
* array as a readonly value. */
int length;			/* The number of bytes at *bytes, not
* including the terminating null. */
const Tcl_ObjType *typePtr;	/* Denotes the object's type. Always
* corresponds to the type of the object's
* internal rep. NULL indicates the object has
* no internal rep (has no type). */
union {			/* The internal representation: */
long longValue;		/*   - an long integer value. */
double doubleValue;	/*   - a double-precision floating value. */
void *otherValuePtr;	/*   - another, type-specific value. */
Tcl_WideInt wideValue;	/*   - a long long value. */
struct {		/*   - internal rep as two pointers. */
void *ptr1;
void *ptr2;
} twoPtrValue;
struct {		/*   - internal rep as a pointer and a long,
*     the main use of which is a bignum's
*     tightly packed fields, where the alloc,
*     used and signum flags are packed into a
*     single word with everything else hung
*     off the pointer. */
void *ptr;
unsigned long value;
} ptrAndLongRep;
} internalRep;
} Tcl_Obj;


成员bytes是一个char*指针,用来存储字符串,length表示bytes存储的字符串的长度。

成员const Tcl_ObjType *typePtr定义了一个对象的类型,这些类型有string、int、bytearray等等,默认的是tclEmptyString类型,即为null,当作二进制字符串处理。因为一个对象有不同的类型,这就解释了为什么对象是字符串,却可以被解释为数字或数组。

假如定义一个对象Tcl_Obj *objPtr,对象被解释为数组,那么由Tcl_SetByteArrayObj()函数可以设置这个对象的数组长度,并把传入数组的内容复制到这个对象的数组里,代码如下

#define SET_BYTEARRAY(objPtr, baPtr) \
(objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (baPtr)

void
Tcl_SetByteArrayObj(
Tcl_Obj *objPtr,		/* Object to initialize as a ByteArray. */
const unsigned char *bytes,	/* The array of bytes to use as the new
value. May be NULL even if length > 0. */
int length)			/* Length of the array of bytes, which must
be >= 0. */
{
ByteArray *byteArrayPtr;

if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetByteArrayObj");
}
TclFreeIntRep(objPtr);
TclInvalidateStringRep(objPtr);

if (length < 0) {
length = 0;
}
byteArrayPtr = ckalloc(BYTEARRAY_SIZE(length));
byteArrayPtr->used = length;//设置数组的长度
byteArrayPtr->allocated = length;

if ((bytes != NULL) && (length > 0)) {
memcpy(byteArrayPtr->bytes, bytes, (size_t) length);//复制二进制字符串的内容
}
objPtr->typePtr = &properByteArrayType;
SET_BYTEARRAY(objPtr, byteArrayPtr);//把数组关联到对象里
}


在通过Tcl的API自定义命令时,可以通过Tcl_SetObjResult()来设置返回的对象。


5. binary命令

之前自己对binary scan和binary
format这2个命令存在疑惑,有了上面这些基础总算完全明白这2个命令了。


5.1 binary format

binary format命令是把参数按照一定格式转换为二进制字符串,并返回二进制字符串,格式类型可以查看官方的说明文档,使用如下

binary formatformatString ?arg arg ...?

举例:

binary format a7a*a alpha bravo charlie

返回二进制字符串alpha\000\000bravoc

其中a代表的类型为unicode码,7代表第一个参数要转换的个数,而alpha中只有5个字符,不足的补0。第二个参数转换的类型为a*表示全部字符都转换。第3个参数类型为a,没有指定要转换的个数,那么默认只转第1个字符。

binary format i3 {3 -3 65536 1}

返回\x03\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x01\x00

其中类型是小端的32位有符号整数,指定为第一个参数的前3个数字。


5.2 binary scan

与binary format相反,binary
scan是把一个二进制字符串按一定的格式输出到指定的变量,并返回设置的变量的个数,使用如下

binary scanstring formatString ?varName varName ...?

举例:
set str \x05\x00\x00\x00\x07\x00\x00\x00\xf0\xff\xff\xff

   binary scan $str i2i* var1 var2

   返回2,var1的值是57,var2的值是-16

   binary scan abcde\000fghi a6a10 var1 var2

  返回1,var1的值是abcde\000,由于字符个数不够,并没有设置var2


5.3使用的对象

  binary format命令返回一个二进制字符串对象,这个对象的类型是什么呢,binary scan使用的二进制字符串对象的类型又是什么呢?
  经过调试,objPtr->typePtr的类型既不为string类型也不为空,而是bytearray,即对象实际上是一个数组,这数组里存放着二进制字符串,数组的长度指定二进制字符串的长度。
  一般定义一个简单的对象,如
  set a 123    
  对象a的类型是空即tclEmptyString类型,默认是一个字符串,当a被expr命令调用时,a的类型会被转换为int,被binary scan命令调用时,a会被转换为bytearray类型而不是string类型。



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: