A Crash Course in Tcl
Table of Contents
- 1. Introduction
- 2. Tcl Statements
- 3. Commands and Substitution
- 4. Tcl Evaluation
- 5. The Tcl Order of Evaluation
- 6. Recursive Evaluation
- 7. Control Structures
1. Introduction
Tcl (normally pronounced tickle) is a simple, fast, and extensible scripting language. It is well suited to string processing tasks, and has a sufficiently large standard library of commands to be useful for everyday tasks. Tcl is extremely easy to add to existing programs as a ready-made scripting solution, and its distribution terms are rather loose. Tcl is a worthwhile language to learn, and this short tutorial is meant to get you started.
The Tcl scripting language originated from Berkeley, where Dr. John Ousterhout and his students at Berkeley found themselves implementing ad hoc scripting languages to control various software tools. Realizing the wastefulness of writing a new script interpreter for each software project, Dr. Ousterhout sought to build a single reusable, embeddable scripting language. Tcl has been through many changes since its inception, and it has superceded its original purpose. Tcl is now widely used for scripting on many platforms.
This tutorial assumes at least a basic familiarity with the fundamental concepts of computer programming. I have aimed for clarity rather than conciseness; I realize that this introduction may be a bit slow for experienced programmers.
2. Tcl Statements
Tcl programs consist of statements (individual pieces of a program that do something), and each Tcl statement generally occupies one line (though statements may also be separated with semicolons, and they may span multiple lines under certain conditions). Each statement in turn consists of a command (a word that makes Tcl do something) and any number of arguments (pieces of information that control how the command operates). These arguments are separated by whitespace (spaces or tabs) and are affected by certain grouping symbols. A typical line of Tcl code has the following structure:
something arg1 arg2 {arg three} "arg four"
This line of code begins with the command "something" and contains the four arguments "arg1", "arg2", "arg three", and "arg four". Note that the curly braces and quotation marks group text into arguments; in this example, curly braces prevent "arg" and "three" from being treated as separate arguments, but rather as "arg three". Curly braces and quotation marks serve slightly different purposes, which we will clarify shortly. Let’s now take a look at a simple but complete Tcl program.
puts {Hello, world!}
set zealotry {Tcl rules!}
puts "w00t! $zealotry"
The first line consists of the command puts, and one argument. The text Hello, world! is enclosed in curly braces ({ }), so it comprises a single argument. puts prints its argument to a file (or the terminal if no file is specified), so this line of code causes "Hello, world!" to appear on the terminal.
The second line of code sets a variable. Tcl variables associate names with pieces of data. This line of code associates the text "Tcl rules!" with the name "zealotry", so that the program can retrieve it later. Again, curly braces group the two words "Tcl rules!" together into a single argument. Curly braces prevent variable substitution (which we will discuss shortly); dollar signs and other special characters act like ordinary characters inside curly braces.
The third line of code is similar to the first, except that the argument to puts uses quotes instead of curly braces. The only difference is that quotes allow Tcl to perform variable substitution, whereas curly braces do not. Any dollar sign ($) followed by a variable name is considered a request for substitution, and Tcl will replace this text with the value of the given variable. In this case, Tcl will replace $zealotry with the value we gave that variable earlier, "Tcl rules!". The finished piece of text is given to the puts command, and so Tcl prints out "w00t! Tcl rules!". If a variable name contains special characters or spaces, you can protect it with curly braces. For instance, if our variable were called scripting envy instead of zealotry we would have to write it as ${scripting envy}.
Variable substitution can actually take place anywhere, not just inside quotes. For instance, puts $zealotry would simply print the value of the variable zealotry, and puts $zealotry$zealotry would print the variable twice. However, puts $zealotry $zealotry would not work, since this would parse as a command with two separate arguments.
3. Commands and Substitution
Every Tcl command has a return value (a piece of data produced by the command). Many commands have an empty return value (that is, they don’t return anything useful); this is represented by an empty string. However, most commands return do return useful information. For instance, the expr command evaluates mathematical expressions (such as (4 * 5 + 3) / 10) and returns the resulting number. Scripts use command substitution to access return values.
Command substitution is similar to simple variable substitution, except that it substitutes the return value of a Tcl command instead of the value of a variable. Square brackets ([ ]) trigger command substitution.
Let’s examine a simple example of command substitution. In this example we will use the expr command to calculate a number, and then print it out with puts.
set num [expr 1+2+3]
puts "The result is $num"
The first line of code sets the variable "num" to the return value of the expr command. This return value will be the number 1+2+3, which is 6. Therefore, this line sets "num" to the number 6. The second line uses simple variable substitution to print out the value of the variable "num".
Command substitution works inside quotes, but not inside curly braces. For instance, we could have written puts "The result is [expr 1+2+3]" instead of breaking the script into two statements. It is also entirely valid to mix multiple substitutions of different types in the same statement. Scripts commonly build large strings by combining multiple variables, commands, and special characters.
4. Tcl Evaluation
As you begin to construct increasingly complex Tcl statements, it is important to understand the exact order in which substitutions are performed. We will provide a sufficient summary here and leave the exact details to a reference manual. Please understand that this description is just a model, and perhaps a slightly oversimplified one at that. The Tcl interpreter performs various optimizations internally, but those are irrelevant to our discussion.
5. The Tcl Order of Evaluation
- The Tcl file is broken into statements, separated by newlines or by semicolons. However, newlines and semicolons enclosed within quotes or curly braces are ignored. In addition, statements beginning with a hash (#) character are ignored to allow comments to be added to the program. Comments extend from the opening hash mark to the end of the line.
- Backslash substitution is performed. This replaces certain combinations such as \n and \t with the corresponding control characters (in this case, newline and tab). This is an important feature, since some special characters are difficult to insert into a source file.
- The statement is broken into words. Words are groups of characters, possibly contained in curly braces or quotes, separated by spaces.
- Variable substitution is performed once on the entire statement.
- Command substitution is performed once on the entire statement.
- The first word is treated as the name of a command, and Tcl attempts to execute this command with the rest of the words as arguments.
6. Recursive Evaluation
Tcl would be a weak language if not for recursive evaluation. This feature allows scripts to evaluate parts of themselves as separate scripts, and substitute the results into other data. For instance, a Tcl script can invoke the Tcl interpreter on a piece of user-speficied text, or on a script prepared by the program itself. While this may sound silly and useless at first, it is actually a very convenient and necessary feature.
The eval command combines all of its arguments into a string (piece of text), and then runs the Tcl interpreter on it. eval returns the result of the code it evaluates (as a string).
Let’s look at an example of recursive evaluation with the eval command. In this example, we will use recursive evaluation to perform double substitution.
set varname {$message}
set message {Hello, world!}
eval "puts $varname"
This example begins by setting the variable "varname" to "$message". Note that the $ does not cause variable substitution in this case, since it is enclosed with curly braces. The script then sets "message" to "Hello, world!".
Now for the tricky part. The third line begins with the eval command. However, eval is a normal Tcl command, and Tcl performs its normal substitution passes before executing the command. After substitution, this line becomes equivalent to eval {puts $message}. The eval command evaluates this argument like any other piece of Tcl code, and puts prints "Hello, world!" to the terminal.
7. Control Structures
A procedural language such as Tcl would be fairly useless without a mechanism to control the flow of its execution. Tcl provides several commands conditionally or repeatedly executing sections of code. This allows programs to make decisions based on their input.
The most important Tcl control command is if. This command uses expr to evaluate a logical expression (such as $x = 1 or 2
set number 1
if {$number = 1} {
} else {
}
The if statement checks to see if the variable "number" is equal to one. If it is, if calls eval on the next argument, which is a puts command enclosed in curly braces. If the value is not equal to one, if invokes the block of code after the (optional) else argument. This allows the program to choose between two alternatives based on the outcome of a simple test.
Note that if is a command, just like any other. It is not a reserved word, and a script could even redefine the meaning of if (though this would probably be a bad idea). Tcl is a unique language in that it has no reserved words.