Hi there,
When I am reading the book "Carpenter's Complete Guide to SAS Macro", I made confuse in Program 14.3.6e which is about comments.
The Program is as follows:
%macro abc; *%put in abc; %mend abc; %macro doit; *%abc %put here; *%let x = %abc; %put value of x is &x; %mend doit; %doit ;
Log show:
215 %doit ; here in abc value of x is *
The author explains:
1. SAS looks for macro statements and generally ignores most of the things that otherwise have meaning in the Base SAS language (for example, asterisks are not seen as tokens and are therefore not interpreted as the keyword that starts a comment). So, *%put in abc and *%let x = %abc statements are executed.
2. a macro call is not seen as a macro statement and can still be commented on in this manner.
My questions:
1. Why the macro call would be commented?
2. What is the difference when a macro handle a macro call and a macro statement?
However, when run %put %doit;, log show:
216 %put %doit; in abc here in abc value of x is * ** *
Why the *%abc executed this time?
The macro processor just looks for the trigger characters % and & to start processing the text of your code. There are only a limited number of ways to force it to ignore those triggers and the statement comment in your code is NOT one of them. It will treat a statement comment the same way it treats any other SAS statement inside your macro. To the macro processor the * that starts a statement comment is no different than the * used in multiplication.
If you want code to be ignored by the macro processor either use a macro comment.
%* This is a macro comment and will ignore %abc and &xyz ;
Or a block comment
/* This is block comment and will ignore %abc and &xyz
and semi-colons (;)
and unbalanced quotes.
*/
Let's look what you coded. Here is the first (inner) macro.
%macro abc;
*%put in abc;
%mend abc;
So when you run that it will emit an * and the execute the %PUT statement. So it only generates part of a SAS statement. You could use that macro like this if you wanted.
x_squared = x %abc x ;
And it would generate this SAS statment:
x_squared = x * x ;
Now let's look at the second (outer) macro defintion.
%macro doit;
*%abc
%put here;
*%let x = %abc;
%put value of x is &x;
%mend doit;
So again you are emiting an * and then calling %ABC. So that will emit another *. You then run the %PUT macro statement. You then emit a third * and run the %LET statement. Since you are again calling %ABC the value of X should be an asterisk. And finally you ran another %PUT statement that writes some constant text and the value of X.
You can turn on the MPRINT MLOGIC and SYMBOLGEN options to see more informaton in the log about how it is being processed.
40 options mprint mlogic symbolgen; 41 %doit ; MLOGIC(DOIT): Beginning execution. MLOGIC(DOIT): %PUT here here MLOGIC(DOIT): %LET (variable name is X) MPRINT(DOIT): *%abc MLOGIC(ABC): Beginning execution. MLOGIC(ABC): %PUT in abc in abc MLOGIC(ABC): Ending execution. MLOGIC(DOIT): %PUT value of x is &x SYMBOLGEN: Macro variable X resolves to * value of x is * MLOGIC(DOIT): Ending execution. MPRINT(): *
And you can wrap the call to %DOIT inside a third macro to see how the emitted * is returned by %DOIT.
50 options mprint mlogic symbolgen; 51 52 %macro three ; 53 %doit ; 54 %mend three; 55 56 %three; MLOGIC(THREE): Beginning execution. MLOGIC(DOIT): Beginning execution. MLOGIC(DOIT): %PUT here here MLOGIC(DOIT): %LET (variable name is X) MPRINT(DOIT): *%abc MLOGIC(ABC): Beginning execution. MLOGIC(ABC): %PUT in abc in abc MLOGIC(ABC): Ending execution. MLOGIC(DOIT): %PUT value of x is &x SYMBOLGEN: Macro variable X resolves to * value of x is * MLOGIC(DOIT): Ending execution. MPRINT(THREE): * ; MLOGIC(THREE): Ending execution.
For more fun call %DOIT inside of quotes.
125 options nomprint nomlogic nosymbolgen; 126 127 %put When you "%doit" what happens?; in abc here in abc value of x is * When you "** *" what happens?
No idea. Perhaps because it is in the middle of the %LET macro statement? Or because of the missing semi-colon? You can cause weird things by leaving the final semi-colon off the end of the last statement in a macro. Essentially the statement ends up be run in the calling environment instead of in the macro.
The second %PUT does show when you call %DOIT inside quotes.
Like I said in my first response, it is not the macro call but the attempt to embed macro code into the middle of a statement comment. You can replicate the disappearing %PUT without the inner macro call.
139 data _null_; 140 *%put in abc; ; 141 run; NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 142 143 %macro xx ; 144 data _null_; 145 *%put in abc; ; 146 run; 147 %mend xx; 148 %xx; in abc NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds
Outside of the macro environment this line is a comment:
*%put in abc; ;
But inside the macro environment it is three separate things:
*
%put in abc;
;
I might ask the questions in a nuclear way. Let me ask again in another way.
The macro definition
%macro abc;
*%put in abc;
%mend abc;
%macro doit;
*%abc
%put here;
*%let x = %abc;
%put value of x is &x;
%mend doit;
Using color to match the code to the output.
Now run
%doit;
the log output
249 %doit ; MLOGIC(DOIT): Beginning execution. MLOGIC(DOIT): %PUT here here MLOGIC(DOIT): %LET (variable name is X) MPRINT(DOIT): *%abc MLOGIC(ABC): Beginning execution. MLOGIC(ABC): %PUT in abc in abc MLOGIC(ABC): Ending execution. MLOGIC(DOIT): %PUT value of x is &x SYMBOLGEN: Macro variable X resolves to * ; value of x is * ; MLOGIC(DOIT): Ending execution. MPRINT(ABC): *
From the output, we can see that the green and blue code had executed.
Why the red code "*%abc" was ignored?
Now let run
%put %doit;
The log output
250 %put %doit; MLOGIC(DOIT): Beginning execution. MLOGIC(ABC): Beginning execution. MLOGIC(ABC): %PUT in abc in abc ** MLOGIC(ABC): Ending execution. MLOGIC(DOIT): %PUT here here MLOGIC(DOIT): %LET (variable name is X) MPRINT(DOIT): * MLOGIC(ABC): Beginning execution. MLOGIC(ABC): %PUT in abc in abc MLOGIC(ABC): Ending execution. MLOGIC(DOIT): %PUT value of x is &x SYMBOLGEN: Macro variable X resolves to * ; value of x is * ; MLOGIC(DOIT): Ending execution.
All of the red, green, and blue code executed.
Why the red code executed this time?
I had inserted the Macro definition as SAS code and the code has not been colored right. Re-color as follows
%macro doit; *%abc %put here; *%let x = %abc; %put value of x is &x; %mend doit;
Like I said before I believe it might be related to the fact that you inner macro, %ABC, has incomplete statements. You have a macro statement embedded in the middle of a comment statement. So the single semi-colon ends the %PUT statement and there is no semi-colon to end the comment statement. But you would need to ask SAS to know exactly where in their parsing of this code the fact that running it inside a macro versus outside a macro makes a difference in whether the %PUT output is generated or not.
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.