【问题标题】:SAS macro execution orderSAS 宏执行顺序
【发布时间】:2018-02-23 06:35:42
【问题描述】:

我使用宏来锁定数据集:

%macro lockTab(member=APP_DATABASE,timeout=30,retry=500);
  %global LOCK_&member;
  %let LOCK_&member = ;
  %local starttime;
  %let starttime = %sysfunc(datetime());
  %put try to lock &member.: &starttime;
  %do %until (&syslckrc = 0
       or %sysevalf(%sysfunc(datetime()) > (&starttime + &timeout)));
      lock APPLIB.&member.;
      %put syslckrc=&syslckrc;
      %if &syslckrc > 0 %then %let rc=%sysfunc(sleep(&retry.));
  %end;
  %let endtime = %sysfunc(datetime());
  %put end of try to lock &member.: &endtime;
  %if &syslckrc <= 0 %then %do;
      %let LOCK_&member = LOCK;
  %end;
  %else %do;
    %let _appRetcode = 12;
    %let _appErrtext = Database is locked.;
  %end;
    %put ende Locktab: appretcode: &_appRetcode;
    %put ende Locktab: syslckrc: &syslckrc;
%mend;

这是我使用宏的代码(_appRetcode 是一个全局变量), 宏微调器只是在网页上显示加载微调器的数据步骤。 然后锁定数据集并放出在lockTab中设置的_appRetcode。 %debug 打印出所有具有作用域的宏变量。

%spinner(show)

%lockTab

%put EYECATCHER &_appRetcode;

%debug(DUMP Variablen nach LOCKTAB)

这是我的 SAS 日志:

NOTE: 1 record was written to the file _WEBOUT.
      The minimum record length was 42.
      The maximum record length was 42.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


SYMBOLGEN:  Macro variable _APPRETCODE resolves to 0
EYECATCHER 0
SYMBOLGEN:  Macro variable MEMBER resolves to APP_DATABASE
SYMBOLGEN:  Macro variable MEMBER resolves to APP_DATABASE
SYMBOLGEN:  Macro variable MEMBER resolves to APP_DATABASE
                                                                                          The SAS System

SYMBOLGEN:  Macro variable STARTTIME resolves to 1834989255.00056
try to lock APP_DATABASE: 1834989255.00056
SYMBOLGEN:  Macro variable MEMBER resolves to APP_DATABASE
ERROR: A lock is not available for APPLIB.APP_DATABASE.DATA.
ERROR: Lock held by process 1360575.
SYMBOLGEN:  Macro variable SYSLCKRC resolves to 70031
syslckrc=70031
SYMBOLGEN:  Macro variable SYSLCKRC resolves to 70031
SYMBOLGEN:  Macro variable RETRY resolves to 500
SYMBOLGEN:  Macro variable SYSLCKRC resolves to 70031
SYMBOLGEN:  Macro variable STARTTIME resolves to 1834989255.00056
SYMBOLGEN:  Macro variable TIMEOUT resolves to 30
SYMBOLGEN:  Macro variable MEMBER resolves to APP_DATABASE
ERROR: A lock is not available for APPLIB.APP_DATABASE.DATA.
ERROR: Lock held by process 1360575.
.......
end of try to lock APP_DATABASE: 1834989285.01467
SYMBOLGEN:  Macro variable SYSLCKRC resolves to 70031
SYMBOLGEN:  Macro variable _APPRETCODE resolves to 12
ende Locktab: appretcode: 12
                                                                                          The SAS System

SYMBOLGEN:  Macro variable SYSLCKRC resolves to 70031
ende Locktab: syslckrc: 70031

为什么在我的宏输出之前打印出 EYECATCHER?

我希望首先输出宏 lockTab,然后是“EYECATCHER 12”。 ?????

%debug 给出:(范围/变量/值)GLOBAL / _APPRETCODE / 12

