当前位置:   article > 正文

学习 TCL 语言流程控制这一篇就够了_tcl for循环

tcl for循环

导读:写博客是为了检验自己对所学知识的掌握情况,同时把自己正在学的知识教给他人

目录

〇  引言

一  什么是流程控制

二  TCL 语言中的流程控制命令

2.1  TCL 中的条件判断命令:if 和 switch

2.2  TCL 中的循环命令:while 、 for 及 foreach

2.3  TCL 中的跳出循环命令:break 和 continue

三  有关花括号的几点注意事项

3.1  花括号与双引号的区别

3.2  注意事项一

3.3  注意事项二

四  总结

〇  引言

TCL 语言可谓是极其小众的脚本语言了,至于小众到什么程度呢,我们可以通过下面这个有趣的事情来看。当我们用搜索引擎搜索 TCL 时,你会发现展现在你面前的并不是 TCL 脚本语言相关的搜索结果,而是一家名称为 “ TCL 科技集团股份有限公司 ” 相关的产品信息。

好家伙,还是一家主营业务是半导体的公司!这电视也不便宜啊!

于是去公司的招聘公众号看了下,还真招收电子类的博士做 FPGA 和 IP 设计。

这么看这 TCL 公司和 TCL 语言还真有点缘分哈!

好了,我们言归正传!今天要讨论的 TCL ,并不是上述讲的做电视机的,此 TCL 非彼 TCL 。TCL(Tool Command Language)是一种脚本语言。目前 TCL 语言主要广泛应用于 EDA  即电子设计自动化工具中,帮助开发人员快速实现自动化任务。例如,Cadence 公司的布局布线工具 Innovus、Synopsys 公司的逻辑综合工具 Design Compiler、Xilinx 公司的设计工具 Vivado 。当然,比如 OpenSees 这类有限元分析软件 是基于 TCL 环境开发的,所以也可以使用 TCL 对其进行二次开发。虽说 TCL 能做的远不止这些,但是由于万能的 Python 的存在,且市面上 Python 的教程更加丰富,所以一些能用 Python 去实现的大家都不会去学习一些比较冷门的语言去代替。因此,大家学习 TCL 都是有特定的需求才学的,就像笔者一样,掌握 TCL 是工作中必须的技能之一,但是奈何,目前 TCL 相关的教程并不算丰富。为了帮助大家更好的学习并掌握 TCL 脚本语言,下面列出了几个学习 TCL 的资源。

  1. 官方文档:TCL 的官方文档是学习 TCL 语言的最佳资源之一。可以在 TCL 官方网站上找到完整的文档和教程,包括语法基础、控制结构、函数和库等方面的内容。链接如下:https://www.tcl.tk/doc/
  2. TCL Wiki:TCL Wiki 是一个由 TCL 社区维护的在线资源库,包含了大量的 TCL 代码示例、教程和文档。链接如下: https://wiki.tcl-lang.org/
  3. 相关中文书籍

一  什么是流程控制

一般情况下,程序的执行顺序是按照我们编写的语句的顺序依次执行的,但是有时候我们需要根据自己的需求,选择性的执行或重复执行某些语句,就需要用到流程控制命令。通过这些流程控制命令我们能够用简洁的代码实现一些较为复杂的逻辑功能,以及提高工作效率。和大多数脚本语言类似,TCL 也包含:条件判断语句 循环控制语句 。下面,会通过多个例子来解释每个命令的用法,并且会按照:【用途+语法规则+解释说明+脚本举例】 的顺序来阐述。

二  TCL 语言中的流程控制命令

2.1  TCL 中的条件判断命令:ifswitch

用途:

条件判断语句用于根据某个表达式的值,从若干个给定的语句中选择一个来执行。在 TCL 中条件判断命令包括 if 和 switch 。

if-elseif-else

语法规则:

  1. if {expr1} ?then? {
  2. body 1
  3. } elseif {expr2} ?then? {
  4. body 2
  5. } elseif {
  6. ...
  7. } else {
  8. body N
  9. }

