A powerful feature of the Emu system is the ability to
modify and extend the system by writing scripts in Tcl. Tcl (which
stands for tool command language) is an interpreted language which
is easily extended to provide facilities such as these.
Tcl is somewhat strange as a language in terms of its
rules for dealing with variables. In fact the rules are quite
simple and small in number so aren't too hard to master. This
section gives a brief overview of the language, the reader is
referred to one of the Tcl books for more complete coverage.
Tcl commands consist of a command name and any number of
arguments separated by spaces. For example:
will construct a list of its four arguments.
All arguments must appear on one line (with one exception
discussed later), although in a file you can break a line as long
as you precede the newline character with a backslash, eg:
is read as one command
You can define new commands (procedures) as we'll see later.
Variables can be created and given values with the 'set' command:
and examined also with the
set command with no second argument:
In tcl, you must be careful to distinguish between the
name of a variable (myname above) and its value. To
use the value of a variable you must
precede it with a dollar sign:
What happens is that the value of
myname
gets substituted into the command
before
it is evaluated, so after substitution the command reads:
thus the result is as shown. Had you written:
the result would be:
since you used the name of the variable
(
myname) not its value
(
$myname).
The times that you want to use the name of a variable are
with specific commands which will either set the variable for
you or evaluate it themselves (like set).
Most of the time you will want to use
$varname to get the variable's value.
Forgetting the dollar sign can cause many many bugs in
scripts.
As well as substituting the values of variables into
commands, it is also possible to substitute the result of
running a command into another command, in the following
manner:
here the
llength command has been used to
find the length of a list. Since the square bracket
notation has been used, the text inside the brackets is evaluated first:
and the command becomes:
(the braces serve to delimit the value returned by the list command, if
you typed:
you would be giving five arguments to
llength, which is too many. What you really
mean is the list of five numbers 1 2 3 4 5, which we can write
as
{ 1 2 3 4 5 }).
Command substitution happens recursively so you can have
square brackets inside my square brackets:
since the result of the innermost list is
{2 3
4}, the result of the outermost list is
{1 2
3 {2 3 4} 5} which has five elements (one of which is
a list).
Variables are substituted in a command before it is
executed. If a variable occurs within a string (i.e., inside
quotes) it is substituted into that string:
sets the variable
myname to
"my
name is Steve Cassidy". The only time that
substitution doesn't occur is inside curly brackets {}:
This feature is useful because it delays evaluation of the
variables, for example when defining procedures (where the variables
will be evaluated when the procedure is run) and in loops
(where they are evaluated each time around the loop).
The data types that we have seen in Tcl already are
numbers, strings, and lists. Lists are in fact really strings
with each list element separated by a space and sublists
delimited by curly brackets. However, special commands exists to
manipulate lists so it's best to think of them as a separate
type. Lists can contain a mixture of types; they don't need to
be lists of just numbers or strings (or lists).
Arrays are available and can be indexed not only with
numbers but with words as keys. Their elements can be set with
the syntax:
and used with the usual dollar syntax:
(
puts stands for
put string and
prints its single argument to the screen).
Arrays are one dimensional but you can pretend that they
are multidimensional by just separating the indexes with a
comma:
but remember that all you are doing is making up a string using
the indexes: therefore,
myarray(1,2) is not the
same as
myarray(1, 2) (note the space after
the comma).
New commands are defined with the proc
command, which takes two arguments: an argument list and a
script. Both should be enclosed in curly brackets. For
example:
Like all other procedure calls, everything must be on one line.
However, since the material within curly brackets is taken
literally, it can be split over more than one line
as
long as the opening curly bracket is on the same line as the
proc so we can write:
the second argument to the proc command, the script, is just a
list of commands to be executed, one per line (or you can use
a semicolon to separate commands). You may only refer to
local variables (those in the argument list or those that you
define in the procedure) unless you include a
global definition in the procedure, eg:
the reference to
$prefix will use the
global variable. Setting
prefix within this
procedure will also change the global value.
The loop commands enable a script to be repeated a number
of times; the curly bracket notation is commonly used to delimit
the script and prevent early evaluation. You must also use
curly brackets on the condition part of the loop since that is
evaluated each time around the loop:
note that you have to use the command
expr to
evaluate an expression, otherwise it's just a string
"$i-1".
here there are four arguments to the
for
command an initialisation script, a loop test script (which in
interpreted in the same way as the condition in a
while loop), a script to evaluate each time
around the loop, and the loop body script.
The foreach command iterates over the
elements of a list, setting a variable (ll
in the example below) to successive elements of the list on
each iteration.