Some SM users seem to be confused by variables and vectors; if you are one of these, the section on quoting (see section What Quotes What When) might help.
SM maintains a set of variables which are defined with one of the statements
DEFINE name value
or
DEFINE name { value_list }
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 {},
variables are not expanded (i.e. replaced by their value) in value_list,
whereas they are in value. In fact, the list can be delimited by
<> rather than {}; 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
(see section 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,
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,
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 }
invoked as
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,
DEFINE noise ? { Ring bell? } IF('$noise' != 'n') { bell }
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
define term : if($?term) { termtype $term }
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
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 { }. 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 {}), 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,
FOREACH x ( U B V R I J K ) { SET $x_red = $x IF(B-V >1)}
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 12
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.
By default variables are global, so if you have a variable $i, and
a macro that you call also uses a variable $i, the macro will change
the value that you so carefully defined. To avoid this, it is possible to
force variables (and also vectors) to be local, using a command like
DEFINE i LOCAL; in this case the variable $i will softly and
suddenly disappear when you leave the current macro (and therefore you
cannot make variables local at the topmost level, i.e. at the command prompt).
In fact, such variables aren't strictly local, they have what's called
nested scope, as they are visible from any macros that you may call -- they
simply do not propagate backwards up the call stack. You are free to make
a variable local in any (or all) macros, there's no restriction on how
deep such local declarations may be nested.
Go to the first, previous, next, last section, table of contents.