Transcript Slide 1

Chapter 5: Passing and Processing Macro
Parameters
5.1 Validating Parameter Values
5.2 Data-Driven Macro Calls
5.3 Working with Special Characters
1
Chapter 5: Passing and Processing Macro
Parameters
5.1 Validating Parameter Values
5.2 Data-Driven Macro Calls
5.3 Working with Special Characters
2
Objectives

3
Validate macro parameters.
Parameter Validation
Up to this point, many of Orion Star’s applications have
minimal parameter validation. The developers want to
increase the amount of validation to reduce difficulties
caused by user input. All macro applications should
perform the following actions:
 establish rules for valid values
– Are null values valid?
– What are valid values?
 validate parameter values against valid values
 generate error or warning message when invalid
values are encountered and possibly terminate the
macro
4
Without Parameter Validation (Review)
The PRINTLST macro prints a subset of data based on
the variables Country, Gender, and Type from
orion.customer_dim.
%macro printlst(country=AU,gender=F,type=CLUB);
%upvalue
proc print data=orion.customer_dim;
var Customer_Name Customer_ID Customer_Age_Group
Customer_Type;
where Customer_Country = "&country" and
Customer_Gender = "&gender" and
upcase(Customer_Type) contains "&type";
title "Listing of Customer Names Subsetted By:";
title2 "Country=&country Gender=&gender Customer Type=&type";
run;
title;
%mend printlst;
5
Without parameter validation, what potential problems
might a user of this macro encounter?
m205d01
Without Parameter Validation (Review)
COUNTRY
A null value or an invalid value will return
zero rows.
GENDER
A null value or an invalid value will return
zero rows.
A null value might result in an incorrect
subset of data or zero rows. An invalid
value might result in an incorrect subset of
data or zero rows.
TYPE *
* The CONTAINS operator selects observations that
include the specified substring. The substring AL, null
values, and blank values are found in the variable
Customer_Type.
6
Validation Against a Known List of Values
When a list of valid values is known, the macro
applications should use one of these to validate
parameter values:
 the OR operator for equals conditions
 the AND operator for not-equals conditions
 the user-defined FIND macro
 the IN operator

