Most SAS programmers know that macro quoting functions exist. Some SAS programmers know a few macro quoting functions. Very few SAS programmers are experts in macro quoting and know exactly what the different functions do. And when they do it. The topic of macro quoting is advanced. In this post, I will present 5 macro quoting functions that will solve most problems that macro programmers encounter. These are the %Str, %Nrstr, %Bquote, %Nrbquote and %Superq functions. I will not go into detail about each function or why masking is necessary. Rather, I will present examples and highlight the differences between the functions. In the summary, I link to literature that explains the concept in more depth.
Str and Nrstr Function
First off, let us explore the %Str and %Nrstr Functions. %Str is probably the most used quoting function of all. Perhaps because it was the first quoting function in the macro facility. %Str and %Nrstr are quite similar. They both mask the special characters ) = ; ( | ¬ + # ^ — ~ * , / ‘ < “ > and mnemonics such as OR and GE and so on. However, Nrstr masks the macro triggers & and % as well. Both functions mask text before it is sent to the macro processor. This means that text masked by one of these functions is not sent to the macro processor. Only the resulting text is. Let us look at a few examples.
In the code below, I want to save an entire Proc Print step in a macro variable. However, the macro processor interprets the first semicolon as the end of the macro variable definition. Consequently, only ‘proc print data=sashelp.class’ is stored in the macro variable st.
%let ds = sashelp.class; %let st = proc print data=&ds; run;; %put &st;
We can use the SAS %Str Function to mask the entire statement. This stores the entire statement in the macro variable.
%let ds = sashelp.class; %let st = %str(proc print data=&ds; run;); %put &st;
Suppose, I do not want to resolve the macro variable &ds. Instead, I want to store the Proc Print statement exactly as is stands. I can use the %Nrstr Function to do this. Hint: NR stands for No Rescan or Not Resolved. Meaning that macro triggers are masked and macro expressions are not resolved by the SAS macro processor.
%let ds = sashelp.class; %let st = %nrstr(proc print data=&ds; run;); %put &st;
Obviously, we could also have quoted only the semicolons and ampersand in the code above.
Bquote and Nrbquote
Next, let us take a look at the %Bquote and %Nrbquote Functions. %Bquote and %Nrbquote mask the same symbols as %Str and %Nrstr respectively. However, they also mask unmatched symbols, that SAS expects to come in pairs like ‘, “, ( and ). Consider the code below. The string “The dog’s tail” contains an unmatched single quotation mark. If we revolve the macro variable a without quoting, SAS will look for the matching quotation mark. Since this does not exist, there will be problems. Luckily, the %Bquote Function successfully masks the string and remove the special meaning from the unmatched quotation mark.
data _null_; v = "The dog's tail"; call symputx('a',v); run; %let b = %bquote(&a); %put &b;
Again, the Nr part of %Nrbquote means ‘Not Resolved’. Consequently, the Nrbquote Function masks macro triggers % and & and prevents them from being resolved by the macro processor. Consider the example below. Here, we create the macro variable a with the value AT&T. The first code snippet results in two warnings. One in the first line, where SAS tries to resolve the macro variable T because during tokenization, SAS interprets the ampersand as a macro trigger. In a clean SAS session, the T macro variable does not exist. In the %Put Statement, SAS issues a warning because the macro variable a resolves to AT&T. Again, SAS interprets the T as a macro variable and attempts to resolve it.
%let a = AT&T; %put The value of a is &a;
We can get rid of the second warning if we use the Nrbquote Function. In the code below, SAS attempts to resolve &T in the first line. However, the Nrbquote function ensures that the ampersand is masked in the result. Therefore, it does not try to resolve &T in the %Put Statement. Remember, Bquote and Nrbquote are execution time functions.
%let a = %nrbquote(AT&T); %put The value of a is &a;
It’s All About Timing
Besides the unmatched symbols masking, the difference between the Str/Nrstr and Bquote/Nrbquote is all about timing. It is very important to understand that the Str class functions mask text before it goes through the macro processor. The Quote class function masks the result from the macro processor. Let us consider an example. The %Left Function left aligns text and requires a single argument. In this case, I want to left-align the text ” one, two”. However, SAS interprets the comma as an argument separator. Therefore, SAS yields an error.
%let a = %left( one, two);
We need to mask the comma to tell SAS to interpret the comma as plain text. Since the argument contains no macro triggers and I want to mask the actual text on my screen, my first choice is %Str. This works like a charm and the %Left Function executes with success.
%let a = %left(%str( one, two)); %put &a.;
What if the argument is not plain text though? What if the argument to the %Left Function is in a macro variable? Consider the code below. Now, the Str Function is no good because now we want to mask the resolved value. Not the plain text (&a) inside the %Left Function. Since the resolved value does not contain macro triggers to be masked and we want to mask the resolved value, we use the %Bquote Function. This gives us the correct result.
%let a = one, two; %let b = %left(%bquote( &a)); %put &b.;
Generally speaking, when we want to quote the current value of an argument, we use Str and Nrstr. This is typically constant text with no reference to macro statements. All other quoting functions will work on resolved values.
Finally, let us consider the %Superq Function. The Superq Function operates on values of macro variables only. It masks all items that require quoting at macro execution. Also, it does not issue any warnings, that macro variables were not resolved as the Nrbquote Function does. The Superq and Nrbfunction mask the same symbols though. In that sense, the Superq Function is the strongest of all quoting functions in SAS. You will often see it used when accounting for special characters in user defined input.
Consider the code below. Suppose, I want to display the macro variable value in the log with no resolution at all. Here, the macro variable a contains both an ampersand and a percent sign. Consider the three %Put Statements. In the first, no quoting is done. Therefore, SAS attempts to resolve both the macro variable &Somevar and the macro %DoIt. Since the macro %DoIt exists, this executes. &Somevar does not exist, so SAS issues a warning in the log. Instead, we use the Superq function to display the value of a in the log. The Superq Function retrieves the value of a from the global symbol table and quotes it immediately. This prevents the macro processor from making any attempt to resolve anything that might occur in the resolved value.
%macro DoIt; %put Macro DoIt Was Called!; %mend; data _null_; call symputx('a', 'Macro Var &SomeVar and Macro Call %DoIt'); run; %put &a; %put %superq(a);
In this post, I demonstrate examples of the five macro quoting functions Str, Nrstr, Bquote, Nrbquote and Superq. If you know about these functions, you can get far in the field of masking. It can be a bit confusing to decide which function to use under you specific circumstances. The SAS Documentation has a nice overview in Deciding When to Use a Macro Quoting Function and Which Function to Use.
Macro quoting is a very advanced topic. Needless to say, I do not attempt to give a thorough insight into macro quoting. Rather, I scratch the surface and demonstrate what the common quoting functions do. And perhaps most importantly, when they do it. Remember, understanding macro quoting is understanding the timing of the functions. For more thorough literature, I recommend A Serious Look Macro Quoting and Chapter 7.1 on Quoting Functions in Carpenter’s Complete Guide to the SAS Macro Language. Also, consult the SAS Macro Quoting Documentation.
You can download the entire code from this post here.