Tcl脚本初步学习

1.命令

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

命令

命令名

参数

set a 15

set

a15

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

26


有些命令是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里没有专门的变量定义,变量的外在表现形式为$替换操作,内在表现形式为对象。

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

set 123 abc

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

set abc 123

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

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

set aabc\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定义了一个对象的类型,这些类型有stringintbytearray等等,默认的是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);//把数组关联到对象里
}

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

5. binary命令

之前自己对binary scanbinary format2个命令存在疑惑,有了上面这些基础总算完全明白这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类型。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值