Scopes of Macro Variables |
Changing the Values of Existing Macro Variables |
When the macro processor executes a macro program statement that can create a macro variable (such as a %LET statement), the macro processor attempts to change the value of an existing macro variable rather than create a new macro variable. The %GLOBAL and %LOCAL statements are exceptions.
To illustrate, consider the following %LET statements. Both statements assign values to the macro variable NEW:
%let new=inventry; %macro name1; %let new=report; %mend name1;
Suppose you submit the following statements:
%name1 data &new;
These statements produce the following statement:
data report;
Because NEW exists as a global variable, the macro processor changes the value of the variable rather than creating a new one. The macro NAME1's local symbol table remains empty.
The following figure illustrates the contents of the global and local symbol tables before, during, and after NAME1's execution.
Snapshots of Symbol Tables
Creating Local Variables |
When the macro processor executes a macro program statement that can create a macro variable, the macro processor creates the variable in the local symbol table if no macro variable with the same name is available to it. Consider the following example:
%let new=inventry; %macro name2; %let new=report; %let old=warehse; %mend name2; %name2 data &new; set &old; run;
After NAME2 executes, the SAS compiler sees the following statements:
data report; set &old; run;
The macro processor encounters the reference &OLD after macro NAME2 has finished executing. Thus, the macro variable OLD no longer exists. The macro processor is not able to resolve the reference and issues a warning message.
The following figure illustrates the contents of the global and local symbol tables at various stages.
Symbol Tables at Various Stages
But suppose you place the SAS statements inside the macro NAME2, as in the following program:%let new=inventry; %macro name2; %let new=report; %let old=warehse; data &new; set &old; run; %mend name2; %name2
In this case, the macro processor generates the SET statement during the execution of NAME2, and it locates OLD in NAME2's local symbol table. Therefore, executing the macro produces the following statements:
data report; set warehse; run;
The same rule applies regardless of how many levels of nesting exist. Consider the following example:
%let new=inventry; %macro conditn; %let old=sales; %let cond=cases>0; %mend conditn; %macro name3; %let new=report; %let old=warehse; %conditn data &new; set &old; if &cond; run; %mend name3; %name3
The macro processor generates these statements:
data report; set sales; if &cond; run;
CONDITN finishes executing before the macro processor reaches the reference &COND, so no variable named COND exists when the macro processor attempts to resolve the reference. Thus, the macro processor issues a warning message and generates the unresolved reference as part of the constant text and issues a warning message. The following figure shows the symbol tables at each step.
Symbol Tables Showing Two Levels of Nesting
Notice that the placement of a macro invocation is what creates a nested scope, not the placement of the macro definition. For example, invoking CONDITN from within NAME3 creates the nested scope. It is not necessary to define CONDITN within NAME3.
Forcing a Macro Variable to Be Local |
At times you need to ensure that the macro processor creates a local macro variable rather than changing the value of an existing macro variable. In this case, use the %LOCAL statement to create the macro variable.
Always make all macro variables created within macros local when you do not need their values after the macro stops executing. Debugging the large macro programs is easier if you minimize the possibility of inadvertently changing a macro variable's value. Also, local macro variables do not exist after their defining macro finishes executing, while global variables exist for the duration of the SAS session. Therefore, local variables use less overall storage.
Suppose you want to use the macro NAMELST to create a list of names for a VAR statement, as shown here:
%macro namelst(name,number); %do n=1 %to &number; &name&n %end; %mend namelst;
You invoke NAMELST in this program:
%let n=North State Industries; proc print; var %namelst(dept,5); title "Quarterly Report for &n"; run;
After macro execution, the SAS compiler sees the following statements:
proc print; var dept1 dept2 dept3 dept4 dept5; title "Quarterly Report for 6"; run;
The macro processor changes the value of the global variable N each time it executes the iterative %DO loop. (After the loop stops executing, the value of N is 6, as described in %DO Statement.) To prevent conflicts, use a %LOCAL statement to create a local variable N, as shown here:
%macro namels2(name,number); %local n; %do n=1 %to &number; &name&n %end; %mend namels2;
Now execute the same program:
%let n=North State Industries; proc print; var %namels2(dept,5); title "Quarterly Report for &n"; run;
The macro processor generates the following statements:
proc print; var dept1 dept2 dept3 dept4 dept5; title "Quarterly Report for North State Industries"; run;
The following figure shows the symbol tables before NAMELS2 executes, while NAMELS2 is executing, and when the macro processor encounters the reference &N in the TITLE statement.
Symbol Tables for Global and Local Variables with the Same Name
Creating Global Macro Variables |
The %GLOBAL statement creates a global macro variable if a variable with the same name does not already exist there, regardless of what scope is current.
For example, in the following program, the macro CONDITN contains a %GLOBAL statement that creates the macro variable COND as a global variable:
%macro conditn; %global cond; %let old=sales; %let cond=cases>0; %mend conditn;
Here is the rest of the program:
%let new=inventry; %macro name4; %let new=report; %let old=warehse; %conditn data &new; set &old; if &cond; run; %mend name4; %name4
Invoking NAME4 generates these statements:
data report; set sales; if cases>0; run;
Suppose you want to put the SAS DATA step statements outside NAME4. In this case, all the macro variables must be global for the macro processor to resolve the references. You cannot add OLD to the %GLOBAL statement in CONDITN because the %LET statement in NAME4 has already created OLD as a local variable to NAME4 by the time CONDITN begins to execute. (You cannot use the %GLOBAL statement to make an existing local variable global.)
Thus, to make OLD global, use the %GLOBAL statement before the variable reference appears anywhere else, as shown here in the macro NAME5:
%let new=inventry; %macro conditn; %global cond; %let old=sales; %let cond=cases>0; %mend conditn; %macro name5; %global old; %let new=report; %let old=warehse; %conditn %mend name5; %name5 data &new; set &old; if &cond; run;
Now the %LET statement in NAME5 changes the value of the existing global variable OLD rather than creating OLD as a local variable. The SAS compiler sees the following statements:
data report; set sales; if cases>0; run;
Creating Global Variables Based on the Value of Local Variables |
To use a local variable such as a parameter outside a macro, use a %LET statement to assign the value to a global variable with a different name, as in this program:
%macro namels3(name,number); %local n; %global g_number; %let g_number=&number; %do n=1 %to &number; &name&n %end; %mend namels3;
Now invoke the macro NAMELS3 in the following the program:
%let n=North State Industries; proc print; var %namels3(dept,5); title "Quarterly Report for &n"; footnote "Survey of &g_number Departments"; run;
The compiler sees the following statements:
proc print; var dept1 dept2 dept3 dept4 dept5; title "Quarterly Report for North State Industries"; footnote "Survey of 5 Departments"; run;
Copyright © 2009 by SAS Institute Inc., Cary, NC, USA. All rights reserved.