Date: Thu, 12 Dec 2002 09:26:28 -0500
Reply-To: Ian Whitlock <WHITLOI1@WESTAT.COM>
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: Ian Whitlock <WHITLOI1@WESTAT.COM>
Subject: Re: recruiting cheesy, sleasy SAS tricks tip call execute
Content-Type: text/plain; charset="iso-8859-1"
Ron,
You say:
> NOTE: call execute will not work correctly,
> i.e., as you expect,
> when you pass a complex macro call to it.
> a macro with complexity is one that has symput,
> or macro control statements: %IF or %DO, etc.
There two things wrong with this. Complexity and the use of macro %IF, %DO,
etc. have nothing to do with the problems caused by invoking macros with
CALL EXECUTE. On the other hand, SYMPUT definitely causes problems in most
cases, but it is not the only problem. It is far better to understand the
problem.
SAS is a sequentially step oriented language. Hence one cannot execute one
step inside another. Macros generate code which may consist of steps. When
a macro is invoked during SAS compile time, after each step is generated
(i.e. when the word scanner reaches a step boundary) execution of the step
takes place. This means that the produce of a step in a macro may be used
in a subsequent part of the macro. (This is essentially why step boundaries
are so much more important in macro than in plain SAS.)
When a macro is invoked via CALL EXECUTE it is during the execution of a
DATA step. This has consequences that should be spelled out.
The steps of the macro are generated, but neither compiled nor
executed until the executing DATA step finishes execution.
Consequently, any produce of an executed step generated by the macro will
not be available during the generation of any SAS code by the macro. It is
also true that no macro instructions in the macro can use this produce
either. The use of CALL SYMPUT to assign a value to a macro variable is a
simple and most important example. However, the same problems arise when
using CALL EXECUTE in a generated DATA step, or when generated SQL code is
used to create a macro variable. Is this a complete list? I have always
been careful to leave the door open to other possibilities. Here is the
simplest example I have found so far.
%macro q ;
data q ;
x = "HELLO from dataset Q" ;
run ;
title "Print of Dataset &syslast" ;
%mend q ;
data w ; x = 1 ; run ;
data _null_ ;
call execute ( '%q' ) ;
run ;
proc print data = q ;
run ;
Note the macro has only one step and one global statement. No macro
instructions are used with the exception of the reference to one system
provided macro variable. However, the title on the subsequent print will be
incorrect because the principle given above was violated.
I consider the use of %NRSTR to postpone the execution of the macro until
after the executing DATA step far too important to be included in any list
of sleazy tricks. I even resent calling it a trick. In fact I wish SI
would add a new routine CALL NREXECUTE to facilitate this type of code. If
there is any sleaze in CALL EXECUTE, it lies in the lack of programmer
control over the log.
IanWhitlock@westat.com
-----Original Message-----
From: Fehd, Ronald J. (PHPPO) [mailto:rjf2@CDC.GOV]
Sent: Wednesday, December 11, 2002 8:58 AM
To: SAS-L@LISTSERV.UGA.EDU
Subject: Re: recruiting cheesy, sleasy SAS tricks tip call execute
> From: Michael L. Davis [mailto:michael@BASSETTCONSULTING.COM]
> I'd like to do a Coder's Corner presentation at NESUG next
> year on the subject of "Cheesy, Sleasy SAS Tricks".
> - Michael "Mad Doggy" Davis
What a pile of bones you are collecting here, MadDog!
Don't know the cheese factor of this one.
maybe ToFu?! LOL %-D
This is a trick I use for debugging call execute
enabling the mVar CMD=put Cmd;
will write your call execute statements to file PRINT;
once they look correct then disable that statement.
and your code executes.
using NoRescanString inside call execute
guarantees that macro calls in Cmd will execute when popped
not pushed.
NOTE: call execute will not work correctly,
i.e., as you expect,
when you pass a complex macro call to it.
a macro with complexity is one that has symput,
or macro control statements: %IF or %DO, etc.
DATA X;MemName='X';output;stop;run;
%*note:MemName is available from DICTIONARY.TABLES;
%LET CMD = call execute('%nrstr(' !! Cmd !! ');' );
%LET CMD = put Cmd;%*TESTING;
%LET LIBREF = WORK;
%LET DATA = X;
%LET CONDITION =1;%*for testing;
%MACRO TEST1(DATA=);PROC FREQ data = &DATA.;run;%MEND;
%MACRO TEST2(DATA=,COND=);
%IF &COND. %THEN %DO;
PROC FREQ data = &DATA.;run;%END;%MEND;
DATA _NULL_;
length Cmd $ 72;%*may be longer;
file PRINT;
do until(EndoFile);
set WORK.&DATA.
(where = (&CONDITION.))
end = EndoFile;
Cmd = "proc PRINT data = &LIBREF.."
!! trim(MemName)
!! ';';
&CMD.;
Cmd = "%TEST1(DATA=&LIBREF.."
!! trim(MemName)
!! ');';
&CMD.;
Cmd = "%TEST1(DATA=&LIBREF.."
!! trim(MemName)
!! ",COND=1);';
&CMD.;
%*do until(EndoFile);end;
stop;
run;
%*NOTE: call execute happens in this step;
run;
Ron Fehd the macro maven CDC Atlanta GA USA RJF2@cdc.gov
If you think I know what I'm doing
it's probably because you know even less about it.
-- Pot-Shots by Ashleigh Brilliant
do not fold, spindle, or mutilate -- IBM punch card
... the call execute argument(s)