@node Useful Macros, Quoting, Overloading, Top @chapter Examples of Useful Macros @findex startup, system initialisation macro @findex examples, macros When you start SM the directory specified as @code{macro} in your @file{.sm} file is searched for a file @file{default}, and then the macro @code{startup } from that file is executed. At the time of writing of this manual, @code{startup} was defined as: @example startup ## macro invoked upon startup FOREACH 1 @{ default_font device edit file_type history_char \ macro macro2 overload printer prompt prompt2 SHELL @} @{ DEFINE $1 : @} FOREACH 1 @{ TeX_strings case_fold_search fan_compress \ line_up_exponents noclobber overload \ remember_history_line traceback uppercase @} @{ DEFINE $1 : IF($?$1) @{ IF('$$1' == '0') @{ DEFINE $1 DELETE @} @} @} IF($?prompt) @{ PROMPT $prompt\n DEFINE prompt DELETE @} ELSE @{ PROMPT : @} IF($?device) @{ DEVICE $device @} ELSE @{ DEFINE device nodevice @} IF($?default_font && $?TeX_strings == 0) @{ echo You can only define a default font if you use TeX @} IF($?history_char) @{ # use $history_char as history character IF('$history_char' != '0' && '$history_char' != '1') @{ EDIT history_char $history_char @} EDIT ^ ^ DEFINE history_char DELETE @} # load the default macros DEFINE mfiles < stats utils > # $mfiles is used by `sav' FOREACH f ( mongo $mfiles ) @{ MACRO READ "$!macro"$f @} FOREACH var ( x_col y_col data_file ) @{ DEFINE $var . @} # load uppercase if defined in .sm file IF($?uppercase) @{ MACRO READ "$!macro"uppercase @} # and overload keywords such as erase, if so desired set_overload $?overload # and some keymaps IF($?edit) @{ READ EDIT "$!edit" @} # and an optional macro file, with macro startup2 IF($?macro2) @{ MACRO READ "$!macro2"default IF(is_set(startup2,1)) @{ startup2 @} # startup2 is defined @} # provide a \n after the IF @end example @noindent As this macro is executed every time that you run SM, let us consider it in some detail. After setting the prompt, it looks for entries for a number of variables in your @file{.sm} file. Some (such as @code{printer}) are simply @code{DEFINE}d, while some (such as @code{TeX_strings}) are only @code{DEFINE}d if they have a non-zero value. Because some of the values might not be numeric, the comparison is forced to be done on strings by enclosing the quantities in single quotes. An entry @code{prompt} is interpreted as a primary prompt, mostly for compatibility with the use of @code{$prompt2} to set the secondary prompt. If @code{device} is defined it is used to set the default plotting device, and both it and @code{printer} are used by a couple of macros (@code{hcopy} and @code{hmacro}) that produce hardcopy. The variables @code{TeX_strings} and @code{default_fonts} are used in producing labels (@pxref{Fonts}). Because @TeX{} uses @code{^} for superscripts, we allow you to put a @code{history_char} line in @file{.sm} to specify a character to use rather than @code{^} for history (I use @code{`}). If you use @code{0}, or omit the value (so it is set to @code{1}), no history character is defined to replace @code{^}. The variable @code{file_type} is used by the @code{IMAGE} command to determine the file format that you use (e.g. C, or unformatted fortran). @code{Startup} doesn't have to check that @code{macro} was successfully defined as it must have been found for @code{startup} to have been read in the first place. @code{Macro} specifies where to look for macro libraries, and @code{startup} next sets the variable @code{mfiles} containing the names of some of @findex variables, mlist the system macros to be loaded, and reads them. The macro @code{load} defined below also maintains the @code{mfiles} list, as does @code{unload}. It is used by the @code{sav} macro, which is discussed below the main listing of macros that follows. We also set some variables used by the @code{id} macro. As part of our effort to be nice to users, if you have @code{uppercase 1} in your @file{.sm} file, we also load the @code{uppercase} macros. Next @code{startup} overloads some keywords if @code{overload} is in your @file{.sm} file, reads a file of keybindings (if @code{edit} is given in @file{.sm}), and finally tries to read a second optional macro directory @code{macro2}, and executes a macro @code{startup2} if it's defined (that's what the macro @code{is_set} is checking). This is quite important, as it provides a way to customise SM to your personal taste without convincing the local SM guru that your taste should be foisted on everyone. If you want a prompt that is different, or a definition of @code{q} that just quits without asking questions, you can get them by using @code{macro2}. @findex customising SM @findex startup2, private startup macro @findex private initialisation @findex startup, private macros You can see that it is possible to tailor SM pretty much as you wish without changing a line of code, just by playing with the @code{startup} macro. SM provides various compatibility macros, and some to package often-used functions. The macro files @file{stats} and @file{utils}, which are read when SM is started, provide various useful macros, a few of which are presented here. To see a current list, either look at the files directly, set @code{VERBOSE} to zero and list all the macros, look at the listing in this manual (@pxref{Libraries}), or use @code{lsm} to list macro files (this only works if you are running Unix; try @code{lsm demos}). We give here a number of macros taken from the files @file{default}, @file{mongo}, @file{stats}, and @file{utils}. Among those not listed are those like @code{lin} defined to be @code{lines} that are pure abbreviations, those like @code{xlogarithm} defined as @code{SET x=lg(x)} which provide functionality in a perhaps familiar form, and many more like those that are given here which provide enhancements (e.g. the macro @code{barhist}). A discussion of a few of the more interesting or obscure follows. Keywords are written in uppercase, because you might have been playing tricks with overloading the lowercase equivalents. Many of these macros, in fact all from @file{default} and @file{mongo}, start with @code{##} so as not to show up in listings made when @code{VERBOSE} is 0, and so as not to be @code{SAVE}d. In the interest of brevity we have omitted most of these initial comments. @findex macros, examples @example cumulate 2 # Find the cumulative distribution of $1 in $2 DEFINE sum 0 SET $2=0*$1 SET HELP $2 Cumulation of $1 DO i=0,DIMEN($1)-1 @{ DEFINE sum ( $sum + $1[$i] ) SET $2[$i] = $sum @} define sum delete da 1 DATA "$1" del1 1 DELETE HISTORY \n dev 1 del1 DEFINE device $1 DEVICE $1 dra 2 # Draw, accepting expressions define 1 ($1) define 2 ($2) draw $1 $2 edit_hist # Edit the history list del1 MACRO all 0 100000 # define "all" from buffer WRITE STANDARD Editing History Buffer\n MACRO EDIT all # do the editing DELETE 0 100000 # empty history buffer WRITE HISTORY all # replace history by "all" era del1 ERASE gauss 1 # Evaluate a Gaussian : N($mean,$sig) SET $0 = 1/(SQRT(2*PI)*$sig)*EXP(-(($1-$mean)/$sig)**2/2) get 2 # Syntax: get i j. Read a column from a file. # Name of vector is jth word of line i. DEFINE nn READ $1 $2 echo reading $nn\n READ $nn $2 SET HELP $nn Column $2 from $data_file DEFINE nn DELETE hardcopy DEVICE nodevice # close old device hcopy 13 ## hcopy [printer] [l1] [l2] Make hardcopy of playback buffer # optionally specify printer ($1) and desired lines ($2-$3) # if the printer ($1) is omitted (i.e. $1 is missing or a # number), it will be taken from the value of the environment # variable PRINTER, if defined. IF($?printer == 0) @{ DEFINE printer ? @{ what kind of printer? @} @} IF($?1) @{ IF(WHATIS($1) == 0) @{ # a number if($?2) @{ DEFINE 3 $2 @} DEFINE 2 $1 DEFINE 1 DELETE @} @} IF($?1) @{ DEVICE $printer $1 @} ELSE @{ IF($?PRINTER == 0) @{ DEFINE PRINTER : @} # which one? IF($?PRINTER) @{ DEVICE $printer $PRINTER @} ELSE @{ DEVICE $printer @} @} IF($?2 == 0) @{ DEFINE 2 0 DEFINE 3 10000 @} ELSE @{ IF($?3 == 0) @{ DEFINE 3 $2 @} @} playback $2 $3 \n DEVICE $device bell hmacro 12 ## hmacro [macro] [printer] Make hardcopy of a macro # If only 1 argument is present, it is taken to be the printer # unless an environment PRINTER variable is defined, when # that's used as a printer, and the argument is taken to be # a macro. If no macro is specified, make a temp one IF($?printer == 0) @{ DEFINE printer ? @{ what kind of printer? @} @} del1 IF($?2 == 0) @{ # only one arg IF($?PRINTER == 0) @{ DEFINE PRINTER : @} IF($?PRINTER) @{ DEFINE 2 $PRINTER @} @} IF($?1) @{ if($?2) @{ # 2 args DEFINE _mac $1 DEFINE _temp 0 # no temp macro @} ELSE @{ # 1 arg, take as printer DEFINE 2 $1 # printer DEFINE _temp 1 # need temp macro @} @} ELSE @{ # no $1 IF($?2 == 0) @{ DEFINE 2 " " @} DEFINE _temp 1 # need temp macro @} IF($_temp) @{ DEFINE _mac _mac echo "Create temporary macro, exit with ^X" MACRO EDIT $_mac IF(is_set($_mac,1) == 0) @{ DEFINE _mac DELETE DEFINE _temp DELETE DEFINE _test DELETE RETURN @} @} DEVICE $printer $2 $_mac \n DEVICE $device IF($_temp) @{ MACRO $_mac DELETE @} DEFINE _mac DELETE DEFINE _temp DELETE bell load # load macros in default directory DEFINE macro : # get default directory MACRO READ "$!macro"$1 # read macro file IF($?mfiles == 0) @{ DEFINE mfiles $1 @} ELSE @{ DEFINE 3 0 FOREACH 2 ( $mfiles ) @{ IF('$2' == '$1') @{ DEFINE 3 1 @} @} IF($3 == 0) @{ DEFINE mfiles < $mfiles $1 > @} @} load2 1 # load macros in (second) default directory DEFINE macro2 : # get directory IF($?macro2) @{ MACRO READ "$!macro2"$1 # read macro file @} ELSE @{ echo Directory macro2 is not defined @} logerr 3 # logerr x y error, where y is logged, and error isn't SET _y = 10**$2 SET d_y = LG(_y + $3) - $2 ERRORBAR $1 $2 d_y 2 SET d_y = $2 - LG(_y - $3) ERRORBAR $1 $2 d_y 4 DELETE _y DELETE d_y lsq 15 # do a least squares fit to a set of vectors # syntax: lsq x y [ x2 y2 [rms]] Fit line y2=$a*x2+$b to x y # optionally, calculate rms residual as $rms # see rxy to find product moment correlation coeff, # and spear for Spearman's corr. coeff., and significance SET _n = DIMEN($1) # number of points SET _sx = SUM($1) # sigma x SET _sy = SUM($2) # sigma y SET _sxy = SUM($1*$2) # sigma xy SET _sxx = SUM($1*$1) # sigma xx DEFINE a ( (_n*_sxy - _sx*_sy)/(_n*_sxx - _sx*_sx) ) DEFINE b ( (_sy - $a*_sx)/_n ) IF($?3 && $?4) @{ SET $4=$a*$3+$b IF($?5) @{ DEFINE $5 ( sqrt(sum(($a*$1 + $b - $2)**2)/dimen($2)) ) @} @} FOREACH v ( _n _sx _sy _sxy _sxx ) @{ DELETE $v @} playback ## define "all" from buffer, and run it # with args, only playback those lines IF($?1 == 0) @{ DEFINE 1 0 DEFINE 2 10000 @} ELSE @{ IF($?2 == 0) @{ DEFINE 2 $1 @} @} del1 MACRO all $1 $2 all read_old 1 del1 # read a Mongo file onto the history buffer READ OLD temp $1 WRITE HISTORY temp MACRO temp @{ DELETE @} rel 2 # Relocate, accepting expressions define 1 ($1) define 2 ($2) relocate $1 $2 reverse 1 # reverse the order of a vector SET _i = DIMEN($1),1,-1 SORT < _i $1 > DELETE _i sav 1 # Save to a file $1, don't save from files `$mfiles' _save $1 _save 1 # Save to a file $1, don't save from files `$mfiles' del1 FOREACH 2 ( $mfiles ) @{ MACRO DELETE "$!macro"$2 @} DEFINE 2 0 define 2 ? @{ save vectors? @} SAVE "$!1" 1 $2 1 FOREACH 2 ( $mfiles ) @{ MACRO READ "$!macro"$2 @} @end example @code{Cumulate} is given as a way @emph{not} to write macros if you can help it (in this case, I couldn't). A better example is @code{reverse} which reverses the order of the elements in a vector without resorting to a @code{DO} loop. The macro @code{da} could have been defined to be @code{DATA}, but there are various special characters that appear in filenames; try @code{data /usr/spool/junk} or @code{data disk$data:[ETHELRED]junk.dat}. The macro @code{da} provides a set of double quotes to escape these unwanted interpretations. Incidently, @code{da "/usr/spool/junk"} won't work. @code{DELETE HISTORY} deletes the last command on the history buffer, so @code{del1} alone on a line will delete itself, which can be used to prevent a command from appearing on the history list, for example changing devices with @code{dev}; @code{dev} also defines a variable @code{device} which is used by the @code{hcopy } and @code{hmacro} macros to make hardcopies, while returning you to your initial device. The @code{startup} macro listed above also sets @code{device}, if it is specified in your @file{.sm} file. You should be careful @emph{not} to include more than one @code{del1} macro in any macro that you write yourself, as each @code{del1} will remove a command from history and you could find commands mysteriously disappearing. @findex lost commands @code{Gauss} evaluates a Gaussian, e.g. @code{SET x=-3,3,0.05 SET g=gauss(x) lim x g box con x g}, an example of using a macro like a function definition. (For this example to work, you have to define variables @code{mean} and @code{sig} first). There is an example of reading variables from files and using them in macro @code{get}. This reads a word from a line in a file with the @code{DEFINE nn READ i j} command, which sets @code{$nn} to be the @code{j}th word on line @code{i} of the current data file. This variable is then used to @code{READ} a vector, which is given the appropriate name. So if a file looks like: @example This is an example file alpha beta gamma delta 1 10 0.1 1e1 2 20 0.2 1e2 3 30 0.3 1e3 4 40 0.4 1e4 5 50 0.5 1e5 @end example @noindent then the commands @example GET 2 1 GET 2 2 GET 2 3 GET 2 4 @end example @noindent will read `1 2 3 4 5' into vector @code{alpha}, `10 20 30 40 50' into @code{beta} and so forth. Note that @example DEFINE READ file_id 1 LABEL $file_id @end example @noindent will write out `This is an example file' to the current position of the plot pointer (see, e.g. @code{RELOCATE}). Incidently, @code{READ ROW omega 5} would set the vector @code{omega} to have values `3 30 0.3 1e3'. The macros @code{hcopy} and @code{hmacro} make hardcopies of, respectively, the playback buffer and a macro. Both assume that the variables @code{device} and @code{printer} are set. @code{device} is set from your @file{.sm} file and by the @code{dev} macro; @code{printer} is assumed set in @file{.sm}. (See `startup' file above). If all is well, the macros switch to device @code{printer} (with an argument to specify which sub-printer is desired. We have so many laser printers here...), execute the desired commands, and return to the initial @code{device}. When the @code{printer} device is closed, hardcopy will result. Note the use of @code{\n} to ensure that no nasty things happen; if there were no @code{\n} and the buffer ended with @code{LABEL Hi}, the plot could appear with a label @code{Hi device tek4010}. The versions of @code{hcopy} and @code{hmacro} given here accept a variable number of arguments (`13' means up to 3 arguments). The first (if present) is taken to be the desired laser printer@footnote{Actually, if the environment (VMS: logical) @file{.sm} variable @code{PRINTER} is defined the macros pretend that @emph{it} was the first argument, so you can simply type @code{hcopy}.}, the next argument is the number of the first line that you want played back, and the third is the last line number. (If you omit both line numbers you'll get the whole buffer; if you omit the second you'll just get the one line). The macro sees what it has been given by using @code{$?} to see which variables are defined, and acts accordingly. @code{hmacro} is somewhat similar, except that if you omit an argument it is taken to be the macro name, and a temporary one is created for you. The @code{playback} macro deals with its arguments in a similar way, and is discussed further in the examples at the end of this section. @code{load} enables you to read a set of macros from a directory specified as @code{macro} in your environment file. @code{Load2} is similar, but it looks in directory @code{macro2}. The macro @code{unload} (not listed here) will undefine the @code{load}ed macros. Note that a list of all the @code{load}ed macros is kept in @code{$mlist}, which is used by the @code{sav} macro to avoid @code{SAVE}ing lots of system macros. @code{sav} is written in terms of a macro @code{_save} so that it won't itself be forgotten (by @code{MACRO DELETE}) while in the middle of saving macros. If you want to put errorbars on logarithmic plots, @code{logerr} is the macro you've been looking for. It calculates the correct length for the errorbars, and plots them de-logging and re-logging as appropriate. The macros @code{rel} and @code{dra} illustrate a method of using expressions, rather than numbers, in the commands @code{RELOCATE} and @code{DRAW}. There are Good Reasons why @code{DRAW} won't accept an expression directly (@pxref{Command Internals}). These macros exploit the fact that the arguments to a macro are whitespace delimited, so a string such as @code{1+2/$x} comprises one argument. Redefining the arguments means that the macros don't have to define, and then delete, a couple of variables to hold the expressions. Now that you have had your appetite whetted, we strongly recommend that you take the time to look through the other macros that are available (@pxref{Libraries}). Otherwise how would you know that there are macros to draw arrows on plots, do KS and Wilcoxon tests on vectors, and a host of other good things? @findex good advice @include examples.txi @node Quoting, Keywords, Useful Macros, Top @chapter What Quotes What When This chapter is not really needed as all of its contents can be found elsewhere in this manual, but as people manage to become confused anyway, here's a summary. There are three ways in which characters can alter SM's behaviour: they can affect the way that characters and keywords are interpreted, they can be special to the grammar, and they can perform both functions. If you are confused, you might find a verbosity of four or five helpful. @table @code @item "@dots{}" Turn off the expansion of variables, the significance of mathematical operators such as @code{/} or @code{:}, and the recognition of keywords. For example, after @code{DEFINE rhl Patricia}, @code{/data/$rhl} would be interpreted as four tokens (@code{/}, @code{data}, @code{/}, and @code{Patricia}), while @code{"/data/$rhl"} is only one (@code{/data/$rhl}). Note that in the former case, the @code{data} will be taken to be part of a @code{DATA} command, and may well lead to a syntax error. If you need to force a variable to be expanded within double quotes, use an exclamation mark: @code{"$!rhl"}. Double quotes have no syntactical significance. @item '@dots{}' Single quotes surround strings which may contain white space (spaces or tabs), characters such as @code{+} or @code{/}, or keywords. They don't affect variable expansion, so you have to enclose them in double quotes if you want to protect them. Of course, you must make sure that you are not quoting the single quotes -- use @code{'"$abcd"'} rather than @code{"'$abcd'"} . Strings are significant to the grammar so only use single quotes where they are needed. For example @code{DATA 'my_file'} is a syntax error, and @code{SET s='abc'} and @code{SET s=abc} mean quite different things. @item @{@dots{}@} Turn off all interpretation of special characters and keywords, just like double quotes. In fact, braces even turn off the expansion of @code{$!var}, to expand a variable within braces you need to say @code{$!!var} but you only very seldom need this. Braces have syntactical significance, delimiting lists. Wherever you can use braces you can use angle brackets. @item <@dots{}> Almost identical to @{@dots{}@}, but don't turn off variable expansions. In fact, @code{<>} don't always turn off keyword interpretation -- specifically they only do so in @code{str_list}'s (if you want to know what this means you'll have to read SM's grammar in file @file{control.y}). In practice you'll probably only meet this if you try saying @code{Foreach f < quit when ahead > @{ echo $f @}}. @item (@dots{}) Parentheses don't turn off any sort of expansion, but can have syntactical significance. You are most likely to see this in @code{DEFINE var ( 1 + 2 )} where the parentheses tell SM to evaluate the expression before defining the variable @code{var} as @code{3}. Note that @code{DEFINE var < 1 + 2 >} defines @code{var} as @code{ 1 + 2 }. @item $name Expand @code{name} as a variable. Expansion is turned off within single and double quotes and within braces. Because the expansion happens before the parser sees the input, variables cannot have any syntactical significance as the parser never knows about them. This means that variables could be used to make SM look like something quite different; for example after @code{DEFINE begin "@{ " DEFINE end "@} "}, you can say @example MACRO hi $begin echo Hello World $!!end @end example @noindent (This is a little tricky. The spaces in @code{DEFINE begin "@{ "} are needed so that SM is still in quote mode when it processes the @code{@{}. You can probably figure out why I need to say @code{$!!end} -- the @code{!!} should be a Helpful Hint.) @item $(expr) Evaluate the expression @code{expr} and substitute the resulting value. This is identical to @code{DEFINE temp ( expr ) $temp}, but much more convenient. @end table As a reasonably complex example, try to guess the output from: @example DEFINE hi @{<"$!('Hello')" World>@} DEFINE hello $hi echo :$hi:$hello: @end example @noindent If you are not sure, try it (you might find @code{VERBOSE 5} helpful)@footnote{The @{@} turn off all expansions, so @code{hi} is defined to be @code{<"$!('Hello')" World>}. The statement defining @code{hello} then becomes @code{DEFINE hello <"$!('Hello')" World>}, and the `!' ensures that the expression @code{'Hello'} is evaluated and substituted; @code{'Hello'} is a string valued vector, admittedly with only one element, so it evaluates to the five characters `Hello' and the statement becomes @code{DEFINE hello } which means that @code{hello} is defined as @code{Hello World}. Apart from being a red herring, the colons are only there to make it easy to see which variable expands to what.}. @node Keywords, Glossary, Quoting, Top @chapter Reserved Keywords Keywords are reserved, so don't try to use them as macro names or whatever. You can use the lowercase forms if you explicitly ask to be allowed to overload them. The control words are : @example WORD STRING FLOAT INTEGER ( ) @{ @} \n ! APROPOS BREAK CHDIR DEFINE DELETE DO EDIT ELSE FOREACH HELP HISTORY IF KEY LIST LOCAL MACRO OLD OVERLOAD PRINT PROMPT QUIT READ RESTORE RETURN ROW SAVE SET STANDARD TABLE TERMTYPE USER VERBOSE WHILE WRITE @end example Arithmetic words are : @example ABS ACOS ASIN ATAN ATAN2 CONCAT COS DIMEN EXP FFT INT LG LN PI RANDOM SIN SQRT STRLEN SUM TAN WHATIS POWER_SYMBOL [ ] = + - * ** / < > | & ? : @end example SM plotting keywords are: @example ANGLE ASPECT AXIS BOX CONNECT CONTOUR CTYPE CURSOR DATA DEVICE DOT DRAW ERASE ERRORBAR EXPAND FORMAT GRID HISTOGRAM IMAGE LABEL LEVELS LIMITS LINES LOCATION LTYPE LWEIGHT MINMAX NOTATION POINTS PTYPE PUTLABEL RANGE RELOCATE SHADE SORT SPLINE TICKSIZE WHATIS WINDOW XLABEL YLABEL @end example With the exception of @code{POWER_SYMBOL} (which is equivalent to @code{**}) these are described below, with the convention that arguments between square brackets are optional. This has nothing to do with their use in subscripting arrays! @findex special characters, []