调用具有未指定参数的其他宏的SAS宏



我正在尝试做一个以其他宏为输入的宏,这些宏可以有不同数量的参数。想象一下我有一个宏:

%MACRO foo(text = );
%PUT &text.;
%MEND foo;

我想创建一个call_macro宏,它调用foo(),指定文本。问题是,我可能想用其他参数调用另一个宏fuu()

我想到过这样的东西:

%MACRO call_macro(macro = , args = );
%&macro.(&args.);
%MEND call_macro;
%call_macro(macro=foo, args='text=Hello');

这显然不起作用,因为我调用的是%foo('text=Hello')而不是%foo(text=Hello)。有办法摆脱这种局面吗?

(就上下文而言,我正试图为SAS创建一个在R中使用的映射函数。目标是有一个函数map,它接受数据集列表、要应用的函数和该函数的参数,在所有数据集上执行该函数(

如果要在SAS中使用DATA,请使用SAS数据步骤和过程。即使数据实际上是关于要运行的代码的元数据,也是如此。

因此,如果你有一个包含三个变量的数据集,REMOTE、MACRO和ARGS,你可以使用它来生成一系列RSUBMIT/ENDRSUBMIT块,将宏调用发送到每个不同的并行进程。然后只需使用%INCLUDE来运行生成的代码。

filename code temp;
data _null_;
set metadata ;
by remote ;
file code;
if first.remote then put 'rsubmit ' remote ';' ;
put '%' macro '(' args ');';
if last.remote then put 'endrsubmit;' ;
run;
%include code / source2;

事实上,RSUBMIT语句可能需要更复杂才能真正实现并行执行,但如何从元数据生成代码的想法才是关键。

只需省略引号。

%MACRO call_macro(macro = , args = );
%&macro.(&args.);
%MEND call_macro;
%call_macro(macro=foo, args=text=Hello);

如果在没有等号的情况下调用宏,它将不起作用因为在你的通话中

%call_macro(foo, text=Hello);

第二自变量将不被解释为具有值text=Hello而是被解释为值Hello的参数text

如果使用PARMBUFF选项对调度宏进行编码,则不需要将参数嵌入到另一个参数中。PARMBUFF为宏提供参数,包括任何边界圆括号。

示例:

将调度的宏参数作为调度宏的一阶参数提供。

%macro one (data=);
%put INFO:   Macro:&SYSMACRONAME.  &=data;
%mend;
%macro two (data=, vars=);
%put INFO:   Macro:&SYSMACRONAME. &=data &=vars;
%mend;
%macro three (data=, vars=, out=);
%put INFO:   Macro:&SYSMACRONAME. &=data &=vars &=out;
%mend;
%macro dispatch (macro=) / PARMBUFF;
%put INFO: -----;
%put INFO: &SYSMACRONAME. &=SYSPBUFF; 
%put INFO: &=macro;
%if %length(&macro) %then %do;
%let syspbuff = %sysfunc(prxchange(%str(s/,?s*macros*=s*w+,?//i),-1,&syspbuff));
%local invoke;
%let invoke = &macro &syspbuff;
%&invoke
%end;
%put INFO: -----;
%mend;
%dispatch(macro=one, data=foobar)
%dispatch(data=foobar, macro = one)
%dispatch(macro=two, data=foobar, vars=p q r)
%dispatch(macro=three, data=foobar, vars=p q r, out=snafu)
%one (data=x)

将记录

INFO: -----
INFO: DISPATCH SYSPBUFF=(macro=one, data=foobar)
INFO: MACRO=one
INFO:   Macro:ONE  DATA=foobar
INFO:
INFO: -----
INFO: DISPATCH SYSPBUFF=(data=foobar, macro = one)
INFO: MACRO=one
INFO:   Macro:ONE  DATA=foobar
INFO:
INFO: -----
INFO: DISPATCH SYSPBUFF=(macro=two, data=foobar, vars=p q r)
INFO: MACRO=two
INFO:   Macro:TWO DATA=foobar VARS=p q r
INFO:
INFO: -----
INFO: DISPATCH SYSPBUFF=(macro=three, data=foobar, vars=p q r, out=snafu)
INFO: MACRO=three
INFO:   Macro:THREE DATA=foobar VARS=p q r OUT=snafu
INFO:
INFO:   Macro:ONE  DATA=x

如果您确实想这样做,那么您需要保护子宏参数中的逗号。您可以尝试宏引用或实际引用。但最简单的方法是利用这样一个事实,即宏调用中括号内的逗号不会被视为指示新参数的开始。

因此,只需将不使用%作为单个参数的宏调用传递给call_macro宏即可。

%macro call_macro(arg);
%put &=sysmacroname: &=arg ;
%&arg.
%mend;
%macro test1(a,b=);
%put &=sysmacroname: &=a &=b ;
%mend;
%macro test2(c,d,e);
%put &=sysmacroname: &=c &=d &=e;
%mend;
%call_macro(test1(b=xyz,a=123))
%call_macro(test2(456,e=abc,d=89))
%call_macro(foo(text=Hello))

如果由于某种原因CALL_MACRO需要知道它要调用的宏的名称,可以通过简单的%SCAN((函数调用来提取。

%local macroname;
%let macroname=%scan(&arg,1,());

我解决了。设置args="par_1=val_1, par_2=val_2",然后在宏内部使用args=%sysfunc(COMPRESS(&args.,'"');