7
The IN operator is new in SAS 9.2.
Validation Using the OR and AND Operators
%macro grplist(type);
%let type=%upcase(&type);
%if &type= or (&type ne GOLD and &type ne INTERNET
and &type ne CATALOG) %then
%do;
%if &type = %then
%put ERROR: A null value for TYPE is not valid.;
%else %put ERROR: Value of TYPE: &type is not valid.;
%put ERROR- Valid values are CATALOG, INTERNET or GOLD;
%put ERROR- The macro will terminate now.;
%return;
%end;
proc print data=orion.customer_dim;
var Customer_Group Customer_Name Customer_Gender
Customer_Age;
where upcase(Customer_Group) contains "&type";
title "&type Customers";
run;
title;
%mend grplist;
8
m205d02a
Validation Using the OR and AND Operators
Partial SAS Log
1922 %grplist()
ERROR: A null value for TYPE is not valid.
Valid values are CATALOG, INTERNET or GOLD
The macro will terminate now.
1923 %grplist(silver)
ERROR: Value of TYPE: SILVER is not valid.
Valid values are CATALOG, INTERNET or GOLD
The macro will terminate now.
1924
%grplist(catalog)
NOTE: There were 8 observations read from the data set ORION.CUSTOMER_DIM.
WHERE UPCASE(Customer_Group) contains 'CATALOG';
NOTE: PROCEDURE PRINT used (Total process time):
real time
0.00 seconds
cpu time
0.00 seconds
9
Validation Using the FIND Macro
The FIND macro simplifies the %IF statement logic.
%macro grplist(type);
%let type=%upcase(&type);
%if &type= or %find(GOLD INTERNET CATALOG ,&type)=0 %then
%do;
%if &type = %then
%put ERROR: A null value for TYPE is not valid.;
%else %put ERROR: Value of TYPE: &type is not valid.;
%put ERROR- Valid values are CATALOG, INTERNET or GOLD;
%put ERROR- The macro will terminate now.;
%return;
%end;
proc print data=orion.customer_dim;
var Customer_Group Customer_Name Customer_Gender
Customer_Age;
where upcase(Customer_Group) contains "&type";
title "&type Customers";
run;
title;
%mend grplist;
10
m205d02b
Using the IN Operator
Although similar in functionality to the DATA step IN
operator, the macro IN operator is syntactically different.
Macro
DATA Step
The # can be used in place of the keyword
IN.
Yes
No
The operator requires parentheses around
the list of values.
No
Yes
The operator requires the MINOPERATOR
option or system option.
Yes
No
Placement of the NOT operator is a
consideration.
The operator allows for null values.
11
Before the IN Before the IN
expression
operator
No
Yes
Incorrect Validation of Null Using the IN
Operator
%macro grplist(type)/minoperator;
%let type=%upcase(&type);
%if &type= or not(&type in GOLD INTERNET CATALOG) %then
%do;
%if &type = %then
%put ERROR: A null value for TYPE is not valid.;
%else %put ERROR: Value of TYPE: &type is not valid.;
%put ERROR- Valid values are CATALOG, INTERNET or GOLD;
%put ERROR- The macro will terminate now.;
%return;
%end;
proc print data=orion.customer_dim;
var Customer_Group Customer_Name Customer_Gender
Customer_Age;
where upcase(Customer_Group) contains "&type";
title "&type Customers";
run;
title;
%mend grplist;
12
m205d02c
Incorrect Validation of Null Using the IN
Operator
If the macro variables in the IN expression resolve to a
null value, the macro processor generates the following
errors:
2145 %grplist()
SYMBOLGEN: Macro variable TYPE resolves to
SYMBOLGEN: Macro variable TYPE resolves to
ERROR: Operand missing for IN operator in argument to %EVAL
function.
ERROR: The macro GRPLIST will stop executing.
The IN operator does not recognize a null value as a valid
value. If TYPE resolves to null, the %IF statement
resolves to this statement:
%if = or not(
13
in GOLD INTERNET CATALOG) %then %do;
Validation of Null Using the IN Operator
Testing for a null value must be done separately and prior
to the %IF statement containing the IN operator.
%if &type= %then
%do;
%put ERROR: A null value for TYPE is not valid.;
%put ERROR- Valid values are CATALOG, INTERNET or GOLD;
%put ERROR- The macro will terminate now.;
%return;
%end;
%if not(&type in GOLD INTERNET CATALOG) %then
%do;
%put ERROR: Value of TYPE: &type is not valid.;
%put ERROR- Valid values are CATALOG, INTERNET or GOLD;
%put ERROR- The macro will terminate now.;
%return;
%end;
14
m205d03
Validating Null
Using the IN Operator
This demonstration illustrates using the IN
operator to test against a list of values.
15
m205d03
Validation Using a Dynamic List of Values
To reduce maintenance associated with parameter
validation, the Orion Star programmers want to generate
a data-driven list to replace the hardcoded values.
%if not(&country in AU CA DE IL TR US ZA) %then %do;
The SQL procedure can be used to create the list of valid
values dynamically and to save the result into a macro
variable.
16
The SQL Procedure INTO Clause (Review)
proc sql noprint;
select distinct country into :countrylist separated by ' '
from orion.customer;
quit;
Partial SAS Log
2241 %put Customer Countries: &countrylist;
Customer Countries: AU CA DE IL TR US ZA
17
m205d04
The SQL Procedure INTO Clause (Review)
The INTO clause can store the unique values of
a specified column in a single macro variable.
General form of the INTO clause to create a list of
unique values in one macro variable:
SELECT DISTINCT col1, . . .
INTO :mvar SEPARATED BY 'delimiter', . . .
FROM table-expression
WHERE where-expression
other clauses;
18
Validating Using
a Dynamic List of Values
This demonstration illustrates using the SQL
procedure to generate a data-driven list.
19
m205d04
Exercise
This exercise reinforces the concepts discussed
previously.
20
Chapter 5: Passing and Processing Macro
Parameters
5.1 Validating Parameter Values
5.2 Data-Driven Macro Calls
5.3 Working with Special Characters
21
Objectives
Generate repetitive macro calls using the following:
 %DO loop
 CALL EXECUTE routine
 SQL procedure
