How often have you wanted a secret decoder ring to view the resolved values of your macro variables or to isolate an error or warning that is occurring in your SAS macro code logic? Well, the MFILE option can be that decoder!
When you use the MFILE and MPRINT options and use a FILENAME statement with the MPRINT fileref, SAS routes the code that is generated and submitted by your macro to a text file the next time that you call your macro. You can then examine and run all or part of the code in the text file to help debug your program. This blog post provides three examples of how you can use these options to improve your use of macro code.
Example 1: Understanding the macro code
Here’s an example where I am using code that was written by another programmer. I want to understand what the macro variables inside the TEST macro resolve to and what SAS code the TEST macro creates:
%macro test(value); ods rtf file="&value..rtf"; proc print data=one(where=(state="&value")); run; ods rtf close; %mend; data one; input state $ age; datalines; VA 21 VA 23 MD 23 MD 12 MA 12 MA 34 ; proc sort ; by state; run; data _null_; set one; by state; if first.state then call execute('%test('||state||')'); run;
Here is how I call the TEST macro with the MFILE and MPRINT options in effect and a FILENAME statement that uses the MPRINT fileref:
options mprint mfile; filename mprint "c:\temp\nomacro.sas"; data _null_; set one; by state; if first.state then call execute('%test('||state||')'); run;
This program results in the following code being sent to the nomacro.sas file:
ods rtf file="MA.rtf"; proc print data=one(where=(state="MA")); run; ods rtf close; ods rtf file="MD.rtf"; proc print data=one(where=(state="MD")); run; ods rtf close; ods rtf file="VA.rtf"; proc print data=one(where=(state="VA")); run; ods rtf close;
In the file, I see that all of the macro variables resolved to state abbreviations, and I can then choose to run all or part of the code as desired. That was easy!
Example 2: Understanding exactly where an issue occurs in macro code
In the following log file, I’m confused because the NOTE about an invalid argument to the INPUT function seems to occur on the line where I invoked my macro and I want more specific information:
Kevin Russell explains why the NOTE occurs in this location in his Surviving the SAS® Macro Jungle by Using Your Own Programming Toolkit paper:
The line number in the NOTE points to the line where the macro is invoked instead of pointing to the line that contains the INPUT function. The NOTE points to this line because it is the invocation of the macro that generates the INPUT function code that then generates the NOTE. Because there is currently no option other than having the NOTE point to the line where the macro is invoked, you can use the MFILE system option to debug.
I can use the MFILE option to discover where the problem with the INPUT function actually occurs:
filename mprint "c:\temp\nomacro_note.sas"; options mprint mfile; %cars
The resulting submission of the code from the nomacro_note.sas file helps me find the problematic line, line 75. It is not hard to find the issue when you use the problematic function only one time; but in the real world, these functions are used OFTEN:
Example 3: Including dependent code for the macro
What if I have some precode that is outside of the macro, or another macro that I need to use as part of my debugging? In this case, I am not sure that I will need a PROC PRINT step to debug my CARS macro, but I would like to ensure that it is included in my decoded file (using MFILE). So, I can use the MFILE option to include that code in a file that I can parse out later. Here's the code that I want to run:
%let name1=Asia; %let i=1; proc print data=sashelp.cars; title "&&name&i"; run; %macro cars; data cars; set sashelp.cars; new=input(origin,1.); run; %mend;
I wrap the code in the OUTER macro and then use MFILE and MPRINT to “decode”:
%macro outer; %let name1=Asia; %let i=1; proc print data=sashelp.cars; title "&&name&i"; run; %macro cars; data cars; set sashelp.cars; new=input(origin,1.); run; %mend; %cars %mend outer; filename mprint "c:\temp\outer.sas"; options mprint mfile; %outer
Here is the outer.sas file for later decoding:
proc print data=sashelp.cars; title "Asia"; run; data cars; set sashelp.cars; new=input(origin,1.); run;
Paired with the MPRINT option, the MFILE option is especially helpful if you are seeing errors, warning messages, or code behavior that you cannot explain or diagnose easily from reading your SAS log. MFILE gives you clean code that you can submit, without having to copy the MPRINT output from the log window to another file and remove the (MPRINT) headers. It is a code strategy that might also prove useful if you need to involve SAS Technical Support, because it’s especially helpful for you to provide SAS Technical Support with the smallest subset of your code that demonstrates the problem that you are encountering.
Although these options are useful, note these restrictions:
- If you generate code with MFILE, it does not contain any formatting such as code indention.
- If you generate code with MFILE, it does not contain PL1 style comments (/* comment here */).
- If the macro is a stored compiled macro that was compiled with the NOMPRINT option in effect, then the MFILE and MPRINT options do not generate a file.
Tell me how you have found this blog useful!