语法解释:

  1. if 获取两个参数,第一个是条件判断参数也就是一个表达式,即语法规则中的 expr1 ,第二个参数是紧跟着条件后面的那个语句也就是一个 TCL 脚本,即 body 1 。其中 then 和 else 是可选参数,一般我们会保留 else,而去除 then 。
  2. if 命令还可以拥有多个 elseif 子句,每个子句都包括“ expr ”和 “ body ”这两个参数,最后还可接一个 else 子句,else 子句仅包括 “ body ”这一个参数,在前面表达式判定结果都为假时,才会执行该脚本。
  3. 此外,若表达式的内容为单独的 1 、yes 、true,则判定为真;若为 0 、no 、false 则判定为假。
数值非00
yes/noyesno
true/falsetruefalse

Example:

  1. # example_1
  2. set x -10
  3. if {$x<0} {
  4. set x 0
  5. }
  6. puts $x

输出结果:0


  1. # example_2
  2. set x 0
  3. if { $x < 0 } {
  4. puts "变量 x 的值为负"
  5. } elseif { $x > 0 } {
  6. puts "变量 x 的值为正"
  7. } else {
  8. puts "x 的值为 0"
  9. }

输出结果:x 的值为 0


  1. # example_3
  2. if { 1 && yes && true } {
  3. puts "Run tcl script"
  4. }

输出结果:Run tcl script


  1. # example_4
  2. if { 0 || no || false } {
  3. puts "Run tcl script"
  4. } else {
  5. puts "expr is false"
  6. }

输出结果:expr is false


说明:例 3 和 例 4 用到了逻辑操作符,&& 代表逻辑与 ; | | 代表逻辑或 。

switch

语法规则:

  1. switch ?option? string {
  2. pattern 1 {
  3. body 1
  4. }
  5. pattern 2 {
  6. body 2
  7. }
  8. ...
  9. pattern N {
  10. body N
  11. }
  12. default {
  13. body_default
  14. }
  15. }

语法解释:

  1. switch 命令用一个字符串与多个模式进行比较,执行能匹配的那个模式所关联的 TCL 脚本;其中 option 为模式匹配的方式,switch 支持三种匹配方式:-exact 、-glob 、-regexp 。TCL 解释器默认是 -exact 模式匹配方式。建议在待检测值之前使用 “ -- ” 以表示选项结束。
  2. switch 命令的效果可以通过 if 命令加上一连串的 elseif 达到,但是 switch 支持的表达式结构更加广泛。
  3. switch 命令的最后一个模式是 default ,它可以与任意值匹配,在其它模式均无法匹配时就执行 default 相关联的 TCL 脚本。
  4. 如果 switch 命令的某个脚本是 - ,那么 switch 会使用下一个模式的脚本。在多个模式对应相同的脚本时,这样会更加简洁。
  5. 在 switch 语句中,注释只能放在 Body 里面。  

Example:

  1. # 根据多边形的边数对其进行命名。
  2. # 在这个脚本中,我们使用了 switch 语句来检查多边形的边数,并根据其值设置多边形的名称。
  3. # 以下是代码示例:
  4. set num_edges 7
  5. switch $num_edges {
  6. 0 -
  7. 1 -
  8. 2 {
  9. set polygon_name "Not a polygon"
  10. }
  11. 3 {
  12. set polygon_name "Triangle"
  13. }
  14. 4 {
  15. set polygon_name "Quadrilateral"
  16. }
  17. 5 {
  18. set polygon_name "Pentagon"
  19. }
  20. 6 {
  21. set polygon_name "Hexagon"
  22. }
  23. default {
  24. set polygon_name "Polygon with $num_edges edges"
  25. }
  26. }
  27. puts $polygon_name
  28. # 在这个示例中,我们首先将变量 num_edges 设置为多边形的边数。然后,使用 switch 来检查 num_edges 的值。如果 num_edges 等于 0/1/2,将变量 polygon_name 设置为 Not a polygon 。如果 num_edges 等于 3,将变量 polygon_name 设置为 Triangle ,以此类推。如果 num_edges 不匹配任何一个 case,则执行 default 关联的TCL 脚本,将 polygon_name 设置为 Polygon with $numedges edges 。最后,我们使用 puts 命令打印 polygon_name 的值。

