带有 if 和 include 的宏环境变量可见性
Macro environment variable visibility with if and include
美好的一天,
我 运行 进入以下情况,其中宏变量被定义为全局变量取决于它们是否来自 include ....在宏中定义的变量不应该在宏之外可见,对吧。这失败了:
%macro if_env;
%let a=100;
%mend if_env;
%if_env;
%put &a.;
WARNING: Apparent symbolic reference A not resolved.
这符合预期。
但是,我 运行 遇到了一个问题,变量流向全局 space:
我有一个包含文件: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.;
WARNING: Apparent symbolic reference B not resolved.
到目前为止一切都很好。现在,我添加了 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.;
WARNING: Apparent symbolic reference C not resolved.
最后一步:将实际包含添加到代码中:
%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-command 怎么会有不同的名称space 取决于它是否在 include 中?
知道为什么会这样吗?是错误还是真正奇特的功能?
编辑:
很有意思。基于 SAS documentation 应该在包含的末尾使用分号。很高兴对此事作出澄清。感谢您的回答。
%include
语句以分号结束。
%if
语句以分号结束。
宏中的分号终止宏中的%if
。
- 当
%if
的计算结果为真时,%include
语句开始,但在调用后以分号结束。因此 %include
语句执行范围与 %put
语句相同。
- 当 %if` 的计算结果为 false 时,调用后的分号只是空语句或独立的分号。
这种宏编程的微妙之处常常被忽视。
要强制 %include
出现在宏范围内,请使用
... %then %do; %include ...; %end;
或
... %then %include ... %str(;) ;
我不会称它为 SAS 中的错误,而是您程序中的错误。由于您的宏没有提供分号来终止 %INCLUDE
语句,因此宏在 %include
语句运行之前结束。因此局部符号 space 不再存在并且 %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.
美好的一天,
我 运行 进入以下情况,其中宏变量被定义为全局变量取决于它们是否来自 include ....在宏中定义的变量不应该在宏之外可见,对吧。这失败了:
%macro if_env;
%let a=100;
%mend if_env;
%if_env;
%put &a.;
WARNING: Apparent symbolic reference A not resolved.
这符合预期。 但是,我 运行 遇到了一个问题,变量流向全局 space:
我有一个包含文件: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.;
WARNING: Apparent symbolic reference B not resolved.
到目前为止一切都很好。现在,我添加了 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.;
WARNING: Apparent symbolic reference C not resolved.
最后一步:将实际包含添加到代码中:
%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-command 怎么会有不同的名称space 取决于它是否在 include 中?
知道为什么会这样吗?是错误还是真正奇特的功能?
编辑: 很有意思。基于 SAS documentation 应该在包含的末尾使用分号。很高兴对此事作出澄清。感谢您的回答。
%include
语句以分号结束。
%if
语句以分号结束。
宏中的分号终止宏中的%if
。
- 当
%if
的计算结果为真时,%include
语句开始,但在调用后以分号结束。因此%include
语句执行范围与%put
语句相同。 - 当 %if` 的计算结果为 false 时,调用后的分号只是空语句或独立的分号。
这种宏编程的微妙之处常常被忽视。
要强制 %include
出现在宏范围内,请使用
... %then %do; %include ...; %end;
或
... %then %include ... %str(;) ;
我不会称它为 SAS 中的错误,而是您程序中的错误。由于您的宏没有提供分号来终止 %INCLUDE
语句,因此宏在 %include
语句运行之前结束。因此局部符号 space 不再存在并且 %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.