【问题讨论】:

    标签: sas sas-macro


    【解决方案1】:

    我认为这个问题与解析器决定宏调用何时结束有关。如果一个宏是用参数定义的(甚至是一个空参数列表),那么宏调用不会在空白处结束。它在右括号处结束。它还将以 SAS 语言标记(包括 SAS 语言分号)或其他宏调用结束。

    这就是为什么像下面这样丑陋的东西会起作用的原因:

    %macro doit (x=) ;
      %put &=x  ;
    %mend doit;
    %doit     (x=3)
    

    换@Allan的例子,如果demo1和demo2不带参数定义,代码可以工作,因为demo1和demo3的调用会被空格触发。

    358  %macro demo1; %put 1 first; %mend;
    359  %macro demo3; %put 3 third; %mend;
    360  %macro x;
    361    %demo1
    362    %put 2 second;
    363    %demo3
    364  %mend x;
    365  %x
    1 first
    2 second
    3 third
    

    但是如果 %demo1 是用参数列表定义的,那么空白是不足以结束宏调用的。甚至 %PUT 语句也不会结束宏调用。 SAS 一直在寻找参数列表,直到它调用 %demo3,并意识到“嗯,必须完成第一个宏调用”。此时 %PUT 语句已经执行完毕。

    366  %macro demo1(); %put 1 first; %mend;
    367  %macro demo3; %put 3 third; %mend;
    368  %macro x;
    369    %demo1
    370    %put 2 second;
    371    %demo3
    372  %mend x;
    373  %x
    2 second
    1 first
    3 third
    

    作为证据,请考虑以下内容。看起来我正在将 VAR 参数传递给 %X (没有定义参数)。但是 %demo1 的调用仍然在愉快地等待一个参数列表,并且它接受它。这表明 %PUT 语句不足以结束对 %demo1 的调用。

    404  %macro demo1(var=); %put 1 first; %put &=var ;%mend;
    405  %macro x;
    406    %demo1
    407    %put 2 second;
    408  %mend x;
    409  %x(var=hello)
    2 second
    1 first
    VAR=hello
    

    我很难记住 Ian Whitlock 教给我的所有规则,有时我害怕将我记错的规则归咎于他。但我很有信心他相信所有的宏都应该至少有一个参数(他对宏的定义是“一个参数化的代码单元”),并且宏调用应该总是以括号结尾,即使它是一个空列表接受默认值的参数,即 %doit()。这样可以确保宏按预期执行,而无需添加有时会搞砸的 SAS 语言分号。

    【讨论】:

      【解决方案2】:

      只是一个想法: 您是否尝试在宏调用后放置分号?缺少分号通常会带来一些问题。即使宏看起来运行正常。

      【讨论】:

      • 有人告诉我在调用宏时不要使用分号。如果我调用“%lockTab()”而不是“%locktab”,它会起作用。所以它看起来与括号有关。但为什么?解析器错误?
      • 好的,所以你可以通过在宏调用之后添加括号来实现它,就像 %lockTab()?不知道为什么会这样。但是,如果您仍然可以正常工作,那就太好了!
      • 在宏调用之后包含分号绝对不是一个好习惯——它们会导致错误。考虑:%macro x(); y=x;%mend; data; if 0 then %x(); else 1=1;run; 会因为过早的 if-else 逻辑终止而导致错误。
      • @AllanBowe 很高兴您指出了这一点。在过去的 10 年里,我经常使用宏,并且从未遇到过由此引起的错误。您提供的示例是一个有效的示例,但我在实践中从未遇到过这样的用例。
      【解决方案3】:

      您提供的代码是否包含在父宏中?

      我能够重现这种行为,但只能在另一个宏中。

      示例代码:

      %macro x;
        %macro demo1(); %put see;  %mend;
        %macro demo2(); %put this; %mend;
        %demo1          %put here; %demo2()
      %mend;
      %x
      

      哪个打印:

      here  
      see
      this
      

      对比:

      %macro demo1(); %put see;  %mend;
      %macro demo2(); %put this; %mend;
      %demo1          %put here; %demo2()
      

      哪些打印:

      see  
      here
      this
      

      这确实看起来是一个解析器错误,或者至少 - 一个不一致。

      我建议将子宏定义移到父包装器之外。我还建议始终使用括号定义宏,然后这样调用它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-29
        • 2019-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多