输出结果:Polygon with 7 edges

可以修改 num_edges 的值来测试不同边数的多边形。


下面三个例子说明了 TCL 解释器中花括号的行为。

  1. # example_1
  2. set fruit "apple"
  3. switch $fruit {
  4. "banana" {
  5. puts "This is a banana"
  6. }
  7. "apple" {
  8. puts "This is an apple"
  9. }
  10. "orange" {
  11. puts "This is an orange"
  12. }
  13. default {
  14. puts "I don't know what fruit this is"
  15. }
  16. }

输出结果:This is an apple

在这个例子中,变量 $fruit 没有被花括号包围,因此 TCL 在执行 switch 语句之前会替换变量的值。


如果我们将变量用花括号括起来,TCL 将不会替换变量的值,而是将其视为字面字符串。例如:

  1. # example_2
  2. set fruit "apple"
  3. switch {$fruit} {
  4. "banana" {
  5. puts "This is a banana"
  6. }
  7. "apple" {
  8. puts "This is an apple"
  9. }
  10. "orange" {
  11. puts "This is an orange"
  12. }
  13. default {
  14. puts "I don't know what fruit this is"
  15. }
  16. }

输出结果:I don't know what fruit this is

因为 TCL 将字符串 "{$fruit}" 视为字面字符串,而不是替换变量的值。


如果我们在将匹配模式中 "apple" 改为 $fruit 

  1. # example_3
  2. set fruit "apple"
  3. switch {$fruit} {
  4. "banana" {
  5. puts "This is a banana"
  6. }
  7. $fruit {
  8. puts "This is an apple"
  9. }
  10. "orange" {
  11. puts "This is an orange"
  12. }
  13. default {
  14. puts "I don't know what fruit this is"
  15. }
  16. }

输出结果: This is an apple,因为 $fruit 也是位于第二个大括号里面的。


总之,需要注意的是,这种行为在 TCL 中是一致的,而不是特定于 switch 语句。花括号用于防止 TCL 中的变量替换,这种行为在整个语言中是一致的。


  1. # 在 switch 中添加注释只能放在待执行的脚本中,如果放在模式匹配中会报错
  2. set variable 0
  3. switch $variable {
  4. 1 {
  5. # 如果 $variable 等于 1,则执行此代码块
  6. puts "Variable is equal to 1"
  7. }
  8. 2 {
  9. # 如果 $variable 等于 2,则执行此代码块
  10. puts "Variable is equal to 2"
  11. }
  12. default {
  13. # 如果 $variable 不等于 12,则执行此代码块
  14. puts "Variable is not equal to 1 or 2"
  15. }
  16. }

输出结果:Variable is not equal to 1 or 2


如果将注释放在模式匹配部分,则会报如下错误

  1. set variable 0
  2. switch $variable {
  3. # 如果 $variable 等于 1,则执行此代码块
  4. 1 {
  5. puts "Variable is equal to 1"
  6. }
  7. 2 {
  8. # 如果 $variable 等于 2,则执行此代码块
  9. puts "Variable is equal to 2"
  10. }
  11. default {
  12. # 如果 $variable 不等于 12,则执行此代码块
  13. puts "Variable is not equal to 1 or 2"
  14. }
  15. }

报错:

extra switch pattern with no body, this may be due to a comment incorrectly placed outside of a switch body - see the "switch" documentation

2.2  TCL 中的循环命令:while forforeach

用途:

循环命令是 TCL 语言中非常重要的控制结构,可以帮助简化代码并实现重复执行的功能。

while loop

语法规则:

  1. while {condition} {
  2. # 条件为真时执行的代码
  3. }

语法解释:

condition 是一个布尔表达式,在每次循环迭代之前进行评估,如果条件为真则执行循环内的代码,这个过程会一直持续,直至条件为假。

