Have you ever written a macro and wondered if there was an easy way to pass values to the macro? You can by using macro parameters. Macro parameters enable you to pass values into the macro at macro invocation, and set default values for macro variables within the macro definition. In this blog post, I also discuss how you can pass in a varying number of parameter values.
There are two types of macro parameters: positional and keyword.
Positional Parameters
You can use positional parameters to assign values based on their position in the macro definition and at invocation. The order that you use to specify the values must match the order in which they are listed in the %MACRO statement. When specifying multiple positional parameters, use a comma to separate the parameters. If you do not pass a value to the macro when it is invoked, a null value is assigned to the macro variable specified in the %MACRO statement.
Here is an example:
%macro test(var1,var2,var3); %put &=var1; %put &=var2; %put &=var3; %mend test; /** Each value corresponds to the position of each variable in the definition. **/ /** Here, I am passing numeric values. **/ %test(1,2,3) /** The first position matches with var1 and is given a null value. **/ %test(,2,3) /** I pass no values, so var1-var3 are created with null values. **/ %test() /** The first value contains a comma, so I use %STR to mask the comma. **/ /** Otherwise, I would receive an error similar to this: ERROR: More **/ /** positional parameters found than defined. **/ %test(%str(1,1.1),2,3) /** Each value corresponds to the position of each variable in the definition. **/ /** Here, I am passing character values. **/ %test(a,b,c) /** I gave the first (var1) and second (var2) positions a value of **/ /** b and c, so var3 is left with a null value. **/ %test(b,c) |
Here are the log results:
173 /** Each value corresponds to the position of each variable in the definition. **/ 174 /** Here, I am passing numeric values. **/ 175 %test(1,2,3) VAR1=1 VAR2=2 VAR3=3 176 /** The first position matches with var1 and is given a null value. **/ 177 %test(,2,3) VAR1= VAR2=2 VAR3=3 178 /** I pass no values, so var1-var3 are created with null values. **/ 179 %test() VAR1= VAR2= VAR3= 180 /** The first value contains a comma, so I use %STR to mask the comma. **/ 181 /** Otherwise, I would receive an error similar to this: ERROR: More **/ 182 /** positional parameters found than defined. **/ 183 %test(%str(1,1.1),2,3) VAR1=1,1.1 VAR2=2 VAR3=3 184 /** Each value corresponds to the position of each variable in the definition. **/ 185 /** Here, I am passing character values. **/ 186 %test(a,b,c) VAR1=a VAR2=b VAR3=c 187 /** I gave the first (var1) and second (var2) positions a value of **/ 188 /** b and c, so var3 is left with a null value. **/ 189 %test(b,c) VAR1=b VAR2=c VAR3= |
Keyword Parameters
The benefit of using keyword parameters is the ability to give the macro variables a default value within the macro definition. When you assign values using keyword parameters, you must include an equal sign after the macro variable name.
Here is an example:
%macro test(color=blue,id=123); %put &=color; %put &=id; %mend test; /** Values passed to the macro overwrite default values from the definition. **/ %test(color=red,id=456) /** Passing in no values allows the default values to take precedence. **/ %test() /** You are not required to pass in a value for each keyword parameter. **/ %test(color=green) /** The order of variables does not matter. **/ %test(id=789,color=yellow) |
Here are the log results:
270 /** Values passed to the macro overwrite default values from the definition. **/ 271 %test(color=red,id=456) COLOR=red ID=456 272 /** Passing in no values allows the default values to take precedence. **/ 273 %test() COLOR=blue ID=123 274 /** You are not required to pass in a value for each keyword parameter. **/ 275 %test(color=green) COLOR=green ID=123 276 /** The order of variables does not matter. **/ 277 %test(id=789,color=yellow) COLOR=yellow ID=789 |
If the macro definition combines positional and keyword parameters, positional parameters must come first. If you do not follow this order, this error is generated:
ERROR: All positional parameters must precede keyword parameters. |
Here is an example:
%macro test(val,color=blue,id=123); %put &=color; %put &=id; %put &=val; %mend test; /** The positional parameter is listed first. **/ %test(1,color=red,id=456) Here are the log results: 318 /** The positional parameter is listed first. **/ 319 %test(1,color=red,id=456) COLOR=red ID=456 VAL=1 |
PARMBUFF
The PARMBUFF option creates a macro variable called &SYSPBUFF that contains the entire list of parameter values, including the parentheses. This enables you to pass in a varying number of parameter values. In the following example, you can pass any number of parameter values to the macro. This following example illustrates how to parse each word in the parameter list:
%macro makes/parmbuff; /** The COUNTW function counts the number of words within &SYSPBUFF. **/ %let cnt=%sysfunc(countw(&syspbuff)); /** The %DO loop increments based on the number of words returned to the macro. **/ /** variable &CNT. **/ %do i= 1 %to &cnt; /** The %SCAN function extracts each word from &SYSPBUFF. **/ %let make=%scan(&syspbuff,&i); %put &make; %end; %mend makes; %makes(toyota,ford,chevy) |
Here are the log results:
19 %macro makes/parmbuff; 20 /** The COUNTW function counts the number of words within &SYSPBUFF. **/ 21 %let cnt=%sysfunc(countw(&syspbuff)); 22 /** The %DO loop increments based on the number of words returned to the macro **/ 23 /** variable &CNT. **/ 24 %do i= 1 %to &cnt; 25 /** The %SCAN function extracts each word from &SYSPBUFF. **/ 26 %let make=%scan(&syspbuff,&i); 27 %put &make; 28 %end; 29 %mend makes; 30 31 %makes(toyota,ford,chevy) toyota ford chevy |
When you specify the PARMBUFF option and the macro definition includes both positional and keyword parameters, the parameters still receive values when you invoke the macro. In this scenario, the entire invocation list of values is assigned to &SYSPBUFF. Here is an example:
%macro test(b,a=300)/parmbuff; %put &=syspbuff; %put _local_; %mend; %test(200,a=100) |
Here are the log results:
SYSPBUFF=(200,a=100) TEST A 100 TEST B 200 |
Notice that &SYSPBUFF includes the entire parameter list (including the parentheses), but each individual parameter still receives its own value.
If you need to know all the parameter values that are passed to the macro, specify the PARMBUFF option in the macro definition to get access to &SYSPBUFF, which contains all the parameter values. For more information about PARMBUFF, see %MACRO Statement in SASĀ® 9.4 Macro Language: Reference, Fifth Edition.
I hope this blog post has helped you understand how to pass values to a macro. If you have SAS macro questions that you would like me to cover in future blog posts, please comment below.
WANT MORE GREAT INSIGHTS MONTHLY? | SUBSCRIBE TO THE SAS TECH REPORT
2 Comments
Thanks Russ. With your last example, %macro test(b,a=300)/parmbuff; if a user invokes it like %test(200,q=100) is there any way to make it throw "ERROR: The keyword parameter Q was not defined with the macro"? So far I haven't found one, which means if I turn on the parmbuff option as a macro developer, I become responsible for doing a lot more validation of user input.
The only way to have that scenario cause an error would be to write out your own error in the macro. You could parse out the value in &SYSPBUFF and compare with the values in the NAME column from SASHELP.VMACRO. If a variable does not exist use %put ERROR: to write out your own error.