Some Generalities on Macros and Macro Variables ...

1.  Macro variables are ordinarily alphanumeric strings.  Thus if you
    define &num as

    %let num = 100 + 200 ;

    then the contents of &num are actually NOT 300; it will just be the
    character string '100 + 200' ;

    However, when the program executes, the value looks to the SAS
    interpreter the same as if you had written in 100 + 200, and
    it evaluates this expression correctly as equalling 300.


2.  When macro variables or macro functions are used in titles, the
    titles must be given in double quotes:

    Doesn't work:   title1 = 'Today is &sysdate' ;

    Does work   :   title1 = "Today is &sysdate" ;

3.  The function SYMPUT:

    Ordinarily macro variables are created outside of SAS data
    steps.  Their values are set in advance and do not depend on
    the data.

    There are occasions where you want to have available
    information from one data step that might be useful in a later
    data step.  This is what the function SYMPUT accomplishes.  See
    the program example "~john-c/5412/macexamp.sas".

4.  When you include macros in your program, it is a good idea to
    add the MPRINT option on the 'options' line:

    options   linesize = 100  MPRINT ;

    This causes a printout of the translated macro to be printed on
    the log file.  This can be very useful for debugging a macro.

5.  Note that unless you take some precautions, variables defined
    in a macro may have the same name as variables that you use
    elsewhere in your program.  This can result in changing the
    data without intending to do so.  You may not realize it has
    happened.

    This problem is especially bad when you are using a macro that
    someone else has developed, and you are making use of it in your
    program by the "%include" statement.  You may not even know what
    variable names have been chosen previously.

    You can make variables "local" to the macro by using the
    %LOCAL command near the beginning of the macro:

    %LOCAL xtemp ytemp zmacvar wmacvar ;

    However, these will be *macro* variables.


6.  Positional parameters vs. keyword parameters:

    Here is a macro which makes use of both positional and
    keyword parameters:

=======================================================================

*Example of use of positional and keyword parameters ...             ;

options linesize = 80 MPRINT ;

footnote "~john-c/5421/macros.sas &sysdate &systime" ;

*----------------------------------------------------------------------;

    %macro mv(dataset, atitle, stats = n mean std, varbls = 1) ;

       proc means data = &dataset &stats ;
            var &varbls ;

       title "&atitle" ;

    %mend ;
*----------------------------------------------------------------------;

data xvals ;
     input age weight height FEV1 ;

cards;
31 155 175 2.44
48 176 165 3.45
50 104 144 1.22
63 117 180 182
;
run ;

%mv(xvals, Summary Stats: from Proc Means, stats = n sum var,
    varbls = age weight height FEV1) ;
=======================================================================

The first two parameters to the macro, 'xvals' and 'title', are
positional parameters.  The last two, 'stats = ' and 'varbls = '
are keyword parameters.  Note that:

    1)  The positional parameters always precede the keyword
        parameters

    2)  The keyword parameters have default values.  If the macro
        is called with the keyword parameter fields left blank, as in

        %mv(xvals, Summary Stats: from Proc Means) ;

        then the default values are used.

The following is the printout from the program above:

========================================================================

                         Summary Stats: from Proc Means                        1
                                                 18:24 Monday, November 11, 2002

                    Variable  N           Sum      Variance
                    ---------------------------------------
                    AGE       4   192.0000000   172.6666667
                    WEIGHT    4   552.0000000       1110.00
                    HEIGHT    4   664.0000000   254.0000000
                    FEV1      4   189.1100000       8067.57
                    ---------------------------------------
 
                     ~john-c/5421/macros.sas 11NOV02 18:24
========================================================================

Another macro example: a macro that finds the median in an
array of numbers (array length, 20 or smaller; here only
the median of the first 6 nonblank values is found):

options linesize = 100  mprint ;

* ====================================================================;

%macro xmed(x, maxlen, xmedian) ;

* --------------------------------------------------------------------;
*                                                                     ;
*  Sort the array in DESCENDING order: missing values occur last.     ;
*                                                                     ;
* --------------------------------------------------------------------;

do i = 2 to &maxlen ;

   do j = 1 to i - 1 ;

      ti = &x(i) ;
      tj = &x(j) ;
      if ti eq . then ti = -99999 ;
      if tj eq . then tj = -99999 ;
      t = ti - tj ;

      if (t > 0) then do ;

         temp = &x(j) ;
         &x(j) = &x(i) ;
         &x(i) = temp ;

      end ;

   end ;

end ;

xlen = 0 ;

do i = 1 to &maxlen ;

    a = &x(i) ;
    if a ne . then xlen = xlen + 1 ;

end ;

xmid = int(xlen / 2) ;

if 2 * xmid eq xlen then do ;

   xmedian = .5 * (&x(xmid) + &x(xmid + 1)) ;

