为什么 proc 在 SAS 宏中编写时不需要 % 符号

Why proc does not need a % symbol when written inside a SAS macro

我有一个关于 SAS 宏的基本问题。在 sas 宏中,当你写一个 let 语句或一个 put 语句或一个 if 语句时,你总是在它前面加上 %.

但是当你在宏里面写一个'proc'的时候,为什么我们不需要写%proc呢? 或者例如 %data?

%表示宏语法——宏函数、宏语句或宏命令。基本上,SAS Macro Language Reference 涵盖的内容。

当你在宏中有一个过程时,你要求宏做的就是将该过程键入堆栈,就像你已经键入它一样。您不需要 % 因为 proc 是您要求输入的文本,而不是对宏语言解释器本身的命令。

SAS Macro language和SAS Base是两种本质上独立的语言——后者是SAS的核心,前者是一个帮手,可以让某些重复性的事情变得更容易。它们只是松散地集成。

%let%put 是宏语句:它们与您可以在数据步骤中使用的 put 不同。它们共享名称和功能的基本概念,但除了 and printf in 中的 printf 没有其他共同点。

因为数据步语言和宏语言是两种不同的编程环境。当 SAS 标记您的语句时,它会查找特定的关键字。其中一个关键字是 % 触发器。在 运行 之前,单词扫描器将宏语句从 SAS 语句中分离出来,并将它们传递给适当的处理器。宏语句总是在 SAS 语句之前编译和解析。

当您使用宏时,您是将文本字符串存储在某个宏变量或宏程序中。就 SAS 而言,宏变量或程序中的任何内容都是原始文本。

考虑以下两个宏:

宏 1:

%macro foo1;
    data bar1;
       var1 = 'a';
       var2 = 'b';
       var3 = 'c';
       var4 = 'd';

       keep var1-var3;
    run;
%mend;

宏 2:

%macro foo2;
       keep
       %do i = 1 %to 3;
           var&i
       %end;
%mend;

data bar2;
   var1 = 'a';
   var2 = 'b';
   var3 = 'c';
   var4 = 'd';

   %foo2;
run;

编译宏 1 时,在调用它之前什么也不会发生。这是因为您已将所有这些文本存储在宏程序中。调用宏语句时:

%foo1;

SAS 将短语 foo1 传递给宏处理器,程序为 运行,解析后的文本被吐回单词扫描仪,然后逐一处理各个标记。就SAS而言,它看到的正是里面包含的datastep:

data bar1;
   var1 = 'a';
   var2 = 'b';
   var3 = 'c';
   var4 = 'd';

   keep var1-var3;
run;

当我们 运行 宏 2 时,我们将得到完全相同的输出,但它的执行方式不同。

当我们编译宏foo2时,我们还存储了一些关于内部宏循环的信息。这个特定的循环只是按顺序创建文本 "var1 var2 var3"。请注意,在循环之前有一段文字:"keep." 这是完全有效的,因为它只是一段文字。

我们在数据步骤中执行宏。当我们开始数据步骤的编译过程时,单词扫描器找到宏触发器 % 并将该信息传递给宏处理器。当它发现 foo2 是一个有效的已编译宏时,宏处理器 运行 执行宏程序,并将生成的文本发送到单词扫描器:

keep
var1
var2
var3

我们故意用分号结束宏的调用。这告诉词扫描器我们在语句的末尾,最终被发送到编译器。

一旦宏完成,单词扫描仪就会继续前进,将语句传递到输入堆栈,直到它到达 run 边界或另一个 proc 步骤。

我们可以在数据步骤之外调用 foo2,但 SAS 会出错并指出它们不是有效语句。这相当于在一行中键入 keep var1 var2 var3; 并尝试 运行 它。那段特定的文本仅在数据步骤中有用,尽管 SAS 会很乐意 运行 它随处可见。

SAS 看不到宏。它只理解数据步骤和过程语言。只有宏处理器才能看到和使用宏触发器。单词扫描器阻止编译器看到任何宏触发器。将单词扫描器想象成一个特殊的过滤器:它只将文本分发到可以读取它的地方。

有一些例外,数据步骤中的一些函数可以弥合 SAS 和宏之间的差距,但实际上与此没有任何关系。

出于同样的原因,我在编辑 HTML 时不必在网页中的单词周围键入 <>。我网页中的文字不是 HTML 命令,就像 SAS 代码语句不是 SAS 宏处理器的命令一样。