Debugging Techniques

Using System Options to Track Problems

The SAS system options MLOGIC, MLOGICNEST, MPRINT, MPRINTNEST, and SYMBOLGEN can help you track the macro code and SAS code generated by your macro. Messages generated by these options appear in the SAS log, prefixed by the name of the option responsible for the message.
Note: Whenever you use the macro facility, use the following macro options: MACRO, MERROR, and SERROR. SOURCE is a system option that is helpful when using the macro facility. It is also helpful to use the SOURCE2 system option when using the %INCLUDE.
Although the following sections discuss each system option separately, you can, of course, combine them. However, each option can produce a significant amount of output, and too much information can be as confusing as too little. So, use only those options that you think you might need and turn them off when you complete the debugging.

Tracing the Flow of Execution with MLOGIC

The MLOGIC system option traces the flow of execution of your macro, including the resolution of parameters, the scope of variables (global or local), the conditions of macro expressions being evaluated, the number of loop iterations, and the beginning and end of each macro execution. Use the MLOGIC option when you think a bug lies in the program logic (as opposed to simple syntax errors).
Note: MLOGIC can produce a lot of output, so use it only when necessary, and turn it off when debugging is finished.
In the following example, the macro FIRST calls the macro SECOND to evaluate an expression:
%macro second(param);
   %let a = %eval(&param); &a
%mend second;

%macro first(exp);
   %if (%second(&exp) ge 0) %then
      %put **** result >= 0 ****;
   %else
      %put **** result < 0 ****;
%mend first;

options mlogic;
%first(1+2)
Submitting this example with option MLOGIC shows when each macro starts execution, the values of passed parameters, and the result of the expression evaluation.
MLOGIC(FIRST):  Beginning execution.
MLOGIC(FIRST):  Parameter EXP has value 1+2
MLOGIC(SECOND):  Beginning execution.
MLOGIC(SECOND):  Parameter PARAM has value 1+2
MLOGIC(SECOND):  %LET (variable name is A)
MLOGIC(SECOND):  Ending execution.
MLOGIC(FIRST):  %IF condition (%second(&exp) ge 0) is TRUE
MLOGIC(FIRST):  %PUT **** result >= 0 ****
MLOGIC(FIRST):  Ending execution.

Nesting Information Generated by MLOGICNEST

MLOGICNEST allows the macro nesting information to be written to the SAS log in the MLOGIC output. The setting of MLOGICNEST does not imply the setting of MLOGIC. You must set both MLOGIC and MLOGICNEST in order for output (with nesting information) to be written to the SAS log.
For more information and an example, see MLOGICNEST System Option.

Examining the Generated SAS Statements with MPRINT

The MPRINT system option writes to the SAS log each SAS statement generated by a macro. Use the MPRINT option when you suspect your bug lies in code that is generated in a manner that you did not expect.
For example, the following program generates a simple DATA step:
%macro second(param);
   %let a = %eval(&param); &a
%mend second;

%macro first(exp);
   data _null_;
      var=%second(&exp);
      put var=;
   run;
%mend first;

options mprint;
%first(1+2)
When you submit these statements with option MPRINT, these lines are written to the SAS log:
MPRINT(FIRST):   DATA _NULL_;
MPRINT(FIRST):   VAR=
MPRINT(SECOND):  3
MPRINT(FIRST):  ;
MPRINT(FIRST):   PUT VAR=;
MPRINT(FIRST):   RUN;

VAR=3
The MPRINT option shows you the generated text and identifies the macro that generated it.

Nesting Information Generated by MPRINTNEST

MPRINTNEST allows the macro nesting information to be written to the SAS log in the MPRINT output. This value has no effect on the MPRINT output that is sent to an external file. For more information, see MFILE System Option.
The setting of MPRINTNEST does not imply the setting of MPRINT. You must set both MPRINT and MPRINTNEST in order for output (with the nesting information) to be written to the SAS log.
For more information and an example, see MPRINTNEST System Option.

Storing MPRINT Output in an External File

