SAS macro symbol table(2):特殊规则
上篇对macro symbol table的常规应用进行了简单的梳理,本篇对如call symput的非宏语言在建立宏变量时symbol table的特殊规则进行梳理。
1.the into : operator in PROC SQL
“into :”算符并不不属于宏语言,但是其定义宏变量的过程基本与使用%let相同:先由当前local,再向上级直到global中搜寻所定义的宏变量是否存在,再进行相应的处里。参见SAS macro symbol table(1)。
style=”text-align: center;”>需要了解的是,在proc sql执行过程中,会自动产生三个包含该proc sql过程信息的宏变量:sqlobs、sqlrc和sqloops,如下:
- SQLOBS: set to the number of rows produced with a SELECT statement.
- SQLRC: set to the return code from an SQL statement.
- SQLOOPS: set to the number of iterations of the inner loop of PROC SQL.
合理的使用以上三个宏变量,对程序的编写可以起到很好的作用。
2.call symput DATA step routine
2.1常规情况
由于call symput并不是属于宏语言,所以其定义宏变量的过程与%let等并不相同,具体规则为:当data步执行时,如果当前的symbol table不为空,call symput 在当前的symbol table中建立宏变量;如果当前symbol table完全为空,则call symput向上搜寻直到global,在最近的非空symbol table中建立宏变量。
注意上述“当前symbol table完全为空”:
- 此主要对于local symbol table而言,因为global symbol table始终不为空(即在open code中,call symput直接建立全局宏变量)。
- 只要当前local不为空即可,不需要管所定义的宏变量是否已存在。我们知道,对一个非空local,使用%let定义宏变量A时,若宏变量A不存在,向上级直到global中搜寻再处理;而使用call symput时,直接在当前local中建立宏变量A。
具体参见以下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /*Example 1:CALL SYMPUT with Complete DATA Step and Nonempty Local*/ %macro test1(local_p); data _null_; x1='it is test1'; call symput('m_var1',x1); run; %put ** Inside the macro: **; %put _user_; %mend; %test1(1) data temp1; y1="&m_var1"; run; %put ** In open code: **; %put _user_; /*Example 2:CALL SYMPUT with Complete DATA Step and empty Local*/ %macro test2; data _null_; x2='it is test2'; call symput('m_var2',x2); run; %put ** Inside the macro: **; %put _user_; %mend; %test2 data temp2; y2="&m_var2"; run; %put ** In open code: **; %put _user_; |
- Example 1,log显示如下。宏test1的local不为空,所以直接在其中建立局部宏变量m_var1,在宏test1执行完后local symbol table被清空,所以外部的data temp1中的&m_var1无法解析,输出警告。
** Inside the macro: ** TEST1 LOCAL_P 1 TEST1 M_VAR1 it is test WARNING: Apparent symbolic reference M_VAR1 not resolved.
- Example 2,log显示如下。宏test2的local完全为空,所以向上到global中建立宏变量m_var2,并且外部的data temp2中的&m_var2解析为“it is test2”。
** Inside the macro: ** GLOBAL M_VAR2 it is test2 NOTE: The data set WORK.TEMP2 has 1 observations and 1 variables. ** In open code: ** GLOBAL M_VAR2 it is test2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /*Example 3:CALL SYMPUT with Incomplete DATA Step and Nonempty Local*/ %macro test3(local_p); data _null_; x3='it is test3'; call symput('m_var3',x3); %put ** Inside the macro: **; %put _user_; %mend; %test3(3) run; data temp3; y3="&m_var3"; run; %put ** In open code: **; %put _user_; |
- Example 3,log显示如下。注意,与Example 1相比,宏test3中的data是不完整的(缺少“run”),直到遇到open code中的“run”,所以当前的symbol table是global,所以m_var3建立在global,并且外部的data temp3中的&m_var3解析为“it is test3”。
NOTE: The data set WORK.TEMP3 has 1 observations and 1 variables. ** In open code: ** GLOBAL M_VAR3 it is test3
2.2特殊情况
- 若call symput在proc sql之后使用,宏变量一定建立在local中。因为proc sql会自动产生局部宏变量如sqlobs等,所以local非空。
- 宏调用时建立宏变量syspubff,其在local中。
SYSPBUFF: contains text supplied as macro parameter values. Used in conjunction with macro programs defined with the PARMBUFF option.
- 执行的宏包含一个computed %goto语句时,宏变量建立在local在中。
%GOTO label: ranches macro processing to the specified macro label within the macro program.
具体参见以下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /*Example 4:CALL SYMPUT with SYSPBUFF and empty Local*/ %macro test4 / parmbuff; data _null_; x4='it is test4'; call symput('m_var4',x4); run; %put ** Inside the macro: **; %put _user_; %put &syspbuff; %mend; %test4 data temp4; y4="&m_var4"; run; %put ** In open code: **; %put _user_; %put &syspbuff; |
- Example 4,log显示如下。因为宏变量syspbuff包含所有宏的所有参数值列表,所以在宏调用时建立syspbuff,即使当前local为空,call symput也“认为”其不空,进行处理,建立局部(local)宏变量。
** Inside the macro: ** TEST4 M_VAR4 it is test4 y4="&m_var4"; WARNING: Apparent symbolic reference M_VAR4 not resolved. ** In open code: ** WARNING: Apparent symbolic reference SYSPBUFF not resolved. &syspbuff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /*Example 5:CALL SYMPUT with %GOTO and empty Local*/ %macro test5; %goto &want; %height: data temp_h(keep=name height); set sashelp.class; call symput('m_var5',height); run; %weight: data temp_w(keep=name weight); set sashelp.class; call symput('m_varm5',weight); run; %put ** Inside the macro: **; %put _user_; %mend; %let want=weight; %test5 data temp5; y5="&m_var5"; run; %put ** In open code: **; %put _user_; |
- Example 5,log显示如下。因为%goto语句会转到定义好的宏标签,而其并不知道宏标签的symbol table情况,所以,即使当前的local为空,call symput也“认为”其不空,进行处理,建立局部(local)宏变量。
** Inside the macro: ** TEST5 M_VARM5 112 GLOBAL WANT weight y5="&m_var5"; WARNING: Apparent symbolic reference M_VAR5 not resolved. ** In open code: ** GLOBAL WANT weight
3.call symputx DATA step routine
call symputx用法基本与call symput相同,但call symputx多了一个参数可以直接指定宏变量的symbol table,如下:
CALL SYMPUTX(macro-variable, text<,symbol-table>)
The third argument is optional and it tells the macro processor the symbol table where the macro variable should be stored, and it can be one of three values:
- G, 定义宏变量在global中,即使local存在。
- L, 定义宏变量在最内层的local中。当该宏程序未执行时,不存在local,此时最内层的就是global了,宏变量存储于其中。
- F, 定义宏变量可以在任何symbol table中。CALL SYMPUTX 会更新包含该变量的最内层的local,所有的local都不存在是,在最内层local建立存储该宏变量。
尤其需注意使用“L”和“F”的区别。
4.other tips
- 可以在sashelp.vmacro中查看所有存在的宏变量的scope和value等信息。
- 可以通过使用%symdel来删除全局(global)宏变量,不可删除局部(local)宏变量。
例:Delete all user-defined macro variables from the global symbol table
- 可以通过%symexist、%symglobal、%symlocal 来检验宏变量、全局宏变量、局部宏变量是否存在。
参考文献
1.SAS 9.2 Macro Language Reference
2.Carpenter’s Complete Guide to the SAS Macro Language (2nd Edition)
虽不太懂SAS~但继续顶一个
[回复]