我有一个关于SAS宏的基本问题。在sas宏内部,当你编写一个let语句或put语句或if语句时,你总是用%前缀。
但是当你在宏中写一个'proc'时,为什么我们不需要写%proc? 或者例如%data?
答案 0 :(得分:5)
因为数据步骤语言和宏语言是两种不同的编程环境。当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;
当我们运行Macro 2时,我们将获得完全相同的输出,但它的执行方式不同。
当我们编译宏foo2
时,我们还存储了一些关于内部宏循环的信息。此特定循环只是顺序创建文本“var1 var2 var3”。请注意,循环之前有一段文字:“keep。”这完全有效,因为它只是一段文字。
我们在数据步骤中执行宏。当我们开始数据步骤的编译过程时,单词scanner扫描程序找到宏触发器%
并将该信息传递给宏处理器。当它发现foo2
是一个有效的编译宏时,宏处理器运行宏程序,并将生成的文本发送到单词scanner:
keep
var1
var2
var3
我们故意以分号结束宏的调用。这告诉扫描器这个词我们在一个语句的末尾,最终会被发送到编译器。
宏完成之后,扫描程序一直保持不变,将语句传递给输入堆栈,直到它到达run
边界或其他proc
步骤。
我们可以在数据步骤之外调用foo2
,但SAS会错误地说它们不是有效的语句。这相当于在一行上键入keep var1 var2 var3;
并尝试运行它。该特定文本仅在数据步骤中有用,尽管SAS很乐意尝试在任何地方运行它。
SAS没有看到宏。它只能理解数据步骤和proc语言。只有宏处理器才能看到并使用宏触发器。单词scanner扫描程序可防止编译器看到任何宏触发器。将扫描仪这个词想象成一个特殊的过滤器:它只将文本分发给可以读取它的地方。
有一些例外情况,数据步骤中的某些功能可以弥合SAS和宏之间的差距,但它实际上并没有与此有任何关系。
答案 1 :(得分:2)
%
表示宏语法 - 宏函数,宏语句或宏命令。基本上,SAS Macro Language Reference涵盖的内容。
当您在宏中有一个proc时,您要求宏执行的操作就是将该proc键入堆栈,就像您键入它一样。您不需要%
,因为proc是您要求输入的文本,而不是宏语言解释器本身的命令。
%let
或%put
是宏语句:它们与您在数据步骤中可以使用的put
不同。他们分享了功能的名称和基本概念,但c中printf
和r printf
中的Function
共同拥有其他内容。
答案 2 :(得分:0)
出于同样的原因,当我编辑HTML时,我不必在网页中的字词周围输入<>
。我的网页中的单词不是HTML命令,就像SAS代码语句不是SAS宏处理器的命令一样。