美好的一天,
我遇到了以下情况,其中宏变量被定义为全局,取决于它们是否来自包含....宏中定义的变量不应该在宏之外,右边可见。这失败了:
%macro if_env;
%let a=100;
%mend if_env;
%if_env;
%put &a.;
警告:未解析显式符号引用A.
这是预期的。 但是,我遇到了一个问题,变量渗透到全局空间:
我有一个包含文件:C:\ TEMP \ test.sas,它只包含变量的设置a b c d :(用于测试目的)
%let a=100;
%let B=200;
%let C=300;
%let D=400;
这也符合预期:
%macro if_env;
%include"C:\TEMP\test.sas";
%mend if_env;
%if_env;
%put &B.;
警告:未解析明显的符号引用B.
到目前为止一切顺利。现在,我添加了if子句'include if file exists'-condition:
%macro if_env;
%if %sysfunc(fileexist(C:\TEMP\test.sas)) %then
%let C=100
%mend if_env;
%if_env;
%put &C.;
警告:未解析显式符号引用C.
最后一步:将实际包含添加到代码中:
%macro if_env;
%if %sysfunc(fileexist(C:\TEMP\test.sas)) %then
%include"C:\TEMP\test.sas";
%mend if_env;
%if_env;
%put &A.;
%put &B.;
%put &C.;
%put &D.;
嗯,不是计算。这不应该发生。 %let - 命令如何具有不同的命名空间,具体取决于它是否在 include 中?100 200 300 400
知道为什么会这样吗?错误或真正奇特的功能?
修改 很有意思。基于SAS documentation,应该在include的末尾使用分号。很高兴澄清此事。谢谢你的回答。
答案 0 :(得分:4)
%include
语句以分号结束。
%if
语句以分号结束。
宏中的分号终止宏中的%if
。
%if
计算为true时,%include
语句开始,但在调用之后以分号结束。因此%include
语句执行范围与%put
语句相同。这种宏编程的微妙之处经常被忽视。
要强制%include
在宏范围内使用
... %then %do; %include ...; %end;
或
... %then %include ... %str(;) ;
答案 1 :(得分:3)
我不会把它称为SAS中的错误,而是程序中的错误。由于您的宏没有提供分号来终止%INCLUDE
语句,因此宏在%include
语句运行之前结束。因此,本地符号空间不再存在,%let
语句创建全局宏。
如果格式化代码以使SAS代码和宏代码在不同的行上,则更清晰。
%if 1=1 %then
%include test
;
添加%do/%end
将允许您为%include提供分号。
%if 1=1 %then %do;
%include test ;
%end;
如果在另一个宏内部调用此宏,则宏变量将被创建为该调用宏的本地。所以这是一个技巧,可用于将宏变量推送到父环境中。
%macro if_env;
%include test
%mend if_env;
%macro outer ;
%if_env;
%put _local_;
%mend outer;
启用MLOGIC选项以查看正在发生的事情。
235 options mlogic source2;
236 %outer ;
MLOGIC(OUTER): Beginning execution.
MLOGIC(IF_ENV): Beginning execution.
MLOGIC(IF_ENV): Ending execution.
NOTE: %INCLUDE (level 1) file TEST is file /.../#LN00048.
237 +%let a=1;
238 +%let b=2;
239 +%let c=3;
NOTE: %INCLUDE (level 1) ending.
MLOGIC(OUTER): %PUT _local_
OUTER A 1
OUTER B 2
OUTER C 3
MLOGIC(OUTER): Ending execution.