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.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.