宏似乎陷入无限循环,不知道如何调试

时间:2018-02-09 09:48:38

标签: sas sas-macro

我正在尝试定义一个宏函数,该函数从空格分隔列表中返回唯一列表项。这个宏本身使用我测试过的其他宏,并且看起来自己工作得很好(参见下面的例子),这都是非常简单的代码。

但由于某种原因,代码无限期运行,我不知道如何正确调试它。我通常使用%put语句进行调试,但由于没有错误,因此不会在此处打印,我会手动停止代码。

这是主宏,其次是我使用的其他便捷宏,你可以执行整批加载宏,然后查看给定的例子。

*---------------------------------------------------------------;
* LIST_UNIQUE                                                   ;
* Return only unique items from list,                           ;
* in order of first appearance                                  ;
*---------------------------------------------------------------;
/* EXAMPLE
%put %list_unique();    ** (nothing)
%put %list_unique(a);   ** a
%put %list_unique(a a); ** doesn't work (should be a)
%put %list_unique(a b); ** doesn't work (should be a b)
*/
%macro list_unique(data);
%local out curr_item;
%do i=1 %to %list_length(&data);
   %let curr_item = %extract(&data,&i);
   %if not %list_in(&curr_item,&out) %then %let out = &out &curr_item;
%end;
&out
%mend;

*---------------------------------------------------------------;
* LIST_LENGTH                                                   ;
* Length of space separated list                                ;
*---------------------------------------------------------------;
/* EXAMPLES :   
   %put %list_length(); ** 0
   %put %list_length(item1 item2 item3); ** 3
*/
%macro list_length(data);
%sysfunc(countw(&data,%str( )))
%mend;

*---------------------------------------------------------------;
* LIST_IN                                                       ;
* check if item is in list                                      ;
*---------------------------------------------------------------;
/* EXAMPLE
%put %list_in(,a);        ** 0
%put %list_in(a,);        ** 0
%put %list_in(a,a);       ** 1
%put %list_in(a,a a);     ** 1
%put %list_in(b,a b c d); ** 1
%put %list_in(e,a b c d); ** 0
*/
%macro list_in
(item /* item to search in list */
,list /* space separated list to quote */
);
/* exception when list has null length */
%if not %length(&list) %then 0%return; 
/* general case */
%do i=1 %to %list_length(&list);
   %if %extract_pos(&list,&i) = &item %then 1%return;
%end;
0
%mend;

*-------------------------------------------------------------------------------;
* EXTRACT_POS                                                                   ;
* Extracts subset of values from space separated list                           ;
*-------------------------------------------------------------------------------;
/* EXAMPLES
%put %extract_pos(,1);        ** (nothing)
%put %extract_pos(a b c d,);  ** (nothing)
%put %extract_pos(a b c d,1); ** a
%put %extract_pos(a b c d,2 1:3 1); ** b a b c a
*/
%macro extract_pos
(data
,ind
);
%local i j token output new_ind;
%do i=1 %to %sysfunc(countw(&ind,%str( )));
  %let token = %scan(&ind,&i,%str( ));
  %if %index(&token,:) %then %do; /* if token with ':' */
    %do j=%scan(&token,1,:) %to %scan(&token,2,:);
      %let output = &output %scan(&data,&j,%str( ));
    %end;
  %end;
  %else %do;                      /* if simple token */
      %let output = &output %scan(&data,&token,%str( ));
  %end;
%end;
&output
%mend;

3 个答案:

答案 0 :(得分:2)

您无法保护调用的宏修改宏变量,但如果宏设计得当,则不会。除非您打算修改任何现有的宏变量,否则您需要将宏变量定义为local。您的一个或多个宏使用宏变量I而未将其定义为本地。因此,如果已存在名为I的宏变量,则宏修改现有变量的值。

您的一个宏也在调用%extract()而不是%extract_pos()

我还简化了您的%list_in()宏,只是调用现有的SAS功能,例如您的%list_length()宏。

%macro list_unique
/*---------------------------------------------------------------
Return only unique items from list
---------------------------------------------------------------*/
(data  /* Space delimited list of items */
);
%local i curr_item out ;
%do i=1 %to %list_length(&data);
  %let curr_item = %extract_pos(&data,&i);
  %if not %list_in(&curr_item,&out) %then %let out=&out &curr_item;
%end;
&out
%mend list_unique;

%macro list_length(data);
%sysfunc(countw(&data,%str( )))
%mend list_length;

%macro list_in
/*---------------------------------------------------------------
Check if item is in list
---------------------------------------------------------------*/
(item /* item to find in list */
,list /* space separated list to search */
);
%sysevalf(%sysfunc(indexw(&list,&item,%str( ))),boolean)
%mend list_in;

%macro extract_pos
/*-------------------------------------------------------------------------------
Extracts subset of values from space separated list
-------------------------------------------------------------------------------*/
(data   /* Space delimited list of values */
,ind    /* Space delimited list of positions or position ranges */
);
%local i j token output;
%do i=1 %to %sysfunc(countw(&ind,%str( )));
  %let token = %scan(&ind,&i,%str( ));
  %do j=%scan(&token,1,:) %to %scan(&token,-1,:);
/* Token is single position or range in format start:end */
    %let output = &output %scan(&data,&j,%str( ));
  %end;
%end;
&output
%mend extract_pos;

测试

831  %put %list_unique();    %** (nothing);

832  %put %list_unique(a);   %** a ;
a
833  %put %list_unique(a a); %** doesnot work (should be a);
a
834  %put %list_unique(a b); %** doesnot work (should be a b);
a b

答案 1 :(得分:1)

  1. 通过将此行添加到代码的开头来启用宏调试,这将解析宏代码和变量:

    Options macrogen symbolgen mlogic mprint mfile;
    
  2. 运行您的代码并查看日志以获取详细信息,

  3. 完成后通过使用以下选项替换步骤1中的选项来禁用宏调试:

    Options nomacrogen NoSymbolgen nomlogic nomprint nomfile;
    
  4. 有关详细信息,请查看SAS调试文档 http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a001066200.htm

答案 2 :(得分:0)

变量I在nameSpace中共享。一个简单的解决方法是在每个宏中使用不同的循环变量。

找到一些关于SAS共享逻辑的文档。 SAS Blogs