22
Data-Dependent Macro Calls
The Orion Star programmers need to call the MEMLIST
macro for each value of Customer_Type. Because
the value of Customer_Type can change, they want
to generate data-dependent macro calls as illustrated
below:
%memlist(Orion Club members inactive)
%memlist(Orion Club members low activity)
%memlist(Orion Club members medium activity)
%memlist(Orion Club members high activity)
%memlist(Orion Club Gold members low activity)
%memlist(Orion Club Gold members medium activity)
%memlist(Orion Club Gold members high activity)
%memlist(Internet/Catalog Customers)
23
Data-Dependent Macro Calls
Three different methods can be used to generate
data-dependent macro calls.
1. %DO loop
2. CALL EXECUTE routine
3. SQL procedure
24
Method 1: %DO Loop
Generally used to generate SAS code, the %DO loop can
be used to generate data-dependent macro calls.
%macro gencall;
data _null_;
set orion.customer_type end=final;
call symputx(cats('type', _n_, Customer_Type,'L');
if final then call symputx('n',_n_,'L');
run;
%do num=1 %to &n;
%memlist(&&type&num)
%end;
%mend gencall;
%gencall
25
m205d05
Method 1: %DO Loop
Partial Symbol Table
Variable
Value
NUM
1
TYPE1
Orion Club members inactive
TYPE2
Orion Club members low activity
TYPE3
Orion Club members medium activity
Generate Macro Calls
%memlist(&&type&num)
%memlist(&type1)
%memlist(Orion Club members inactive)
26
Method 1: %DO Loop
Partial SAS Log
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
proc print data=Orion.Customer_dim;
var Customer_Name Customer_ID Customer_Age_Group;
where Customer_Type="Orion Club members low activity";
title "A List of Orion Club members low activity";
run;
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
title;
proc print data=Orion.Customer_dim;
var Customer_Name Customer_ID Customer_Age_Group;
where Customer_Type="Orion Club members medium activity";
title "A List of Orion Club members medium activity";
run;
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
title;
proc print data=Orion.Customer_dim;
var Customer_Name Customer_ID Customer_Age_Group;
where Customer_Type="Orion Club members high activity";
title "A List of Orion Club members high activity";
run;
27
Generating Code with the DATA Step
The EXECUTE routine processes a text string during
DATA step execution and can be used to generate
data-driven macro calls.
General form of the CALL EXECUTE statement:
CALL EXECUTE (argument);
The value of argument can be one of the following:
 a text expression, enclosed in quotation marks
 the name of a character variable
 a character expression that is resolved by the DATA
step to a macro text expression
28
Generating Code with the DATA Step
If argument is a text expression, it is inserted into the
input stack as additional program code that will execute
after the current DATA step.
Partial SAS Log
334
335
336
337
data new;
Dog='Paisley';
call execute('proc print; run;') ;
run;
NOTE: The data set WORK.NEW has 1 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time
0.01 seconds
cpu time
0.01 seconds
NOTE: CALL EXECUTE generated line.
1
+ proc print; run;
NOTE: There were 1 observations read from the data set WORK.NEW.
NOTE: PROCEDURE PRINT used (Total process time):
real time
0.00 seconds
cpu time
0.00 seconds
29
Executing Macro Code from a DATA Step
If the argument to the CALL EXECUTE routine resolves to
a macro call, the macro executes immediately and DATA
step execution pauses while the macro executes.
 Macro language statements within the macro definition
are executed.
 All other SAS code generated by the macro is inserted
into the input stack to execute after the current DATA
step.
30
Method 2: CALL EXECUTE Routine
Use the CALL EXECUTE routine to generate a macro call
for each value of Customer_Type.
data _null_;
set orion.customer_type(keep=Customer_Type) end=final;
macrocall=catt('%memlist(', Customer_Type, ')');
call execute(macrocall) ;
run;
 The orion.customer_type data set contains
one observation for each unique value of
Customer_Type.
31
m205d06
Method 2: CALL EXECUTE Routine
Partial SAS Log
858
859
860
861
862
data _null_;
set orion.customer_type(keep=Customer_Type) end=final;
macrocall=catt('%memlist(', Customer_Type, ')');
call execute(macrocall) ;
run;
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
MPRINT(MEMLIST):
32
proc print data=Orion.Customer_dim;
var Customer_Name Customer_ID Customer_Age_Group;
where Customer_Type="Orion Club members inactive";
title "A List of Orion Club members inactive";
run;
title;
proc print data=Orion.Customer_dim;
var Customer_Name Customer_ID Customer_Age_Group;
where Customer_Type="Orion Club members low activity";
title "A List of Orion Club members low activity";
run;
title;
proc print data=Orion.Customer_dim;
var Customer_Name Customer_ID Customer_Age_Group;
where Customer_Type="Orion Club members medium activity";
title "A List of Orion Club members medium activity";
run;
title;
Method 3: The SQL Procedure
Use the INTO clause of PROC SQL to create a macro
variable that contains a macro call for each value.
proc sql noprint;
select distinct catt('%memlist(', customer_type, ')')
into :mcalls separated by ' '
from orion.customer_type;
quit;
&mcalls
33
*Resolution results in macro calls;
m205d07
Exercise
This exercise reinforces the concepts discussed
previously.
34
Chapter 5: Passing and Processing Macro
Parameters
5.1 Validating Parameter Values
5.2 Data-Driven Macro Calls
5.3 Working with Special Characters
35
Objectives




36
List and describe special characters.
Pass special characters.
Use special characters in functions.
Protect special characters in resolved values.
Special Characters
The macro language is a character-based language.
Special characters can be misinterpreted by the macro
processor when they appear in text strings, including
these operators.
blank , ; “ ‘ ( ) | + - * / < > = ¬ ^ ~ % & #
The following mnemonics might also be misinterpreted:
AND OR NOT EQ NE LE LT GE GT IN
37
Comma: Argument Separator or Part of Text?
Commas are used as separators between parameter
values in macro calls and as arguments in functions.
%macro name(fullname);
%let first=%scan(&fullname,2);
%let last=%scan(&fullname,1);
%let newname=&first &last;
%put &newname;
%mend name;
%name(Taylor, Jenna)
The comma will be misinterpreted as a
separator instead of as part of the value.
38
Quotation Mark: Literal Delimiter or
Part of Text?
An apostrophe or unmatched quotation mark is treated as
the beginning of a quoted string, causing the windowing
environment to stop responding.
%macro unmatched(fullname);
%let first=%scan(&fullname,2);
%let last=%scan(&fullname,1);
%let newname=&first &last;
%put &newname;
%mend unmatched;
%unmatched(O'Malley, George)
The apostrophe is treated as the
beginning of a quoted string.
39
OR: Logical Operator or a Text Abbreviation?
The literal OR is interpreted as a logical operator that
requires an expression on each side of the OR operator.
%macro operator(state);
%if &state = OR %then %put State is Oregon;
%else %put State is &state;
%mend operator;
%operator(PA)
The %IF statement resolves to
%if PA=
OR
which is not allowed.
40
%then,
Ampersand: Macro Trigger or Part of Text?
Macro triggers found in a macro call are resolved before
the macro executes.
%macro ampersand(company);
%put &company;
%mend ampersand;
%ampersand(AT&T)
The ampersand will be misinterpreted
as a macro trigger.
41
Quoting Functions
Macro quoting functions resolve ambiguities by masking
the significance of special characters and mnemonics
so that the macro processor does not misinterpret them
to be part of the syntax of a macro statement or
expression.
The following are the most commonly used quoting
functions:
 %STR and %NRSTR
 %SUPERQ
 %BQUOTE
42
Masking Special Characters
Word Scanner
Macro Processor
The value of the macro variable
should contain an ampersand
and a percent sign as text.
Input Stack
%let xyz=%nrstr(&A+%B);
43
...
Masking Special Characters
Word Scanner
%
let
xyz
=
%
nrstr
(
&
A
+
%
B
)
;
44
Macro Processor
The word scanner identifies
individual tokens.
...
Masking Special Characters
Word Scanner
Macro Processor
%let
xyz
=
%
nrstr
(
&
A
+
%
B
)
;
45
The macro trigger %let
redirects tokens to the macro
processor.
...
Masking Special Characters
Word Scanner
Macro Processor
%let xyz=%nrstr(
&
A
+
%
B
)
;
46
When %NRSTR is encountered,
the macro processor masks
special tokens that appear within
the FUNCTION argument.
...
Masking Special Characters
Word Scanner
Macro Processor
%let xyz=%nrstr(&A+%B
In effect, each individual
character within a special token
is treated as plain text.
In reality, those tokens are stored
as otherwise unused
hexadecimal characters.
)
;
47
...
Masking Special Characters
Word Scanner
Macro Processor
%let xyz=%nrstr(&A+%B)
Normal tokenization resumes
after the %NRSTR is terminated
with a right parenthesis.
;
48
...
Masking Special Characters
Word Scanner
Macro Processor
%let xyz=%nrstr(&A+%B)
The macro processor will
interpret this semicolon as the
end of the %LET statement.
;
49
Masking Special Characters
The quoting functions mask special characters by
converting them to hexadecimal values called delta
characters.
%let xyz=%nrstr(&A+%B);
Becomes:
50
01 0F 41 15 10 42 02
Viewing Masked Characters
The SYMBOLGEN option generates additional messages
to the SAS log when a value is masked.
109 options symbolgen;
110 %let xyz=%nrstr(&A+%B);
111 %put &xyz;
SYMBOLGEN: Macro variable XYZ resolves to &A+%B
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have
been unquoted for printing.
&A+%B
The %PUT statement with the _USER_ argument
displays the unprintable characters stored as a result of
macro quoting.
51
Compile Time versus Execution Time
The compilation functions (%STR and %NRSTR) treat
special characters as text in a macro program statement
in open code or while compiling a macro.
The execution functions (%SUPERQ and %BQUOTE)
mask special characters during macro execution. The
macro processor resolves the expression or value and
masks the result.
52
Compile Time versus Execution Time
To help distinguish between compile-time quoting
functions and execution-time quoting functions, the Orion
Star programmers developed this “golden rule”:
 If you can see the special character, meaning you
typed the special character, then it is a compile-time
issue.
 If you cannot see the special character, meaning the
macro facility typed the special character, then it is
an execution-time issue.
53
Passing Special Characters: Compile Time
Compile-time masking is necessary when a user types
special characters in one of the following:
 macro statements valid in open code, such as %LET
and %PUT statements
 macro programming logic, such as an %IF statement
 parameter values on a macro call
 macro function arguments
 Orion Star's golden rule: If the special character can
be seen, a compile-time function is needed.
54
Masking Tokens at Compile Time
The %STR function masks special characters and
mnemonics typed by a user.
General form of the %STR function:
%STR(character-string)
character-string
55
can be any combination of text and
macro triggers.
Tokens Masked by the %STR Function
The %STR function performs the following actions:
 forces the macro processor to interpret special
characters and mnemonics as plain text during
compilation by masking their usual meanings

masks these special characters and mnemonics:
blank , ; + - * / < > = ¬ ^ ~ # |
AND OR NOT EQ NE LE LT GE GT IN
56

masks single quotation marks, double quotation
marks, and parentheses when they appear in pairs

attempts to resolve the ampersand (&) and the percent
(%) sign
Passing a Comma as Text
The %STR function causes the comma to be interpreted
as text, not as a separator.
%macro comma(fullname);
%let first=%scan(&fullname,2);
%let last=%scan(&fullname,1);
%let newname=&first &last;
%put &newname;
%mend comma;
%comma(%str(Taylor, Jenna))
Partial SAS Log
64
%comma(%str(Taylor, Jenna))
Jenna Taylor
57
Passing an Unmatched Quotation Mark as Text
The %STR function requires unmatched quotation marks
and parentheses to be preceded by a percent sign (%).
%macro unmatched(fullname);
%let first=%scan(&fullname,2);
%let last=%scan(&fullname,1);
%let newname=&first &last;
%put &newname;
%mend unmatched;
%unmatched(%str(O%'Malley, George))
58
Using OR as a Text Abbreviation
The %STR function causes special characters in macro
programming logic to be interpreted as a text string on the
right side of the equal sign.
%macro operator(state);
%if &state = %str(OR) %then %put State is Oregon;
%else %put State is &state;
%mend operator;
%operator(PA)
Partial SAS Log
77
%operator(PA)
State is PA
59
Special Characters as Function Arguments
The comma is used as a separator between function
arguments. To specify a comma as a delimiter, use the
%STR function.
%macro comma(fullname);
%let first=%scan(&fullname,2,%str(,));
%let last=%scan(&fullname,1,%str(,));
%let newname=&first &last;
%put &newname;
%mend comma;
%comma(%str(Taylor, Jenna))
60
Masking & and % at Compile Time
In addition to masking the same characters as the %STR
function, the %NRSTR function masks the ampersand (&)
and percent (%) sign.
General form of the %NRSTR function:
%NRSTR(character-string)
character-string
61
can be any combination of text and
macro triggers.
Passing an Ampersand as Text
The %NRSTR function prevents the macro processor
from recognizing &T as a macro variable reference.
%macro ampersand(company);
%put &company;
%mend ampersand;
%ampersand(%nrstr(AT&T))
Partial SAS Log
99
%ampersand(%nrstr(AT&T))
AT&T
62
Passing Special Characters
This demonstration illustrates using the
%NRSTR function to pass special characters
in a macro call.
63
m205d08
Passing an Unbalanced Quotation Mark as Text
SAS Log
1
%macro unmatched(fullname);
2
%let first=%scan(&fullname,2);
3
%let last=%scan(&fullname,1);
4
%let newname=&first &last;
5
%put &newname;
6
%mend unmatched;
7
8
9
%unmatched(%str(O%'Malley, George))
ERROR: Literal contains unmatched quote.
ERROR: The macro UNMATCHED will stop executing.
If the value of FULLNAME is masked, why does the
macro generate errors?
64
What Went Wrong?
Word Scanner
Macro Processor
Macro Symbol Table
FULLNAME O'Malley, George
The macro variable FULLNAME
contains a masked apostrophe
and comma.
Input Stack
%let last=%scan(&fullname,1);
65
...
What Went Wrong?
Function
Word Scanner
%
scan
(
&
fullname
,
1
)
;
Macro Processor
%let last=
The macro variable reference will
be resolved as the %SCAN
function call is constructed.
The result of the %SCAN
function will be placed after the
= sign in the %LET statement.
Macro Symbol Table
FULLNAME O'Malley, George
Input Stack
%let last=%scan(&fullname,1);
66
...
What Went Wrong?
Word Scanner
Macro Processor
%let last=O'Malley
;
The masking applied to the
apostrophe is removed when
the macro variable is resolved
in the %SCAN function.
Macro Symbol Table
FULLNAME O'Malley, George
Input Stack
%let last=%scan(&fullname,1);
67
...
What Went Wrong?
Word Scanner
Macro Processor
%let last=O'Malley;
The semicolon that should end
the %LET statement is
interpreted as part of the literal.
The literal was not terminated.
Macro Symbol Table
FULLNAME O'Malley, George
Input Stack
%let last=%scan(&fullname,1);
68
Unmasking of Special Characters
When a special character is masked with a macro quoting
function, it is unmasked under these conditions:
 It leaves the word scanner and is passed to the DATA
step compiler, SAS procedures, SAS macro facility,
or other parts of SAS.
 It is resolved in the %SCAN, %SUBSTR, or
%UPCASE function.
 It is explicitly unmasked by the %UNQUOTE function.
69
Passing Special Characters: Execution Time
Execution-time masking is necessary when a macro
variable that contains special characters resolves
in one of the following:
 macro programming logic
 macro invocation
 macro function
 Orion Star's golden rule: If you cannot see the special
character, an execution-time quoting function is
needed.
70
Masking All Tokens at Execution Time
The %SUPERQ function masks all special characters and
mnemonics during execution.
General form of the %SUPERQ function:
%SUPERQ(argument)
argument
can be a macro variable name or an
expression that resolves to a macro
variable name.
Do not precede the argument with an ampersand (&).
71
Resolving OR as a Text Abbreviation
Masking the resolved value of state with the
%SUPERQ function prevents the macro processor from
misinterpreting the resolved value OR as a mnemonic.
%macro operator(state);
%if %superq(state)=%str(OR) %then %put State is Oregon;
%else %put State is &state;
%mend operator;
SAS Log
55
%operator(OR)
State is Oregon
72
Resolving a Comma as Text
If the resolved value of a function argument contains
commas, additional execution-time macro quoting is
required.
%let name=Taylor, Jenna;
%let initial=%substr(&name,1,1);
The resolution of &NAME creates a %SUBSTR function
call that appears to have four arguments.
%substr(Taylor, Jenna,1,1)
1
73
2
3 4
Masking Function Arguments
Masking the resolved value of name with the %SUPERQ
function prevents the macro processor from
misinterpreting the comma in the resolved value as a
separator.
%let name=Taylor, Jenna;
%let initial=%substr(%superq(name),1,1);
SAS Log
97
%put Last name begins with &initial.;
Last name begins with T
74
Masking Function Results
Occasionally, the result of a macro function can contain
special characters that are misinterpreted because they
are unmasked by a function.
%macro unmatched(fullname);
%let first=%scan(&fullname,2);
%let last=%scan(&fullname,1);
%let newname=&first &last;
%put &newname;
%mend unmatched;
%unmatched(%str(O%'Malley, George))
When the UNMATCHED macro executes, the second
%LET statement using the %SCAN function contains an
unmatched single quotation mark.
%let last=O'Malley;
75
Masking Function Results
The %QSCAN function masks the result, loading the
unmatched single quotation mark into the macro variable
as a masked character.
%macro unmatched(fullname);
%let first=%qscan(&fullname,2);
%let last=%qscan(&fullname,1);
%let newname=&first &last;
%put &newname;
%mend unmatched;
SAS Log
132 %unmatched(%str(O%'Malley, George))
George O'Malley
76
Masking Function Results
Many macro functions and autocall macros have “Q”
equivalents that return masked results.
%CMPRES
%LEFT
%LOWCASE
%SCAN
%SUBSTR
%SYSFUNC
%TRIM
%UPCASE
77
%QCMPRES
%QLEFT
%QLOWCASE
%QSCAN
%QSUBSTR
%QSYSFUNC
%QTRIM
%QUPCASE
Resolving Special Characters
This demonstration illustrates using the
%QSCAN and %QSYSFUNC functions
to mask special characters in resolved values.
78
m205d09
& and % in Resolved Values
Depending on the circumstance, you might or might not
want the ampersand or the percent sign to be recognized
as macro triggers.
Using this function
79
Treats & or % as
%SUPERQ
text
%BQUOTE
macro triggers
& and % as Text in Resolved Values
The %SUPERQ function treats all special characters,
including the ampersand (&) and percent (%) sign, as text.
184
185
186
187
188
189
190
191
192
%macro resolves(name);
%let t=INC.;
data _null_;
call symputx('company', 'AT&T');
run;
%if &name=%superq(company) %then %put Values Are The Same;
%else %put Company=%bquote(&company) Name=&name;
%mend resolves;
%resolves(%nrstr(AT&T))
NOTE: DATA statement used (Total process time):
real time
0.01 seconds
cpu time
0.03 seconds
SYMBOLGEN:
SYMBOLGEN:
Macro variable NAME resolves to AT&T
Some characters in the above value which were subject to macro quoting have been
unquoted for printing.
Values Are The Same

80
No attempt was made to resolve &T.
& and % as Macro Triggers in Resolved Values
To attempt resolution of embedded macro triggers in
resolved values, use the %BQUOTE function.
General form of the %BQUOTE function:
%BQUOTE(character-string | text-expression)
The %BQUOTE function masks the same special
characters and mnemonics as the %SUPERQ function
during macro execution.
81
& and % as Macro Triggers in Resolved Values
193
194
195
196
197
198
199
200
201
%macro resolveb(name);
%let t=INC.;
data _null_;
call symputx('company', 'AT&T');
run;
%if &name=%bquote(&company) %then %put Values Are The Same;
%else %put Company=%bquote(&company) Name=&name;
%mend resolveb;
%resolveb(%nrstr(AT&T))
NOTE: DATA statement used (Total process time):
real time
0.00 seconds
cpu time
0.00 seconds
SYMBOLGEN:
SYMBOLGEN:
Macro variable NAME resolves to AT&T
Some characters in the above value which were subject to macro quoting have been
unquoted for printing.
SYMBOLGEN: Macro variable COMPANY resolves to AT&T
SYMBOLGEN: Macro variable T resolves to INC.
SYMBOLGEN: Macro variable COMPANY resolves to AT&T
SYMBOLGEN: Macro variable T resolves to INC.
SYMBOLGEN: Macro variable NAME resolves to AT&T
SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been
unquoted for printing.
Company=ATINC. Name=AT&T
The %BQUOTE function recognizes the &T in AT&T
as a macro trigger.
82
%SUPERQ versus %BQUOTE
The %SUPERQ function is the recommended macro
quoting function when you perform direct macro variable
substitution and all characters are to be treated as text.
Use the %BQUOTE function in situations where the
resolution of a macro trigger is desired or the argument is
an expression rather than a single macro variable reference.
%SUPERQ %BQUOTE
83
Accepts a single macro name
X
X
Accepts an expression that
yields a macro variable name
Does not treat % and & as
macro triggers
X
X
X
Masking an Ampersand
in Resolved Values
This demonstration illustrates using the
%SUPERQ function to mask the ampersand
in resolved values.
84
m205d10
Unmasking Characters
Occasionally, the process of masking characters using
macro quoting functions produces unexpected results
when the resulting string is resolved.
The %UNQUOTE function reverses the effects of macro
quoting and restores the normal syntax interpretation.
General form of the %UNQUOTE function:
%UNQUOTE(character-string | text-expression)
85
Masked Characters
Disrupt Compilation
This demonstration illustrates how a masked
character will disrupt compilation.
86
m205d011
Unmasking Characters with
the %UNQUOTE Function
This demonstration illustrates how the
%UNQUOTE function unmasks special
characters to enable normal compilation.
87
m205d012
When to Use the %UNQUOTE Function
The following conditions require the %UNQUOTE
function:
 When a value was previously masked by a quoting
function and you want to use the unmasked value later
in the same macro.
 When masking text with a macro quoting function
changes the way that the word scanner tokenizes it.
The generated SAS statements appear to be correct,
but the SAS compiler does not recognize them as
valid syntax.
88
Exercise
This exercise reinforces the concepts discussed
previously.
89