Chapter 8 Masking Special Characters and Mnemonic Operators

Introduction

Why Are Quoting Functions Called Quoting Functions?

Illustrating the Need for Macro Quoting Functions

Describing the Commonly Used Macro Quoting Functions

Understanding How Macro Quoting Functions Work

Applying Macro Quoting Functions

Specifying Macro Program Parameters That Contain Special Characters or Mnemonic Operators

Unmasking Text and the %UNQUOTE Function

Using Quoting Versions of Macro Character Functions and Autocall Macro Programs

 

Introduction

The SAS macro language is a text-handling language. The macro facility relies on specific syntax structures in the language to perform its tasks when it constructs SAS code for you. The macro facility relies on triggers such as ampersands and percent signs to understand when you want it to resolve a macro variable and to invoke a macro program. It relies on symbols such as parentheses and plus signs, and on mnemonic operators like GT and EQ, to construct expressions and determine how to evaluate them.

Occasionally, however, your applications might require that the macro processor interpret special characters and operators simply as text and not as triggers or symbols. This chapter addresses how to write your macro programming instructions so that the macro processor interprets special characters and mnemonic operators as text.

The macro language contains several functions that you can apply to mask these special characters and mnemonic operators from interpretation by the macro processor. This chapter describes how to apply four commonly used quoting functions:

• %STR and %NRSTR

• %BQUOTE

• %SUPERQ

This chapter also describes a fifth macro quoting function, %UNQUOTE, which removes the mask from a value so that the special characters and mnemonic operators in the value are not treated as text.

Additionally, several functions and autocall macro programs listed in Chapter 6 have a quoting version, and a few examples of them are presented at the end of this chapter. This set of quoting functions and autocall macro programs perform the same actions as their nonquoting counterparts, and they also mask special characters and mnemonic operators. These functions include:

• %QSCAN

• %QSUBSTR

• %QSYSFUNC

• %QUPCASE

The autocall macro programs include:

• %QCMPRES

• %QLEFT

• %QLOWCASE

• %QTRIM

Why Are Quoting Functions Called Quoting Functions?

Macro functions that mask special characters and mnemonic operators are called quoting functions because they behave like single quotation marks in the SAS language. Just as characters that are enclosed in single quotation marks in a SAS language statement are ignored, so too are the special characters and mnemonic operators that are in the arguments to, or results of, a macro quoting function. The difference is that the macro quoting functions offer much more flexibility in what characters to ignore and when to ignore them.

Illustrating the Need for Macro Quoting Functions

Consider how SAS processes the following code where the intention is to assign the three statements in a PROC PRINT step as the value of a macro variable.

%let wontwork=proc print data=books.ytdsales;var saleprice;run;

After you submit the %LET statement, the macro processor assigns the underlined text to the macro variable WONTWORK. The macro processor treats the first semicolon it encounters as termination of the macro variable assignment. This semicolon terminating the PROC PRINT statement is not stored in the macro variable WONTWORK. After the macro processor assigns the underlined text to the macro variable WONTWORK, processing returns to the input stack and the word scanner. The word scanner tokenizes the next two statements and sends the tokens to the compiler. SAS cannot compile the VAR statement since it is not submitted as part of a PROC step. An error condition is generated as shown in the following SAS log.

1122  %let wontwork=proc print data=books.ytdsales;var saleprice;

                                                   ---

                                                   180

1122! run;

ERROR 180-322: Statement is not valid or it is used out of

               proper order.

This %LET statement demonstrates that SAS macro programmers need a way to mask semicolons, other special characters, and mnemonic operators from the macro processor’s interpretation of them. Sometimes, the task requires that you specify that certain special characters and mnemonic operators be treated simply as text.

The next %LET statement solves the problems with the above %LET statement. It applies the macro quoting function %STR to the entire PROC step. This function blocks the macro processor from interpreting any of the semicolons within the parentheses as %LET statement terminators when it compiles the %LET statement. Now all three PROC step statements, including the semicolons, are assigned to WILLWORK.

%let willwork=

    %str(proc print data=books.ytdsales;var  saleprice;run;);

If you submit a %PUT statement to display the value of WILLWORK, the macro processor writes the following to the SAS log:

1124  %put &willwork;

proc print data=books.ytdsales;var saleprice;run;

This %PUT statement does not cause the PROC PRINT step to execute. Instead, it just displays the value of the macro variable WILLWORK. If you submit the following, the PROC PRINT step does execute:

&willwork

Describing the Commonly Used Macro Quoting Functions

This section presents a brief description of the four most commonly used macro quoting functions: %STR, %NRSTR, %BQUOTE, and %SUPERQ. Three lesser-used functions, %NRBQUOTE, %QUOTE, and %NRQUOTE, are mentioned at the end of the section.

Use the %STR and %NRSTR functions to mask items during compilation. Use the %BQUOTE function to mask text or resolved values of text expressions during execution.

The “NR” function, %NRSTR, does the same as its non-“NR” counterpart, %STR, and this function also masks the ampersand (&) and percent sign (%) macro triggers.

The %SUPERQ function is also an execution function. Use it when you want to mask the value of a macro variable so that this value is treated as text and any further macro references in the value are not resolved.

The special characters and mnemonic operators that macro quoting functions can mask include:

blank

;

¬

^

~

,

'

)

