DATA Step, Macro, Functions and more

Is there a simpler way to use Macro Quoting here?

Accepted Solution Solved
Reply
Trusted Advisor
Posts: 1,631
Accepted Solution

Is there a simpler way to use Macro Quoting here?

Let's suppose I have a list of parameter names in a SAS data set, two of which are shown here

GainRange_Test Gain DCGN_L (None) 401

Image_Test UnifRMS (%rms) 114

Note that the second parameter name contains a percent sign, if I'm not careful SAS will think I am talking about the %rms macro, when in fact this is just text.

So, if I capture these parameter names in a SAS macro variable &parameters as follows:

proc sql noprint;

select distinct parameter into Smiley Tonguearameters separated by '~' from use_these_parameters1;

quit;

%put PARAMETERS %superq(parameters);

The %put statement gives the correct result:

PARAMETERS GainRange_Test Gain DCGN_L (None) 401~Image_Test UnifRMS (%rms) 114

Now, I want to run this macro variable through a macro %eqt1 that does some useful tasks ... please note that I have stripped most of the useful tasks out of the example next just to illustrate the problem

%macro eqt1(string=);

%do ii=1 %to %sysfunc(countw(%nrbquote(&string),~));

  %let thisword=%qscan(%nrbquote(&string),&ii,~);

  %put II &ii PARAMETER "%quote(%qupcase(%nrbquote(&thisword)))";

%end;

%mend;

%eqt1(string=%superq(parameters))


Works properly (as far as I can tell), however note that in the line of the macro which begins with %put II that I have a whole lot of quoting going on. If I leave out some of this quoting, for example, if I remove the %quote function, I get a WARNING in my SASLOG

WARNING: Apparent invocation of macro RMS not resolved.

even though everything seems to work properly. The WARNING makes me nervous, but so does this extreme amount of quoting within a single command. So, my questions are:

1) Should I worry about this WARNING?

2) Is there a simpler way to do this quoting that doesn't produce the WARNING?


Accepted Solutions
Solution
‎04-08-2014 12:37 PM
Super User
Posts: 5,099

Re: Is there a simpler way to use Macro Quoting here?

Paige,

Much of the time, the warning won't hurt anything, but there are some pitfalls.  What if there actually was a macro named %RMS?  Can you guarantee that the "apparent invocations" will never actually find a macro with that name?  The other pitfall involves SASAUTOS and the autocall facility.  Once a search for a named macro fails, the automatic search process is turned off.  Additional macros would not be found, when they exist in the autocall library but have not yet been defined in the program.

I would guess this works, but haven't tested it:

%let thisword=%superq(thisword);

The %PUT statement shouldn't attempt to unquote anything.  While you have simplified your application, it is unlikely that quoting will produce any harm in subsequent code.

Good luck.

View solution in original post


All Replies
Solution
‎04-08-2014 12:37 PM
Super User
Posts: 5,099

Re: Is there a simpler way to use Macro Quoting here?

Paige,

Much of the time, the warning won't hurt anything, but there are some pitfalls.  What if there actually was a macro named %RMS?  Can you guarantee that the "apparent invocations" will never actually find a macro with that name?  The other pitfall involves SASAUTOS and the autocall facility.  Once a search for a named macro fails, the automatic search process is turned off.  Additional macros would not be found, when they exist in the autocall library but have not yet been defined in the program.

I would guess this works, but haven't tested it:

%let thisword=%superq(thisword);

The %PUT statement shouldn't attempt to unquote anything.  While you have simplified your application, it is unlikely that quoting will produce any harm in subsequent code.

Good luck.

Trusted Advisor
Posts: 1,631

Re: Is there a simpler way to use Macro Quoting here?

Can you guarantee that the "apparent invocations" will never actually find a macro with that name?  The other pitfall involves SASAUTOS and the autocall facility.

Today, I can state that there are no %rms macros available to the system. I cannot state that this will always be true in the future, nor can I anticipate possible future parameter names that might contain other text strings beginning with a percent sign. Thus, my desire to make sure the code always avoids trying to use %rms (or %whatever) in the parameter names as a macro invocation.

I would guess this works, but haven't tested it:

%let thisword=%superq(thisword);

Hmmm ... appears to work as you stated, I remove all the quoting from the %put statement except I still need %qupcase, and it works.

So, I don't know if there's a simple explanation why this works, I will attempt to figure this out, but if you can explain in one paragraph why this works, it would be greatly appreciated.

And why doesn't %NRBQUOTE work here? It seems to me that from my reading of the docs about %NRBQUOTE, it should do what I want as well, but it does not.

Super User
Posts: 5,099

Re: Is there a simpler way to use Macro Quoting here?

Best guess:  %nrbquote needs to resolve &STRING.  As part of that resolution, it keeps re-resolving until all macro triggers (& and %) are gone.  Once that happens, %nrbquote works on the resulting string.

The attempted invocation of %rms occurs when resolving &string, before %nrbquote starts quoting.

Respected Advisor
Posts: 3,777

Re: Is there a simpler way to use Macro Quoting here?

Are the strings data or code.  I you can keep them out of the code (macro world) then no problem.  Maybe easier said than done.

Super User
Super User
Posts: 6,502

Re: Is there a simpler way to use Macro Quoting here?

I would put the call to %SUPERQ() right after the SQL code that creates the string.

data have ;

input parameter $50. ;

cards4;

GainRange_Test Gain DCGN_L (None) 401

What about, comma?

Image_Test UnifRMS (%rms) 114

;;;;

proc sql noprint;

select distinct parameter into Smiley Tonguearameters separated by '~' from have;

%let parameters=%superq(parameters);

quit;

%macro eqt1(string=);

%do ii=1 %to %sysfunc(countw(&string,~));

  %let thisword=%qscan(&string,&ii,~);

  %let upword = %qupcase(&thisword);

  %put II=&ii PARAMETER=|&upword|;

%end;

%mend;


%eqt1(string=&parameters);

Trusted Advisor
Posts: 1,631

Re: Is there a simpler way to use Macro Quoting here?

Thanks, everyone.

I had a feeling there were much simpler ways to get this done, I just have to get to the point where these concepts are much clearer in my mind.

🔒 This topic is solved and locked.

Need further help from the community? Please ask a new question.

Discussion stats
  • 6 replies
  • 278 views
  • 3 likes
  • 4 in conversation