BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
BenF
Calcite | Level 5

I'm calling a macro where the macro name to be called is stored in a macro variable. I don't understand the behavior I'm seeing. The actual code is more complicated, but it boils down to this:

 

%macro child(d=, t=, p=);

  %put CHILD>>> d = [&d];
  %put CHILD>>> t = [&t];
  %put CHILD>>> p = [&p];

%mend child;


%macro parent;
  %local dsn tab path macroName;

  %let macroName = %bquote(child);
  %let dsn = testDsn;
  %let tab = testTab;
  %let path = testPath;

  %put PARENT>>> macroName = [&macroName];
  %put PARENT>>> dsn = [&dsn];
  %put PARENT>>> tab = [&tab];
  %put PARENT>>> path = [&path];

  %&macroName(d=&dsn, t=&tab, p=&path);
%mend parent;

%parent;

What I see when I run this interactively using SAS Studio 3.6 running SAS release: 9.04.01M4P11092016 is:

 
PARENT>>> macroName = [child]
PARENT>>> dsn = [testDsn]
PARENT>>> tab = [testTab]
PARENT>>> path = [testPath]
CHILD>>> d = []
CHILD>>> t = []
CHILD>>> p = []
NOTE: Line generated by the invoked macro "PARENT".
86 %&macroName(d=&dsn, t=&tab, p=&path);
_
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
 
MPRINT(PARENT): (d=testDsn, t=testTab, p=testPath);

 

Notes:

1. With the macro name as a quoted macro variable (red highlight), it looks like the macro gets called with no arguments.

2. It works as expected if the macro name is not quoted.

3. I could not find anything about this behavior using a web search.

4. For those questioning WHY I would want to do this: I have a cross study, data-driven utility that is used to create Excel subject line listing. I am extending it to allow for custom Excel tabs where I can do things like highlight specific cells.

5. For those wondering WHY I'm asking when I have a workaround: The macro facility is sometimes mysterious to me. I just want to better understand what is going on. It took me a while to debug this...

 

Thanks for your help.

 

Ben

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

The quoting around the name is confusing the parser such that it no longer recognizes the following text in parentheses as part of the macro call.

 

So there are two solutions.  Define the macro you are calling to not have any parameters (or call it without setting any parameter values). 

%&macroName ;

Or unquote the name before trying to use it.  Since you already decided that macroName must have the name of a macro then removing the quoting will not make the program any more unsafe than it already is.

%let macroName=%unquote(&macroName);
%&macroName(parm1=,parm2=)

 

 

View solution in original post

13 REPLIES 13
data_null__
Jade | Level 19

You don't need to use %BQUOTE.

 

%let macroName = %bquote(child);

 

You can just assign Child to macroname.

 

BenF
Calcite | Level 5
As I said, the actual code is more complicated. I want to know why having a
quoted macro variable in the call breaks the call.
PaigeMiller
Diamond | Level 26

This works if you take out the %bquote, as there seems to be no need to use macro quoting on the text string child

 

