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类型。
  • 9
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
## 1 自定义命令 (1)编写自定义命令 > 1 编写自定义命令内容 > 2 注册指定命令 ```tcl /* *set up numbers sort command */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <tcl.h> // numbers sort int NumSort(ClientData ClientData, Tcl_Interp *Interp, int objc, Tcl_Obj *const objv[]) { double arr[objc], tmp; char *pstr, *pstr2; char buf[100]; int cnt = 1, cnt2 = 0, i = 0; //1. string convert number,numbers sort for(cnt = 1; cnt < objc; ++cnt) { //1.1 string convert number tmp = atof(Tcl_GetString(objv[cnt])); //1.2 numbers sort if(cnt == 1) arr[0] = tmp; else { for(cnt2 = cnt-1; cnt2 > 0; --cnt2) { if(tmp >= arr[cnt2 -1]) { arr[cnt2] = tmp; break; } else arr[cnt2] = arr[cnt2 -1]; } } } //2. numbers convert string and return for(cnt2 = 0; cnt2 < objc -1;++cnt2) { Tcl_AppendResult(Interp,gcvt(arr[cnt2], sizeof(arr[cnt2]), buf), " ",NULL); } return 0; } int Numsort_Init(Tcl_Interp *Interp) { //login command Tcl_CreateObjCommand (Interp, "numsort", NumSort, 0, 0); return TCL_OK; } ``` > 注解: (1)初始化函数Init的名字必须是文件名首字母大写+"_Init",上文c文件名是numsort.c, 故初始化函数名为Numsort_Init; ## 2 编译生成动态库 (1) 格式: gcc -fPIC -shared ____.c -o lib____.so ``` $ gcc -fPIC -shared numsort.c -o libnumsort.so ``` > 注解: (1) ____.c 代表要进行编译的C文件名 (2)lib___是lib+C文件名,生成动态库的库名为lib__.so ## 3 加载动态库 (1) 格式: load libname ```tcl % load libnumsort.so ``` ## 4 调用自定义命令 (1) commondname args ```tcl % numsort 1 1.1 2 2.2 22 3.3 90 2.5 11.11 1 1.1 2 2.2 2.5 3.3 11.11 22 90 ``` ## 1 自定义命令 (1)编写自定义命令 > 1 编写自定义命令内容 > 2 注册指定命令 ```tcl /* *set up numbers sort command */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <tcl.h> // numbers sort int NumSort(ClientData ClientData, Tcl_Interp *Interp, int objc, Tcl_Obj *const objv[]) { double arr[objc], tmp; char *pstr, *pstr2; char buf[100]; int cnt = 1, cnt2 = 0, i = 0; //1. string convert number,numbers sort for(cnt = 1; cnt < objc; ++cnt) { //1.1 string convert number tmp = atof(Tcl_GetString(objv[cnt])); //1.2 numbers sort if(cnt == 1) arr[0] = tmp; else { for(cnt2 = cnt-1; cnt2 > 0; --cnt2) { if(tmp >= arr[cnt2 -1]) { arr[cnt2] = tmp; break; } else arr[cnt2] = arr[cnt2 -1]; } } } //2. numbers convert string and return for(cnt2 = 0; cnt2 < objc -1;++cnt2) { Tcl_AppendResult(Interp,gcvt(arr[cnt2], sizeof(arr[cnt2]), buf), " ",NULL); } return 0; } int Numsort_Init(Tcl_Interp *Interp) { //login command Tcl_CreateObjCommand (Interp, "numsort", NumSort, 0, 0); return TCL_OK; } ``` > 注解: (1)初始化函数Init的名字必须是文件名首字母大写+"_Init",上文c文件名是numsort.c, 故初始化函数名为Numsort_Init; ## 2 编译生成动态库 (1) 格式: gcc -fPIC -shared ____.c -o lib____.so ``` $ gcc -fPIC -shared numsort.c -o libnumsort.so ``` > 注解: (1) ____.c 代表要进行编译的C文件名 (2)lib___是lib+C文件名,生成动态库的库名为lib__.so ## 3 加载动态库 (1) 格式: load libname ```tcl % load libnumsort.so ``` ## 4 调用自定义命令 (1) commondname args ```tcl % numsort 1 1.1 2 2.2 22 3.3 90 2.5 11.11 1 1.1 2 2.2 2.5 3.3 11.11 22 90 ```
Vivado是一款由Xilinx公司开发的综合布局工具,它可以用于FPGA的设计和开发。TCL(Tool Command Language)是一种脚本语言,可以用于编写Vivado的脚本文件。 Vivado TCL脚本可以用来自动化常见的Vivado任务,简化项目的构建过程。使用TCL脚本可以消除手动执行繁琐的Vivado命令的需要,提高开发效率。TCL脚本可以实现一系列操作,如创建工程、添加IP核、设置约束、合成、实现、生成比特流等。通过编写TCL脚本,可以将这些步骤一次性执行,大大减少了错误和重复的劳动。 Vivado TCL脚本使用起来非常简单。首先,在Vivado中创建一个新的TCL脚本文件。然后,在脚本中编写Vivado命令,每个命令占一行。例如,我们可以使用以下命令创建一个新的工程: create_project my_project ./my_project 然后,我们可以使用以下命令设置约束: set_property -name {TIME_PERIOD} -value {10} [get_pins {clk}] set_property -name {CLOCK_DELAY} -value {2} [get_pins {clk}] 最后,我们可以使用以下命令执行合成和实现: synth_design -top {my_design} place_design route_design 当我们需要运行TCL脚本时,只需在Vivado的TCL控制台中输入以下命令: source ./my_script.tcl Vivado将自动执行脚本中的命令,并根据脚本的内容进行操作。 总的来说,Vivado TCL脚本提供了一种高效便捷的方法来自动化Vivado项目的构建过程。通过编写和执行脚本,我们可以简化开发流程,提高开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值