使用if和include的宏环境变量可见性

时间:2018-04-17 10:27:13

标签: macros sas visibility

美好的一天,

我遇到了以下情况,其中宏变量被定义为全局,取决于它们是否来自包含....宏中定义的变量不应该在宏之外,右边可见。这失败了:

%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.;
  

100   200   300   400

嗯,不是计算。这不应该发生。 %let - 命令如何具有不同的命名空间,具体取决于它是否在 include 中?

知道为什么会这样吗?错误或真正奇特的功能?

修改 很有意思。基于SAS documentation,应该在include的末尾使用分号。很高兴澄清此事。谢谢你的回答。

2 个答案:

答案 0 :(得分:4)

%include语句以分号结束。

%if语句以分号结束。

宏中的分号终止宏中的%if

  • %if计算为true时,%include语句开始,但在调用之后以分号结束。因此%include语句执行范围与%put语句相同。
  • 当%if`计算为false时,调用后的分号只是一个空语句或独立的分号。

这种宏编程的微妙之处经常被忽视。

要强制%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.