DATA Step, Macro, Functions and more

Odd use of %STR() at execution time

Accepted Solution Solved
Reply
PROC Star
Posts: 1,450
Accepted Solution

Odd use of %STR() at execution time

Hi All,

 

Over on Stack Overflow there was a routine question about how to macro quote a value like OR, and one of the comments surprised me. https://stackoverflow.com/questions/50395483/how-to-mask-or-with-variable-list-passed-through-using-...

 

A simple macro like:

 

%macro ck(state) ;
  %if &state=RI %then %put Rhode Island! ;
  %else %put Not Rhode Island ;
%mend ck ;

Will choke given a value like OR or 1+.2, because they are seen by the implied %EVAL as operators:

 

100 %ck(OR)
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: &state=RI
ERROR: The macro CK will stop executing.

101 %ck(1+.2)
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: &state=RI
ERROR: The macro CK will stop executing.

 

My answer would be to use a macro execution time quoting function, e.g. %superq(state) or %bquote(&state) to quote the resolved value of STATE.

 

The surprise to me is that apparently %STR(&state) will work (?) for the value of OR:

 

110 %macro ck(state) ;
111 %if %str(&state)=RI %then %put Rhode Island! ;
112 %else %put Not Rhode Island ;
113 %mend ck ;
114
115 %ck(OR)
Not Rhode Island

 

I would have expected that to fail, since %str() works at macro compile time, I would think the OR would still be seen during macro execution time, and would cause problems for %EVAL.

 

Happily, %STR() is not enough to mask 1+.2 , so it still errors:

 

116 %ck(1+.2)
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: &state=RI
ERROR: The macro CK will stop executing.


And happily, %SUPERQ can handle all those scenarios, so I'll definitely keep using %superq and %bquote for execution-time quoting. But I'm curious why %STR(&state) seems to be enough to mask OR.

 

Kind Regards,
--Q.


Accepted Solutions
Solution
‎05-20-2018 03:50 PM
PROC Star
Posts: 1,450

Re: Odd use of %STR() at execution time

Given a macro that uses %STR() to attempt execution-time macro quoting:

 

%macro ck(state) ;
  %if %str(&state)=RI %then %put Rhode Island! ;
  %else %put Not Rhode Island ;
%mend ck ;

 

1. Why does %ck(OR) work? That is, why does %STR() suffice to mask the resolved OR operator?
2. Given that %ck(OR) works, why does %ck(|) not work? Why doesn't %STR() mask the resolved | operator?

 

I think I understand it after re-reading what I consider to be the trinity of macro quoting papers:
https://www.lexjansen.com/nesug/nesug99/bt/bt185.pdf
https://www.lexjansen.com/nesug/nesug03/at/at012.pdf
https://analytics.ncsu.edu/sesug/2008/CS-049.pdf

 

%STR() works at macro compile time. %STR(SOME ARGUMENT) adds an unprintable delta character before SOME ARGUMENT, an unprintable delta character after SOME ARGUMENT, and looks in the argument for a list of symbols that need to be masked by converting them to delta characters. The list includes ; | + - = etc. Since %STR() works at compile time, it cannot mask any symbols that result from resolving a macro reference. because it won't see them.

 

So why does %STR(&state) work when state resolves to OR? It's because even though %STR never sees the OR token, it still adds the delta characters before and after the OR. And it turns out that when %STR() macro quotes an OR, it doesn't actually convert OR into delta characters.  Adding the delta characters to the beginning and end is enough.

 

If you run:

%macro test(dummy) ;
  %let OR=%str(0 OR 1) ;
  %let pipe=%str(0|1) ; 
  %let plus=%str(0+1) ;
  %put _local_ ;
%mend ck ;
%test()


The %PUT _local_ allows you to see some of the delta characters added. This shows that in order to mask OR, %str() does not actually convert the OR token to masked characters. The delta characters added at the beginning and end of the string are enough to mask the OR. But for the pipe operator and + operator, when %STR masks them it converts them to delta characters.

 

I think that explains why %ck(OR) works but %ck(|) and %ck(1+.1) still error.  %STR() doesn't actually have to see the OR in order to mask it, because adding a delta character to the front and end is enough. But for | and + to be masked, %STR() needs to see them, so that they can be converted to a delta character. Since %STR can't see them (when they result from resolving a macro variable), it can't mask them.

 

Sounds reasonable? 

View solution in original post


All Replies
PROC Star
Posts: 1,591

Re: Odd use of %STR() at execution time

Odd use of %STR() at execution time beats all odds of SAS documenatation. Thank you @Quentin Sir for sharing and helping folks like me learn something new. 

Super User
Posts: 10,691

Re: Odd use of %STR() at execution time

[ Edited ]

I am not sure I correctly understood it.

 

Compile stage is before execution stage, then mask a macro variable would not be a problem .

i.e. the mask character(delta) is still there. when in execution stage the macro variable is still be masked .

PROC Star
Posts: 1,450

Re: Odd use of %STR() at execution time


@Ksharp wrote:

I am not sure I correctly understood it.

 

Compile stage is before execution stage, then mask a macro variable would not be a problem .


 

