Have you ever had a macro variable that doesn’t resolve to the value you expect? You’re left with a broken heart, wondering where things went wrong. Typical relationship advice would say, it’s just bad timing—and in macro programming, that might actually be true.
In this post, we’ll take a look at the timing of macro processing and explore one possible remedy for your broken macro relationships: the %NRSTR function. This is the beginning of a series on macro quoting functions to help you better understand where things are going wrong… or why what you're doing is working just fine.
When a SAS program is submitted, it’s sent to an area of memory called the input stack. The input stack holds the program while the word scanner analyzes characters and breaks them into tokens. Tokens are the smallest pieces of meaningful information to SAS.
The four token types are:
A token ends when the word scanner encounters either a blank space or when a new token begins.
The following code would be tokenized as shown by the color coding:
As the word scanner reads each token, it determines where to send it. Everything in the above program is sent from the input stack to the word scanner for tokenization. After tokenization, it’s sent to the compiler and executed.
The ampersand (&) and percent sign (%) are macro triggers. When the word scanner encounters a macro trigger followed by an underscore or character, it sends the information to the macro processor instead of the compiler. The macro processor interprets the macro language and sends the result back to the top of the input stack, where it is re-tokenized by the word scanner.
SAS also creates a global symbol table at the beginning of each session to store automatic and global macro variable values. When a macro definition is called, a local symbol table is also created.
The diagram below shows the processing flow when a program is submitted:
The following code uses product names from a sample data set with orders placed by superstore customers. The data set and code can be downloaded from my GitHub.
Let’s walk through an example of an unproblematic macro.
%let prodnm=Bush Somerset Collection Bookcase;
title "Orders placed for: &prodnm";
proc print data=blog.superstore_small;
where product_name="&prodnm";
run;
Here’s what happens:
Results:
In the following program, the macro variable value contains an &, which is a macro trigger. When the program is run, three warnings are generated in the log- but the correct results are returned. Why?
%let prodnm=C-Line Peel&Stick Add-On Filing Pockets, 8-3/4 x 5-1/8, 10/Pack;
title "Orders placed for: &prodnm";
proc print data=blog.superstore_small;
where product_name="&prodnm";
run;
Log:
Results:
The warnings are harmless because there's no macro variable named stick, so nothing is substituted. But what if there is one?
%let stick=UnwantedText;
%let prodnm=C-Line Peel&Stick Add-On Filing Pockets, 8-3/4 x 5-1/8, 10/Pack;
title "Orders placed for: &prodnm";
proc print data=blog.superstore_small;
where product_name="&prodnm";
run;
This time, a macro variable named stick exists. Now the macro processor encounters &Stick, finds the value UnwantedText in the global symbol table, and substitutes it. The resulting value of prodnm becomes: C-Line PeelUnwantedText Add-On Filing Pockets.
The TITLE and WHERE statements are now incorrect:
title "Orders placed for: C-Line PeelUnwantedText Add-On Filing Pockets";
where product_name="C-Line PeelUnwantedText Add-On Filing Pockets";
This is not a valid value in the data, therefore no rows are returned, and no report is generated.
Log:
To protect your macro values from unintended substitutions, use the %NRSTR quoting function. %NRSTR masks special characters, including & and %, and mnemonic operators in constant text during macro compilation. This prevents the macro processor from resolving macro variables during compilation.
%let stick=UnwantedText;
%let prodnm=%nrstr(C-Line Peel&Stick Add-On Filing Pockets, 8-3/4 x 5-1/8, 10/Pack);
title "Orders placed for: &prodnm";
proc print data=blog.superstore_small;
where product_name="&prodnm";
run;
Log:
Results:
Adding %NRSTR around the value for &prodnm causes the macro processor to treat the & as regular text. Even though a macro variable named stick exists, %NRSTR masks the & so it’s treated as text, not as a macro trigger. You get the expected result, no warnings, and accurate output.
A similar function to %NRSTR is %STR. Both are used to mask special characters and mnemonic operators in constant text at macro compilation, however, %STR does not mask % and &.
The special characters and mnemonics they both mask are:
They also mask the following characters when they occur in pairs. If only one of these characters appears in the text, add a preceding % to mask it.
For example, the following would cause unexpected log notes due to the unclosed quotation mark:
%let prodnm=Eldon Fold 'N Roll Cart System;
To mask it, use %STR with a % in front of the quotation mark:
%let prodnm= %str(Eldon Fold %'N Roll Cart System);
%put &=prodnm;
Log:
Here’s what we’ve covered:
I hope this explanation saves you from future macro heartbreak. Stay tuned for more advice on how to build strong, functional macro relationships.
If this post feels like the macro programming version of a self-help book, that’s because it is—an encouraging first step toward understanding where things might be going wrong. But sometimes, you need more than just good advice… you need macro therapy.
For a deeper dive into macro logic, quoting functions, and how to avoid messy breakups with your code, I highly recommend our SAS e-learning courses. Start with SAS Macro Language 1: Essentials and follow up with SAS Macro Language 2: Advanced Techniques. They’re like a trusted therapist—ready to walk you through the hard parts, step by step.
Find more articles from SAS Global Enablement and Learning here.
If I may suggest, the best "macro quoting" reading ever:
"Secrets of Macro Quoting Functions - How and Why" by Susan O’Connor
https://www.lexjansen.com/nesug/nesug99/bt/bt185.pdf
@yabwon Wonderful, thank you for sharing!
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.