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 March 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-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

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
  • 4507 views
  • 3 likes
  • 4 in conversation