SAS macro symbol table(1):常规应用
SAS macro语言中,理解宏变量(macro variables)的作用域(the scope)是十分重要的,宏变量的作用域决定着该变量的赋值(assign)及宏处理器(macro processor)对该变量的解析(resolve)。所有的宏变量均存储于符号表(symbol table)中,其分为全局(global)和局部(local)两种。
本文将对SAS macro语言中symbol table的概念及常规应用,结合SAS ADV认证中的一些习题做一些简单的梳理。
1.基本概念
Global symbol table
- global symbol table在SAS启动(SAS section)的开始就被创建,其默认存储着所有的自动宏变量(automatic macro variables)如sasdate9,sasday等(除了saspbuff之外)。其也可以存储用户自己定义的宏变量。
- 默认情况下,存储于global symbol table中的宏变量——global macro variables,存在于整个SAS section中,并可以在SAS程序中的任何地方(除了datalines/cards中)被引用(resolved)。
Local symbol table
- local symbol table在一个包含着宏变量的宏程序执行开始时,才被创建,该宏程序执行结束后,相应的local symbol table自动被清除。
- 默认情况下,存储于local symbol table中宏变量——local macro variables,仅可以在与该local symbol table对应的宏程序中被引用。
2.Symbol table的嵌套
复杂的宏程序会出现symbol table嵌套的情形,结合下图对宏变量在不同symbol table的引用进行说明。
global symbol table只有一个;local symbol table可有多个,之间可存在嵌套关系。对于一个给定的symbol table,其中的宏变量可由它本身,及包含于它之内的其他symbol tables所引用(类似于数学中的集合关系)。
- global symbol table中的宏变量可在open code中被引用,也可在L1、L2,L21和L22中被引用。
- L1是一个local symbol table,其中的宏变量仅可以被L1使用。
- L2是一个local symbol table,其中的宏变量仅可以被L2,以及L21和L22使用。
- L21是一个local symbol table,其中的宏变量仅可以被L21使用。
- L22是一个local symbol table,其中的宏变量仅可以被L22使用。
3.symbol table中建立宏变量方式
global symbol table中,建立全局宏变量
- 用%let和%do可定义全局宏变量,在open code中使用。
- 用%global语句可定义全局宏变量,无论是在open code或在宏程序中均可。
- 在data步中,使用call symput或 call symputx可定义全局宏变量。
- 在proc sql中,使用“into :”算符可定义全局宏变量。
local symbol table中,建立局部宏变量
- 用%let和%do可定义局部宏变量,在宏程序中使用。
- 用%local语句可定义局部宏变量,仅在宏程序中均可。
- 在宏程序中直接使用宏参数(macro parameters)可定义的局部宏变量。
- 在data步中,使用call symput或 call symputx可定义局部宏变量。
- 在proc sql中,使用“into :”算符可定义局部宏变量。
4.symbol table中宏变量处理过程
宏处理器对宏变量处理一般包括创建、修改及解析等,其主要包括两个步骤:
- 在symbol table中搜寻该宏变量,确定其是否已经存在。由最内层local开始,向上级local搜寻,直到达到global中。
- 根据搜寻结果,已存在时进行修改或解析,不存在时进行创建或警告。
具体过程如上流程图所示。
例子:
Example1 考查:%let在不同位置时对宏变量的创建/修改的过程,%put在open code是对宏变量的解析过程,以及带有宏参数时创建local table的知识:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /*SAS ADV 50:第20题 What is written to the SAS log?*/ %let a=cat; %macro animal; %let a=dog; %mend; %animal %put a is &a; /*SAS ADV 130(A00-212):第25题 What is written to the SAS log?*/ %let a = cat; %macro animal(a = frog); %let a = bird; %mend; %animal(a = pig) %put a is &a; |
由之前介绍,我们知道:在open code时%let直接创建/修改global中的宏变量,在宏程序中%let由local向global检查宏变量是否存在,再进行处理。open code中%put对global中的宏变量进行解析。详细分析如下:
- 第一题log中输出的a为dog:global中a=cat,执行宏animal时,%let a=dog,其先在animal的local(此时为空)中搜寻是否已经存在宏变量a,为没有,向上到global中搜寻,有宏变量a=cat,于是用dog替换cat,即对global中宏变量a进行了修改,%put得到a为dog。
- 第二题log中输出的a为dog:之所以结果不同,是因为这里宏animal在定义时带有宏参数a=pig,即animal的local中有宏变量a存在。global中a=cat,执行宏animal,赋pig为animal local中宏变量a的值,%let a=bird,在local中搜寻,发现a=pig,进行修改a=bird。这是animal local中a=bird,global中a=cat不变,%put得到a为cat。
Example2 考查:local table的嵌套引用、解析,以及call symput创建宏变量的知识:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /*SAS ADV 50:第21题改编 What is written to the SAS log?*/ %macro trans; %let type=Airplane; %location(Automobile) %put trans type is &type; %mend; %macro location(type); data _null_; call symput('type', 'Train'); %put call type is &type; run; %put location type is &type; %mend; %trans %put out type is &type; |
log输出结果为:
call type is Automobile location type is Train trans type is Airplane out type is &type
宏trans和location编译完成后,%trans,执行宏trans,详细分析如下:
- %let type=Airplane,在trans local(此时为空)搜寻type是否存在,为没有,向上到global中搜寻,为没有,于是在trans local中创建type=Airplane。
- %location(Automobile),执行宏location。
- 注意,宏location在定义时有宏参数type,所以location local中有宏变量type(其独立于trans local中的type),宏location执行开始就将Automobile赋值给location local中的type;
- 根据宏执行规则,同一data步中“%put call type is &type;”先于“call symput”解析执行,从最内层的local(即location local)开始搜索,发现type=Automobile,于是解析输出到log中;
- “call symput(‘type’, ‘Train’);”,同样从最内层的local(即location local)开始搜索,发现type=Automobile,将其修改为type=Train,再“%put location type is &type;”,解析输出到log中;
- 宏location执行完毕,location local被清空。
- “%put trans type is &type;”,从当前层trans local开始搜索,发现type=Airplane,解析输出到log中。宏trans执行完毕,trans local被清空。
- “%put out type is &type;”,在global中搜寻,没有宏变量type,提示警告,log中为“%put out type is &type;”。
Example3 考查:%local和%global的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /*SAS ADV 50:第22题改编——%global—— What is written to the SAS log?*/ %macro loop; %global day; %do day=2 %to 6; %end; %put day is &day; %mend; %loop %put out day is &day; /*SAS ADV 50:第22题改编——%local—— What is written to the SAS log?*/ %let day=Tuesday; %macro loop; %local day; %do day=2 %to 6; %end; %put loop day is &day; %mend; %loop %put out day is &day; |
- 上面的第一个程序,两个%put得到的都是“7”,因为%global将day“全局化”了。如果没有“%global day;”的话,宏loop local中将建立宏变量day=7,宏loop内的%put得到“7”,open code中的%put无法解析,提示警告。
- 上面的第二个程序,宏loop内的%put得到的都是“7”,因为%local在loop local中建立了宏变量day;open code中的%put直接解析%let创建的宏变量day=Tuesday。如果没有“%local day;”的话,%do向上搜索到global中,将存在的day=Tuesday修改为day=7,两个%put均得到“7”。
参考文献:
1.SAS 9.2 Macro Language Reference
2.Carpenter’s Complete Guide to the SAS Macro Language (2nd Edition)
3.SAS Macro Programming Made Easy (2nd Edition)
果断顶起呀,又一个奋斗在SAS路上的新星~
[回复]
hssnow 回复:
2月 9th, 2011 at 18:14
俺现在还相当的菜呢,你是统计小巨星,呵呵,加油!
[回复]
6 %put a is &a;
WARNING: 没有解析符号引用 AMP。
a is &
6 %put a is &a;
–
180
ERROR 180-322: 语句无效或未按正确顺序使用
sas新手,按照您的例子做的,为什么会出现错误呢?求指点?
[回复]