在程序中获取区分大小写的宏列表

时间:2017-02-09 21:22:20

标签: sas sas-macro

基于此post,我可以使用以下代码获取程序中已编译宏的列表,这些宏按其首次出现排序:

%macro FirstMacro();
  %put Hello, World!;
%mend;

%macro SecondMacro();
  %put Goodbye, cruel world!;
%mend;

proc sql;
  select objname, created
  from dictionary.catalogs
  where objtype='MACRO' and libname ^= 'SASHELP'
  order by created
  ;
quit;

然而,这会以大写形式给出所有宏。

               Object Name                           Date Created
               --------------------------------------------------
               FIRSTMACRO                        09FEB17:16:12:31
               SECONDMACRO                       09FEB17:16:12:31

我使用PascalCase作为我的宏名称(如上图所示)。有没有办法获得类似的列表,但保留了区分大小写?

似乎PROC SCAPROC可能提供这样的列表,但我不清楚。 PROC SCAPROC首次发布时(在9.2中)有note表示PROC SCAPROC不支持何时使用%MACRO。但是,该说明表明这将是未来SAS版本的一项功能。使用SAS 9.4,尚不清楚该功能是否已添加。

我能想到的唯一另一种选择是用其他语言编写脚本,分析上面的文本以获取宏名称。

3 个答案:

答案 0 :(得分:0)

所以,这可能会给你你想要的东西,至少在上面的例子中。

它不会在宏运行时扩展宏 - 这意味着,你无法看到内部宏发生了什么,运行时。如果您在运行时生成宏,即使用数据创建宏(如

),这可能会出现问题
data _null_;
  set something;
  call execute ('%macro ',name_var,'; ... ; %mend;');
run;

可能无法正常显示。但是,如果您只是在代码中编写宏并编译它们,那么是的,您可以使用它 - 尽管您必须至少作为其中的一部分运行编译步骤(这不会分析明文,它会分析一个工作时的工作)。

所以,如果我做这样的事情:

proc scaproc;
  record 'c:\temp\recording.txt' expandmacros;
run;

%macro PascalCaseMacro();
  %put PascalCaseMacro;
%mend;

%PascalCaseMacro;

proc scaproc; 
   write; 
run;

我得到这样的输出:

/* JOBSPLIT: PROCNAME DATASTEP */
/* A bunch of lines like that with JOBSPLIT at the start */


%macro PascalCaseMacro();
  %put PascalCaseMacro;
%mend;

%PascalCaseMacro;

/* Some more JOBSPLIT lines */

然后,您可以为该文本文件解析以%macro开头的行。

我认为你的问题的技术答案是“不”,他们没有实现这个:虽然它确实通过宏目录的一些访问来更新技术信息,但它并没有包含在宏的详细信息中运行(在/ * JOBSPLIT * /行中)。我认为,这正是技术说明所谈论的内容;即,这对优化宏代码并不完全有用。生成宏的实际代码(我认为所有需要的)都在那里。 (但是,如果你有一个存储编译的宏,可用。)

答案 1 :(得分:0)

我能够从this帖子调整Windows批处理脚本,以获取给定程序中定义的区分大小写的宏列表。

REM GetListOfDefinedMacros.bat

@ECHO OFF

SET /P SASFILE= Enter SAS filepath: 
SET SASFILE=%SASFILE:"=%

ECHO.
ECHO The defined macros are:
ECHO.

FOR /F "tokens=*" %%A IN ('FINDSTR "macro" "%SASFILE%" ^| FINDSTR "("') DO CALL :FindString "%%A"
ECHO. 
pause
GOTO :eof

:FindString
SET String=%~1
SET String=%String:*macro =%
SET String=%String:)=X%
SET String=%String:(=`%
FOR /F "tokens=1 delims=`" %%A IN ('ECHO.%String%') DO ECHO.%%A
GOTO :eof

程序会提示用户输入SAS程序的完整文件路径。然后它解析代码,查找包含“macro”和“(”的行,返回它们之间的任何字符。

必须遵守以下假设:

  • 每行包含一个编程语句; “macro”和“(”必须位于同一行,
  • 使用括号定义宏;它不适用于%macro MacroName;样式定义。

请注意,该脚本不会列出已编译的宏。它只能检测在给定程序中具有定义的宏。通过%include或AUTOCALL编译的宏将不会显示。

例如,

/*C:\temp\sample sas program.sas*/

%macro FirstMacro();
  %put NOTE: Hello, world!;
%mend;

%macro SecondMacro();
  %put ERROR: Goodbye, cruel world!;
%mend;

%macro ThirdMacro(input);
  %if &input. = hi %then %FirstMacro();
  %else %SecondMacro();
%mend;

%ThirdMacro(hi);
%ThirdMacro(bye);

这会将以下输出提供给命令提示符:

Enter SAS filepath: "C:\temp\sample sas program.sas"

The defined macros are:

FirstMacro
SecondMacro
ThirdMacro

Press any key to continue . . .

从那里,您可以复制并粘贴列表。或者,可以修改代码以将列表重定向到文件。

答案 2 :(得分:0)

这是一个原生SAS解决方案,它应该只依赖于BASE功能。它适用于Windows上的增强编辑器。

%macro ListMacroDefinitions();
  /*Get file-path of current program's source code.*/
  proc sql noprint;
    select distinct xpath
    into : _SASProgramPath trimmed
    from dictionary.extfiles
    where xpath contains "%sysget(SAS_EXECFILENAME)"
    ;
  quit;

  /*Read in source code, parse for macro names, and
    output to log.*/
  options nonotes;
  data _null_;
    infile "&_SASProgramPath." dlm = '```';
    length 
      line        $ 256
      macro_name  $ 32
    ;
    input line;

    if line =: '%macro' then do;
      indexLeftParenthesis  = index(line, '(');
      macroNameLength       = indexLeftParenthesis - 8;
      macro_name            = substr(line, 8, macroNameLength); 
      put macro_name;
    end;
  run;
  options notes;
  dm 'wpgm';
%mend;

首先确定当前节目的名称使用%sysget(SAS_EXECFILENAME)%SYSGET函数返回environment variable SAS_EXECFILENAME的值

  

指定当前SAS源文件的文件名(如果是)   从增强编辑器提交。

然后查看DICTIONARY.EXTFILES table并提取与当前源文件的名称(即当前正在编辑的程序)相关联的文件路径。此文件路径分配给宏变量。

接下来,数据步骤读入当前程序的源文件。它逐行读取文件,在INFILE语句中设置一个不存在的分隔符(三个后退标记)。

  

默认情况下,如果INPUT语句尝试读取超过的结尾   当前输入数据记录,然后它将输入指针移动到第1列   读取剩余值的下一条记录。

将分隔符定义为从未出现在源代码中的字符串会导致读入的行永远不会被解析,因此可以整体读取。检查每一行是否contains是一个宏定义(通过=:运算符)。具体来说,它会查找字符串'%宏'。然后,我们手动解析每个定义行以查找'%宏'之间的字符。声明和第一个括号。结果输出到日志。在此过程中,会禁用备注。最后,发出窗口命令wpgm。将宏名称写入日志时,将选择日志窗口。 wpgm命令将焦点返回到最后一个程序窗口,该窗口应该是当前正在编辑的程序。

整个过程放在一个宏中。如果将宏放在AUTOCALL库中(通过发出%put %sysfunc(pathname(sasautos));找到),则可以获得当前程序中定义的所有宏的列表。请注意,要完成此列表,必须在运行宏之前保存当前程序。