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:
/* 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;
Why would %BQUOTE() not have any effect just because you used it in the middle of a %LET statement?
@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?
%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;
@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?
@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.
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 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.
@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.
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.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.