You can store text that is generated by the macro facility during macro execution in an external file. Printing the statements generated during macro execution to a file is useful for debugging macros when you want to test generated text in a later SAS session.
To use this feature, set both the MFILE and MPRINT system options on. Also assign MPRINT as the fileref for the file to contain the output generated by the macro facility:
options mprint mfile;
filename mprint 'external-file';
The external file created by the MPRINT system option remains open until the SAS session terminates. The MPRINT text generated by the macro facility is written to the log during the SAS session and to the external file when the session ends. The text consists of program statements generated during macro execution with macro variable references and macro expressions resolved. Only statements generated by the macro are stored in the external file. Any program statements outside the macro are not written to the external file. Each statement begins on a new line with one space separating words. The text is stored in the external file without the MPRINT(macroname: prefix, which is displayed in the log.
If MPRINT is not assigned as a fileref or if the file cannot be accessed, warnings are written to the log and MFILE is turned off. To use the feature again, you must specify MFILE again.
By default, the MPRINT and MFILE options are off.
The following example uses the MPRINT and MFILE options to store generated text in the external file named TEMPOUT:
options mprint mfile;
filename mprint 'TEMPOUT';

%macro temp;
   data one;
      %do i=1 %to 3;
         x&i=&i;
      %end;
   run;
%mend temp;

%temp
The macro facility writes the following lines to the SAS log and creates the external file named TEMPOUT:
MPRINT(TEMP):   DATA ONE;
NOTE: The macro generated output from MPRINT will also be written
      to external file '/u/local/abcdef/TEMPOUT' while OPTIONS
      MPRINT and MFILE are set.
MPRINT(TEMP):   X1=1;
MPRINT(TEMP):   X2=2;
MPRINT(TEMP):   X3=3;
MPRINT(TEMP):   RUN;
When the SAS session ends, the file TEMPOUT contains:
DATA ONE;
X1=1;
X2=2;
X3=3;
RUN;
Note: Using MPRINT to write code to an external file is a debugging tool only. It should not be used to create SAS code files for purposes other than debugging.

Examining Macro Variable Resolution with SYMBOLGEN

The SYMBOLGEN system option tells you what each macro variable resolves to by writing messages to the SAS log. This option is especially useful in spotting quoting problems, where the macro variable resolves to something other than what you intended because of a special character.
For example, suppose you submit the following statements:
options symbolgen;

%let a1=dog;
%let b2=cat;
%let b=1;
%let c=2;
%let d=a;
%let e=b;
%put **** &&&d&b ****;
%put **** &&&e&c ****;
The SYMBOLGEN option writes these lines to the SAS log:
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable D resolves to a
SYMBOLGEN:  Macro variable B resolves to 1
SYMBOLGEN:  Macro variable A1 resolves to dog
**** dog ****

SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable E resolves to b
SYMBOLGEN:  Macro variable C resolves to 2
SYMBOLGEN:  Macro variable B2 resolves to cat
**** cat ****
Reading the log provided by the SYMBOLGEN option is easier than examining the program statements to trace the indirect resolution. Notice that the SYMBOLGEN option traces each step of the macro variable resolution by the macro processor. When the resolution is complete, the %PUT statement writes the value to the SAS log.
When you use SYMBOLGEN to trace the values of macro variables that have been masked with a macro quoting function, you might see an additional message about the quoting being “stripped for printing.” For example, suppose you submit the following statements, with SYMBOLGEN set to on:
%let nickname = %str(My name%'s O%'Malley, but I%'m called Bruce);
%put *** &nickname ***;
The SAS log contains the following after these statements have executed:
SYMBOLGEN:  Macro variable NICKNAME resolves to
                            My name's O'Malley, but I'm called Bruce
SYMBOLGEN:  Some characters in the above value which were
                           subject to macro quoting have been
                           unquoted for printing.
*** My name's O'Malley, but I'm called Bruce ***
You can ignore the unquoting message.

Using the %PUT Statement to Track Problems

Along with using the SYMBOLGEN system option to write the values of macro variables to the SAS log, you might find it useful to use the %PUT statement while developing and debugging your macros. When the macro is finished, you can delete or comment out the %PUT statements. The following table provides some occasions where you might find the %PUT statement helpful in debugging, and an example of each:
Example %PUT Statements That Are Useful when Debugging Macros
Situation
Example
show a macro variable's value
%PUT ****&=variable-name****;
check leading or trailing blanks in a variable's value
%PUT ***&variable-name***;
check double-ampersand resolution, as during a loop
%PUT ***variable-name&i = &&variable-name***;
check evaluation of a condition
%PUT ***This condition was met.***;
As you recall, macro variables are stored in symbol tables. There is a global symbol table, which contains global macro variables, and a local symbol table, which contains local macro variables. During the debugging process, you might find it helpful on occasion to print these tables to examine the scope and values of a group of macro variables. To do so, use the %PUT statement with one of the following options:
_ALL_
describes all currently defined macro variables, regardless of scope. User-generated global and local variables as well as automatic macro variables are included.
_AUTOMATIC_
describes all automatic macro variables. The scope is listed as AUTOMATIC. All automatic macro variables are global except SYSPBUFF.
_GLOBAL_
describes all global macro variables that were not created by the macro processor. The scope is listed as GLOBAL. Automatic macro variables are not listed.
_LOCAL_
describes user-generated local macro variables defined within the currently executing macro. The scope is listed as the name of the macro in which the macro variable is defined.
_USER_
describes all user-generated macro variables, regardless of scope. For global macro variables, the scope is GLOBAL; for local macro variables, the scope is the name of the macro.
The following example uses the %PUT statement with the argument _USER_ to examine the global and local variables available to the macro TOTINV. Notice the use of the user-generated macro variable TRACE to control when the %PUT statement writes values to the log.
%macro totinv(var);
   %global macvar;
   data inv;
      retain total 0;
      set sasuser.houses end=final;
      total=total+&var;
      if final then call symput("macvar",put(total,dollar14.2));
   run;

   %if &trace = ON  %then
      %do;
         %put *** Tracing macro scopes. ***;
         %put _USER_;
      %end;
%mend totinv;

%let trace=ON;
%totinv(price)
%put *** TOTAL=&macvar ***;
When you submit these statements, the first %PUT statement in the macro TOTINV writes the message about tracing being on and then writes the scope and value of all user generated macro variables to the SAS log.
*** Tracing macro scopes. ***
TOTINV VAR price
GLOBAL TRACE ON
GLOBAL MACVAR  $1,240,800.00
*** TOTAL= $1,240,800.00 ***
See Scopes of Macro Variables for a more detailed discussion of macro variable scopes.