Example:

  1. # Example_1
  2. # 以下是一个 while 循环的示例,它打印从 15 的数字:
  3. set i 1
  4. while {$i<=5} {
  5. puts $i
  6. incr i
  7. # incr i 相当于 set i [expr {$i + 1}]
  8. }

输出结果:

1

2

3

4

5

在这个示例中,condition 是 $i <= 5,只要 i 小于或等于 5,它就为真。在循环内部,使用puts 命令打印 i 的值,然后使用 incr 命令递增 i 的值。

for loop

语法规则:

for start condition next body

语法解释:

  1. start 是循环前执行的语句
  2. condition 是循环条件
  3. next 是每次循环后执行的语句
  4. body 是循环体

Example:

  1. # Example_1
  2. # 以下是一个简单的例子,用 for 循环来打印 15
  3. for {set i 1} {$i <= 5} {incr i} {
  4. puts $i
  5. }

输出结果:

1

2

3

4

5

在这个例子中,我们使用了 set 命令来初始化变量 i,然后在 condition 中检查 i 是否小于或等于 5,如果是,则执行循环体中的代码,然后在 next 中使用 incr 命令递增 i 的值。 

foreach loop

语法规则:

  1. foreach varName list ?varName1 list1 ... ? {
  2. body
  3. }

语法解释:

其中,varName 是循环变量的名称,list 是要循环遍历的列表,body 是循环体。可以使用多个varName list 对来循环遍历多个列表。

Example:

  1. # Example_1
  2. # 以下是一个简单的代码案例,它使用foreach循环遍历一个列表并打印出每个元素
  3. set my_list {1 2 3 4 5}
  4. foreach item $my_list {
  5. puts $item
  6. }

输出结果:

1

2

3

4

5

在这个例子中,我们首先定义了一个名为 my_list 的列表。然后,使用 foreach 循环遍历这个列表,并将每个元素存储在变量 item 中。在循环的每次迭代中,使用 puts 命令打印出 item 的值。

2.3  TCL 中的跳出循环命令:breakcontinue

用途:

TCL 中有两个命令可以用于控制循环:break 和 continue 。

二者区别:

在 TCL 中,break 用于立即终止循环并继续执行循环后的下一条语句,而 continue 用于跳过当前循环迭代并继续执行下一次迭代。

  1. # Example_1
  2. # 以下是如何在TCL循环中使用break的示例:
  3. set i 0
  4. while {$i < 10} {
  5. incr i
  6. if {$i == 5} {
  7. break
  8. }
  9. puts $i
  10. }
  11. puts "Loop finished"

输出结果:

1

2

3

4

Loop finished

在这个例子中,循环将打印数字 1 到 4,然后在 i 等于 5 时跳出 while 循环。最后的 puts 语句将被执行,打印 Loop finished 。


  1. # Example_2
  2. # 以下是如何在TCL循环中使用continue的示例:
  3. set i 0
  4. while {$i < 10} {
  5. incr i
  6. if {$i == 5} {
  7. continue
  8. }
  9. puts $i
  10. }
  11. puts "Loop finished"

输出结果:

1

2

3

4

6

7

8

9

10

Loop finished


从输出结果,可以看出,continue 和 break 的区别,continue 是跳过当前循环,也就是说跳过了 puts $i 这个语句,直接进入下一个循环,而 break 是直接跳出 while 循环,直接进入循环后的语句。

三  有关花括号的几点注意事项

3.1  {...}  "..." 的区别

花括号用于定义文字字符串,这意味着花括号里面的内容被视为单个字符串,这与双引号不同,双引号允许变量替换和命令替换。

  1. set my_name TCL
  2. puts "Hello $my_name"
  3. puts {Hello $my_name}

输出结果:

Hello TCL

Hello $my_name

3.2  注意事项一

从上述各个循环语句的格式来看,可以发现: 用于条件判断的“布尔表达式”和待执行的 “ tcl脚本 ” 均放在花括号内部,目的是防止执行命令前发生替换,而导致控制结构进入死循环。

  1. # Example_1
  2. set a 10
  3. while {$a < 10000} {
  4. set a [expr {$a ** 2}]
  5. puts $a
  6. }

