Hi All:
Just a quick question here:
I take great effort to make my code readable, but when programs with imbedded macro programs are executed the macro code in the SAS log is all over the place. Is there any way to retain the original format to make it more easily readable?
Thanks in advance.
Do you have examples of what you mean?
In general the issue I have seen is that for long statements the MPRINT lines will be flowed into a single line. Indentation is also lost.
Is this what you are talking about? If so I think you are out of luck.
What you can control are your comments.
When writing a macro I distinquish in my comments those that are useful when reviewing the log and those that are useful when editing or reviewing the code. An example of the latter is and explaination of a particularly tricky piece of code or a special syntax requirement so that I don't break the code code the next time I edit it.
For the first type I use normal *...; comments. These will print with the code lines when MPRINT is on. For the latter I use %*... ; comments. I try not to use /* */ comments other than for header blocks and rarely when I need to embed a comment in the middle of a statement.
Placement of your comments are important.
1) Do not put *..; comments at the end of a line after the code because then the comment prints below the statement in the log.
2) Place comments for conditional blocks of code inside the conditional so that they will print only when the condition is true.
%if %sysfunc(exist(mydata)) %then %do;
* Generate summary of MYDATA;
proc summary data=mydata ....
%end;
I'll do the best I can with the code samples....
Here is my code (just a small part of the program):
545 if substr("&imember",11,1) = 'A' and length(account_number) ge 10 then do;
546 if substr(account_number,10,1) = '-' then substr(text,14,12) = account_number;
547 else do;
548 substr(text,14,9) = substr(account_number,1,9);
549 substr(text,23,1) = '-';
550 substr(text,24,2) = substr(account_number,10,2);
551 end;
552 end;
553
554 if substr("&imember",11,1) = 'C' then do;
555 substr(text,14,12) = account_number;
556 substr(text,26,1) = ' ';
557 substr(text,35,1) = ' ';
558 end;
559
560 substr(text,27,8) = trade_date;
561
And this is how my log looks (sort of):
if substr("46TR092911A.xls",11,1) = 'A' and
46 + length(account_number) ge 10 then do; if substr(account_number,10,1) = '-' then substr(text,14,12) = account_number; else do; substr(text,14,9) =
substr(account_number,1,9); substr(text,23,1) = '-'; substr
47 +(text,24,2) = substr(account_number,10,2); end; end; if substr("46TR092911A.xls",11,1) = 'C' then do; substr(text,14,12) = account_number; substr(text,26,1) = ' ';
substr(text,35,1) = ' '; end; substr(text,27,8
48 +) = trade_date; transaction_type = upcase(transaction_type); if transaction_type =: 'B' then trans_type = '100'; else if transaction_type =: 'S' then trans_type = '690'; else if
transaction_type =: 'E' then trans_type = '400'; else if
Which makes it rather hard to read. The text seems to loose all syntax. It actually goes beyond the right side of my screen in the SAS log window. (Here it seems to wrap within this window).
It's not a big problem, but it is a pain in the backside.
The + signs are usually an indication of included code and not macro generation.
Normally I turn off SOURCE2 and turn on MPRINT.
How are you calling the macro? Are you using SAS/Connect so that macro is generating code that is sent to the remote session?
Are you using CALL EXECUTE to call the macro?
You might try changing that to instead write code to a file and %INC the file. Here is an example.
275 %macro test;
276 data x;
277 line1='This is testing how long lines of code look';
278 line2='This is testing how long lines of code look';
279 line3='This is testing how long lines of code look';
280 run;
281 %mend test;
282
283 data _null_;
284 call execute('%test');
285 run;
MPRINT(TEST): data x;
MPRINT(TEST): line1='This is testing how long lines of code look';
MPRINT(TEST): line2='This is testing how long lines of code look';
MPRINT(TEST): line3='This is testing how long lines of code look';
MPRINT(TEST): run;
NOTE: DATA statement used (Total processtime):
real time 0.00 seconds
cpu time 0.00 seconds
NOTE: CALL EXECUTE generated line.
1 +data x; line1='This is testing how longlines of code look'; line2='This istesting how long
lines of code look'; line3='This is testing how long lines of codelook'; run;
NOTE: The data set WORK.X has 1 observationsand 3 variables.
NOTE: DATA statement used (Total processtime):
real time 0.01 seconds
cpu time 0.00 seconds
286
287 filename code temp;
288 data _null_;
289 file code;
290 put '%test;';
291 run;
NOTE: The file CODE is:
Filename=C:\DOCUME~1\ABERNA~1\LOCALS~1\Temp\SAS TemporaryFiles\_TD2288\#LN00010,
RECFM=V,LRECL=256,File Size (bytes)=0,
Last Modified=30Sep2011:14:29:38,
Create Time=30Sep2011:14:29:38
NOTE: 1 record was written to the file CODE.
The minimum record length was 6.
The maximum record length was 6.
NOTE: DATA statement used (Total processtime):
real time 0.00 seconds
cpu time 0.01 seconds
292 %inc code;
MPRINT(TEST): data x;
MPRINT(TEST): line1='This is testing how long lines of code look';
MPRINT(TEST): line2='This is testing how long lines of code look';
MPRINT(TEST): line3='This is testing how long lines of code look';
MPRINT(TEST): run;
NOTE: The data set WORK.X has 1 observationsand 3 variables.
NOTE: DATA statement used (Total processtime):
real time 0.00 seconds
cpu time 0.00 seconds
Sorry for the delay - going to be a busy week...
You are correct - i run this code from a CALL EXECUTE. Unfortunately, I can't change thsi because the code runs against each member of a directory In cases when I do use the %INCLUDE, I don't have this problem.
I usually turn off SOURCE2 as well, but I need to see what is happening during development.
Why do you think that you cannot change it to not use CALL EXECUTE?
Change a program like this:
data _null_;
set members ;
call execute(cats('%nstr(%%mymacro)','(',memname,');'));
run;
to a program like this:
filename code temp;
data _null_;
set members;
file code;
put '%mymacro(' memname ');' ;
run;
%inc code / source2 ;
This is because SAS is expanding the macro and passing the statements onto the command stack. You can prevent this by using %NRSTR to protect the macro call from executing at that point. Then SAS will push the macro call onto the stack and it will then execute after the current data step has finished. There are also other timing issues that can be solved by using this technique.
Here is an example to show the difference in how the log will look.
%macro x;
* This is a macro with a few lines of code ;
Data _null_;
x='Just to see what happens when it is invoked from ';
y='call execute and see how it looks in the SAS log.';
run;
* end of macro x;
%mend x;
options mprint;
data _null_;
call execute('%x;');
run;
data _null_;
call execute('%nrstr(%%x;)');
run;
for a development stage, assign fileref mprint to a writeable file and switch on options MPRINT and MFILE. Then re-run your process. The option MFILE passes code generated by macros to the mprint file.
In enterprise guide 4.3 open that mprint file into a code window and "format code" the keyboard equivalent is CTRL+i
It will not be the original source, but will be readable.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.
Find more tutorials on the SAS Users YouTube channel.