Go to the previous, next section.

String Variables

SM maintains a set of variables which are defined with the statement

DEFINE name value
or
DEFINE name { value_list 2
or
DEFINE name ( expression )
where name must consist of digits, letters and `_' (but must not start with a digit), and may be a keyword.

Value may be a word or a number. Value_list has no such restrictions and may contain many words. Note that due to the presence of the {2, variables are not expanded in value_list, whereas they are in value. In fact, the list can be delimited by <> rather than {2; see DEFINE for details.

The expression in DEFINE variable ( expr ) should be a scalar; if it is not, the first element of the vector will be used and you will be warned, if VERBOSE (@xref{VERBOSE}) is one or greater. Sometimes you just want to evaluate an expression and treat the answer as a string; in this case use the special vector form $(expr) which is replaced by the value of the expression -- for example echo e is $(exp(1)). Expressions are further discussed under `Vectors and Arithmetic'.

There are a number of special variables whose value is always the current value of some internal SM variable such as the current position or the point type. The variable "date" is also special and expands to give the current time and date, -- try typing echo $date. You can freeze these variables at their current value by saying define name | (see below).

Each time SM reads $name it replaces it by its value, considered as a character string. For example, @br

DEFINE hi hello
WRITE STANDARD $hi
will print hello. This expansion is done before even the lowest level of lex analysis, so if a command is attempting to read a value it is possible to give it the name of a SM variable. An example would be the XLABEL command, which writes a string as the x-axis label of a graph, @br
DEFINE name Aelfred
XLABEL My name is $name
will invoke the XLABEL command, and write My name is Aelfred below the x-axis. (Incidentally, DEFINE Aelfred Aethelstan YLABEL $$name will write Aethelstan as the y-axis label, which can be handy in macros. The use of the double $$ indicates to SM to do a double translation, as it first expands to $Aelfred which then expands to Aethelstan).

A variable can be deleted by DEFINE name DELETE so for example the macro

MACRO undef 1 { DEFINE $1 DELETE 2
invoked as @br
undef name
will undefine the variable name (see the section on macros if you are confused).

There are also three special values, :, |, and ?. The command define name : means `get the value of name from the environment file'. If this fails, and if the variable is all uppercase, SM will then try to use the value of an environment (VMS: logical) variable of the same name. Using define name ? means `read the value of name from the keyboard'. You can specify a prompt to be used, see DEFINE for details. The form with | has changed a little with version 2.1.1. The variables that you can use with | have not changed, but their usage has slightly. They are all defined for you when SM starts and each is always correct, tracking the current value of the corresponding internal variable. For example, try echo $angle angle 45 echo $angle. If you now say define angle |, $angle will cease to track the internal value and will remain fixed (the same effect can be achieved with define angle 45). When you say define angle delete it will once more track the internal value. Your old code will continue to work, but in many cases it is possible to remove the explicit definition with |. This special sort of variable will not be SAVEd, and will not show up if you list the currently defined variables. A list of the | variables is given in the section on DEFINE.

So using the example `.sm' environment file listed in the previous section of the manual, DEFINE name : will define name to be Robert, DEFINE angle | will give the last value set by the ANGLE command, and DEFINE datafile ? will ask you for the value of `datafile', which can be useful in macros. For example, @br

DEFINE noise ? { Ring bell? 2 IF('$noise' != 'n') { bell 2
will execute the macro bell if you type anything but n in reply to the question `Ring bell?'.

When writing macros, it is also sometimes useful to know if a variable has been defined. The variable $?name has the value 1 if name is defined, otherwise it is 0. For instance, there is a line@br

define term : if($?term) { termtype $term 2 
in the startup file, to set a termtype if present in the environment file.

There are also commands to read the values of variables from data files defined with the DATA command.

DEFINE name READ i
or
DEFINE name READ i j
will set name to be the i'th line of the file (or the j'th word of the i'th line). An example is given in the section on `useful macros'. You can read variables from the headers of binary files (specified with the IMAGE command) using DEFINE name IMAGE, although this is only supported for a limited class of file_type's (see section Two-Dimensional Graphics).

All currently defined variables may be listed with

LIST DEFINE [ begin end ]
where the optional begin and end define the range of variables (alphabetically) to be listed. You might prefer to use the macro lsv which won't appear on your history list.

Variables are usually not expanded within double quotes or { 2. If for some reason you need to force expansion within double quotes, it can be done with $!name. The macro `load' discussed under useful macros gives an example of this mechanism. If you need to expand a variable, with no questions asked (and even within {2), use $!!name.

Sometimes you may want to terminate a variable name where SM doesn't want to, and this can be done with a trick involving double quotes. Say you are writing a macro to find all the stars redder than B-V = 1.0 in a set of data vectors, and you want to rename them with a trailing "_red", so star goes to star_red. So you write a foreach loop,@br

FOREACH x ( U B V R I J K ) { SET $x_red = $x IF(B-V >1)2
Well, that won't work because SM thinks that you are referring to a previously defined variable named x_red, so it will complain that x_red is not defined. But if you write it as $x""_red the "" separate the x from the _red until $x is expanded, and then disappear, and all is well. When a variable is read, SM skips over all whitespace before the definition, and this can cause problems if you hit ^C in the middle, as the rest of the command will be thrown away. If you ever hit a ^C, and can't get a prompt, try typing any non-whitespace character.

Variables are string-variables, and are not primarily designed for doing arithmetic (that's what vectors are for). This is a common source of confusion so let's consider some examples (at the risk of anticipating some later sections of the manual).

DEFINE a 10
defines a variable a which consists of the two characters `1' and `2', and which can be used anywhere -- for example xlabel $a. What about vectors? Consider
SET x=10
which defines a single-element vector whose value is ten, ready to be used in expressions such as
SET y=$a + x*12
Note that the $a is still just the two characters `1' and `0', but in this context that is interpreted as the number ten. So what does
DEFINE y $a+x*12
do? Well, actually it results in a syntax error (the `+' ends a word), so try
DEFINE y <$a+x*12>
This defines the variable y as the string `10+x*12', it doesn't evaluate the expression. You can evaluate the expression if you want with
DEFINE y ( $a+x*12 )
which defines y as the string `130'. Incidently, you can sometimes get away without an explicit variable with the syntax $($a+x*12) which also expands to the string `130'.

The fact that variables are simply strings can be used to build complex commands; consider for example the macro

readem          # read multiple lines columns with names in row 1
                READ ROW names 1.s
                DEFINE rc <$(names[(0)]) 1>
                DO i=2,DIMEN(names) {
                        DEFINE rc <$rc $(names[($i - 1)]) $i>
                }
                LINES 2 0
                READ < $rc >
which reads the names of a set of columns from line 1, builds a command to read the data in the variable rc, and then reads all the data in one command. You could of course loop through names reading each column in turn, but this should be a good deal faster.

Go to the previous, next section.