在SAS中,执行没有分号的宏?

use*_*008 5 sas sas-macro

我在SAS中多次运行宏,如下所示:

%mymac(a,b);
%mymac(a,c);
.
%mymac(a,a)
%mymac(a,w);
.
Run Code Online (Sandbox Code Playgroud)

我的程序/宏类似于:

/* begin program here */

data original_data;
set mylib.mydata;
run;

%macro mymac(x,y);

data mydata1;
set original_data;
where school_district="&x";
run;

proc means data=mydata1;
var income;
run;

%mend mymac;
Run Code Online (Sandbox Code Playgroud)

我意识到我忘记了一个分号(如(a,a)中所示)并且SAS似乎并不介意.它运行所有的宏调用没有问题.当我添加分号时,我比较了输出,我看不出有什么区别.

这是正常的,SAS没有丢失分号的错误吗?

Rob*_*dge 5

分号不是必需的宏调用。

通常将它们包含在内,因为人们习惯于将分号视为“终止语句”或结束行的一种方式。我个人更喜欢在可能的情况下包含它们,因为我相信这会使我的代码更具可读性。

请记住,宏只是简单地评估自己并返回它们解析为的任何内容,这可能是一个看起来像数字、字符串或其他任何东西的代码块......

以这个不使用分号的例子为例:

%macro field_list();
    name, 
    age, 
    sex, 
    height
%mend;

proc sql;
  select %field_list()
  from sashelp.class
  ;
quit;
Run Code Online (Sandbox Code Playgroud)

尝试在您自己的机器上option mprint;启用它。运行宏的结果只是返回其中的代码块。这将导致执行以下代码:

proc sql;
  select  name, age, sex, height
  from sashelp.class
  ;
quit;
Run Code Online (Sandbox Code Playgroud)

如果我们在调用宏之后有一个分号,那么 SAS 将尝试运行的代码将包含这样的无效语法的分号(注意高度后面的分号):

proc sql;
  select  name, age, sex, height ;
  from sashelp.class
  ;
quit;
Run Code Online (Sandbox Code Playgroud)

这是因为调用宏不需要分号,所以它只是被留下并包含在步骤的执行中。

当您像在上面给出的示例中那样调用宏时,可以包含分号,因为您的宏是一个完全独立的步骤。在开放代码中,像这样使用多余的分号并没有什么害处:

%macro example2(inDS=, outDs=);
  data &outDs;
    set &inDs;
  run;
%mend;

%example2(inDS=sashelp.class, outDs=tmp_class);
Run Code Online (Sandbox Code Playgroud)

这基本上评估为:

data tmp_class;
  set sashelp.class;
run;;
Run Code Online (Sandbox Code Playgroud)

请注意我们调用中剩余的最后一个额外的分号?我们可以拥有任意数量的代码,并且代码仍然可以正常运行,即:

%example2(inDS=sashelp.class, outDs=tmp_class);;;;;;
Run Code Online (Sandbox Code Playgroud)

解决为:

data tmp_class;
  set sashelp.class;
run;;;;;;;
Run Code Online (Sandbox Code Playgroud)

它仍然可以正常运行,因为它是有效的语法。


spa*_*ead 4

It is usually fine. The main thing to understand about SAS Macro is that it is a code-generating tool, not a real programming language. While %my_mac(x,y); looks like a traditional function call in a C-like language, where you would want to end every statement with a ;, here a terminating ; has no real significance. Rather, it is the SAS code that is generated inside of %my_mac(x,y) that does. In your case, that code is grammatical SAS and is fine. If you mentally replace the %my_mac(x,y) call with the code that it generates (i.e. data mydata.....run;) you see that it is grammatical even without ending %my_mac(x,y) with a ;. If you wrote %my_mac(x,y); instead, it would just generate data mydate.....run;;, which is fine, but the ; is redundant.

As a matter of fact, skipping a semi-colon is also a hack for having a return value for a macro. For example:

%MACRO x_plus_n (x = , y= );
    %SYSEVALF (&x + &y)
%MEND;

%LET x = 3 ;
%LET y = 4 ;
%LET z = %x_plus_n (x = &x , y= &y) is the result;
%PUT ------------- &z;
Run Code Online (Sandbox Code Playgroud)

Notice the missing ; on the %SYSEVALF line. This allows the macro to not terminate until the end of the line beginning %LET z = ...., where there is a ;. The output created by x_plus_n becomes a kind of return value for the macro.

  • @sparc_spread - 我通过在宏调用和分号之间添加文本使示例更有意义。如果没有额外的文字,您想要表达的观点就不那么明显了。 (3认同)
  • 如果没有这种编辑,这基本上与问题所问的相反(它在宏内缺少“;”,这很有用,但不是原始问题正在做的事情,即在宏“外部”跳过它)。有了这个编辑就合适了。 (2认同)
  • @Joe 同意了。我用一个新的开头段落进行了编辑,更直接地解决了问题,“返回值黑客”现在是一个有用的事后想法。 (2认同)