输出结果:

100

10000


  1. # Example_2
  2. set a 10
  3. while "$a < 10000" {
  4. set a [expr {$a ** 2}]
  5. puts $a
  6. }

输出结果:

100

10000

100000000

10000000000000000

100000000000000000000000000000000

 .......无限循环

下面的例子,只要 x 小于或等于 3,就会打印出 x 的值。如果 x 大于3,则使用 continue 语句跳过该次迭代。如果 x 大于 7,则使用 break 语句退出循环。

循环后,代码打印出一个带有循环结束时 x 的值的消息。

  1. # Example_3
  2. # 以下是while后面的布尔表达式使用花括号时的例子:
  3. set x 0
  4. while {$x < 5} {
  5. set x [expr {$x + 1}]
  6. if {$x > 7} break
  7. if "$x > 3" continue
  8. puts "x is $x"
  9. }
  10. puts "exited second loop with X equal to $x"

输出结果为:

x is 1

x is 2

x is 3

exited second loop with X equal to 5


结果解释:首先将 x 的初始值设置为 0 ,然后在第一次迭代时,通过 set 命令将 x 值加 1 ,故循环内部第一次输出 1 。循环在 x 的值为 4 时被 continue 关键字跳过,因此没有输出 x is 4。循环在 x 的值为 5 时,由于布尔表达式为假,所以循环终止,进而执行最后的 puts 语句。


  1. # Example_4
  2. # 与例子3的区别在于布尔表达式由花括号变成了双引号
  3. set x 0
  4. while "$x < 5" {
  5. set x [expr {$x + 1}]
  6. if {$x > 7} break
  7. if "$x > 3" continue
  8. puts "x is $x"
  9. }
  10. puts "exited second loop with X equal to $x"

输出结果:

x is 1

x is 2

x is 3

exited second loop with X equal to 8


结果解释:首先将 x 的初始值设置为 0 ,然后在第一次迭代时,通过 set 命令将 x 值加 1 ,故循环内部第一次输出 1 。循环在 x 的值为 4 时被 continue 关键字跳过,因此没有输出 x is 4。但是由于双引号与花括号的区别,这个例子的布尔表达式一直为真,实际上布尔表达式为 0 < 5 。所以 x 的值为 8 时由于 break 关键字,循环才终止。如果没有 break 则会进入无限循环。

3.3  注意事项二

从上述各个循环语句的格式来看,可以发现:在 TCL 中,每个左花括号必须与前面的字符在同一行。如果不在同一行,TCL 会抛出语法错误。

  1. # Example_1
  2. set x 1
  3. if { $x > 0 }
  4. {
  5. puts "x的值大于0"
  6. }

报错:

wrong # args: no script following " $x > 0 " argument while executing "if { $x > 0 } "


TCL 解释器报错,称 “ $x > 0 ” 这个参数后面没有跟脚本,也就是此时  if  仅获取到了 1 个参数,而正确用法  if  命令后面要接两个参数。

  1. # Example_2
  2. set y 0
  3. if { $y > 0 } {
  4. puts "y的值大于0"
  5. }
  6. elseif { $y < 0 } {
  7. puts "y的值小于0"
  8. }
  9. else {
  10. puts "y等于0"
  11. }

报错:

invalid command name "elseif"
    while executing
"elseif { $y < 0 } {
    puts "y的值小于0"
}"

elseif 和 else 命令均不能单独起一行,因为其实际上时 if 命令的组成部分,而不独立的一个命令。

四  总结

学习一门语言贵在坚持,希望自己能够通过写博客的形式,坚持下去,而非三天打鱼,两天晒网!

希望这篇文章对正在学习 TCL 的您有所帮助,喜欢的话请动动您的小手点点赞,您的点赞加收藏将会是笔者学习的动力源泉!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/188014
推荐阅读
相关标签
  

闽ICP备14008679号