BookmarkSubscribeRSS Feed
pchegoor
Pyrite | Level 9

I am trying to understand why the Macro quoting function %bquote works in the simple %LET  statement below.

 

In the code below  I  understand why the First %LET  does not work and the Second %LET works. 

 

But why does the Third %LET also work even though %bquote has no  Macro quoting effect during the compilation of %LET  statement?  I would have expected this to end up with an error similar to error seen from the execution of  First  %LET below.

 

Any thoughts  @Quentin , @ArtC   and others?  Code executed on SAS Studio which comes with SAS OnDemand for Academics.

 

Error  from First %LET statement in below Code:

%Let x1= Example;Sample;;
                             _______
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
 
 
Code :
/* This obviously will not work*/
%Let x1= Example;Sample;;

%Put &=x1;

/* This will work*/
%Let x2= %str(Example;Sample;);

%Put &=x2;


/* This too will work. Not sure why*/
%Let x3= %bquote(Example;Sample;);


%Put &=x3;

 

9 REPLIES 9
Tom
Super User Tom
Super User

Why would %BQUOTE() not have any effect just because you used it in the middle of a %LET statement?

pchegoor
Pyrite | Level 9

@Tom   I meant to say when the third  %LET statement compiles, the semicolon after the word Example will not be masked by the %bquote and therefore the macro processor should regard this semicolon as terminating the %LET  statement similar to what happens when the First %LET compiles and executes. An Error is what i was expecting. Am i wrong?

Tom
Super User Tom
Super User

%BQUOTE() definitely quotes semi-colons.  Wouldn't be much of a macro quoting function if it didn't.

Try it.

%let x=%bquote(;);

%let y=a&x.b;

%put &=y;

 

pchegoor
Pyrite | Level 9

@Tom   Sure Tom.   But  what i don't understand is why this quoting is happening.

 

According the  documentation :  https://documentation.sas.com/?docsetId=mcrolref&docsetTarget=p0frhtfqvguv78n1owh5wfeopdrj.htm&docse...

 

%BQUOTE and %NRBQUOTE mask values during execution of a macro or a macro language statement in open code.

 

As per the statement above, %bquote will not mask the semicolon after the word Example while the third %LET statement compiles, and this semicolon will thus end the  %LET  statement and when it executes the value assigned to macro variable x3  should only be Example . The orphan token Sample should result in an Error.

 

Am I wrong in understanding the above?

FreelanceReinh
Jade | Level 19

@pchegoor wrote:

According the  documentation :  https://documentation.sas.com/?docsetId=mcrolref&docsetTarget=p0frhtfqvguv78n1owh5wfeopdrj.htm&docse...

 

%BQUOTE and %NRBQUOTE mask values during execution of a macro or a macro language statement in open code.

 

As per the statement above, %bquote will not mask the semicolon after the word Example while the third %LET statement compiles,...


My understanding is that "a macro language statement in open code" -- such as your %LET statement -- is immediately executed upon submission. (After all, the assigned value can be retrieved in the next statement.) Hence, "as per the statement above," %bquote will mask the semicolon.

 

However, in a macro the same %LET statement would not work because the (first) semicolon would be processed during compilation of the macro. It would mark the end of the %LET statement (as %bquote does not quote it during compilation) and during macro execution it would not even be considered part of the argument of %bquote.

Quentin
Super User

Hi @pchegoor , I can't give you a good explanation for why %BQUOTE works like %STR() in open code.  I know that it does, because I've seen people do it, and it works, but it always feels wrong to me when I see it, and I don't use %BQUOTE that way myself.

 

The difference between %STR and %BQUOTE is clear when they are used inside of a macro definition.  As the docs says, %STR() masks characters during macro compile time, and %BQUOTE masks characters during macro execution time.  

 

%macro foo1() ;
  %*This does NOT work cuz %BQUOTE masks at macro execution time ;
  %Let x1= %bquote(Example;Sample;);
  %put &=x1 ;
%mend foo1 ;
%foo1()

%macro foo2() ;
  %*This does work cuz %STR masks at macro compile time ;
  %Let x2= %str(Example;Sample;);
  %put &=x2 ;
%mend foo2 ;
%foo2()

So why would both %STR() and %BQUOTE work in open code when masking a semicolon?:

%Let x1= %bquote(Example;Sample;);
%put &=x1 ;

%Let x2= %str(Example;Sample;);
%put &=x2 ;

I'm not sure.  One thing I've heard is that the while the definition of compile-time and execution-time for a macro are clear (because macros are explicitly compiled and then executed), it's not as clear what those terms really mean for open macro statements.  Is an open %LET statement really compiled rather than just being interpreted

 

I tend to follow the rule that when you (a person reading code) can see the symbol to be masked, use %STR/%NRSTR.  When you cannot see the symbol to be masked, because it results from resolving a macro variable / expression, use %BQUOTE/%SUPERQ.

 

To my mind, it's odd that in open code, %BQUOTE is able to do the work that %STR() is intended to do.  Note that %STR() cannot do the work of %BQUOTE.  For example, below open code works with BQUOTE, but would not work with %STR() because you would have unmatched quotes:

data _null_ ; 
  call symputx("x","Example'Sample") ;
run ;               

%put %bquote(&x) ;

Some people use %BQUOTE in open code because it can mask a single quote or single parenthesis, without marking it with a % sign:

%let x1=%bquote(Example'Sample) ;

But I always use %STR in this setting, even at the cost of typing an extra %:

%let x2=%str(Example%'Sample) ;
The Boston Area SAS Users Group is hosting free webinars!
Next webinar will be in January 2025. Until then, check out our archives: https://www.basug.org/videos. And be sure to subscribe to our our email list.
Tom
Super User Tom
Super User

The only use I have ever found for %BQUOTE() is to add single quotes around macro variable values.

%let sql_date = %bquote('%sysfunc(today(),yymmdd10.)');

In general if I want to add macro quoting to macro variable I use %SUPERQ().  If I want to add quoting to constant text I use %STR() or possible %NRSTR() and stick in the extra percent signs where needed.

pchegoor
Pyrite | Level 9

@Tom    One other way of putting quotes around macro variable values is using the %tslit  function.  I believe this was available starting 9.4  release of SAS  when DS2  language became production-ready.

 

%let sql_date = %tslit(%sysfunc(today(),yymmdd10.));

%Put &=sql_date;

 

Also, I tend to use %bquote  mostly when there is a need to resolve the value of macro variables within single quotes though there are other ways of doing this too.

 

 

%Let x=1;

%Let y=%bquote('&x');

%Put &=y;   

 

 

 

 @Quentin   Thanks for your explanation. Sometimes this Macro Quoting subject tends to get trickier and a bit frustrating.

Tom
Super User Tom
Super User

I usually avoid the SAS written macros. They are usually in-efficient, probably because they were originally written for older versions of SAS.

For example you could simplify TSLIT to:

%macro tslit(value);
%sysfunc(quote(&value,%str(%')))
%mend tslit;

See %SQUOTE() macro.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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
  • 9 replies
  • 4052 views
  • 3 likes
  • 4 in conversation