SM

Edition 2.4.0 (pre-release), July 1996

by Robert Lupton and Patricia Monger


Table of Contents


Introduction

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.

Description of SM

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.

A simple plot

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.

Facilities within the Command Interpreter

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.

String Variables

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
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 { }. 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.

Command History

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
Go to start of line.
^B
Go back one character. (Equivalent to ).
^C
Interrupt (as usual).
^D
Delete character under cursor.
^E
Go to end of line.
^F
Go forward one character. (Equivalent to ).
^H
Identical to ^? (DEL). Delete character to left of cursor.
^I (TAB)
Insert spaces up to the next tab stop. By default a tab is taken to be 8 characters wide, but this may be changed by specifying tabsize in your `.sm' file.
^J (LF)
Equivalent to ^M.
^K
Delete to end of line. The deleted string is stored, and may be restored using ^Y, repeatedly if so desired.
^L
Redraw the current line.
^M (CR)
Send line to be executed. Some terminals seem to replace ^M with a linefeed (^J), thereby making it impossible to make SM obey you. We therefore make ^@ equivalent to ^M for emergency use. (This is control-space on many terminals).
^N
Get the next command on the history list, if it exists (see ^P). (Equivalent to ).
^O
Execute the previous command on the history list. Equivalent to ^P^E^M.
^P
Get the previous command on the history list, if it exists (see ^N).(Equivalent to ).
^Q
Quote next character; Turn off any special significance to the editor. ^Q is often used by the terminal, so we have defined ^[-q (that is escape followed by q) as an alternative.
^R
Search backwards (reversed) for a string; the opposite of ^S. The `string' can actually be any regular expression (see the manual entry for APROPOS). If you specify a zero-length string (i.e. simply hit carriage return) the previous search string will be reused.
^S
Search forward for a string; the opposite of ^R. ^S is often used by the terminal, so we have defined ^[-s (that is escape followed by s) as an alternative.
^T
Toggle insert/overwrite. By default, characters are inserted before the cursor. If overwrite is set, they replace the character under the cursor. Note that ESC-u will not correctly restore words deleted with ESC-d in overwrite mode.
^U
Delete from the cursor to the start of the line.
^V
Go forward 5 lines.
^W
Delete the previous word. Identical to ESC-h
^Y
Insert the string most recently deleted with ^K after the cursor.
^Z
Return to the operating system, without killing SM. (Under VMS, if you are running SM in a spawned subprocess ^Z will attach you to DCL. Otherwise, SM returns you to DCL.)
^? (DEL)
Equivalent to ^H.
ESC-^D
Delete this line and remove it from the history list. Note that this is different from just clearing a line with (e.g.) ^U, which only erases a copy of the line.
ESC-<
Go to the first line of a macro, or the oldest history command.
ESC->
Go to the last line of a macro, or the most recent history command.
ESC-g
Go to a given line of a macro, or a given history command. You'll be prompted for the line number, if you change your mind you can get out with DEL or ^H.
ESC-q
Quote the next character, turning off any special significance to the editor. Identical to ^Q.
ESC-s
Search forward for a string. Identical to ^S.
ESC-v
The opposite of ^V, go back 5 lines.
ESC-y
Like ^Y, except that it gets older deletions, cycling back through a collection of (currently 5) deleted lines.

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
Go to the start of the previous word.
ESC-d
Delete to the beginning of the next word.
ESC-f
Go to the beginning of the next word.
ESC-h
Delete back to the beginning of the current word. The same as ^W.
ESC-u
Restore the last word deleted, putting it before the cursor. Further 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.

Changing Key-Bindings

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
start_of_line
^B
previous_char
^C
^D
delete_char
^E
end_of_line
^F
next_char
^G
illegal
^H, DEL
delete_previous_char
^I
tab
^J
carriage_return
^K
kill_to_end
^L
refresh
^M, ^@
carriage_return
^N
next_line
^O
insert_line_above
^P
previous_line
^Q, ESC-q
quote_next
^R
search_reverse
^S
search_forward
^T
toggle_overwrite
^U
delete_to_start
^V
scroll_forward
^W, ESC-h
delete_previous_word
^X
exit_editor
^Y
yank_buffer
^Z
attach_to_shell
ESC-<
first_line
ESC->
last_line
\034
escape
ESC-b
previous_word
ESC-d
delete_next_word
ESC-f
next_word
ESC-g
goto_line
ESC-u
undelete_word
ESC-v
scroll_back
ESC-y
yank_previous_buffer
ESC-^D
delete_from_history
^
history_char

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.

Talking to the Operating System

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.

Macros

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.

DO and FOREACH loops, WHILE loops, and IF statements

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).

The Help Command

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.

Saving and Restoring a Session

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.

Vectors and Arithmetic

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.

Drawing Labels and SM's TeX Emulation

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.

An Introduction to TeX

(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.

Available Fonts

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.

SM's TeX Control Sequences

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
Draw a bar over str.
\border n str
Add an n-pixel border of whitespace to str and draw it.
\centre
\center
Center a string horizontally
\over str1 str2
Draw 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
Don't actually draw str, but take up as much space as str would have if you had drawn it.
\smash str
Draw str but pretend that it took up no space.
\strut
Make the current formula have at least the depth and height of a parenthesis.

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.

SM's Extensions to TeX

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
Insert a points (such as would be drawn with 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
Draw a horizontal line at the level of the current baseline, of length 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