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 = [¯oName]; %put PARENT>>> dsn = [&dsn]; %put PARENT>>> tab = [&tab]; %put PARENT>>> path = [&path]; %¯oName(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 %¯oName(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
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).
%¯oName ;
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(¯oName);
%¯oName(parm1=,parm2=)
You don't need to use %BQUOTE.
%let macroName = %bquote(child);
You can just assign Child to macroname.
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.
@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.
@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.
@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.
Very interesting question. Here is my wild guess
%let macroName = %bquote(child);
%¯oName(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 %¯oName 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 %¯oName 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.
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).
%¯oName ;
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(¯oName);
%¯oName(parm1=,parm2=)
@Tom, now you're confusing me.
If we simply take the %bquote out of the original code, no %unquote is needed.
@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.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.