end ;

if 2 * xmid ne xlen then do ;

   &xmedian = &x(xmid + 1) ;

end ;

%mend ;

*======================================================================;

data xdata ;

     x1 = 12; x2 = 10; x3 = 2 ; x4 = 4; x5 = 1 ; x6 = 9 ; output ;
     x1 =  .; x2 = 19; x3 = 4 ; x4 = 9; x5 = 8 ; x6 = . ; output ;
     x1 =  7; x2 =  9; x3 = . ; x4 = 1; x5 = 1 ; x6 = 0 ; output ;
     x1 = 27; x2 = 99; x3 = 0 ; x4 = 5; x5 = . ; x6 = . ; output ;
     x1 =  1; x2 =  .; x3 = 3 ; x4 = 8; x5 = . ; x6 = 7 ; output ;

run ;

data xarrays ;
     set xdata ;
     array x(20) ;
     retain pass 1 ;
     file 'outmed.file' ;

     if pass eq 1 then do ;

        put ' Data Points and Medians: program ~john-c/median.sas' ;
        put " Date: &sysdate   Time: &systime" ;
        put ' ' ;
        put ' ' ;

     end ;

     pass = pass + 1 ;

     x(1) = x1 ; x(2) = x2 ; x(3) = x3 ;
     x(4) = x4 ; x(5) = x5 ; x(6) = x6 ;

     %xmed(x, 20, xmedian) ;

     put @2 'X-Values: ' x1 x2 x3 x4 x5 x6 @30 '  Median: ' xmedian ;

run ;

options linesize = 100  mprint ;

* ====================================================================;

%macro xmed(x, maxlen, xmedian) ;

* --------------------------------------------------------------------;
*                                                                     ;
*  Sort the array in DESCENDING order: missing values occur last.     ;
*                                                                     ;
* --------------------------------------------------------------------;

do i = 2 to &maxlen ;

   do j = 1 to i - 1 ;

      ti = &x(i) ;
      tj = &x(j) ;
      if ti eq . then ti = -99999 ;
      if tj eq . then tj = -99999 ;
      t = ti - tj ;

      if (t > 0) then do ;

         temp = &x(j) ;
         &x(j) = &x(i) ;
         &x(i) = temp ;

      end ;

   end ;

end ;

xlen = 0 ;

do i = 1 to &maxlen ;

    a = &x(i) ;
    if a ne . then xlen = xlen + 1 ;

end ;

xmid = int(xlen / 2) ;

if 2 * xmid eq xlen then do ;

   xmedian = .5 * (&x(xmid) + &x(xmid + 1)) ;

end ;

if 2 * xmid ne xlen then do ;

   &xmedian = &x(xmid + 1) ;

end ;

%mend ;

*======================================================================;

data xdata ;

     x1 = 12; x2 = 10; x3 = 2 ; x4 = 4; x5 = 1 ; x6 = 9 ; output ;
     x1 =  .; x2 = 19; x3 = 4 ; x4 = 9; x5 = 8 ; x6 = . ; output ;
     x1 =  7; x2 =  9; x3 = . ; x4 = 1; x5 = 1 ; x6 = 0 ; output ;
     x1 = 27; x2 = 99; x3 = 0 ; x4 = 5; x5 = . ; x6 = . ; output ;
     x1 =  1; x2 =  .; x3 = 3 ; x4 = 8; x5 = . ; x6 = 7 ; output ;

run ;

data xarrays ;
     set xdata ;
     array x(20) ;
     retain pass 1 ;
     file 'outmed.file' ;

     if pass eq 1 then do ;

        put ' Data Points and Medians: program ~john-c/median.sas' ;
        put " Date: &sysdate   Time: &systime" ;
        put ' ' ;
        put ' ' ;

     end ;

     pass = pass + 1 ;

     x(1) = x1 ; x(2) = x2 ; x(3) = x3 ;
     x(4) = x4 ; x(5) = x5 ; x(6) = x6 ;

     %xmed(x, 20, xmedian) ;

     put @2 'X-Values: ' x1 x2 x3 x4 x5 x6 @30 '  Median: ' xmedian ;

run ;

*======================================================================;

Output from the program:

*----------------------------------------------------------------------;

 Data Points and Medians: program ~john-c/median.sas
 Date: 10NOV02   Time: 14:06
 
 
 X-Values: 12 10 9 4 2 1       Median: 6.5
 X-Values: 19 9 8 4 . .        Median: 8.5
 X-Values: 9 7 1 1 0 .         Median: 1
 X-Values: 99 27 5 0 . .       Median: 16
 X-Values: 8 7 3 1 . .         Median: 5

*======================================================================;

PubH 5421  ~john-c/5421/notes.023a  Last update: November 30, 2005.