每天进步一点点,幸福生活快一点。
当一个宏里面还嵌套一个或者多个宏,这个叫做嵌套宏。先看一个简单的例子:
%let dsn=sashelp.cars;
%macro mac(dsn=,obs=);
data test;
set &dsn;
run;
data test2;
set test(obs=&obs);
run;
%mend;
%mac(dsn=&dsn,obs=5);
如果数据集的名称已经存储在宏变量中,则可以重写宏调用以利用该存储值。
以上面的程序为例,在调用宏mac之前,括号里面的任何宏引用(macro references)必须先被解析,所以&dsn会被解析成sashelp.cars,之后就变成了%mac(dsn=sashelp.cars,obs=5);
下面看一个嵌套宏:
%macro precomp(sex=,no=no);
options &no.mprint &no.symbolgen &no.mlogic; /*①*/
data test;
set sashelp.class;
if sex=&sex;
run;
* Create the location data set;
%locate(sex=&sex,no=&no) /*②*/
data test2;
set sashelp.cars;
run;
%mend precomp;
%macro locate(sex=, no=no);
options &no.mprint &no.symbolgen &no.mlogic; /*③*/
data test3;
set sashelp.class;
if sex=&sex;
run;
%mend locate;
%precomp(sex="F");
在上面的程序中,&no宏参数用的是默认的值,也就是NO,
①位置,在OPTION语句能执行之前,&no必须被解析,也就是NO,因此这句话变成了options nomprint nosymbolgen nomlogic;
②位置,在宏locate被调用之前,宏引用(macro references) &SUBJECT and &NO必须被解析,所以%locate(sex=&sex,no=&no)被解析成%locate(subject=1234, no=no)
③位置,当%locate被执行的时候,&NO被解析成NO,对应的options也变成了options nomprint nosymbolgen nomlogic;
定义宏的顺序并不重要,只要每个宏都是在调用之前是已经定义的。
%macro precomp(sex=,no=);
data test;
set sashelp.class(obs=&no);
if sex=&sex;
run;
* Create the location data set;
%locate(sex=&sex,obs=&no)
data test2;
set sashelp.cars;
run;
%mend precomp;
%precomp(sex="F",no=7);
%macro locate(sex=, no=);
data test3;
set sashelp.class(obs=&no);
if sex=&sex;
run;
%mend locate;
比如我在定义宏locate之前就调用了宏precomp,这时候肯定会出错的
Note:
在我将这上面的程序复制到SAS的时候,发现报错了,显示这个no打错了,但是我明明是从SAS复制到这上面,然后又复制到SAS的时候出错了,所以你们如果复制出现问题的话,建议重新手打一遍,我记得以前的时候也出现了这样的情况,明明肉眼看是长得一样,可就是出问题。
同时发现这个set莫名其妙地变红了,发现data前面好像插入了什么符号,键盘右键移动一格的时候,光标并没有向右移动一格,好像卡住了一样,了解这个的欢迎解释一下。可能是这上面的代码编辑器会自动插入什么字符。
如果你第一次运行过locate这个宏的时候,其实SAS已经编译完成了,所以第二次你再跑宏precomp的时候,就可以正常运行了,但是这样编程肯定是有问题的。
%macro precomp(sexmain=,obs=);
/*调用precomp里的宏参数*/
%locate(sex=&sexmain,no=&obs)
data test2;
set sashelp.cars;
run;
%mend precomp;
%macro locate(sex=, no=);
data test3;
set sashelp.class(obs=&no);
if sex=&sex;
run;
%mend locate;
%precomp(sexmain="F",obs=7);
在precomp里的参数不需要和locate保持一致,只要保证你调用的是正确的宏参数就行了,就像下面加粗部分%locate(sex=&sexmain,no=&obs)。同时,你调用宏precomp的时候也就调用了宏locate。
同时需要注意的是%locate(sex=&sexmain,no=&obs)里面的&sexmain和&obs是先被解析,之后才是宏locate被调用。
详细解析一下这两个宏执行的步骤:
①:当我调用%precomp(sexmain="F",obs=7)的时候,因为不包含任何宏引用,所以不需要一个解析的过程直接就宏变量sexmain接收到值"F",宏变量obs接收到值7;
②:调用%locate(sex=&sexmain,no=&obs)的时候,&sexmain和&obs先解析成对应的值;
③:宏locate被调用
④:宏变量sex接收到值"F",宏变量no接收到值7;
⑤:之后编译locate里面的这段程序,
data test3;
set sashelp.class(obs=&no);
if sex=&sex;
run;
对应的宏变量被解析成对应的值,之后才能被运行。
对应的流程图解释可以参照下面这张图,注意我上面的①完成后应该有一个宏precomp展开的过程,就是下面红框这部分
我觉得了解宏执行的顺序,跟以前一篇文章了解宏变量解析的顺序是一样的,对你debug宏有很大帮助,你只有知道宏是怎样运行,才可能知道你的程序在哪出问题。
The end。