2月 9, 2011

Posted by in | 3 条评论

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的引用进行说明。
SAS macro 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。
    1. 注意,宏location在定义时有宏参数type,所以location local中有宏变量type(其独立于trans local中的type),宏location执行开始就将Automobile赋值给location local中的type;
    2. 根据宏执行规则,同一data步中“%put call type is &type;”先于“call symput”解析执行,从最内层的local(即location local)开始搜索,发现type=Automobile,于是解析输出到log中;
    3. “call symput(‘type’, ‘Train’);”,同样从最内层的local(即location local)开始搜索,发现type=Automobile,将其修改为type=Train,再“%put location type is &type;”,解析输出到log中;
    4. 宏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)

  1. 果断顶起呀,又一个奋斗在SAS路上的新星~

    [回复]

    hssnow 回复:

    俺现在还相当的菜呢,你是统计小巨星,呵呵,加油!

    [回复]

  2. 6 %put a is &a;

    WARNING: 没有解析符号引用 AMP。
    a is &amp
    6 %put a is &a;

    180
    ERROR 180-322: 语句无效或未按正确顺序使用
    sas新手,按照您的例子做的,为什么会出现错误呢?求指点?

    [回复]

发表评论

返回顶部