tcl Control Structures


Syntax

  • if expr1 ?then? body1 elseif expr2 ?then? body2 ... ?else? ?bodyN?
  • for start test next body
  • while test body
  • foreach varlist1 list1 ?varlist2 list2 ...? body

Remarks

Documentation: break, for, foreach, if, switch, uplevel, while

Adding a new control structure to Tcl

In Tcl, a control structure is basically just another command. This is one possible implementation of a do ... while / do ... until control structure.

proc do {body keyword expression} {
    uplevel 1 $body
    switch $keyword {
        while {uplevel 1 [list while $expression $body]}
        until {uplevel 1 [list while !($expression) $body]}
        default {
            return -code error "unknown keyword \"$keyword\": must be until or while"
        }
    }
}

Common for both kinds of do-loops is that the script named body will always be executed at least once, so we do that right away. The invocation uplevel 1 $body means "execute script at the caller's stack level". This way, all variables used by the script will be visible, and any results produced will stay at the caller's level. The script then selects, based on the keyword parameter, whether to iterate while a condition is true or until it is false, which is the same as iterating while the logical negation of the condition is true. If an unexpected keyword is given, an error message is produced.

if / while / for

if expr1 ?then? body1 elseif expr2 ?then? body2 ... ?else? ?bodyN?

exprN is an expression that evaluates to a boolean value. bodyN is a list of commands.

set i 5
if {$i < 10} {
  puts {hello world}
} elseif {$i < 70} {
  puts {enjoy world}
} else {
  puts {goodbye world}
}

for start test next body

start, next and body are lists of commands. test is an expression that evaluates to a boolean values.

The break command will break out of the loop. The continue command will skip to the next iteration of the loop.

The common usage is:

for {set i 0} {$i < 5} {incr i} {
  puts "$i: hello world"
}

Since start and next are lists of commands, any command may be present.

for {set i 0; set j 5} {$i < 5} {incr i; incr j -1} {
  puts "i:$i j:$j"
}

while test body

The test is any expression that evaluates to a boolean value. While test is true, body is executed.

set x 0
while {$x < 5} {
  puts "hello world"
  incr x
}

The break command will break out of the loop. The continue command will skip to the next iteration of the loop.

set lineCount 0
while {[gets stdin line] >= 0} {
  puts "[incr lineCount]: $line"
  if { $line eq "exit" } {
    break
  }  
}

List iteration: foreach

foreach varlist1 list1 ?varlist2 list2 ...? body

foreach is a powerful control structure that allows looping over a list or multiple lists.

set alpha [list a b c d e f]
foreach {key} $alpha {
   puts "key: $key"
}

Multiple variable names may be specified.

set alphaindexes [list a 1 b 2 c 3 d 4 e 5 f 6]
foreach {key num} $alphaindexes {
   puts "key:$key num:$num"
}

Multiple lists can be iterated over at the same time.

set alpha [list a b c d e f]
set indexes [list 1 2 3 4 5 6]
foreach {key} $alpha {idx} $indexes {
   puts "key: $key idx:$idx"
}