Since %STR() works at macro compile time, it cannot quote a value that results from resolving a macro variable. Because it works before the macro variable has resolved.  

 

So below, the first comparison succeeds because %STR() masks the + operator.  The second comparison errors because %STR() can't mask the + operator that results from resolving MVAR because it doesn't see it.

 

%macro test(dummy) ;
  %if %str(1+A)=%str(1+A) %then %put 1+A=1+A ;

  %local mvar ;
  %let mvar=1+B ;
  %if %str(&mvar)=%str(1+B) %then %put 1+B=1+B ;
%mend ;

%test()

The surprise to me was that %STR() can effectively mask OR  which results from resolving MVAR. 

 

%macro test(dummy) ;
  %if %str(1 OR A)=%str(1 OR A) %then %put 1+A=1+A ;

  %local mvar ;
  %let mvar=1 OR B ;
  %if %str(&mvar)=%str(1 OR B) %then %put 1 OR B=1 OR B ;
%mend ;

%test()

 

I think I understand it now, will add a separate post with my explanation.

 

 

Super User
Posts: 10,691

Re: Odd use of %STR() at execution time

@Quentin

 

Interesting thing is if there is not =-/* ,the code would work.

 

 

%macro test(dummy) ;
  %if %str(1+A)=%str(1+A) %then %put 1+A=1+A ;

  %local mvar ;
  %let mvar=1BB ;
  %if %str(&mvar)=%str(1+B) %then %put 1+B=1+B ;
%mend ;

%test()

 

It looks like SAS add %eval() where string has '+' .

 

if there is a '+' ,then code would look like  %if %str(%eval(1+b))  -->  %if  delta %eval() delta 

if there is not a '+' then code would look like  %if %str(1bb)  -->  %if  delta 1bb delta 

so this should work .

PROC Star
Posts: 1,450

Re: Odd use of %STR() at execution time

[ Edited ]

The %IF statement always uses %EVAL to evaluate the expression.  I added a separate answer.

 

I think the short answer is that %str(&mvar) can "work" to mask OR because of the way %STR() quotes OR, which is different than the way %STR() quotes + or |. 

 

%STR() quotes OR by adding a delta character at the beginning and end of the quoted string.

%STR() quotes + and | by adding a delta character at the beginning and end of the quoted string, and converting the quoted symbols into delta characters.

 

Since %STR(OR) doesn't convert OR into delta characters, I think its a side effect that %STR(&mvar) works when MVAR resolves to OR.

Solution
‎05-20-2018 03:50 PM
PROC Star
Posts: 1,450

Re: Odd use of %STR() at execution time

Given a macro that uses %STR() to attempt execution-time macro quoting:

 

%macro ck(state) ;
  %if %str(&state)=RI %then %put Rhode Island! ;
  %else %put Not Rhode Island ;
%mend ck ;

 

1. Why does %ck(OR) work? That is, why does %STR() suffice to mask the resolved OR operator?
2. Given that %ck(OR) works, why does %ck(|) not work? Why doesn't %STR() mask the resolved | operator?

 

I think I understand it after re-reading what I consider to be the trinity of macro quoting papers:
https://www.lexjansen.com/nesug/nesug99/bt/bt185.pdf
https://www.lexjansen.com/nesug/nesug03/at/at012.pdf
https://analytics.ncsu.edu/sesug/2008/CS-049.pdf

 

%STR() works at macro compile time. %STR(SOME ARGUMENT) adds an unprintable delta character before SOME ARGUMENT, an unprintable delta character after SOME ARGUMENT, and looks in the argument for a list of symbols that need to be masked by converting them to delta characters. The list includes ; | + - = etc. Since %STR() works at compile time, it cannot mask any symbols that result from resolving a macro reference. because it won't see them.

 

So why does %STR(&state) work when state resolves to OR? It's because even though %STR never sees the OR token, it still adds the delta characters before and after the OR. And it turns out that when %STR() macro quotes an OR, it doesn't actually convert OR into delta characters.  Adding the delta characters to the beginning and end is enough.

 

If you run:

%macro test(dummy) ;
  %let OR=%str(0 OR 1) ;
  %let pipe=%str(0|1) ; 
  %let plus=%str(0+1) ;
  %put _local_ ;
%mend ck ;
%test()


The %PUT _local_ allows you to see some of the delta characters added. This shows that in order to mask OR, %str() does not actually convert the OR token to masked characters. The delta characters added at the beginning and end of the string are enough to mask the OR. But for the pipe operator and + operator, when %STR masks them it converts them to delta characters.

 

I think that explains why %ck(OR) works but %ck(|) and %ck(1+.1) still error.  %STR() doesn't actually have to see the OR in order to mask it, because adding a delta character to the front and end is enough. But for | and + to be masked, %STR() needs to see them, so that they can be converted to a delta character. Since %STR can't see them (when they result from resolving a macro variable), it can't mask them.

 

Sounds reasonable? 

Super User
Posts: 10,691

Re: Odd use of %STR() at execution time

That is just what I want to say .

☑ This topic is solved.

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

Discussion stats
  • 7 replies
  • 154 views
  • 1 like
  • 3 in conversation