Macro quoting made easy

10

Are there times when you need to pass special characters to a macro variable but cannot find the right technique to accomplish the task?  In this article I’ll discuss the different macro quoting functions and give a simple technique to help you determine which macro quoting function to use.

Why do we need macro quoting?  The SAS macro language is a character-based language. With macro, you can specify special characters as text.  Some of these special characters (for example, a semicolon or percent sign) are part of the SAS language instruction set, so we need a way for the macro processor to interpret a particular special character when it’s being used as text in the macro language.  Macro quoting functions tell the macro processor to treat these special characters as text rather than as part of the macro language.  Without macro quoting functions, you would have no way to mask the real meaning of these special characters or mnemonics.

This post will list some all-purpose functions, tell how to determine when to use each type, and show you how to unmask, or unquote special characters.

Two types of macro quoting functions

There are basically two types of macro quoting functions:  compile time and execution time.

Compile time functions:

  • % STR
  • % NRSTR

%STR and %NRSTR mask the same characters except %NRSTR also masks & and % signs.

Execution time functions:

  • %SUPERQ   (Reminder: do not use & with macro variable name)
  • %BQUOTE

There are other execution-time functions, but these are the only two you really need. %BQUOTE and %SUPERQ mask the same characters except %SUPERQ does not attempt to resolve a macro variable reference or a macro invocation that occurs in the value of the specified macro variable.  %SUPERQ masks everything without any further resolution which makes it the best execution-time quoting function to use.

How to determine which type to use

Many times the hardest part of macro quoting is knowing whether you need a compile time function or an execution time function.  A simple technique that will help you easily choose the right one is to follow this motto:

If you can see the problem, it is a compile issue; otherwise, it is execution time.

These examples illustrate when a compile time function is needed.  You can see the potential problem in each of the examples:

macroquote1

There are a few special cases when you have an unmatched quotation mark or an unmatched parenthesis. These unmatched characters must be preceded with a percent sign when assigning a value at compile time.  For example:

macroquote2

These examples illustrate when an execution time function is needed.  You cannot see the potential problem in each of the examples:

macroquote3

Unquoting special characters

Now that we have seen how to mask special characters, we also need a way to reverse the masking. This reversal is referred to as unquoting which means to restore the significance of symbols in an item that was previously masked by a macro quoting function.

Generally, once you use a macro quoting function on a value, the macro processor retains that masking on the value. There are three cases where the unquoting is done for you:

  • The %UNQUOTE function was used.
  • The item leaves the word scanner and is passed to the DATA step compiler, SAS Macro Facility, or other parts of the SAS System.
  • The value is returned from the %SCAN, %SUBSTR, or %UPCASE function.

There are two cases where you might need to use the %UNQUOTE function to restore the original significance to a masked item:

  • When you want to use a value with its restored meaning later in the same macro in which its value was previously masked by a macro quoting function.
  • In some cases, masking text with a macro quoting function changes the way the word scanner tokenizes it, producing SAS statements that look correct but the SAS compiler does not recognize. This is the most common need for %UNQUOTE.

macroquote4

The code generated by the macro may look correct, but an error is generated because the masking placed on the value from the %QSCAN (to be discussed later) is causing the string to be tokenized incorrectly.  This can be corrected by using the %UNQUOTE function.
%unquote(val&v) = &v/500;

Resolving macro variables within single quotes

Many times single quotes are required around a string where the string is made up of a macro variable.  Since macro triggers of percent and ampersand are seen as text within single quotes, a common request is how to resolve a macro variable within single quotes.  We can use %UNQUOTE along with %STR for this task:

macroquote6

An easy way to determine if a quoting function has been used on a macro variable is to use the following statement to print out the values:
%PUT _USER_;

Here is a screenshot of a resulting SAS log. Notice the unusual spaces and characters. These represent the masking done by a quoting function.  Quoting functions mark the beginning and ending of the string as well as any special character.

macroquote7

Other quoting functions

There are a few other functions that mask a result that may contain special characters.  These functions all begin with Q:  %QSYSFUNC, %QSCAN, %QSUBSTR and %QUPCASE. Here are a few examples:

macroquote8

I hope this blog post has been helpful. If you have other SAS macro questions you’d like me to cover in future blogs, please comment below.

