宏分配默认值,避免变量名冲突
Macro to assign default values, avoid collision of variable names
这是我想在宏函数开始时调用的一个小宏。
相当于%if not %length(&x) %then %let x = &val
。
我想使用它,因为它更具可读性,并且可以帮助我解析我的代码以构建文档(我需要使用正则表达式来完成,因为我无法安装外部软件)。
%macro def
/*---------------------
Assign default value
---------------------*/
(_x_data_x_ /* variable name (to be passed raw without &) */
,value /* default value */
);
%if not %length(&&&_x_data_x_) %then %let &_x_data_x_ = &value;
%mend;
工作原理如下:
%macro test(a,b);
%def(b,&a)
%put "&b";
%mend;
%test(%str(,)); /* prints "," */
我选择了不寻常的参数名称 _x_data_x_
,因为宏在输入等于参数名称的值时会失败(即,如果我的 b
参数被命名为 _x_data_x_
)。
除了选择晦涩难懂的名字之外,我还能让它真正安全吗?
这是正确的做法。
您可以通过添加检查使宏更健壮:
%* Prevent self reference because
%* assignment will not bubble to containing scope;
%if %upcase(%superq(x_data_x)) eq X_DATA_X %then %do;
%put ERROR: x_data_x=%superq(x_data_x) is not allowed;
%abort cancel;
%end;
%* Prevent reference to non-existent because
%* assignment will automatically localize
%* and not bubble to containing scope;
%if not %symexist (%superq(x_data_x)) %then %do;
%put ERROR: x_data_x=%superq(x_data_x) is invalid;
%put ERROR: %superq(x_data_x) does not exist in callee scope;
%abort cancel;
%end;
这是我想在宏函数开始时调用的一个小宏。
相当于%if not %length(&x) %then %let x = &val
。
我想使用它,因为它更具可读性,并且可以帮助我解析我的代码以构建文档(我需要使用正则表达式来完成,因为我无法安装外部软件)。
%macro def
/*---------------------
Assign default value
---------------------*/
(_x_data_x_ /* variable name (to be passed raw without &) */
,value /* default value */
);
%if not %length(&&&_x_data_x_) %then %let &_x_data_x_ = &value;
%mend;
工作原理如下:
%macro test(a,b);
%def(b,&a)
%put "&b";
%mend;
%test(%str(,)); /* prints "," */
我选择了不寻常的参数名称 _x_data_x_
,因为宏在输入等于参数名称的值时会失败(即,如果我的 b
参数被命名为 _x_data_x_
)。
除了选择晦涩难懂的名字之外,我还能让它真正安全吗?
这是正确的做法。
您可以通过添加检查使宏更健壮:
%* Prevent self reference because
%* assignment will not bubble to containing scope;
%if %upcase(%superq(x_data_x)) eq X_DATA_X %then %do;
%put ERROR: x_data_x=%superq(x_data_x) is not allowed;
%abort cancel;
%end;
%* Prevent reference to non-existent because
%* assignment will automatically localize
%* and not bubble to containing scope;
%if not %symexist (%superq(x_data_x)) %then %do;
%put ERROR: x_data_x=%superq(x_data_x) is invalid;
%put ERROR: %superq(x_data_x) does not exist in callee scope;
%abort cancel;
%end;