BookmarkSubscribeRSS Feed
su35
Obsidian | Level 7

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?

11 REPLIES 11
Tom
Super User Tom
Super User

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. */

 

su35
Obsidian | Level 7
Hi Tom,
Thanks for your reply.
instead of how to comment the code, I couldn't understand the behave of the code. Or said, why the results are those? How SAS processes those code? What is under the table?
Tom
Super User Tom
Super User

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?
su35
Obsidian | Level 7
Hi Tom,
let me split my question one by one.
As you explain as "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."
"then calling %ABC". why there is not an "in abc" output in log before the "here"?
Tom
Super User Tom
Super User

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.

su35
Obsidian | Level 7
I had added the semi-colon after the *%abc. But no difference. My core question is why the *%abc will not execute when run %doit along, however, when run %put %doit, the *%abc will execute?
Tom
Super User Tom
Super User

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;
 ;
su35
Obsidian | Level 7

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?

 

su35
Obsidian | Level 7

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;
Tom
Super User Tom
Super User

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.

su35
Obsidian | Level 7
Hi Tom,
Thanks for your patient, but I am still confused.
When the %doit run, the first code would be *%abc. The first character is *, the * would be a meaningless character inside a macro and would be left to pass back to base SAS. Then, the second character is % which is a macro trigger. So, no matter how the %abc has been defined, the %abc should be called. But, from log output, we saw this macro call hasn't happened. Why?
However, when %put %doit; run, this macro call exactly happened. Why?
I had tried to add a semi-colon at the end of "*%put in abc;", "*%abc", and both. There is no difference.

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 11 replies
  • 2125 views
  • 0 likes
  • 2 in conversation