Share

About Author

Russ Tyndall

SAS Technical Support Analyst

Russ Tyndall is a Senior Principal Technical Support Analyst in the Foundation SAS group in Technical Support. He has been a SAS user since 1993, and provides general support for the DATA step and Base procedures. He specializes in the SAS macro facility and has been the primary support for more than 18 years .

10 Comments

  1. Well, I laughed out loud at the title, but this is a masterful treatise on macro quoting. Thank you. I try to relearn macro quoting once every year or so, and this is a definite bookmark. Very happy to see that there is no mention made of %NRBQUOTE. Personally, would love to see %NRBQUOTE officially deprecated. I think it only adds confusion to folks trying to learn macro quoting. Totally agree that %STR/%NRSTR/%SUPERQ and occasionally %BQUOTE are the full package. And the "can you see it?" test is one of my golden rules. Will be linking to this post often whenever macro quoting comes up in discussion forums. Great stuff!

  2. Bruno Müller on

    Excellent post about something you will come across quite often. Since SAS9.4 there is a new function %TSLIT that will put single quotes around a macro variable refetence

  3. Very good indeed about the macro quoting.
    As having appetite for more, another idea: Scope and visibility of macro-vars.

    I am thinking of: local(default) global usage, functions subroutines/nested, remote connects, from prompts

    • How about deprecating macro all together? Or at least make it obsolete in favor of more modern programming constructs?

      SAS is 40 years old - how about updating the language like "every other" modern programming language?

      IMO I should be able to say something like this in open code:

      myvar=1; * or $myvar, etc, etc ;

      if (myvar=1) then do;
      data foo;set bar;run;
      end;
      else do;
      put "myvar is not equal 1";
      end;

      etc, etc, you get the idea.

      I shouldn't need a pre-compiler for simple logical constructs that every other modern programming language supports!

      Don't get me wrong - I know macro well, and use it all the time. But I'd rather ***program*** in Python, C#, Java, etc, that support modern code constructs.

      If the SAS language was object oriented, even better.

      Perhaps Viya will help, but I feel like SAS keeps pasting bandaids on tired code.

      • Russ Tyndall

        Similar type syntax is available for SAS Viya 3.0. You can use macro %IF/%THEN/%DO now in open code, for example:

        %if &myvar=1 %then %do;
        data foo;set bar;run;
        %end;
        %else %do;
        %put "myvar is not equal 1";
        %end;

  4. But with it ,%scan still take comma as an argument separator .

    209 %let y= %qsysfunc(date(),worddate.);
    210 %put &y ;
    August 16, 2014
    211 %let x=%scan(%qsysfunc(date(),worddate.),1);
    212 %put &x ;
    August
    213 %let x=%scan(%qsysfunc(date(),worddate.),2);
    214 %put &x ;
    16
    215 %let x=%scan(%qsysfunc(date(),worddate.),3);
    216 %put &x ;
    2014

    • Russ Tyndall

      That is correct. Without %QSYSFUNC the statement would like the following:

      %let x=%scan(August 18, 2014,3);
      %put &x ;

      In this case the 2014 would represent the 'n' argument and the 3 would represent the 'charlist'.

      %QSYSFUNC allows those commas to be treated as text rather than as an argument seperator.

      This is the correct syntax:

      %let x=%scan(%qsysfunc(date(),worddate.),3);
      %put &x ;

  5. Thanks for the posting. I always recall this quotation by Ian Whitlock when refreshing my knowledge of macro quoting:

    "Anyone who thinks macro quoting is simple, probably doesn't understand the problem."

  6. Excellent summary. Just one comment on when to use %unquote based on my experience teaching the SAS Macro Language course back in the 80s: If it looks right, but doesn't work, wrap a %unquote around it and it probably will work.

  7. I really like the distinction between compile-time and execution-time functions. Does it break down, however, with respect to open code macro statements like %LET or %PUT? As far as I understand it, open code macro statements are executed immediately without any compilation yet there are many cases where we still need to use compile-time macro quoting functions (%STR and %NRSTR).

    Does this mean that some type of compiling does actually occur for open code macro statements? Or is the compile-time/execution-time quoting distinction just a handy rule of thumb that does not apply in these instances?

Leave A Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to Top