SM is still evolving slowly, and this documentation may not be true, helpful, or complete. In order of increasing plausibility, information may be obtained from the HELP command, this document, the authors, and the source code. RHL is prepared to guarantee that the executable code has not been patched.
If you find bugs, (reasonable) features that you want, wrong documentation,
or anything else that inspires you please let us know. At least under
Unix the macro gripe should be a convenient way to send us mail.
Please also send us any clever macros that you would like to share.
Next a disclaimer: SM is copyright (C)1987, 1989, 1990, 1991,
1992, 1993, 1994
Robert Lupton and Patricia Monger.
This programme is not public domain, except where specifically stated
to the contrary, either in the code, or in the manual. If you have a
legally acquired copy you may use it on any computer "on the same site",
but you may not give it away or sell it. If you have a legal copy we
will provide some support and allow you with as many upgrades
as you provide tapes for (or wish to retrieve with ftp).
SM is provided `as is' with no warranty, and we are not responsible for any losses resulting from its use.
In addition to this manual there is a tutorial introduction which you might find less intimidating. See section `The SM Tutorial' in The SM Tutorial.
SM is an interactive plotting programme with a flexible command language. The plot data may be defined to SM in a number of ways. There is also a powerful mechanism for defining and editing plot `macros' (sets of SM plot commands that are defined and invoked as plot "subprogrammes").
The features of SM are described fully in the next few sections, but let us start with a description of how to produce your first SM plot. Before you start, notice that SM is case sensitive. Keywords may be typed in lower or uppercase (as we do in this manual), but we would recommend using lowercase. It is in fact possible to change the meanings of lowercase keywords, but this can be confusing. If you are interested, see the section on "overloading". See `uppercase' in the index if you really want to use your shift key.
Let us assume that you have a file called mydata, which looks
like this:
This is an example file 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512
SM has a history mechanism, so
first type DELETE 0 10000 to tell SM to forget any
commands that it has remembered. Then choose a device to plot on. You
do this with a command like dev tek4010. If you don't know what
to call your terminal, use the LIST DEVICE command, ask some local
expert, look at the description
of DEVICE, or (if desperate) read the manual (see section The Stdgraph Graphics Kernel).
You'll know that
you have succeeded if typing BOX draws a box.
You should now have successfully chosen a graphics terminal. To actually
plot something, use the following set of commands. The text after the
# is a comment, you don't have to type this (or the #).
DATA mydata # Specify desired datafile
LINES 3 100 # Choose which lines to use
READ i 1 # Read column 1 into `i'
READ { ii 2 iii 3 } # Read column 2 into `ii' and 3 into `iii'
LIMITS i ii # Choose limits, based on i and ii
BOX # Draw the axes
PTYPE 4 0 # Choose square point markers
POINTS i ii # Plot i against ii
CONNECT i ii # and connect the points
XLABEL This is i # Label the X-axis
YLABEL This is ii # And the Y
You should now have a graph. If you had wanted to plot the third
column instead of the second
you could have typed LIMITS i iii POINTS i iii instead.
And of course you could plot ii against iii as a third
alternative. You
were not limited to only use squares as markers or solid lines to
connect them - see PTYPE and LTYPE for details.
If you want a logarithmic plot, SM makes that easy for you.
You can take logs of a vector using the LG (or LN) commands
on vectors; try it - SET x=1,10 SET y=x**3 set ly=LG(y) LIMITS x ly
CON x ly box. You might have wanted the axes to reflect the fact that you
had logged the y axis. The TICKSIZE command allows you to do this, and
this is in fact the commonest use of it. Try TICKSIZE 0 0 -1 0, and
then repeating the x-y plot.
What if you want hard copy of your hard-earned graph? There is a
command (actually a macro) called playback which will repeat all
the commands that you have typed. Type ERASE to clear the screen, then
HISTORY to see the commands that you have issued. You probably
don't want the ERASE command to be repeated, so type DELETE
to delete it(1).
If there are any other mistakes use DELETE m n to delete
the lines m to n containing them.
Now type playback and your plot should reappear. But we wanted a
hardcopy, so type dev laser lqueue (or whatever your friendly Guru
recommends as a hardcopy device), then playback. This time, those
plotting commands will appear on the laser printer not your terminal. To
make them actually appear, type hardcopy or issue another
dev command.
Be sure to say dev tek4010 (or whatever device you chose)
before you read any more of this
document. It is possible to edit the playback buffer, rather than
simply deleting lines from within it. The section on `examples'
describes how to do this.
In fact, the same plot could have been produced from a data file which
just contained the first column. After saying READ i 1, you could
have said SET ii = i*i SET iii = i**3 and proceeded from there, or
even skipped the file altogether by saying set i = 1,8 instead of
READing it at all. Such possibilities, and a good deal more, are
described in greater detail in the rest of this manual.
What we just did was to define a simple `macro', in this case the
special one called all which playback manipulates. A more
explicit use of a macro would be to define a macro to square a vector,
that is to square each element of a vector.
To do this say(2)
MACRO square 2 { SET $1 = $2*$2 }
So to calculate the vector ii we could now say
square ii i
which is the same as saying
SET ii = i*i
So now that you have met macros, how do you save them? The simplest
and least reliable way is to use SM's history, and hope that
the next time that you use SM it remembers the MACRO
command that you used to define square, so you can re-issue it.
(Try exiting SM, then starting it up again and typing
HISTORY, then ^nnn where nnn is the number
which is next to the desired command in the resulting list.)
A brute force way is to say SAVE filename which will save almost
all of your SM environment, to be recovered using the
RESTORE filename command at some later time, or later SM
session.
Specifically, SAVE will save all your macros, variables, and
vectors, along with your history buffer. This is a very convenient
way in practice but it does mean that you tend to carry around
lots of long-forgotten
macros, variables, and vectors.
Another way is to write the macros to a disk file, using the
MACRO WRITE command (see `Macros'). Then you can retrieve
your macros with MACRO READ. You should note that your macro
all will simply be a macro - to put it onto the history list
say DELETE 0 10000 WRITE HISTORY all. (Of course, you could
write a macro to do this for you).
Maybe saving your
playback buffer is something better done with SAVE, which will
restore your playback buffer, while
preparing files of useful macros is a use for MACRO READ.
Once the idea of macros gets into your blood, you can of course use
an editor to create your own files of macros, to be read with
MACRO READ.
This is a guide to the use of SM variables, the macro processor, the help command, and the history facilities. The vector arithmetic and plotting facilities are described below. Various examples are scattered throughout the text, to give some guidance on the use of SM's capabilities.
Perhaps the most important thing to know is how to escape from
SM. If you have a prompt, simply type QUIT(3).
If you are running some command, try ^C to get a prompt.
Most commands will eventually return control to the keyboard following a
^C. In addition, the parser is reset, and the input buffer cleared.
Sometimes ^C leaves a } on the buffer if it thinks that it'll
help get back to the prompt, which can generate an irrelevant syntax error.
Occasionally it can still be confused -- try typing a few characters
and maybe a }.
When you have interrupted SM with a ^C, a
macro called error_handler is executed, if it is defined. The one
that we provide does things like setting the expansion back to 1, and
resetting any window commands that you might have issued, and then
prints a message handler... to tell you that it's done its work.
If you don't like this,
see `private initialisation' in the index for how to get your own
handler loaded automatically.
If you make a mistake, and SM notices a syntax error, it'll
print a message indicating where you were and which macro you were
running. It is possible for the wrong macro to be reported (if
SM has finished reading the macro before detecting the error),
in which case you'll be told that the error occurred in a macro that
called the offender. Setting VERBOSE (see section Verbose)
to 3 or 4 provides a
more direct way of finding the true location of the error.
If you define the variable traceback to be 1 (maybe with the line
traceback 1 in your `.sm' file)
you'll get a traceback of what macros were active when the error occurred;
the same caveats about the wrong macro being reported apply.
In addition, the usual interrupt capabilities of your operating system will
work under SM, with a couple of quirks.
Under Unix, in case of emergency, type ^\, and SM
will ask you if you want to return to the prompt, and if you
don't it'll offer a core dump, and then exit. As
usual, typing ^Z (from the C-shell) will interrupt the process, which may
be restarted later.
Under VMS, ^Z will interrupt SM, and return you to the command
interpreter (DCL). Typing CONTINUE will then allow you to restart
SM(4).
If SM is running in a SPAWNed sub-process, then ^Z will reATTACH you to its parent. To continue SM, use the DCL ATTACH command. We strongly suggest that you learn how to do this, it makes life much easier -- all you have to do is SPAWN a process from DCL and start SM from there. Do check with your VMS system manager to ensure that you have the right quotas for SPAWNing (Process limit must be at least 3, because SM will use one for itself and one for hardcopies). An especially simple way to do all this is is to use the command file `kept_SM.com' in the main SM directory. It'll handle the spawning and attaching for you.
Another fact to bear in mind is that the characters ^, $, and
# are special, as ^ is used by the history system,
$ introduces a
variable, and # starts a comment. The special meanings of all of
these characters
except ^ can be turned off by preceding them with a \. To type a ^,
use the quote_next character
(initially ^Q or ESC-q) to quote the ^; i.e. type
ESC-q.(5)
A \n is interpreted as a carriage return, and a \ as the
last character on a line escapes the newline, so that the line and the one
following it are treated as one long line.
A \ preceding any other character
(except a "; see next paragraph) is simply a \. This character
is used to set font types in the LABEL commands, so it has no
special meaning to the command interpreter, which simplifies the entering of
strings for LABEL commands.
A further problem is that symbols such as +, -, *,
and / are used
to separate words, which is what you want for mathematics, but maybe not what
you had in mind for filenames.
Enclosing a word
in double quotes turns off all special meanings except ^; an embedded
" may be escaped with a \.
Single quotes are used quite differently; enclosing a word in 'single quotes'
makes it into a string so '12' is a two-character string and not
an integer at all. There are times when this is important; for example
if(y == 'yes') tests if the vector y is equal to the
string `yes', whereas if('yes' == 'yes') asks whether two
identical strings are equal (they are). When you remember that I can
legally say set yes='no' you'll appreciate the distinction.
The characters {} also perform quoting, turning off the special
meanings of all characters (including single and double quotes, but not
^). The difference between double quotes and braces is that
the latter have grammatical value; they are part of the syntax that
SM understands. In most cases you can use angle brackets instead of
curly ones if the grammar needs the brackets but you don't want to
turn off expansions (see section String Variables).
SM is case-sensitive. It will
accept keywords in either upper or lower case, but this is a special
dispensation on its part. If you insist on typing in uppercase say
load uppercase when you first start SM, or put the line
uppercase 1 in your `.sm' file.
Furthermore keywords may not be abbreviated.
This is not a great hardship as it is easy to define macros which
make the minimum abbreviation a synonym for the full command. Many such
macros are predefined for you when you first use SM; see section The System Macro Libraries
for details. In particular, certain common
abbreviations of commands have been predefined by the
SM startup file.
Every time that SM is started, it looks for an environment file
called `.sm' which consists of names of variables and their
values. From # to the end of a line is taken to be a comment. A list
of directories to be searched in order for `.sm' files
is compiled into SM, it usually
consists of the current directory, then your home directory, and then
some system directory. The system default can be over-ridden by
defining the environment variable SMPATH which is
a list of directories separated by single spaces. Each directory on the
search path is tried in turn until a file is found containing the desired
variable, which allows your choices to take preference over those of the
system administrator. In the list of directories
. is taken to be the current directory, and ~ is
your home directory unless you specified a command line -u name
option, in which case it is taken to be name's home directory instead. This
means that sm -u name will usually run SM as if you were name.
If name is null, then SM won't look for a `.sm' file in
anyones home directory.
The default path is equivalent to an SMPATH of
export SMPATH=". ~ /u/sm/lib/"
(or an equivalent incantation). Note
that the directory /u/sm/lib/ ends in a / so that a filename
can be directly appended (on a VMS system it would probably end in a :
or ]).
An example file would be (the filenames are written in Unix)
# I'm a comment line fonts /users/sm/fonts.bin graphcap /users/sm/graphcap help /users/sm/help/ macro /users/sm/macros/ name Robert # Or alternatively `Dr._Lupton'
The fonts file contains the SM fonts (in a binary form),
the graphcap entry is used to
define the file used to describe graphics terminals (see section The Stdgraph Graphics Kernel),
help is the directory used by the help command,
macro is the default directory where macros reside,
and name is what SM will call you (you can put spaces
into your name by using underscores, e.g. My_Lord will be
referred to as My Lord).
You can access
entries in the environment file yourself, as described
in the section on variables. See the section section The System Macro Libraries
to see how entries in the `.sm' file are used to influence the
behaviour of SM, or consult your local expert. You might want
to borrow someones `.sm' file when you first use
SM, although you should do fine without one. For more detail, and
further special entries, see section Environment Variables.
The name of the `.sm' file can be specified on the command line as
"-f name" or you can ask to use name's .sm file with
-u name.
VMS users should ensure that SM has been installed
as a foreign command to take advantage of these capabilities.
SM then tries to read in any macros
in the file `default' in the directory `macro'
and attempts to execute the macro startup if it exists.
If -m filename appears on the command line, this is taken to be the
name of another file of macros and these are read, and the eponymous macro
is executed (after any pre- or suf- fix has been removed. For instance if
you start
SM with the command sm -m /home/tst.m, it will first read
the file /home/tst.m, and then attempt to execute the
macro tst).(6)
Anything left on the command line is treated as if it had been typed
at the prompt, for example sm restore vital.save will start
by RESTORing from the file vital.save (see RESTORE
if you want to know what this means). The -m option is not
really a good way to personalise SM. The startup macro
discussed under `useful macros', which is run every time that you start
SM, looks for a directory macro2 in your `.sm'
file, and if it is there reads a file `default' from it, and
executes the macro startup2 which it expects to find there.
On case-insensitive operating systems, such as VMS, you may need to
quote the command line to prevent it being translated to upper case.
SM then
attempts to read a set of history commands from a file in
the current working directory, passes control to the input routine
and issues a prompt.
The file is given by the entry hist_file in your `.sm'
file, and if it isn't present then no history will be remembered.
You are then able to type commands, as many as will fit on one line(7), and use the features described below.
You can use a combination of these features to run SM in `batch' mode.
If you had a history file that you just wanted to run, then you could
start SM, say playback, and quit. You could have a macro
called batch in batch.m that did just that, and say
sm -m batch.m to execute it. In fact, you don't even need your own
macro as one is pre-defined for you so sm batch is sufficient.
You could write your own macros along this lines to do more complex tasks.
A more convenient alternative (under unix) would be sm -S < history_file
where the -S is explained in the next paragraph.
For completeness, we should mention the other command line flags,
-h, -l logfile, -n, -q,
-s, -S, -v#, and -V.
The -h prints a summary of command line options,
if you specify a logfile with -l everything that you type at the
keyboard is copied into the logfile (except editing commands). When you
start SM it usually runs a macro startup; -n prevents this.
The -s (for `stupid', or `silent' or `suppress') flag disables the
command line editor (although the history list is still saved, so commands
like playback will work),
-q suppresses the initial `Hello' message,
and -S is like -s but it also suppresses the prompt
and stops SM from intercepting ^c. You can get the same effect
as -s from inside SM with the command TERMTYPE none.
If you are reading from a file or pipe SM behaves as if you had
invoked it with the -S flag.
This is useful if SM is
being run from inside another programme, via a pipe (VMS: mailbox), or
on a very stupid terminal.
If you want to set a particular value of verbose, use -v for example
-v-3 is equivalent to the VERBOSE -3 command given interactively.
If you want to know SM's version string without starting SM, you can use
the -V flag.
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.
It is often very useful to be able to repeat a command, or perhaps correct
a mistake in what you have just typed. Ways of doing this are usually
referred to as `history', and SM has two distinct mechanisms.
One is very similar to that of the Unix C-Shell,
and the other allows you to edit commands using a syntax similar to the popular
editor `emacs', or a generalisation of the DCL history under VMS.
If you are not familiar with Unix, emacs, or VMS don't despair; a
description of the commands and how to invoke them follows in this
document.
Both of these mechanisms are implemented by the routine which reads input
lines. As each line is sent to the parser, it is copied onto a
history list. This list may be printed with HISTORY, and
the commands may be
re-used by referring to them by number, as ^nn, or by a unique
abbreviation, as ^abbrev. In addition, the last command may be
repeated by using ^^ and the last word of the last command by
^$.(8)
These symbols are expanded as soon as they are recognised (see examples,
or experiment), and are then available for modification by the editor.
Sometimes a ^string will retrieve a command beginning
string, but not the one that you want. Version 2.1.1 no longer
supports the use of ^TAB
to search for the next-most-recent command beginning string,
but you can use the search commands (^R and ^S) instead.
Some people really don't want ^ to be their
history character, either because they're used to something else (such
as !), or because they want to type lots of real ^s (e.g. you are using
TeX-style strings); if this describes you, rebind them -- see the next
section.
If you are considering the history list as a sort of programme to be
repeated you may think that HISTORY lists the commands in the
wrong order; if so use HISTORY -.
For example, if I type:
PROMPT @ echo I like SM HISTORY
SM will set the prompt to be @, replace the macro echo by
its value WRITE STANDARD and print
I like SM
and then
3 HISTORY 2 echo I like SM 1 PROMPT @
(The actual numbers will be different, depending on what other commands you have executed, and also because SM may have read a history file. In that case there'll be many more commands on the list, but no matter.) If I then type
^2 <CR>
(that is ^2 not control-2) the screen will look like
@ echo I like SM I like SM
as if I had just typed it in (@ is the prompt) . Typing
^^ (Yes, ^$ ) <CR>
will now result in SM printing (truthfully)
I like SM (Yes, SM )
It is possible to delete commands from the history buffer with the
DELETE command. If the command is given with zero, one, or two
arguments, then
the specified range is deleted (but their numbers are not re-used). If
no arguments are given, the last command on the buffer is deleted, and
its number is released to be re-used. In other words, the command
DELETE will delete first itself, and then the
previous command from the history list. The command DELETE HISTORY
only removes itself from the history list, and
several of the common commands are defined as macros which use it,
for instance dev is defined as
DELETE HISTORY DEVICE. This means that the command will not
appear on the history list, to confuse you when you do a playback. But
if you now innocently use dev in a macro, that macro won't appear
on the list either. Still worse, if you use dev twice in one
macro, the previous command will be deleted as well which could be quite
confusing.
You can also delete lines of history using ESC-^D as
described shortly.
The numbering is consecutive, starting at zero. Each command retains its
number until you use a HISTORY command to list the remembered
commands, in which case they are all renumbered, and it is these new numbers
that are listed.
By default only 80 lines are remembered, and as you continue typing earlier ones fall off the list.
Because the history buffer is also used to compose complex commands, this
limit can be aggravating. You may be able to defeat this by
putting many commands on
each line (you may have to use \n to terminate label
commands explicitly)
or by writing macros. Alternatively you can define a longer history buffer
when you start SM by including an entry history in your
environment file
which gives the number of commands to be remembered. If you set
history to be 0 the history list is made infinitely long.
Incidently, it is
the total
number of commands that matters, not the range of history
numbers present.
This limit on the number of history lines isn't enforced while writing a
macro onto the history list (using WRITE HISTORY). You can
use this fact to write a sneaky macro that extends your history; type
HELP extend_history if you are interested.
Some people seem to like their history editors to remember where they were,
so that after they retrieve and execute a command the next ^P
or
will retrieve the command one further back on the
history list (that is, if you have just retrieved command number 123
and executed it as command number 234, then ^P will get you
command number 124; you can execute it as command number 235). If
this describes you, define the variable remember_history_line,
which you can either do directly, or by putting a line
remember_history_line 1 in your `.sm' file.
The editor allows you to modify commands, either as you type them or as you retrieve them from the history list. The various editing commands may be bound to keys of your choosing, but the default bindings are given in this list of possible commands:
^A
^B
^C
^D
^E
^F
^H
^I (TAB)
tabsize in your `.sm' file.
^J (LF)
^K
^L
^M (CR)
^N
^O
^P
^Q
^R
APROPOS). If you specify a zero-length string
(i.e. simply hit carriage return) the previous search string will be reused.
^S
^T
^U
^V
^W
^Y
^Z
^? (DEL)
ESC-^D
ESC-<
ESC->
ESC-g
ESC-q
ESC-s
ESC-v
ESC-y
Some ESC-letter combinations are available which operate upon complete words. A word is defined as a whitespace delimited string, so 2.998e8 is a perfectly good word. In addition, it is possible to undelete words that have been deleted with an ESC-d or ESC-h.
ESC-b
ESC-d
ESC-f
ESC-h
ESC-u
ESC-u's will restore more words. When no more are
available, the bell is rung.
Any printing character is inserted before the cursor (unless overwrite has been set with ^T ). Illegal characters ring the terminal bell. If you insert a non-printing character on a line, the cursor may get confused.
If ever you are stuck at the command interpreter, and you want to send
a signal to the operating system (e.g. a ^Y to DCL), but
SM is catching the key and using it for its own purposes, the
easiest thing to do is to define a macro such as
MACRO aa {aa} , and then run it. While it is running (i.e.
until you type ^C) keys should have their usual functions.
As mentioned above, it is possible to redefine the meanings of keys to
the history (and macro) editor.
The command EDIT keyword key-sequence will make typing that
sequence of keys correspond to the command keyword. For example,
to make ^R redraw the current line, you could say EDIT
refresh ^R.
The keyword can be any in
the list below, or any single character. Each character in the
key-sequence can be a single character, ^c, or \nnn where
nnn is an octal number.
Alternatively, READ EDIT filename will
read a file specifying the new bindings which has two lines of header,
followed by pairs of keyword key-sequence. Lines starting with a
# are comments. An example is the
file for VMS users given below.
A problem can come up with multiple-key sequences. Imagine that you have bound some function to ^X^A, for example
EDIT end_of_line ^X^A
then what happens when you try it? SM sees the ^X and uses its
default binding, exit_editor, and then sees a ^A and
goes to the start of the line, which wasn't the desired effect. The solution
is to tell SM that ^X is not a legal key, in which case it will
either ring the terminal bell (if there are no key-sequences starting with
an ^X), or wait for the next key. In short,
EDIT illegal ^X
EDIT end_of_line ^X^A
should work.
On a somewhat similar topic, the KEY (see section Key) command may be
used to define a key to generate a string. See the end of the section on
macros for how this works.
All the current key definitions may be listed using LIST EDIT,
including the KEY definitions.
The names of operators, and their
default bindings, are given in the following table:
^A
^B
^C
^D
^E
^F
^G
^H, DEL
^I
^J
^K
^L
^M, ^@
^N
^O
^P
^Q, ESC-q
^R
^S
^T
^U
^V
^W, ESC-h
^X
^Y
^Z
ESC-<
ESC->
\034
ESC-b
ESC-d
ESC-f
ESC-g
ESC-u
ESC-v
ESC-y
ESC-^D
^
A simple example of a bindings file for a hardened VMS user might be
# This is a set of DCL-ish key maps for SM # name key toggle_overwrite ^A start_of_line ^H delete_previous_word ^J yank_buffer ^R search_reverse ^[r attach_to_shell ^Y
Note that that's the two characters
^ and A not control-A. It could just as well have been
written \001.
We need a new character for yank_buffer now that ^Y is
otherwise engaged, and I have chosen ^R (which means that I
can't use ^R to search backwards, so I chose ESC-r for
that).
You should be warned that some
terminal protocols map ^M to ^J, so this use of ^J could
render you unable to issue commands. As mentioned above, in an emergency
^@ can be used instead of ^M.
When SM is started, or whenever the TERMTYPE command is
used to change terminals, the arrow keys are bound to the commands
previous_line, ext_line, previous_char, and
ext_char. For terminals such as a Televideo-912, which uses
characters such as ^K for arrow motion, these can supersede the
previous meanings (in this case kill_to_end);
The only fix is to use the EDIT or
READ EDIT command to get what you want, probably within a macro.
If you want to use ' as your history character instead of ^
you need to say edit history_char ` edit ^ ^. If you try
to use a character special to SM such as ! this won't work
(you'll get a syntax error) and you'll have to use the next alternative,
namely put the commands into a file and say read edit filename,
for example:
# Change the history character # name key history_char ! ^ ^
Because this particular change is so common, it's possible to specify
that ` be your history character simply by including a line
history_char ` in your `.sm' file (or you can choose your
own character. Choosing 0 has the effect of using the default, ^).
SM needs to know something about the terminal that you are
using, so as to run the history/macro editor. This is entirely
separate from the problem of describing the terminal's graphics. It
will try to discover what sort of terminal you're on by using the value
of term from your `.sm' file,
or failing that the value
of the environment variable TERM (Unix) or the logical variable
TERM (VMS). A term entry of selanar -21 is
equivalent to a TERMTYPE selanar -21 command.
You can also use the TERMTYPE command directly.
SM then uses the terminal
type specified to look up its properties in the termcap database
(see section Termcap -- A Terminal Database). You can also use
TERMTYPE to specify the size of the screen, or to turn off
SM's idea of where the cursor is. On some terminals, you can
only send a cursor to an absolute position and this is chosen to be
the bottom of the screen. This is not what you want for, e.g., a VT240
as it will lead to your graph scrolling off the screen. The use of a
negative screen size to TERMTYPE will disable this cursor
motion, but will also make editing lines slower. If a line of your
graph is being deleted when the SM prompt appears, you may
need to use TERMTYPE dumb or TERMTYPE none.
Any line from ! to the newline is passed to your shell (DCL under VMS,
the Bourne shell under unix. If you set the variable SHELL in
either your `.sm' file or the environment it will be used instead;
the former takes priority).(9)
For example, !ls or !directory will list the current directory.
The return code from the command is available in the variable
$exit_status, on unix systems it will be 0 for success, for weirder
systems you should look in the system manual for the return value of the
C function system. $exit_status is one of the variables
that can be set with DEFINE exit_status |.
It is also possible to change the directory that SM uses to look
for data or macro files with the CHDIR command - for instance
CHDIR "../more_data"(10).
If a directory name starts with `~', CHDIR replaces the `~'
with your home directory. This is the only place that `~' is treated
specially, for instance it is not interpreted by the DATA command.
Because directory names often contain mathematical
characters such as [ or /, it is wise to quote the directory, or
use the macro cd which quotes it for you.
In SM, it is possible to define sets of plot commands as
"subprogrammes", which can be used just like a plot command, to generate
a standard plot. These plot macros allow variables (e.g.
name of the data file, plot label or limits, etc) to be supplied at
execution time.
You can also bind commands to keys to save typing; for example I
usually bind `cursor' to the PF1 key of my terminal. Such keyboard
macros are discussed under KEY and at the bottom of this section.
The macro facility consists of commands to define macros, delete them, write them to disk files, read them from disk files, delete all those macros defined in a specified disk file and list all currently defined macros. In addition, the help command applied to a macro prints out its definition. It is possible to pass up to 9 arguments to a macro, referred to as $1, ... , $9, and in addition $0 gives the name of the macro. While macro arguments are being read they are treated as if they are in sets of {}, except that variables are expanded. If you want to include a space in an argument, enclose it in quotes. If the number of declared arguments is 10 or more, the macro is treated as having a variable number of arguments. If it is 100 or more the last argument extends to the end of the line. For further discussion see the discussion of how macros are used.
A macro is defined by the statement
MACRO name nargs { body-of-macro }
or
MACRO name nargs < body-of-macro >
where name may be up to 80 characters, and must not be a
keyword(11),
and body-of-macro is the statements within the macro, and may
be up to 2000 characters long. Macros defined using an editor on a file
may be up to 10000 characters. If nargs, the number of
arguments, is 0 it may
be omitted. Macros may also be created using the MACRO EDIT command,
which is discussed below, and which is probably easier. To define the macro
in a disk file, the file format must be: the name of the macro starts in the
first column, followed by a tab or spaces, followed by the number of
arguments, if greater than 0, followed by commands, followed by
comments if any. The next line and
any necessary subsequent lines
contain the macro definition (starting in a column other than the first
one). Any number of macros may appear in the same file, as long as the macro
name is given in the first column and the definition starts in some other
column. The first two blanks or tabs are deleted in continuation
lines, but any further indentation will survive into the macro definition.
Tabs will be replaced by spaces as the macro is read. By default a tab
is taken to be 8 characters wide, but this may be changed by specifying
tabsize in your `.sm' file.
When a macro is invoked, by typing its name wherever a command is
valid, for example at a prompt, it first reads its arguments from the
terminal (if they are not in the lookahead buffer, it will prompt you
for them), and defines them as the variables $1, ..., $9,
before executing the commands contained within the macro. The
number of arguments must be declared correctly.
As an alternative it is possible to declare that a macro has a
variable number of arguments by declaring 10 or more. The macro will
then expect between 0 and the number declared modulo 10 arguments, all
on the same line as the macro itself. (i.e. the argument list is
terminated by a newline, which may either be a `real' one, or an \n).
If the number of arguments is 100 or more it is still reduced modulo 10,
but the last argument is taken to be the rest of the line (which may
consist of many words).
The macro may find out if a particular argument is provided by using
$? to see if the variable is defined. For example the macro check,
in the format in which it would appear in a file,
check 11 if($?1 == 1) { echo Arg 1 is $1 }\n
will echo its argument, if it has one, and
split 102 if($?2 == 0) { DEFINE 2 "(none)" }
echo $1:$2:
if invoked as split word many arguments will print word:many arguments:.
If you add an explicit newline, split word many\n arguments,
you'll get word:many: and then a complaint that arguments
is not a macro.
If you try to execute a non-existent macro, if it is defined SM will
call a special macro called macro_error_handler.
It has two arguments; the first is the string
NOT_FOUND, and the second is the name of your non-existent macro.
When you start SM, the error handler is:
macro_error_handler 2 ## handle errors associated with macros
if($?missing_macro_continue) {
echo $2 is not a macro
RETURN
}
if('$1' == 'NOT_FOUND') {
del1
define 3 "$2 is not a macro; aborting"
} else {
define 3 "Unknown macro error for $2: $1"
}
USER ABORT $3
which causes an immediate syntax error (the USER ABORT),
and remove the errant command from the history list (the del1). You
can turn this off by defining the variable $missing_macro_continue,
which you can do in your `.sm' file; this was the default in SM versions
2.1.0 and earlier, and is what you get if the macro
macro_error_handler isn't defined.
Unfortunately we can get into
trouble with IF's at the end of macros, for much the same reason
that RETURN can get into trouble (see section The Command Interpreter).
The symptoms are that a macro either gets the arguments that were passed to the
macro that called it, or complains that it can't handle numbered
variables at all because it isn't in a macro at all.
To avoid this, there is an explicit \n at the end of the macro check.
It is possible to redefine the values of arguments (it won't affect
the values you originally specified, arguments are passed by value),
or to DEFINE values for arguments that you didn't declare. The
latter case allows you to have temporary variables, local in scope to
the macro.
An example is the rel macro, which is defined as
rel 2 DEFINE 1 ($1) DEFINE 2 ($2) RELOCATE $1 $2
which allows you to specify expressions to the relocate command. For more examples see the `useful macros' section.
Newlines are allowed within macros, and as usual
any text from a # to the
next newline is taken to be a comment. If a # is needed within a
macro, escape the # with a \ or enclose it in double quotes.
If a macro starts with a comment the comment will not affect the
macro's speed of execution. Macros starting with ## are
treated specially by SAVE (they are not saved) and MACRO LIST
(they are not listed if VERBOSE is 0).
If the macro command is given as
MACRO name { DELETE }
or
MACRO name DELETE
the macro will be deleted (you can also delete a macro from the macro editor by specifying a negative number of arguments). If the name is already defined, it will be silently redefined. Macros may be nested freely, and even called recursively. For example, the definition
MACRO aa {aa}
is perfectly legal, but SM will go away and think about it
for ever if you ever type aa (or at least until you type ^C.)
The definition
MACRO zz { zz zz # comment: not recommended }
is also legal, but in this case if you execute it SM
will fill its call and macro stacks
and complain when it grabs more space. As
before, it will think about it forever. More useful examples of
recursive macros are compatible (see section Tips for Mongo Users), which starts
IF($?1 == 0) { compatible 1 RETURN } ...
providing a default value for its argument, and repeat which is
discussed under DO.
To find how a particular macro is defined, type HELP macroname.
For
a listing of the first line of all currently defined macros, type
LIST MACRO
or
LIST MACRO x y
The optional x and y are the alphabetical (actually asciial ) range of
macro names to list. As mentioned above, if VERBOSE is 0, macros
starting with ## are not listed by this command. There is a
macro ls defined as DELETE HISTORY LIST MACRO which will
list macros without appearing on the history list. (Or you could
overload list; see under overload in the index).
A related command is APROPOS pattern which lists all macros and
help files(12)
whose names or initial comments contain the pattern, for example
APROPOS histogram
would list bar_hist and get_hist as well as the
abbreviations hi and hist. If you wanted to find all
macros starting with a single comment character which mentioned
histogram you could say
APROPOS "^#[^#] .*histogram"
where the double quotes prevent the #'s being interpreted as
comment characters.
APROPOS ^[a-z]
will list all macros beginning with lowercase letters -- this is
similar to MACRO LIST a z, but pays no attention to the value of
VERBOSE.
It is also
possible to read macros in from disk, and in fact when SM is started,
it tries to read the file `default' in the directory specified by
macro in the environment file `.sm'. The command to read a
file of macros is
MACRO READ filename
Any line with a # in the first column is treated as a comment, and is
echoed to the terminal if VERBOSE is greater than zero.
All the currently defined macros may be written to a file with
the command
MACRO WRITE filename
If the file exists, it will be overwritten (under VMS, a new version of the file will be written). Macros are written out in alphabetical order.
The command
MACRO WRITE macroname filename
writes the macro macroname to the file filename.
This command remembers which file it last wrote a macro
to, and if the current filename is the same then it appends the macro
to the end of the file, otherwise it overwrites it (or creates a new
version under VMS)
unless the filename is preceded by a +,
in which case the macros will always be appended.
This allows a set
of related macros to be written to a file.
MACRO DELETE filename
undefined all macros which are defined in filename.
This allows a file of macros to be read in, used and forgotten again.
The difference between this command and MACRO macroname DELETE
should be noted.
The SAVE command is probably a better way of saving all current macros.
The format of macros on disk is name nargs text, where
nargs may be omitted if it is 0. Continuation lines start with a
space or tab. See the files in the directory specified by macro in your `.sm' file for examples.
It is possible to define macros from the history list. The command
MACRO name i j
defines a macro name to be lines i to j inclusive of the history list,
as seen using HISTORY.
The opposite of this command, which places a macro upon the
history list, is WRITE HISTORY name. Examples of these commands are the
macros playback and edit_hist given in the section `A
Simple Plot'. This way of defining macros can
be convenient if you have created a useful set of commands on the
history buffer, and now want to save it in a macro and go on to other things.
Editing the playback buffer, and then changing its name to something
else (see next paragraph) is a convenient way of saving it that
implicitly uses this command.
Macros may be edited, using essentially the same keys as described
above for the history editor.
The command MACRO EDIT name starts up the
editor, which works on one line at a time.(13)
The zeroth line has the format
0> Macro name : Number of arguments: n
where name is the name of the macro, and n is the number of arguments to the
macro. If this line is
changed, except to change name or n, any changes made to the
macro will be ignored (note that the space after name is
required). This can be useful if you decide that you
didn't want to make those changes after all. Changing name or
n has the obvious effect, except that if n is negative the
macro is deleted when you exit the editor. An empty macro is also deleted
when you leave the editor (i.e. one with no characters in it, not even
a space).
The first line that you are presented with is the first line in the macro
rather than this special one.
Use ^N (or
) to get the next line,
^P (or
) to get the previous line. Carriage return
(^M) inserts a new line before the cursor, breaking the
line in the process, while ^O inserts a new line before
the current line.
To save the
changes and return to the command interpreter use ^X.
All other
keys have the same meaning as for the history editor (e.g. ^A to
go to the beginning of a line).
Note that ^K and ^Y can be used to copy lines, and
that the bindings can be changed with EDIT or READ EDIT.
It wouldn't be hard to write a macro that wrote out a macro to a file,
invoked your favourite text editor, then read the new definition back
in; see the macro emacs_all for ideas.
It is sometimes convenient to define a key to be equivalent to typing
some string, such as playback or cursor. This can be done
with the KEY command, whose syntax is KEY key string.
If you just type KEY <CR> you'll be prompted for the key and
string. In this case you are not using the history editor to read the key,
and you can simply hit the desired key followed by a space and the
desired string, terminated by a carriage return. If you put KEY,
key and string on one line you'll probably have to quote
the key with ^Q or ESC-q, or write the escape sequences
out in the way used by EDIT. If this sounds confusing, here is
an example. Type KEY<CR>, then hit the PF1 key on your terminal,
type a space, and type "echo Hello World\N". Now just hit the
PF1 key and see what happens. (The closing \N meant `and put a newline
at the end'). These keyboard macros are not generally terminal
independent, but they can be convenient. Definitions for the `PF' keys
on your keyboard can be made in a terminal-independent way by
specifying the key as pfn or PFn where n is 1, 2, 3,
or 4.
If you always use the same
terminal you might want to put some KEY definitions in your private
startup file (see the discussion of startup2 in the section on
useful macros). The current KEY definitions are listed with the
LIST EDIT command, along with the other key bindings.
Related to the macro facility are the DO, FOREACH,
and WHILE commands.
IF is included here as a flow-of-control keyword.
The syntax for a DO loop is
DO variable = expr1 , expr2 [ , expr3 ] { command_list }
where the third expression is optional, defaulting to 1. The value of variable
($variable) is in turn set to expr1, expr1+exp3, ...,
expr2, and the
commands in command_list executed. Changing the value of $variable
within the command list
has no effect upon the loop. Do loops may be nested, but the name of
the variable in each such loop must be distinct. A trivial example
would be
DO val = 123, 123+10, 2 { WRITE STANDARD $val }
while a more interesting example would be
the macro square discussed in the section on examples.
For loops within macros, it's often a good idea to make the loop variable local: DEFINE val LOCAL DO val ... (see section Define).
Because the body of the loop must be scanned (and parsed) repeatedly, loops
with many circuits are rather slow. If at all possible you should try
to use vector operations rather than DO loops.
For example the loop
DO i=0,DIMEN(x)-1 {
SET x[$i]=SQRT(x[$i]) IF(x[$i] > 0)
SET x[$i]=0 IF(x[$i] <= 0)
}
is better written as
SET x=(x > 0) ? SQRT(x) : 0
where the ternary operator ?: is discussed in the section on vectors
(see section Vectors and Arithmetic).
As an alternative to DO loops, SM also has a general looping command, a
while loop, for example
set i=0
while {i < 10} {
commands
set i=i+1
}
is equivalent to a DO loop. In addition to being more flexible, WHILE loops may also be interrupted with the BREAK command, so the previous example could have been written (using variables instead of vectors)
define i 0
while{1} {
echo Hi $i
define i ($i+1)
if($i == 10) { break }
}
Foreach loops are similar to do loops, with syntax
FOREACH variable ( list ) { command_list }
,
FOREACH variable { list } { command_list }
, or
FOREACH variable vector { command_list }
where the list may consist of a number of words or numbers.
a vector.
Each element in the list (or of the vector) is in turn defined to be the
value of
$variable, and then the commands in command_list are executed,
so that for example the commands:
FOREACH i ( one 2 three ) { WRITE STANDARD $i }
SET str = {one 2 three}
FOREACH i str { WRITE STANDARD $i }
will print out:
one 2 three
twice.
Foreach loops may be nested, but again the variables must be distinct.
You can delimit the list with {} so that it can include
keywords (and other things that you want treated as strings such as 0.1
or $date), but even then you can't have the word delete in the
list of a foreach. Sorry.
It's often helpful to make the foreach variable LOCAL (see section Set)
inside macros, e.g.
DEFINE var LOCAL FOREACH var ...
If statements look similar, with syntax
IF ( expr ) { list } ELSE { list2 }
where the ELSE clause is optional, but if it is omitted the closing
} must be followed by a newline (or explicit \n)
(see section The Command Interpreter).
If the (scalar) expression is true (i.e. non-zero), then the commands
list are executed, otherwise list2 is, if present. It is also
possible to use IF statements directly in plotting commands, for
example POINTS x y IF(z > 1/x).
It is possible to write general loops in SM by using of tail-recursive macros. (14) The simplest example would be
macro aa {echo hello, world\n aa}
which prints hello, world and then calls itself, so it prints
hello, world and then calls itself, and so on until you hit ^C.
The absence of
a space before the closing brace is very important, as it allows SM to
discard the macro before calling it again, which means that it won't fill
up its call stack and start complaining. A more interesting example is
the macro repeat which repeats a given macro while the given
condition is true. For example, if you say
macro aa { set i=i+1 calc i }
set i=0 repeat aa while i < 10
it will print the integers from 0 to 9. With a few checks, bells, and whistles the macro looks like:
repeat 103 # Repeat a macro `name' while the condition is true
# syntax: repeat name while condition
# Example: set i=0 repeat body while i < 10
if('$2' != 'while') {
echo Syntax: $0 macro while condition
return
}
if(int((whatis($1)-4*int(whatis($1)/4))/2) == 0) {
echo $1 is not a macro
return
}
macro _$1 {
if(($!!3) == 0) { return }
$!!1
_$!!1}
_$1
macro _$1 delete
and is one of SM's default macros (type "help repeat" if you don't believe me).
There is an online help command. Typing HELP <CR>
or HELP HELP
gives a list of the help menu, or HELP keyword gives help with that keyword.
The help menu consists
of any files in the directory specified by the entry help
in the environment file, so for example HELP data types
the file data in that directory. For all cases except HELP help, the
file is filtered through a version of the Unix utility `more' which pages
the file. When `more' offers you a `...' prompt, type ? to see your
options.
The same filter is used by e.g. LIST MACRO .
If the command is HELP word, after HELP tries to print the file
word, it looks to see if word is a macro, and if so prints
its definition. If word is a variable, its value is then
printed, and if word is also a vector HELP
prints the dimension, followed by the help
string associated with the vector
vector_name (see section on vectors).
The APROPOS command is also useful when you need help.
APROPOS string scans all the help files (if your operating
system allows SM to do such things) and macro headers looking for the
string. The string may actually be a pattern (see the description
of APROPOS for details). If VERBOSE
(see section Verbose) is zero only
the lines from the help files matching the pattern are printed; if
it is larger you are given a couple of lines of context on each side.
It is worth remembering that the index to this manual has an entry
under weird, wherein are listed all sorts of strange happenings,
with explanations and suggestions for workarounds.
If for some reason you want to stop a SM session for later
resumption, and simply suspending the process, `^Z', is not
sufficient, (for instance the machine is going down), then the SAVE command will write a file containing all your currently defined
macros, variables, and vectors, along with your current history buffer
as the macro all. You will be prompted before each class of
objects is saved, or you can put the answers on the command line.
The file is ascii, and can be edited if you so
desire. The filename defaults to `sm.dmp' if not specified, or to
the value of save_file from your `.sm' file.
If some bug has crawled unbeknownst to us into SM, and results
in some sort of panic (such as a segmentation violation), a save file
called `panic.dmp' is written to your temporary directory, no
questions asked.
To restart, RESTORE filename will read them all back, using the
same default file as for SAVE if no filename is specified, and
replace the current history buffer with the value of all
from the savefile. Of course, you could write a macro to preserve the
current buffer (see the definition of edit_all for hints).
If the file wasn't written by SAVE it is assumed to be a
SM history file, one of those written when you quit SM, and
each line is assumed to be a command and written to the end of the
history buffer. This is generally useful when you started SM
in the wrong directory. It wouldn't be hard to write a macro to use
RESTORE to read a history file into a macro.
One problem with SAVE is that it saves lots of macros,
including some of the system ones. Specifically, all macros are saved
except those beginning with "##".
This can be avoided with
the MACRO DELETE filename command, e.g. MACRO DELETE utils
SAVE 1 1 1 MACRO READ utils.
The macro sav discussed under `useful macros' will do this for
you, and indeed not SAVE any macros that have been read with the
load macro. This is probably the best way to use the SAVE
command. In addition, sav also decides to save variables and
macros, only prompting you about saving vectors. sav is a good
candidate for overloading (as save), and indeed is one of the
macros redefined by the set_overload command.
The basic unit of data in SM is the `vector', a named set of one or more numbers or strings. There is no limit to the number of vectors that may be defined. SM allows the user to read vectors from files or define them from the keyboard, to plot them and to perform arithmetic operations upon them. SM's string-valued vectors are less generally useful, but can be used for such purposes as labelling points on a graph.
To read a vector vec from a column of numbers in a file, where the
filename has been specified
using DATA and, possibly, the range of lines in the file to be used
has been specified using the
LINES command, use READ vec nn where nn is the column number,
or READ { vec1 n1 vec2 n2 ... } to read many vectors.
It is also possible to read a row, using READ ROW vec nn, where nn is
the row number in the file. See READ for how to read a
string-valued vector.
Instead of using simple column-oriented input
it is possible to specify a format like those used by C's scanf
functions (Fortran formats are not supported); if you provide your own
format string you can only read numbers.
For example, if your data file has lines like
1:12:30 -45:30:11
you could read it with
read '%d:%d:%d %f:%f:%f' { hr min sec deg dmin dsec }.
A vector may also be defined as SET vec = x1,x2,dx to take on
the values x1,x1+dx,...,x2, where dx defaults to 1
if omitted. If a scalar is
encountered where a vector is expected, it is promoted to be a vector
of the appropriate dimension; all other dimension mismatches are
errors. Example:
SET value = 5 SET x = 0, 50, 2 SET y = x SET y = x*0 + value SET y[0] = 2*pi SET y = value SET x=0,1,.1 SET y=IMAGE(x,1.5) SET s=str SET s='str' SET s[0]=1.23 SET x=1.23 SET s=x SET s=STRING(x)
will define a scalar, value, with a value of 5, then define a vector,
x, with 26 elements, valued 0, 2, 4, 6,..., 50, then define another
vector, y with size 26 and the same values as x,
set all 26 elements of y to have the value 5,
set the first element of y to be 2 pi,
set y
to be a vector with one element with value 5, and finally
set y to be a vector with the values taken from a horizontal
cross-section from 0 to 1 through the current image. Unless a vector
str is defined SET s=str is an error; to make s a
string-valued vector use SET s='str'.
SET s[0]=1.23 makes s[0] have the value "1.23" (a string),
as s is now a pre-existing string vector.
An arithmetic vector x is then
defined, and s is redefined as an arithmetic vector too -- you must
be careful when dealing with string vectors! Finally, we explicitly
convert an arithmetic vector to a string-valued one with the STRING
operator.
This is a somewhat
contrived example, designed mainly to illustrate the convenience of the
SET command. The ability to set particular elements is mostly
used in macros such as smirnov2 which calculates the
Kolmogorov-Smirnov statistic from a pair of vectors.
If you don't have many data points, rather than type them into a file, and use
READ vec nn to define a vector, you can use the command
SET vec = { list }
For example
SET r = 0,10
is equivalent to
SET r = { 0 1 2 3 4 5 6 8 9 10 }
In fact, { list } is an expression, so
SET vec = 2*{1 3 1} is also legal.
If the first element of a list is a word, the vector is taken to be
string-valued: SET s={ William William Henry Steven } defines a
4-element string vector, or you can use a string in quotes:
SET s=<'1' 2 3 4> (if you used SET s={'1' 2 3 4} the first
element would be '1' rather than 1).
Once a vector is defined, you can write it to a file for later study using the
PRINT command.
A scalar may be an integer, a floating point number, a scalar
expression, DIMEN(vector), or WORD[expr]. The last two are the
dimension of a vector, and an element of the vector with expr a
scalar subscript. Note that subscripts start at 0 and that [ ]
`not' () are used to subscript variables.
The expression WORD[expr] is in fact allowed even if expr
is not a scalar, in which case the result is a vector with the same
dimension as expr, and with the values taken from WORD in
the obvious way.
Once vectors are defined, they may be combined into expressions using
the operators +, -, *, /, **,
CONCAT and the
functions COS(), SIN(), TAN(), ACOS(),
ASIN(), ATAN(), ATAN2(), ABS(), DIMEN(), INT(), LG(), EXP(), LN(),
SQRT(), STRING(), STRLEN(), and
SUM().
The meaning of most of these is obvious, ATAN2 is like ATAN
but takes two arguments, x and y and returns an angle in the
proper sector.
DIMEN returns the number of
elements in a vector, SUM gives the sum of all the elements,
CONCAT concatenates two vectors,
INT gives the integral part of a vector, STRING
converts a number to a string, and STRLEN gives the length of a string
(in plotting units, not just the number of characters). STRING uses
the same code as the axis-labelling routines, so FORMAT can be used
to modify its behaviour; whether the x- or y-axis formats is used depends
on whether the label is more nearly horizontal or vertical.
An example would be
set x=3.08e16 define s (string(x)) relocate 0.5 0.5 putlabel 5 $s
The precedence and binding are
as for C (or Fortran), and may be altered by using parentheses
(CONCAT has a binding just below + and -).
All of these operators work element by element, so
y = 2 + sin(x)
is interpreted as
If there is a size mismatch the operation will only be carried out up
to the length of the shorter vector and a message is printed; if
VERBOSE is 1 or more, the line where the error occurred will
be printed too.
The constant PI is predefined.
You can also use WORD([ expr [ , ... ]]) as part of
an expression, where WORD is a macro taking zero or more arguments.
Suppose we define a macro pow with two arguments as
SET $0 = $1**$2
then the command
SET y = 10 + 2*pow(1 + x,3)
is equivalent to SET y = 10 + 2*(1 + x)**3.
(15)
In addition to these arithmetic operations, there are also logical
operators == (equals), != (not equals),
>, >=, <, <=, &&
(logical and), and || (logical or). The meanings of the symbols are the
same as in C, and as in C the value 0 is false while all other values are true.
String vectors may only be concatenated, added, or tested for (in)equality. Adding two string-valued vectors concatenates their elements, so
{ a b c } + { x y z }
results in the vector ax by cz.
Testing equality for string vectors seems to cause some confusion. Consider
set str=<'a' b c d>
if('a' == 'str') { # test if the strings `a' and `str' are equal
if('a' == str) { # test if the string `a' equals the vector `str'
if(a == str) { # test if the vector `a' equals the vector `str'
The second of these tests will succeed, but if you then try
if('b' == str) { # try to see if `b' is an element of str
the test will fail as 'b' == str is the 4-element vector
{ 0 1 0 1 } and only its first element is used by the if test;
what you want is
if(sum('b' == str)) { # is `b' an element of str?
There are also a number of less mathematical operations. If you have an
IMAGE (see section Image) defined, you can extract a set of values
using the expression IMAGE(expr,expr), where the two exprs
give the coordinates where the values are desired. Note that this may be
used as a way of reading large data files that are stored unformatted.
The expression HISTOGRAM(expr : expr) can be used to convert a
vector into a histogram. The second expression is taken to be the
centres of the desired bins: bin boundaries are taken at the mean points
(and points in the first expression lying on a boundary are taken to
fall into the lower bin. Note the use of `:' not `,').
Vectors may be assigned to, using the syntax
SET vec = expr
or
SET vec[ expr ] = expr
or
SET vec = WORD(expr)
or
SET DIMEN(vec) = number
or
SET vec = expr1 IF(expr2)
or
SET vec = expr1 ? expr2 : expr3
The first form sets vec to have the value expr, element by
element, vec is the name of the new vector. The form
vec[expr] may be used to assign to an element of a vector, as usual
the index starts at 0. Before you can use SET to assign values to the
elements of a vector, you must create it using one of the other forms
of the SET command.
If you want to define a vector to which you will subsequently assign values
using SET vec[ expr ] = expr, you may use SET DIMEN(vec) = number
which declares vec to be a vector of size number, and
initialises it to zero. You can optionally supply a qualifier to the
number, either a .f (the default), or a .s to
specify that the vector is string valued.
If the IF clause is present, only those
elements of expr1 for which the corresponding element of expr2 is
true
(non-zero) are copied into vec; in general vec will have a
smaller dimension than expr1. The last SET statement (with ?:)
again borrows
from C. If expr1_i is true, then vec_i is set
to expr2_i, otherwise it is
set to expr3_i. In this form of conditional assignment, the dimension
of vec is the same as that of the right hand side. It may look
strange, but it can be just what you want.
Each vector also has a help field, which may be used to provide a string describing the vector. The field is set by
SET HELP vec str
and viewed by
HELP vec
or via the string-valued expression HELP(name).
If VERBOSE is one or more, if a vector is arithmetic or string
will also be noted. Vectors may be printed using the
PRINT [ file ] [format] { vec1, ..., vecn }
command, where if the optional
file is missing, the values are typed to the keyboard; if the
optional format is omitted, a suitable one will be chosen for you.
Any combination of string- and arithmetic-vectors may be printed.
If a value
exceeds 1e36, it is printed as a *. This is consistent with the
convention used in reading data that a `missing' number is represented
as 1.001e36; see READ for details.
Vectors may be deleted with the command
DELETE vec
and listed with the command
LIST SET
Vectors are listed in ascii order along with their
dimension, and any help string specified using the SET HELP command
Once you start writing (or using) complicated macros you'll get bitten by
the fact that a macro called by a macro called by a friend's macro uses
a scratch vector called x or i, and that this vector quietly
overwrites your vector called x or i. To avoid this,
conscientious macro writers make their vectors LOCAL.
(16).
After the command SET x LOCAL in a macro, any redefinitions of x
within that macro, or any macros called by it, will be discarded when the
macro exits. The vector isn't strictly speaking local to the macro as it's
visible from macros that are more deeply nested, but the effect is similar.
A word on caution: a macro can exit sooner than you expect; the classic
example is
cube 11 # print a vector's cube for people we like
define name local define name :
if('$name' != 'Thatcher') {
set x local set x = $1
set x = x*x*x
print The answer is $(x)
}
Because the if might be followed by an else, the macro is
read and popped from the input stack before it's executed, causing
confusion.
An IF clause has been
added to the plotting commands, to allow only those elements of a
vector which satisfy some condition to be plotted, for example
POINTS x y IF(z > 3*x)
Of course, you could have used the IF command and the regular
POINTS command if you had preferred. In fact,
CONNECT x y IF(z > 3*x)
isn't quite the same as
SET log = z > 3*x SET x = x IF(log) SET y = y IF(log) CONNECT x y
as the former will only connect contiguous points.
There are two separate ways to specify special characters to
SM, by using a syntax
very similar to TeX (the type-setting system created by Donald Knuth
that we used for this manual), or the traditional Mongo way. You might
ask what are the advantages
of TeX? One is that sub- and super- scripts are handled much more naturally,
making it much harder to type
when you meant
Another is that you no longer have to remember that
is hidden
in the Greek font as `q', you can simply type \theta. A
third would be that you may well know TeX already.
If you want to make SM understand TeX strings
you should define the variable
TeX_strings (if you put a line
TeX_strings 1 in your `.sm' file this will be done automatically).
You can, of course, undefine it at any time to revert to the old-fashioned
strings described below.
Using TeX-style
strings is strongly recommended by the authors; all future and most
recent improvements to SM's labels are only supported in TeX mode.
If you want to change the default font used for labels, define the variable
default_font; if you wanted to use the \oe (Old English)
font you could either say (DEFINE default_font oe) interactively,
or put a line in your `.sm file': default_font oe.
This affects axis as well as regular labels and
only works if you use TeX_strings (of course).
For some devices with hardware fonts (for example, postscript printers
or a Tektronix 4010 terminal), if expand is exactly 1, and
angle is exactly 0, the hard fonts will be used for speed.
Various strategies to defeat this are discussed below.
(TeXsperts should skip this section.) If you don't know TeX let's start with an example:
label \pi^{\-21/2} = {\3\int}e^{-x^2}\,dx
will print a well-known result (You'll have to RELOCATE somewhere
where the label will be visible first, of course).
(If
you want to try it now, you should be careful typing those ^'s, as
they are special to the history editor, dealing with this is
discussed below.) In
this example the characters \, {, }, and ^
are special (and so is _ which wasn't used). Postponing \
for the moment, ^ means `make the next group a superscript',
_ means `make the next group a subscript', where a group is
either a single character, a single control sequence (wait a moment!), or a
string enclosed in braces. So A_a^{SM}B would appear as
A \ can serve one of two functions, either
turning off the special meaning of the next character (so \_
is simply a _ with no special significance), or to introduce a
named `control sequence'. These fall into three groups, those that
change fonts, those that serve as abbreviations for single
characters (e.g. \pi in the example), and those that are macros.
The font changes persist
until the end of the string, or the current group, whichever comes
first.
The available fonts are
`greek', `old english', `private', `roman', `script', and `tiny'. They
may be referred to either by a
two-character control sequences (\gr, \oe, \pr,
\rm, \sc, or \ti) or simply by the first character
(e.g. \r for the roman font).
In addition \i or \it
can be used to make the current font italic (remember to use italics
within {} so that their effect is limited!).
The `bold' font \b or \bf is makes the current font bold,
and can be toggled off with a second
\bf if you didn't simply group it. I'd strongly recommend
treating \bf like any other font change, and
group them rather than relying on this toggling action.
The slant of \it letters can be controlled by the command sequence
\slant, which takes an argument which is the tangent of the desired
slope (i.e. it is the degree of shear). You can also compress all letters
along the direction that they are being written using \condense; for
example {\slant0.4\condense0.5 Hello World}.
You can alter the size of the letters
by using an escape such as \6 which scales the current group
(any font change is local to a group).
\6 corresponds to multiplying the size by
or
about 3, \-4 scales by
or 0.48. This is similar to
the `magstep' used in scaling fonts in TeX.
These scale factors
are in addition to the expansion produced by going
up or down (^ or _), or setting EXPAND.
Other control sequences either consist of one non-alphabetic
character, or else a name consisting only of letters, so \, or
\palmtree is valid but \one2three is not. If a
alphabetic name is followed by a space, the space is treated as simply
delimiting the name and is discarded. For example,
AB^{\alpha_\beta CD} will appear as
(note that the space after beta disappeared). How do you make
just a few characters italic (script, old english, etc.)? Try
ABC{\it DEF}GHI. You can't read a subscript, and want it in
`tiny' font? Try \Lambda_{\ti ab}. All of the Greek letters are
defined, as \alpha-\omega,\Alpha-\Omega,
there are various mathematical symbols (e.g. \int, \infty,
or \sqrt), some astronomical (e.g. \AA for
and some
miscellaneous characters (e.g. \snow to draw a snowflake).
You can generate
a complete list of definitions by saying load fonts TeX_defs.
Some of these definitions are more complex than just special characters, if you know TeX most of them should be familiar.
\bar str
str.
\border n str
str and draw it.
\centre
\center
\over str1 str2
str1 over str2, separated by a horizontal line. This isn't
nearly as sophisticated as TeX's \over, and never will be.
It's written in SM's TeX emulator which is pretty limited. If you are
a LaTeX user, SM's \frac may be more familiar.
\phantom str
str, but take up as much space as str
would have if you had drawn it.
\smash str
str but pretend that it took up no space.
\strut
You can also define your own TeX definitions by using the special
command \def\name{value} inside a label. It produces no output,
but defines name to expand to value. For example, I could define
\TeX to produce TeX by saying
LABEL \def\TeX{T\raise-200\kern-20E\raise200X}.
Once a
definition has been made it is remembered forever (well, until you
leave SM actually) whatever devices you plot on. You must make sure that
all curly brackets are properly paired inside your definition. You
can have arguments just like real TeX, referred to as #1,
#2, #3 and so forth, for example
\def\sub#1{_{#1}}
Your SM guru can compile TeX-definitions into the binary fonts file, instructions are given in the fonts appendix.
We have made a number of extensions to TeX that are useful in a plotting package, but wouldn't be especially valuable in a printed document. We have also distorted the meanings of some of TeX's control words; sorry.
\point n s
\apoint angle n s
DOT) into a label. The
string \point43 (or \point 4 3) will draw a point at the
current position in the string, of ptype `4 3'. This sequence,
from the \ to the 3, is treated as a single character as regards
things like subscripts. If you want to specify an angle, use something like
\apoint 45 4 0.
\hrule width
width in screen units. It will be multiplied by the current
expansion.
\kern dx
\kern # moves the current plot position by #
horizontally, where the distance
# is specified in screen units (the whole screen is 32768
across). It is multiplied by the expansion currently in effect, and may be
positive or negative. See also \raise.
\line type length
\line inserts a line into a label, at about the level of the
middle of a lower-case character.
e.g. \line 1 1000 will draw a line of length 1000 (in screen
units, so the screen is 32768 across), of ltype 1.
See also \hrule.
\move dx dy