(

+

-

*

/

<

>

=

|

 

 

AND

OR

NOT

EQ

NE

LE

LT

GE

GT

IN

%

&

#

 

 

%STR and %NRSTR

These two functions mask special characters at the time of compilation. These functions cause their arguments to be tokenized as text. For example, use these functions when you want to assign special characters to a macro variable as was done in the preceding example, or when a macro parameter contains special characters. %STR masks all special characters and mnemonic operators except for ampersands and percent signs. %NRSTR masks the same items as %STR and also masks ampersands and percent signs. When you have an unmatched single quotation mark, an unmatched double quotation mark, or an unmatched parenthesis, precede the unmatched character with a percent sign.

%BQUOTE

The %BQUOTE function masks special characters and mnemonic operators contained in the results from resolving macro expressions. The macro processor resolves macro expressions during execution. Use this function when the operands in your expressions might contain special characters or mnemonic operators at resolution and you want those resolved results to be treated as text. In contrast to %STR and %NRSTR, which mask constant text, the %BQUOTE function masks resolved values, and resolution occurs at execution. %BQUOTE masks all special characters and mnemonic operators except for ampersands and percent signs. Use %SUPERQ when you want to mask the same items as %BQUOTE and additionally mask ampersands and percent signs. When you have an unmatched single quotation mark, an unmatched double quotation mark, or an unmatched parenthesis, do not precede the unmatched character with a percent sign.

%SUPERQ

This function masks the value of a macro variable so that the value is treated solely as text. Percent signs and ampersands in the value of a macro variable are not resolved. The argument to %SUPERQ is the name of a macro variable without the ampersand in front of the macro variable name. With %NRBQUOTE, the macro processor masks the argument after it resolves macro variable references and values. With %SUPERQ, the macro processor masks the argument before it resolves any macro variable references or values.

Other Macro Quoting Functions: %NRBQUOTE, %QUOTE, and %NRQUOTE

The %NRBQUOTE function masks the same items as %BQUOTE and it additionally masks ampersands and percent signs. However, SAS recommends that you use %SUPERQ instead of %NRBQUOTE since %SUPERQ is more complete in its masking.

The %QUOTE and %NRQUOTE functions operate during execution and are equivalent to %BQUOTE and %NRBQUOTE with one exception. The exception is in how the two sets of functions process unmatched parentheses and unmatched quotation marks. Both %BQUOTE and %NRBQUOTE do not require that quotation marks or parentheses without a match be marked with a preceding percent sign, while %QUOTE and %NRQUOTE do require a preceding percent sign.

Understanding How Macro Quoting Functions Work

When the macro processor masks a value, it prefixes and suffixes the value with a hexadecimal character called a delta character. The macro processor selects the delta character at the time it processes the function instruction. To use macro quoting functions productively, you do not need to know what this character is. It might be helpful though to realize that the macro processor places this delta character at the beginning and end of your text string. The macro processor selects the character based on the type of quoting you specify, and it uses this character to preserve leading and trailing blanks in your value. These characters are not included as part of the expression when the macro processor evaluates comparisons. Think of them in these situations as acting like single quotation marks in a SAS language statement.

When you have the SYMBOLGEN option in effect, the macro processor writes a message in the SAS log informing you that it has unquoted the value before displaying it. This message relates to the handling of the delta characters. The following statements cause this SYMBOLGEN message to be displayed, and this message is in bold in the SAS log:

options symbolgen;

%let monthstring=%str(Jan,Feb,Mar);

%let month=%substr(&monthstring,5,3);

%put **** Characters 5-7 in &monthstring = &month;

The SAS log for the preceding code follows.

8    options symbolgen;

9    %let monthstring=%str(Jan,Feb,Mar);

10   %let month=%substr(&monthstring,5,3);

SYMBOLGEN:  Macro variable MONTHSTRING resolves to Jan,Feb,Mar

SYMBOLGEN:  Some characters in the above value which were

            subject to macro quoting have been unquoted for

            printing.

11   %put **** Characters 5-7 in &monthstring = &month;

SYMBOLGEN:  Macro variable MONTHSTRING resolves to Jan,Feb,Mar

SYMBOLGEN:  Some characters in the above value which were

            subject to macro quoting have been unquoted for

            printing.

SYMBOLGEN:  Macro variable MONTH resolves to Feb

**** Characters 5-7 in Jan,Feb,Mar = Feb

Applying Macro Quoting Functions

This section applies macro quoting functions to commonly encountered situations that require masking of special characters or mnemonic operators. The open code examples show results with and without a macro quoting function, and they use %PUT statements to display the results in the SAS log.

Example 8.1: Using %STR to Prevent Interpretation of the Semicolon As a SAS Statement Terminator

This example demonstrates masking semicolons at compilation. The goal is to assign all the code for a PROC SQL step to one macro variable, MYSQLSTEP. The underlined portion in each %LET statement shows what does get assigned to the macro variable MYSQLSTEP.

The first %LET and %PUT statements show the results when you do not apply a quoting function to the value assigned to MYSQLSTEP. The second %LET and %PUT statements show the results of applying the %STR function to the value that is assigned to MYSQLSTEP.

%let mysqlstep=proc sql;title “SAS Files in Library BOOKS”;select memname, memtype from dictionary.members where libname='BOOKS';quit;

%put WITHOUT Quoting Functions MYSQLSTEP=&mysqlstep;

%let mysqlstep=%str(proc sql;title “SAS Files in Library BOOKS”;select memname, memtype from dictionary.members where libname='BOOKS';quit;);

%put WITH Quoting Functions MYSQLSTEP=&mysqlstep;

The SAS log for the preceding statements follows.

1173  %let mysqlstep=proc sql;title “SAS Files in Library BOOKS”

1173! ;select memname, memtype from dictionary.members where

1173! libname='BOOKS';quit;

1173  %let mysqlstep=proc sql;title “SAS Files in Library BOOKS”

1173! ;select memname, memtype from dictionary.members where

       ------

       180

1173! libname='BOOKS';quit;

ERROR 180-322: Statement is not valid or it is used out of

               proper order.

1174  %put WITHOUT Quoting Functions MYSQLSTEP=&mysqlstep;

WITHOUT Quoting Functions MYSQLSTEP=proc sql

1175

1176  %let mysqlstep=%str(proc sql;title “SAS Files in Library

1176! BOOKS”;select memname, memtype from dictionary.members

1176! where libname='BOOKS';quit;);

1177  %put WITH Quoting Functions MYSQLSTEP=&mysqlstep;

WITH Quoting Functions MYSQLSTEP=proc sql;title “SAS Files in

Library BOOKS”;select memname, memtype from dictionary.members

where libname='BOOKS';quit;

Example 8.2: Using %STR to Prevent Interpretation of the Comma as an Argument Delimiter

Example 8.2 demonstrates how to mask commas from interpretation as delimiters between arguments to the macro function %SUBSTR. The goal is to extract text from a string that contains commas. Commas also serve as delimiters between the arguments to %SUBSTR.

The first argument to %SUBSTR is the string from which the text should be extracted. In Example 8.2, this string contains the first three letters of the names of three months separated by commas. The underlined portion in each %LET statement shows what the macro processor decides to interpret as the first argument to %SUBSTR.

Demonstrated with the first %LET and %PUT statements, when the commas in the string Jan,Feb,Mar, are not masked, the macro processor sees five arguments to %SUBSTR. The syntax of %SUBSTR requires two or three arguments, and the presence of five arguments generates errors. Additionally, %SUBSTR tries to convert the text Feb and the text Mar to numbers to determine from which position it should begin to extract text and how many characters it should extract.

The second %LET and %PUT statements show the results of applying the %STR function to the first argument that is passed to %SUBSTR.

%let month=%substr(Jan,Feb,Mar,5,3);

%put WITHOUT Quoting Functions &=month;

%let month=%substr(%str(Jan,Feb,Mar),5,3);

%put WITH Quoting Functions &=month;

The SAS log after submitting the four statements follows.

1178  %let month=%substr(Jan,Feb,Mar,5,3);

ERROR: Macro function %SUBSTR has too many arguments.  The

       excess arguments will be ignored.

ERROR: A character operand was found in the %EVAL function or

       %IF condition where a numeric operand is required. The

       condition was: Feb

ERROR: Argument 2 to macro function %SUBSTR is not a number.

ERROR: A character operand was found in the %EVAL function or

       %IF condition where a numeric operand is required. The

       condition was: Mar

ERROR: Argument 3 to macro function %SUBSTR is not a number.

1179  %put WITHOUT Quoting Functions &=month;

WITHOUT Quoting Functions MONTH=

1180  %let month=%substr(%str(Jan,Feb,Mar),5,3);

1181  %put WITH Quoting Functions &=month;

WITH Quoting Functions MONTH=Feb

Example 8.3:  Using %STR to Preserve Leading and Trailing Blanks

Example 8.3 shows how to preserve leading and trailing blanks in text assigned to a macro variable at compilation. The two %LET statements assign text to a macro variable. By default, the macro processor removes leading and trailing blanks from a text string when assigning it to a macro variable. Applying the %STR function to the text string in the second %LET statement prevents this action.

Both %PUT statements print asterisks adjacent to the start and end of the resolved value assigned to TITLETEXT to make it easier to see that the %STR function preserves leading and trailing blanks.

%let titletext=   B  o  o  k   S  a  l  e  s ;

%put WITHOUT Quoting TITLETEXT=*&titletext*;

%let titletext=%str(   B  o  o  k   S  a  l  e  s );

%put WITH Quoting TITLETEXT=*&titletext*;

The SAS log for the previous statements looks like this:

15   %let titletext=   B  o  o  k   S  a  l  e  s ;

16   %put WITHOUT Quoting TITLETEXT=*&titletext*;

WITHOUT Quoting TITLETEXT=*B  o  o  k   S  a  l  e  s*

17

18   %let titletext=%str(   B  o  o  k   S  a  l  e  s );

19   %put WITH Quoting TITLETEXT=*&titletext*;

WITH Quoting TITLETEXT=*   B  o  o  k   S  a  l  e  s *

Example 8.4: Using %NRSTR to Mask Macro Triggers

Example 8.4 shows how to prevent the two macro triggers, ampersands and percent signs, from interpretation at compilation by masking the triggers with the %NRSTR function. The goal is to assign text that contains an ampersand and a percent sign to the macro variable, REPORTTITLE.

The previous examples in this section used the %STR function, and the %STR function does not mask macro triggers. The %NRSTR function masks all that %STR masks, and it also masks macro triggers.

When the ampersand is not masked, the macro processor interprets the text following the ampersand as a macro variable that should be resolved. The text following the ampersand in this example is Feb. Assume when the statements execute in this example, the macro variable named Feb does not exist in the global symbol table.

When the percent sign is not masked, the macro processor interprets the text following the percent sign as a macro program call that it should execute. The text following the percent sign in this example is Sales. Assume when the statements execute in this example, a macro program named SALES has not already been compiled.

Execution of the first %LET and first %PUT statements generate warnings, not errors. The macro processor does assign a value to REPORTTITLE. Every time it attempts to resolve REPORTTITLE, it also tries to resolve FEB as a macro variable and SALES as a macro program invocation.

%let reporttitle=Jan&Feb %Sales Report;

%put WITHOUT Quoting Functions &=reporttitle;

%let reporttitle=%nrstr(Jan&Feb %Sales Report);

%put WITH Quoting Functions &=reporttitle;

The SAS log for the four statements in Example 8.4 follows:

1188  %let reporttitle=Jan&Feb %Sales Report;

WARNING: Apparent symbolic reference FEB not resolved.

WARNING: Apparent invocation of macro SALES not resolved.

1189  %put WITHOUT Quoting Functions &=reporttitle;

WARNING: Apparent symbolic reference FEB not resolved.

WARNING: Apparent invocation of macro SALES not resolved.

WITHOUT Quoting Functions REPORTTITLE=Jan&Feb %Sales Report

1190  %let reporttitle=%nrstr(Jan&Feb %Sales Report);

1191  %put WITH Quoting Functions &=reporttitle;

WITH Quoting Functions REPORTTITLE=Jan&Feb %Sales Report

Example 8.5: Using %STR to Mask Unbalanced Quotation Marks and Preceding Percent Signs

Example 8.5 shows how to mask an unbalanced quotation mark. The goal is first to assign a string of three names to the macro variable NAMES and then to extract the third name from the string and assign this value to another macro variable, NAME3. Each name contains a single quotation mark.

A macro quoting function is needed in the first %LET statement to mask the quotation marks. If you use %STR, then you also need to precede each of the three quotation marks with a percent sign.

If you submit the first set of eight statements without applying %STR and you do not include the preceding percent signs in the first %LET statement, the second through fourth statements do not execute because of the unbalanced quotation marks. Because of this cascade of errors, the SAS log for the first four statements is not shown.

Note that the example selects the third name from NAMES with the %QSCAN macro function instead of the %SCAN function. The %QSCAN function masks the result of the %SCAN function. The result contains an unmatched single quotation mark. If you used %SCAN, this unmatched single quotation mark generates errors in the statements that follow. Therefore, using %QSCAN masks the single quotation mark in NAME3, which prevents these errors.

%let names=O'DONOVAN,O'HARA,O'MALLEY;

%let name3=%qscan(&names,3);

%put WITHOUT STR and Percent Signs &=names;

%put WITHOUT STR Quoting Function &=name3;

%let names=%str(O%'DONOVAN,O%'HARA,O%'MALLEY);

%let name3=%qscan(&names,3);

%put WITH STR and Percent Signs &=names;

%put WITH STR Quoting Function &=name3;

Because the first group of statements do not execute, the SAS log for only the second group is shown:

28   %let names=%str(O%'DONOVAN,O%'HARA,O%'MALLEY);

29   %let name3=%qscan(&names,3);

30   %put WITH STR and Percent Signs &=names;

WITH STR and Percent Signs NAMES=O'DONOVAN,O'HARA,O'MALLEY

31   %put WITH STR Quoting Function &=name3;

WITH STR Quoting Function NAME3=O'MALLEY

Example 8.6: Masking Macro Triggers and Unbalanced Quotation Marks with %NRSTR and Preceding Percent Signs

Example 8.6 modifies the code in Example 8.5 by replacing the comma delimiter in the string of names with an ampersand delimiter. Since the ampersand is a macro trigger, %STR does not mask this character. It is necessary to use %NRSTR instead of %STR so that the two ampersands are masked. This prevents attempted resolution of a macro variable named O. Since the string of names contains unmatched single quotation marks, percent signs are added preceding each quotation mark.

%let names=%nrstr(O%'DONOVAN&O%'HARA&O%'MALLEY);

%let name3=%qscan(&names,3);

%put WITH NRSTR Quoting Function &=names;

%put WITH NRSTR Quoting Function NAME 3 is: &name3;

The SAS log from the preceding code follows.

36   %let names=%nrstr(O%'DONOVAN&O%'HARA&O%'MALLEY);

37   %let name3=%qscan(&names,3);

38   %put WITH NRSTR Quoting Function &=names;

WITH NRSTR Quoting Function NAMES=O'DONOVAN&O'HARA&O'MALLEY

39   %put WITH NRSTR Quoting Function NAME 3 is: &name3;

WITH NRSTR Quoting Function NAME 3 is: O'MALLEY

Example 8.7: Using %BQUOTE to Prevent Interpretation of Mnemonic Operators

The %SYSEVALF function in Example 8.7 does a Boolean evaluation of a logical expression. It demonstrates why it might be necessary to mask elements of an expression from the macro processor at the time of execution.

Example 8.7 starts by assigning the state abbreviation for Oregon, OR, to the macro variable STATE. Next, it tests whether the value of STATE equals OR. The result of the test is returned as a Boolean value: 0 means false and 1 means true.

You must tell the macro processor when you want to treat a mnemonic operator as text. In Example 8.7, you would use a quoting function to mask OR so that the macro processor treats it as text and not as a mnemonic operator.

The third %LET statement masks the value of STATE with the %BQUOTE function. The %STR function masks the text string to which the value of STATE is compared. The macro processor is

able to evaluate the condition and, in this situation, assigns a value of 1 to the macro variable VALUE because the condition it tested is true.

%let state=OR;

%let value=%sysevalf(&state eq OR, boolean);

%put WITHOUT Quoting Functions &=value;

%let value=%sysevalf( %bquote(&state) eq %str(OR), boolean);

%put WITH Quoting Functions &=value;

The SAS log for the previous statements looks like this:

1200  %let state=OR;

1201  %let value=%sysevalf(&state eq OR, boolean);

ERROR: A character operand was found in the %EVAL function or

       %IF condition where a numeric operand is required. The

       condition was: OR eq OR

1202  %put WITHOUT Quoting Functions &=value;

WITHOUT Quoting Functions VALUE=

1203  %let value=%sysevalf( %bquote(&state) eq %str(OR),

1203! boolean);

1204  %put WITH Quoting Functions &=value;

WITH Quoting Functions VALUE=1

Example 8.8: Using %SUPERQ to Prevent Resolution of Special Characters in a Macro Variable Value

The %SUPERQ macro function in Example 8.8 masks from interpretation text that looks like a macro variable reference. Example 8.8 starts with a PROC MEANS step that analyzes variable SALEPRICE for the publisher Doe&Lee Ltd. The publisher name is written such that the ampersand is adjacent to “Lee.” The program includes the publisher name in a text string that is assigned to a macro variable. When the macro variable is referenced, the usage of %SUPERQ prevents “&Lee” in the text string from being interpreted as a macro variable reference.

The PROC MEANS step computes the total of SALEPRICE for this publisher and saves the sum in the output data set SALESDL. A DATA step follows that creates the macro variable TOTSALES_DL with CALL SYMPUTX. The text assigned to TOTSALES_DL is inserted in the FOOTNOTE statement. The %SUPERQ function is applied to TOTSALES_DL in the FOOTNOTE statement, and this prevents the macro processor from attempting to resolve the “&Lee” as a macro variable reference. CALL SYMPUTX is a SAS language function that assigns values to macro variables. Its features are described in Chapter 9.

proc means data=books.ytdsales

            (where=(publisher='Doe&Lee Ltd.')) noprint;

  var saleprice;

  output out=salesdl sum=;

run;

data _null_;

  set salesdl;

  call symputx('totsales_dl',

          cat('The total sales for Doe&Lee Ltd is ',

              put(saleprice,dollar10.2),'.'));

run;

footnote “%superq(totalsales_dl)”;

Example 8.8 executes without any warnings or errors. The footnote becomes:

The total sales for Doe&Lee Ltd is $ $4,248.97.

Without the %SUPERQ function, the macro processor writes a WARNING to the SAS log. The FOOTNOTE statement without the %SUPERQ function is:

footnote “&totsales_dl”;

Since macro variable LEE does not exist, the WARNING states that the macro processor was unable to resolve the reference to macro variable LEE.

  WARNING: Apparent symbolic reference LEE not resolved.

Specifying Macro Program Parameters That Contain Special Characters or Mnemonic Operators

The preceding discussion and examples describe the use of five quoting functions: %STR, %NRSTR, %BQUOTE, %NRBQUOTE, and %SUPERQ. This section also applies these functions and does so in the context of passing parameters to macro programs where the parameter values might contain special characters or mnemonic operators.

When writing your macro programs and defining parameters for these programs, you need to consider the range of values your parameters might have. Sometimes the parameters passed to your macro program can contain special characters and mnemonic operators that need to be masked to prevent the macro processor from interpreting them.

For example, consider what happens if the value of your parameter contains a comma. The macro processor interprets commas in a macro program call to be separator characters between parameters. When a parameter value contains a special character such as a comma, you must mask that special character so that the macro processor ignores it. Examples below demonstrate this application.

As another example, consider what happens if the value of a parameter contains a mnemonic operator and the parameter is part of a macro expression inside the macro program. As shown in the preceding examples, these elements of a macro expression might need to be masked to prevent the macro processor from interpreting them as operands of the macro expression. The following examples demonstrate this application.

Example 8.9: Masking Special Characters in Parameter Values

When your parameter values can contain special characters, you need to mask them so that the macro processor does not interpret them as anything but text. To do this, you typically place either the %STR or %NRSTR function around the text that needs to be masked. If the value contains any special character other than an ampersand or percent sign adjacent to text, you can use %STR. If the value could contain an ampersand or percent sign adjacent to text, use %NRSTR to prevent the macro processor from interpreting either of those characters as macro triggers. When you mask a parameter value, it stays masked within the macro program, unless you unmask it with %UNQUOTE.

Macro program MOSECTDETAIL in Example 8.9 generates a PROC PRINT step that lists books sold during specific months from a specific section. It has two parameters. The first parameter is the list of months with months specified numerically. The second parameter is one specific section. The list of months will be inserted as the object of the IN operator on the WHERE statement. The program expects the list of months to be separated by commas.

Macro program MOSECTDETAIL is called twice. The first call does not surround the list of months with the %STR function while the second call does. The first call does not execute. The second call executes a PROC PRINT step that lists the books sold for March and June in the Software section. The underlined part of each call to MOSECTDETAIL shows the value that the macro processor interprets as the first parameter, MONTHLIST.

%macro mosectdetail(monthlist,section);

  proc print data=books.ytdsales;

    title “List of titles sold for months &monthlist”;

    where month(datesold) in (&monthlist)

          and section=“&section”;

    var booktitle saleprice;

  run;

%mend mosectdetail;

%mosectdetail(3,6,Software)

%mosectdetail(%str(3,6),Software)

After submitting the first call to MOSECTDETAIL, the macro processor writes the following to the SAS log and does not execute the PROC PRINT step. It sees three positional parameters in the call to MOSECTDETAIL. The comma that separates 3 and 6 is interpreted as the separator between two parameters.

ERROR: More positional parameters found than defined.

The second call to MOSECTDETAIL masks the comma between 3 and 6 from interpretation as the separator between parameter values. After resolution by the macro processor, the following PROC PRINT step is executed by the second call to MOSECTDETAIL.

proc print data=books.ytdsales;

  title “List of titles sold for months 3,6”;

  where month(datesold) in (3,6) and section=“Software”;

  var booktitle saleprice;

run;

Note that if you wanted to run this report for only one month you would not need to mask that value. For example, to request a report for only December for the Certification and Training section, specify the call to MOSECTDETAIL as follows.

%mosectdetail(12,Certification and Training)

Example 8.10:  Preventing Misinterpretation of Special Characters in Parameter Values

Example 8.10 defines a macro program called PUBLISHERSALES that constructs a PROC REPORT step and has three positional parameters. The first parameter, STYLE, specifies the ODS style of the HTML report. The second and third parameters, STYLEHEADER and STYLEREPORT, specify style attributes for two report locations: the header and the body of the report.

ODS style attributes for these PROC REPORT locations are written in the format:

{style-element-name=style-attribute-specification(s)}

The macro program expects the parameters to be in this format as well since it inserts these parameter values exactly as they are specified in the PROC REPORT statement STYLE(HEADER) option and the STYLE(REPORT) option.

Values for the second and third parameters passed to PUBLISHERSALES must be masked to prevent interpretation of the equal sign as a signal to the macro processor to process a keyword parameter. This example uses the %STR quoting function to mask the values of the second and third parameters.

The FONT= attribute requires that the values supplied to it be enclosed in parentheses. The %STR quoting function also masks the parentheses that are found in the FONT= specification for STYLEHEADER in Example 8.10.

The call to PUBLISHERSALES in Example 8.10:

• formats the report in the MEADOW style

• italicizes the headers and writes them in 14 pt Garamond

• writes the body of the report in 12 pt.

%macro publishersales(style,styleheader,stylereport);

  ods html style=&style;

  title “Sales by Publisher”;

  proc report data=books.ytdsales

              style(header)={&styleheader}

              style(report)={&stylereport}

              nowd;

    column publisher saleprice n;

    define publisher / group;

    define saleprice / format=dollar10.2;

  run;

  ods html close;

%mend publishersales;

%publishersales(meadow,

       %str(font_style=italic font_size=14pt font=(Garamond)),

       %str(font_size=12pt))

After resolution by the macro processor, SAS submits the following code:

ods listing close;

ods html style=meadow;

 

title “Sales by Publisher”;

proc report data=books.ytdsales

            style(header)={font_style=italic font_size=14pt

                           font=(Garamond)}

            style(report)={font_size=12pt}

            nowd;

  column publisher saleprice n;

  define publisher / group;

  define saleprice / format=dollar10.2;

run;

ods html close;

Consider what happens if the %STR functions does not surround the second and third parameters in the call to PUBLISHERSALES.

%publishersales(meadow,

           font_style=italic font_size=14pt font=(Garamond),

           font_size=12pt)

The macro processor does not execute this call to PUBLISHERSALES. It stops after reading the first two attributes specified in the second positional parameter. It interprets FONT_STYLE=ITALIC and FONT_SIZE=14PT as keyword parameters and not as elements in STYLEHEADER, the second positional parameter. Since PUBLISHERSALES does not define any keyword parameters, the call to PUBLISHERSALES ends in error and SAS writes the following messages to the SAS log.

ERROR: The keyword parameter FONT_STYLE was not defined with the macro.

ERROR: The keyword parameter FONT_SIZE was not defined with the macro.

Example 8.11:  Masking Special Characters and Mnemonic Operators in Parameter Values

Example 8.11 presents several variations in masking special characters and mnemonic operators in parameters passed to a macro program. It shows ways of masking special characters in the macro program call and ways of masking mnemonic operators within the macro program that might be part of a macro expression.

The purpose of the macro program MYPAGES is to specify text and attributes for a TITLE and FOOTNOTE statement. The macro program has six keyword parameters, three for the title and three for the footnote.

The three parameters for the TITLE statement specify the title text, the justification or position (left, center, or right) of the title, and the color of the title. The parameters for the FOOTNOTE statement are similar: one parameter specifies the footnote text, one specifies the justification, and the third specifies the color of the footnote.

The justification and color parameters for both the TITLE and FOOTNOTE statements have initial values. For the title, the default value for justification is center, and the default color is black. For the footnote, the default value for justification is right, and the default color is black.

The macro program checks to see if a value is specified for TITLETEXT, the text for the title. If not, titles are cleared by submitting a TITLE1 statement with no text. Similarly, the program checks the contents of FOOTNOTETEXT, the text for the footnote. When no value is specified for FOOTNOTETEXT, footnotes are cleared by submitting a FOOTNOTE1 statement with no text.

Problems might arise with this macro program if the values you specify for TITLETEXT or FOOTNOTETEXT contain special characters or mnemonic operators. A macro program call when one of these values contains special characters might not execute, or it might execute incorrectly if you do not mask the special characters in the macro program call. When one of these values contains mnemonic operators, the %IF statement can fail unless you mask the parameter value at execution time within the macro program.

Example 8.11 calls MYPAGES four times, each time demonstrating different applications of macro quoting functions. An explanation of each of the four calls follows the code.

%macro mypages(titletext=,jtitle=center,ctitle=black,

               footnotetext=,jfootnote=right,cfootnote=black);

  %if %superq(titletext)= %then %do;

    title1;

  %end;

  %else %do;

    title justify=&jtitle color=&ctitle

          “&titletext”;

  %end;

  %if %superq(footnotetext)= %then %do;

    footnote1;

  %end;

  %else %do;

    footnote justify=&jfootnote color=&cfootnote

             “&footnotetext”;

  %end;

%mend mypages;

options mprint;

*----First call of MYPAGES;

%mypages(titletext=Sales Report,ctitle=blue,

         footnotetext=Last Review Date: Feb 1%str(,) 2014)

*----Second call of MYPAGES;

%mypages(titletext=2013+ Sales,

         footnotetext=Prepared with SAS &sysver)

*----Third call of MYPAGES;

%mypages(titletext=Sales Report,

         footnotetext=Last Reviewed by %str(O%'Malley))

*----Fourth call of MYPAGES;

%mypages(titletext=%nrstr(Audited&Approved),

         footnotetext=

           %nrstr(%Increase in Sales for Year was 8%%),

         jfootnote=center)

First call to MYPAGES. The first call to MYPAGES specifies text for the title, the color of the title, and text for the footnote. No special characters or mnemonic operators are present in the text for the title so the parameter value is not masked. The text for the footnote does contain a special character, a comma. To prevent the macro processor from interpreting the comma as anything but text, the comma must be masked. The macro quoting function %STR successfully masks the comma. The first call to MYPAGES submits the following two SAS statements.

title justify=center color=blue “Sales Report”;

footnote justify=right color=black

               “Last Review Date: Feb 1, 2014”;

Without the %STR mask around the comma, the macro processor interprets the first call to MYPAGES to have a positional parameter following the comma whose value is 2014. SAS requires that positional parameters precede keyword parameters. The macro processor stops executing the macro program when it detects this problem. It writes the following message to the SAS log.

ERROR: All positional parameters must precede keyword parameters.

 

Note that the call to MYPAGES masks only the comma in the value for FOOTNOTETEXT. The same footnote is produced if you mask the entire value of FOOTNOTETEXT:

%mypages(titletext=Sales Report,ctitle=blue,

         footnotetext=%str(Last Review Date: Feb 1, 2014)

Select the text to mask that is easiest for you to specify. The best way to do this might be to mask the entire value. It might be easier to “count” parentheses if you mask the entire value rather than masking each of the individual special characters within the text value.

Second call to MYPAGES. The second call to MYPAGES specifies text for the title and text for the footnote. The text for the title contains an operator, the plus sign (+). The text for the footnote contains a reference to the automatic variable, SYSVER, whose value is equal to the currently executing version of SAS. The second call to MYPAGES submits the following two SAS statements.

title justify=center color=black “2013+ Sales”;

footnote justify=right color=black “Prepared with SAS 9.4”;

While it is not necessary to mask the plus sign in the macro program call, it is necessary that the value be masked in the %IF statement where it is referenced. The program applies the %SUPERQ function to the TITLETEXT value. In case a similar situation arises with the FOOTNOTETEXT value, the program applies the %SUPERQ function to FOOTNOTETEXT on the %IF statement where FOOTNOTETEXT is referenced. The %BQUOTE function would also work for this application, but to completely prevent resolution of macro triggers that might occur in the value, the %SUPERQ function is used instead.

Consider what happens if you omit the %SUPERQ function from the program and you rewrite the %IF statement as follows.

%if &titletext= %then %do;

The second call to MYPAGES would not execute without masking the value of TITLETEXT at execution. The macro processor interprets the plus sign in the value for TITLETEXT as an operator. With %SUPERQ removed, the same second call to MYPAGES produces the following error messages in the SAS log.

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: &titletext=

ERROR: The macro MYPAGES will stop executing.

 

Note that the reference to SYSVER in the parameter specification for FOOTNOTETEXT is not masked. In this situation, the goal is to display the resolved value of SYSVER in the footnote. SAS resolves the references to SYSVER when the call to MYPAGES is tokenized. This resolution happens before the %IF statement that applies %SUPERQ to FOOTNOTETEXT executes.

Third call to MYPAGES. The third call to MYPAGES specifies text for the title and text for the footnote. The text for the title does not contain any operators or special characters and it is not masked. The text for the footnote contains an unmatched quotation mark that must be masked. The third call to MYPAGES submits the following two SAS statements.

title justify=center color=black “Sales Report”;

footnote justify=right color=black

              “Last Reviewed by O'Malley”;

Both the %STR function and the percent sign preceding the unmatched quotation mark are required to mask the unmatched quotation mark. Without one of the two masking items, SAS does not see a complete call to MYPAGES, and this condition results in processing errors involving unmatched quotation marks and parentheses.

Fourth call to MYPAGES. The fourth call to MYPAGES specifies text for the title, text for the footnote, and center justification of the footnote. The text for the title contains the ampersand macro trigger followed by text. The text for the footnote contains the percent sign macro trigger and concludes with a percent sign. The fourth call to MYPAGES submits the following two SAS statements.

title justify=center color=black “Audited&Approved”;

footnote justify=center color=black

              %Increase in Sales for Year was 8%”;

Since the parameter values for TITLETEXT and FOOTNOTETEXT contain macro triggers, the %NRSTR function must be used instead of the %STR function as in the first call to MYPAGES. Without masking the value for TITLETEXT, the macro processor attempts to resolve a macro variable named APPROVED. Without masking the value for FOOTNOTETEXT, the macro processor attempts to execute a macro program named INCREASE. The macro program MYPAGES does execute with the unmasked parameters and produces the correct TITLE and FOOTNOTE statements. However, SAS writes the following warnings to the SAS log.

WARNING: Apparent symbolic reference APPROVED not resolved.

WARNING: Apparent invocation of macro INCREASE not resolved.

 

There are several ways to specify the concluding percent sign in the value specified for FOOTNOTETEXT. If you remember to leave a space after the percent sign, you do not need to provide any additional instruction to prevent the macro processor from interpreting the percent sign as anything but text.

%mypages(titletext=%nrstr(Audited&Approved),

         footnotetext=

           %nrstr(%Increase in Sales for Year was 8% ),

         jfootnote=center)

Recall that a percent sign can serve as a mask for an unmatched parenthesis. If you put the right parenthesis next to the percent sign, the macro processor interprets the right parenthesis as text.

%mypages(titletext=%nrstr(Audited&Approved),

         footnotetext=

           %nrstr(%Increase in Sales for Year was 8%),

         jfootnote=center)

Submitting the preceding call to MYPAGES does not cause MYPAGES to execute because it needs another right parenthesis to fully specify the call, as shown here:

%mypages(titletext=%nrstr(Audited&Approved),

         footnotetext=

           %nrstr(%Increase in Sales for Year was 8%)),

         jfootnote=center)

Specifying an additional parenthesis as in the immediately preceding call to MYPAGES still does not produce the desired footnote. The concluding percent sign is not treated as text and a right parenthesis becomes part of the footnote. Submitting the preceding call to MYPAGES defines this footnote:

%Increase in Sales for Year was 8)

Another way to code the specification for FOOTNOTETEXT is to insert two concluding percent signs.

%mypages(titletext=%nrstr(Audited&Approved),

         footnotetext=

           %nrstr(%Increase in Sales for Year was 8%%),

         jfootnote=center)

This last call to MYPAGES executes as desired, and it produces the following footnote:

%Increase in Sales for Year was 8%

Unmasking Text and the %UNQUOTE Function

Occasionally you might need to restore the meaning of special characters and mnemonic operators that have been masked. Applying the %UNQUOTE function to the masked value tells the macro processor to remove the mask and resolve the special characters and mnemonic operator.

Example 8.12: Using %UNQUOTE to Cause Interpretation of a Masked Character

In Example 8.12, the call to the macro program MAR has been masked and assigned to the macro variable M. This text is placed in the first TITLE statement. To have the value of M interpreted, the %UNQUOTE function must be used. The second TITLE statement contains the results of applying %UNQUOTE to the value of M.

%macro mar;

  This is March

%mend;

%let m=%nrstr(%mar);

title “Macro call &m generates the following text”;

title2 “%unquote(&m)”;

The TITLE statements after submission of the preceding code are as follows:

Macro call %mar generates the following text

This is March

Using Quoting Versions of Macro Character Functions and Autocall Macro Programs

The results of macro character functions and the SAS autocall macro programs are unmasked or unquoted. The macro processor resolves special characters and mnemonic operators in the results. If you want to mask these items in a result, use the quoting version of the function or autocall macro program.

In Chapter 6, Table 6.1 included descriptions of the quoting versions of macro character functions, and Table 6.7 included descriptions of the quoting versions of SAS autocall macro programs. The %QSCAN function was used in Example 8.5 with unbalanced quotation marks. Two additional examples of using the quoting versions of macro functions follow in Examples 8.13 and 8.14.

Example 8.13: Using %QSYSFUNC to Mask the Result from Applying a SAS Language Function

Described in Chapter 6, the %SYSFUNC function applies SAS language functions to macro variables and text and returns results to the macro facility. When your result could include special characters or mnemonic operators, you should use %QSYSFUNC, which is the quoting version of %SYSFUNC. This function does the same tasks as %SYSFUNC, and it also masks special characters and mnemonic operators.

The macro language statements in Example 8.13 demonstrate an application of %QSYSFUNC. The first %LET statement assigns a value to macro variable PUBLISHER. The next statements convert the text and to an ampersand and remove the blanks. Two %PUT statements display the results.

The second %LET statement converts the text and to an ampersand using the SAS language function TRANWRD and %SYSFUNC, and it stores the result in macro variable PUBLISHER2.

The third %LET statement removes the blanks in PUBLISHER2 using the SAS language function COMPRESS and %SYSFUNC, and it assigns the result to PUBLISHER3. Execution of this %LET statement causes the macro processor to write warnings to the SAS log since the result of the two functions is not quoted, and the macro processor tries to resolve the macro variable reference &LEE in the result.

The fourth %LET statement uses COMPRESS and %QSYSFUNC, and it assigns the result to PUBLISHER3. This time, the value assigned to PUBLISHER3 is quoted through the use of %QSYSFUNC, and the macro processor does not interpret &LEE as a macro variable reference.

Note that the %NRSTR function masks the macro function names in the two %PUT statements. If you do not mask these items, the macro processor attempts to execute these functions. In the %PUT statements, these two function names are meant to be displayed as text and not to be interpreted as calls to the functions. Therefore, without the use of %NRSTR, syntax errors are generated.

%let publisher=Doe and Lee;

%let publisher2=%sysfunc(tranwrd(&publisher,and,&));

%let publisher3=%sysfunc(compress(&publisher2)) Ltd.;

%put PUBLISHER3 defined with %nrstr(%SYSFUNC): &publisher3;

%let publisher3=%qsysfunc(compress(&publisher2)) Ltd.;

%put PUBLISHER3 defined with %nrstr(%QSYSFUNC): &publisher3;

The SAS log from the preceding open code statements follow. Note that execution of the last %LET statement and %PUT statement does not produce any warnings in the SAS log.

230  %let publisher=Doe and Lee;

231  %let publisher2=%sysfunc(tranwrd(&publisher,and,&));

232  %let publisher3=%sysfunc(compress(&publisher2)) Ltd.;

WARNING: Apparent symbolic reference LEE not resolved.

233  %put PUBLISHER3 defined with %nrstr(%SYSFUNC): &publisher3;

WARNING: Apparent symbolic reference LEE not resolved.

PUBLISHER3 defined with %SYSFUNC: Doe&Lee Ltd.

234

235  %let publisher3=%qsysfunc(compress(&publisher2,%str( ))) Ltd.;

236  %put PUBLISHER3 defined with %nrstr(%QSYSFUNC): &publisher3;

PUBLISHER3 defined with %QSYSFUNC: Doe&Lee Ltd.

Example 8.14: Using %QSUBSTR to Mask the Results of %SUBSTR

Example 8.14 uses the %QSUBSTR macro function to mask the results of the %SUBSTR macro function. The macro variable MONTH3 is defined by extracting text from the MONTHS macro variable using the %SUBSTR macro function. This action results in a warning because the macro processor attempts to resolve what looks like a macro variable reference in the text extracted by %SUBSTR.

The macro variable QMONTH3 is defined by extracting text from the MONTHS macro variable using the %QSUBSTR macro function. The %QSUBSTR macro function masks the ampersand in the extraction. No warning messages are generated because the macro processor ignores the ampersand in the text extracted by the %QSUBSTR macro function.

%let months=%nrstr(Jan&Feb&Mar);

%let month3=%substr(&months,8);

%put Unquoted: &month3;

%let qmonth3=%qsubstr(&months,8);

%put Quoted: &qmonth3;

The SAS log from Example 8.14 follows. The warnings result from execution of the %LET statement that defines MONTH3 and from execution of the first %PUT statement. The value assigned to MONTH3 is not masked. Therefore, the macro processor interprets &MAR as a macro variable reference. Since macro variable MAR does not exist in this example, the macro processor issues the warnings.

40   %let months=%nrstr(Jan&Feb&Mar);

41   %let month3=%substr(&months,8);

WARNING: Apparent symbolic reference MAR not resolved.

42   %put Unquoted: &month3;

WARNING: Apparent symbolic reference MAR not resolved.

Unquoted: &Mar

43

44   %let qmonth3=%qsubstr(&months,8);

45   %put Quoted: &qmonth3;

Quoted: &Mar

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.179.139