如何提取SAS程序中所有使用过的函数?



我最近打算做编程习惯的分析。我的工作之一是提取SAS程序中所有使用过的函数,这些程序是由我的许多同事编写的。
我尝试过Perl正则函数,但失败了,这是我到目前为止得到的。

SAS程序文件内容:test.sas

data test;
set sashelp.class(firstobs=2) end=eof;
x = rand('uniform',0,1)- 0.5;
if sign(round(x,.1));
y = %sysfunc(date());
if eof then call execute('dm "postmessage ''42''" continue;');
run;

我的提取试验:

data _null_;
infile 'test.sas' truncover;
input prog $1024.;
start = 1;
stop = length(prog);
FuncPat = prxparse('/b[a-zA-Z_]w*(/');
call prxnext(FuncPat, start, stop, prog, position, length);
do while (position > 0);
found = substr(prog, position, length-1);
put found=;
call prxnext(FuncPat, start, stop, prog, position, length);
end;
run;

所以我有:

found=class
found=rand
found=sign
found=round
found=sysfunc
found=date
found=execute

我要的是:

found=rand
found=sign
found=round
found=date

注意:

  1. 宏函数和子程序不包含;
  2. 用户定义函数不应被忽略;
  3. 如果函数名是宏变量,如&function(),将其删除;

谢谢你的提示。@Basile Starynkevitch提醒,这里是函数的定义。
PS:如果功能substr(left of =)解决,我将加倍感谢。
PS2:我不打算做任何关于SAS的解析工作,只是用perl正则表达式提取function()的所有文本模式。@Dirk Horsten的回答非常好。

好的,这里有很多理论。我研究过SAS语言解析,它非常非常复杂。希望在合理的时间框架内解决这个问题是不现实的。让我从lex开始。SAS有数百个函数,它们的参数变化很大。你有宏函数和正则函数

在SAS和WPL之外没有针对SAS的词法分析器/解析器。有很多人尝试过,但除了WPL之外,我不知道有谁成功了。他们花了数百万美元和一大群人。如果您只想查看函数,那么从只关注数据步骤开始,并首先获取lex。

顺便说一句,我已经用ANTLR试过了,但是,在我看来,这是没有必要的。简单一点,用分号隔开来确定行。SAS程序有两个主要部分:DATA步骤和PROC。在那里中断,然后按行,然后尝试在行内隔离功能。它不会100%,但它是一个尝试。

在我看来,忽略这个词法分析器/解析器、这个理论、这个方法、这个示例语言等等。SAS语言已经有50多年的历史了,它包含了数百个子语言、数百个进程、隐藏特性,以及一些元语言(宏、数据集修饰符、ODS等)。

好运。

在使用它之前检查一下前面的内容。(scan函数从字符串的末尾开始计数,而不是从开始计数。)

进一步:与其写入日志,不如将output写入数据集,这样就可以对结果运行统计数据。

data FUNCTION;
infile 'test.sas' truncover;
input prog $1024.;
start = 1;
stop = length(prog);
FuncPat = prxparse('/b[a-zA-Z_]w*(/');
call prxnext(FuncPat, start, stop, prog, position, length);
do while (position > 0);
found = substr(prog, position, length-1);
if not ( substr(prog, position - 1) eq '.'
or substr(prog, position - 1) eq '%'
or upcase(scan(substr(prog, 1, position - 1), -1)) eq 'CALL'
or upcase(scan(substr(prog, 1, position - 1), -1)) eq 'DATA'
) then output;
call prxnext(FuncPat, start, stop, prog, position, length);
end;
run;

您可能会遇到想要排除的其他不是真正的函数的结构,但这应该是一个好的开始。

最新更新