If for some reason you have to have %bquote (and I can't think of such a reason, because valid names of an actual macro should not need to be surrounded by the %bquote() function), then you want to use 

 

%let macroName = %unquote(%bquote(child));

 

For an explanation of why %unquote would be needed there, I call upon Mr. @Astounding who can explain this a lot better than I can.

--
Paige Miller
BenF
Calcite | Level 5
Thanks! The reason that the macro name is quoted is that it is resolved by
a macro call that is also used to return code fragments that need to be
quoted. Yes, the unquote works. I look forward to an nth degree macro ninja
explaining what is going on.
data_null__
Jade | Level 19

@BenF wrote:
Thanks! The reason that the macro name is quoted is that it is resolved by
a macro call that is also used to return code fragments that need to be
quoted.

I don't understand can you explain or show and example.

PaigeMiller
Diamond | Level 26

@BenF wrote:
Thanks! The reason that the macro name is quoted is that it is resolved by
a macro call that is also used to return code fragments that need to be
quoted. Yes, the unquote works. I look forward to an nth degree macro ninja
explaining what is going on.

Even in the case where you don't have the five letter text string 

 

child

 

and you have a macro variable named (for example) &myvar, you still don't need %bquote if &myvar has to be the name of a macro, which it has to be in this example. Not only does %bquote do nothing here, but as you can see it causes other problems. Now if &myvar can contains special characters that have a meaning to the macro processor, for example if the value of &myvar is

 

Dan+Shay

 

then %bquote would be needed to prevent the macro processor from understanding the + sign as an actual + sign indicating addition, and inside %bquote the + sign would then be interpreted as text which doesn't indicate addition. But if you have the name of a macro in &myvar, then it can't have a + sign (or any other character with special meaning).

 

But, I still struggle to explain %unquote. Basically, I know that if the resolution of the macro seems to be the correct text which results in valid legal SAS code, but produces an error, then %unquote fixes the problem.

 

 

--
Paige Miller
BenF
Calcite | Level 5
Thanks!

I don't want to get too far off topic, but the quoting in the actual code
is needed for exactly the reason you describe. The macro name is resolved
using the same macro that is returning SAS code fragments, which need to be
quoted.

I'm really just interested in why SAS fails in this case. It took me a
while to figure this out and it seems like a non-intuitive behavior (ie,
the macro does gets called but no arguments are passed).

Boring Details
-------------------
I'm creating EXCEL reports that are defined using data stored in formats.
At run time, I read the report definitions from the formats and construct
the report. In this way, I'm able to create reports for many different
studies without having custom SAS programs (other than study-specific
driver programs that just define a bunch of formats that define the reports
to create).

Here are some examples from the report definitions::
proc format;
...

/* Tab -> Report Subset */

value $rptSub

'R_AE_COMP' = "ADSL.R|RCTRANFL='Y'"

'R_AEs' = "FINAL.R|WITHIN30='Y' and SER='Yes'

#ADSL.R|RCTRANFL='Y'"

'R_LGRSAEs' = "FINAL.R|LGRSAE_YN='Y'

#ADSL.R|RCTRANFL='Y'"

;

/* Optional: Tab -> Custom Macro Name to handle dump to Excel */

value $rptHdlr

'R_AE_COMP' = 'lineList_Default_RptHdlr'

;

...


So at run-time, I pull the SAS fragment from $rptSub and use that to subset
the data for the report. That needs to be quoted. The same macro that pulls
the report subset also pulls the name of the macro to use in the rare case
that a custom macro is needed to do the dumping of the data into EXCEL.
PaigeMiller
Diamond | Level 26

@BenF wrote:



I don't want to get too far off topic, but the quoting in the actual code is needed for exactly the reason you describe. The macro name is resolved using the same macro that is returning SAS code fragments, which need to be quoted.





So at run-time, I pull the SAS fragment from $rptSub and use that to subset the data for the report. That needs to be quoted.

Just because you say it needs to be quoted does not mean that it needs to be quoted. I am not convinced.

 

It only needs to be quoted if it contains special characters that have meaning to the macro processor. You haven't explained how that can be, and even in that case, you can't have a macro name that contains these special characters. So mark me down as not believing that you need to quote the macro variable.

 

I leave it to Mr. @Astounding to explain the details of why you need an %unquote.

--
Paige Miller
novinosrin
Tourmaline | Level 20

Very interesting question. Here is my wild guess


%let macroName = %bquote(child);

 %&macroName(d=&dsn, t=&tab, p=&path);

 

1.At compile time, when tokenisation takes place, the %bquote tells the macro processor, that the "quoted value" of  macroname aka a text called  child would have be stored as value. The quoted value remains in effect until the execution of %macro parent is complete. 

2. When %macro child is successfully compiled, an entry of the compiled macro definition is stored in work.sasmacr catalog. However when called from %macro parent, the quoted value despite a prefix of macro trigger  %&macroName remains in effect.

3. What apparently that means is, the macro call does not look for quoted text in the work.sasmacr catalog to execute. 

4. This is almost like having a global and local macro variable with the same name, hmm I am afraid perhaps not the best analogy

5. I suppose the resolved  %&macroName value  %child would mean %remainsquoted(child)

6. %unquote would of course work, but the charm is to understand the length of the duration of value to be remain quoted for macro processor to not interpret as a macro call.

 

All the above is my own guess. Kindly forgive me if nothing is true/makes any sense. 

Tom
Super User Tom
Super User

The quoting around the name is confusing the parser such that it no longer recognizes the following text in parentheses as part of the macro call.

 

So there are two solutions.  Define the macro you are calling to not have any parameters (or call it without setting any parameter values). 

%&macroName ;

Or unquote the name before trying to use it.  Since you already decided that macroName must have the name of a macro then removing the quoting will not make the program any more unsafe than it already is.

%let macroName=%unquote(&macroName);
%&macroName(parm1=,parm2=)

 

 

PaigeMiller
Diamond | Level 26

@Tom, now you're confusing me.

 

If we simply take the %bquote out of the original code, no %unquote is needed.

--
Paige Miller
Tom
Super User Tom
Super User

@PaigeMiller wrote:

@Tom, now you're confusing me.

 

If we simply take the %bquote out of the original code, no %unquote is needed.


Huh?

 

Wait I think I figured out your question. You are confusing the example code posted to demonstrate the problem and the actual problem. The %BQUOTE() is in the code to show an example of what causes the problem.  For example the program might have been using %QSCAN() or %QSYSFUNC() to parse a string into pieces and then later it made a decision that this particular piece should be used as the name of macro.

BenF
Calcite | Level 5
The code I posted was a gross simplification of the actual code. The macro
name to be called is itself the result of a macro call. The macro called
returns both macro names (this case -> no quoting needed) and SAS code
fragments (other places --> quoting needed).

Thanks, Tom for explaining what is going on! I no longer have to wait for
the movie: "SAS Macro Processing: The Movie (in 3D)". 🙂

SAS Innovate 2025: Call for Content

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!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 13 replies
  • 2920 views
  • 0 likes
  • 5 in conversation