LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (November 2008, week 2)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
Date:         Fri, 14 Nov 2008 16:41:45 -0600
Reply-To:     Mary <mlhoward@avalon.net>
Sender:       "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From:         Mary <mlhoward@AVALON.NET>
Subject:      Re: Call Execute usage/behavior on Macros
Comments: To: "Terjeson, Mark" <Mterjeson@RUSSELL.COM>
Content-Type: text/plain; charset="iso-8859-1"

Mark,

Thank you so much for your explanation; I will reread this several times. I actually got brave and did my very first call execute ever today! Despite over 20 years of SAS programming!

And it worked! Happy dance! BUT, I was really confused as to why the output of all the put statements came first; that it is making multiple passes is important to know, as it really isn't the same as a subroutine despite trying to think of it that way.

-Mary ----- Original Message ----- From: Terjeson, Mark To: SAS-L@LISTSERV.UGA.EDU Sent: Friday, November 14, 2008 4:30 PM Subject: Re: Call Execute usage/behavior on Macros

Hi,

As you have deduced already the issue is purely "timing". Once you get a feel for the sas macro parser making pass(es) through the text to resolve as much as it can, and then the resultant text substitutions and macro storage of parts and pieces are done, then the end resultant text goes to the compiler/runtime.

Long story short, if you comment out the %PUT from inside the %MACRO you will notice that the warning message goes away. When the macro parser first looks through the code inside the %MACRO/%MEND it incurs a datastep and a %PUT. It actively looks at that %PUT right then and there and says, "I don't find a pre-set-up storage for &cnt1 yet. And it hasn't got one yet at this time. So it is correct. The datastep code text has been parsed and all the macro references and goodies get resolved, just as if you hand-resolved them yourself, and the text substitutions have been made, and then THAT customized code text gets sent to the compiler. i.e. the CALL SYMPUT() is a datastep instruction that has *not* been executed yet, so the call symput() has *not* created the macro variable storage yet. The call symput() macro variables do not exist until AFTER the datastep has completed. So as you can see the live %PUT didn't have a macro variable container to fetch from until after the datastep completed and only then did a container for &cnt1 exist.

You will note that your datastep does indeed work and complete successfully, and you see in the log your values 1,25,101. Therefore your code actually processes the code in sequence, -and- the values are actually really there upon completion of each of those passes. So during the compiler/runtime execution everything was in order and results were in order timingwise.

In your %MACRO there is no %GLOBAL or %LET, etc. that would have created the storage container for a macro variable called cnt1 at the time your %PUT is incurred. If you placed a %GLOBAL or %LET statement somewhere, you would then have gotten rid of the warning about there not being a macro variable container at the time the %PUT tried to find one. However, you would note that the %PUT would complete successfully BUT would not have a value yet to display. Remember, the macro parser pre-substitutes all of the macro text and reference links and then all of that replicated code text goes to the SAS compiler and the datasteps get executed. During that first datastep the CALL EXECUTE() sends its lines of text to the code queue and after the datastep has completed, THEN the code queued up gets submitted and run, so basically your macro variable still haven't been created yet.

If your intention is to see what the value of the created macro variable is, then you cannot fetch and display it until AFTER it has been created and loaded. So what you really want is a %PUT *after* it has been created. Therefore, it is timing and you want a %PUT after the CALL EXECUTE() has been executed, which got queued up and not run until after the datastep. So, the easy fix is to get the sequencing right, and have the %PUT occur after the CALL SYMPUT, which just means that if you put the %PUT into a CALL EXECUTE() line just after the other CALL EXECUTE, then the %PUT would occur after the &cnt1 got created and loaded and the %PUT would find a container and the value to display.

i.e one of the best ways to debug CALL EXECUTE is to comment out the CALL EXECUTE() and substitute a PUT statement printing the entire line of text to the log.

If you did so, your original CALL EXECUTE text that gets queued up would look like this:

%fam_data(file1 ) %fam_data(file2 ) %fam_data(file3 )

For CALL EXECUTE and SAS MACRO goodies, you can debug by pretending to manually do the code text replacement yourself. Because that way you actually can understand what the compiler is going to see and execute. In other words, you can work backwards to get this all working.

So to get the timing right what you really want is: %fam_data(file1 ) %PUT cnt1 is >&cnt1<; %fam_data(file2 ) %PUT cnt1 is >&cnt1<; %fam_data(file3 ) %PUT cnt1 is >&cnt1<;

Which will work as intented.

Thus, now all you have to do is to create this text going to the compiler. Merely pass the second line with a second CALL EXECUTE() and it will automatically interleave them as seen above.

Now the %PUT will look for and find the macro value at the right time (after it is created and loaded).

I know this paper is overly simplistic for your level of macro use already, but if you checked it out you might get the *feel* for the timing aspects that may or maynot have eluded your initial skilled adroitness.

http://www.pnwsug.org/Conference_2006/Procedings/PNWSUGotherfiles/PN21Ma rkTerjesonMacro101.pdf

Hope this is helpful.

Mark Terjeson Senior Programmer Analyst Investment Management & Research Russell Investments 253-439-2367

Russell Global Leaders in Multi-Manager Investing

-----Original Message----- From: SAS(r) Discussion [mailto:SAS-L@LISTSERV.UGA.EDU] On Behalf Of dc353@hotmail.com Sent: Friday, November 14, 2008 1:03 PM To: SAS-L@LISTSERV.UGA.EDU Subject: Call Execute usage/behavior on Macros

Hi,

This is a follow up on a previous post Macro Control problem. Both Howard Schreirer and Ian Whitlock have helped with this development.

I have the following simplified example:

data f_name; input fname : $12.; cards; file1 file2 file3 ; data file1; cnt = 1; run; data file2; cnt = 25; run; data file3; cnt = 101; run;

options mtrace mprint mlogic; %macro fam_data (tmp_data);

data _null_; set &tmp_data;

put 'cnt = ' cnt; call symput ('cnt1',trim(left(put(cnt,best12.)))); run; %put '&cnt = ' &cnt1;

%mend fam_data;

data _null_; set f_name; %let tmp_data = fname;

call execute('%fam_data('|| &tmp_data ||')'); * call execute('%nrstr(%fam_data('|| &tmp_data ||'))'); put 'test1 ' &tmp_data;

run;

I run the code first as shown and then change the Call execute statement as indicated and run it again. I'm trying to better understand what's actually going on and why &cnt1 doesn't resolve in the first case but does resolve in the second even though cnt always has the right value. I also notice that the put statement "PUT 'TEST1 &TMP_DATA; is being executed at different times relative to the macro between the two different versions. Again, I'm trying to better understand what's actually going on. While the second version is doing what I want it sems the first version if modified could create a new macro variable each time the macro is called. Some of my problem is just about developing a basic understanding of how macros execute. Thanks.

Here is the log:

1 data f_name; 2 input fname : $12.; 3 cards;

NOTE: The data set WORK.F_NAME has 3 observations and 1 variables. NOTE: DATA statement used: real time 0.01 seconds cpu time 0.01 seconds

7 ; 8 9 data file1; cnt = 1; run;

NOTE: The data set WORK.FILE1 has 1 observations and 1 variables. NOTE: DATA statement used: real time 0.01 seconds cpu time 0.01 seconds

10 data file2; cnt = 25; run;

NOTE: The data set WORK.FILE2 has 1 observations and 1 variables. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

11 data file3; cnt = 101; run;

NOTE: The data set WORK.FILE3 has 1 observations and 1 variables. NOTE: DATA statement used: real time 0.01 seconds cpu time 0.01 seconds

12 13 options mtrace mprint mlogic; 14 15 %macro fam_data (tmp_data); 16 17 data _null_; 18 set &tmp_data; 19 20 put 'cnt = ' cnt; 21 call symput ('cnt1',trim(left(put(cnt,best12.)))); 22 23 run; 24 25 %put '&cnt = ' &cnt1; 26 27 %mend fam_data; 28 29 30 data _null_; 31 set f_name; 32 33 %let tmp_data = fname; 34 35 call execute('%fam_data('|| &tmp_data ||')'); 36 * call execute('%nrstr(%fam_data('|| &tmp_data ||'))'); 37 38 put 'test1 ' &tmp_data; 39 run;

MLOGIC(FAM_DATA): Beginning execution. MLOGIC(FAM_DATA): Parameter TMP_DATA has value file1 MPRINT(FAM_DATA): data _null_; MPRINT(FAM_DATA): set file1; MPRINT(FAM_DATA): put 'cnt = ' cnt; MPRINT(FAM_DATA): call symput ('cnt1',trim(left(put(cnt,best12.)))); MPRINT(FAM_DATA): run; MLOGIC(FAM_DATA): %PUT '&cnt = ' &cnt1 WARNING: Apparent symbolic reference CNT1 not resolved. *****COMPARE THIS TO SECOND VERSION '&cnt = ' &cnt1 MLOGIC(FAM_DATA): Ending execution. test1 file1 ------------------------------>>>>>> *****NOTICE WHERE THIS IS (FROM LINE 38) MLOGIC(FAM_DATA): Beginning execution. MLOGIC(FAM_DATA): Parameter TMP_DATA has value file2 MPRINT(FAM_DATA): data _null_; MPRINT(FAM_DATA): set file2; MPRINT(FAM_DATA): put 'cnt = ' cnt; MPRINT(FAM_DATA): call symput ('cnt1',trim(left(put(cnt,best12.)))); MPRINT(FAM_DATA): run; MLOGIC(FAM_DATA): %PUT '&cnt = ' &cnt1 WARNING: Apparent symbolic reference CNT1 not resolved. '&cnt = ' &cnt1 MLOGIC(FAM_DATA): Ending execution. test1 file2 MLOGIC(FAM_DATA): Beginning execution. MLOGIC(FAM_DATA): Parameter TMP_DATA has value file3 MPRINT(FAM_DATA): data _null_; MPRINT(FAM_DATA): set file3; MPRINT(FAM_DATA): put 'cnt = ' cnt; MPRINT(FAM_DATA): call symput ('cnt1',trim(left(put(cnt,best12.)))); MPRINT(FAM_DATA): run; MLOGIC(FAM_DATA): %PUT '&cnt = ' &cnt1 WARNING: Apparent symbolic reference CNT1 not resolved. '&cnt = ' &cnt1 NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

MLOGIC(FAM_DATA): Ending execution. test1 file3 NOTE: There were 3 observations read from the data set WORK.F_NAME.

NOTE: CALL EXECUTE generated line. 1 + data _null_; set file1; put 'cnt = ' cnt; call symput ('cnt1',trim(left(put(cnt,best12.)))); run;

cnt = 1 NOTE: There were 1 observations read from the data set WORK.FILE1. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

2 + data _null_; set file2; put 'cnt = ' cnt; call symput ('cnt1',trim(left(put(cnt,best12.)))); run;

cnt = 25 NOTE: There were 1 observations read from the data set WORK.FILE2. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

3 + data _null_; set file3; put 'cnt = ' cnt; call symput ('cnt1',trim(left(put(cnt,best12.)))); run;

cnt = 101 NOTE: There were 1 observations read from the data set WORK.FILE3. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

***************************************************************** END OF FIRST EXECUTION *****************************************************************

40 data f_name; 41 input fname : $12.; 42 cards;

NOTE: The data set WORK.F_NAME has 3 observations and 1 variables. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

46 ; 47 48 data file1; cnt = 1; run;

NOTE: The data set WORK.FILE1 has 1 observations and 1 variables. NOTE: DATA statement used: real time 0.01 seconds cpu time 0.01 seconds

49 data file2; cnt = 25; run;

NOTE: The data set WORK.FILE2 has 1 observations and 1 variables. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

50 data file3; cnt = 101; run;

NOTE: The data set WORK.FILE3 has 1 observations and 1 variables. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

51 52 options mtrace mprint mlogic; 53 54 %macro fam_data (tmp_data); 55 56 data _null_; 57 set &tmp_data; 58 59 put 'cnt = ' cnt; 60 call symput ('cnt1',trim(left(put(cnt,best12.)))); 61 62 run; 63 64 %put '&cnt = ' &cnt1; 65 66 %mend fam_data; 67 68 69 data _null_; 70 set f_name; 71 72 %let tmp_data = fname; 73 74 * call execute('%fam_data('|| &tmp_data ||')'); 75 call execute('%nrstr(%fam_data('|| &tmp_data ||'))'); 76 77 put 'test1 ' &tmp_data; 78 run;

test1 file1 test1 file2 ----------------->>>>>> NOTICE HOW THESE ARE WRITTEN TO LOG (FROM LINE 77) test1 file3 NOTE: There were 3 observations read from the data set WORK.F_NAME. NOTE: DATA statement used: real time 0.01 seconds cpu time 0.01 seconds

NOTE: CALL EXECUTE generated line. 1 + %fam_data(file1 ) MLOGIC(FAM_DATA): Beginning execution. MLOGIC(FAM_DATA): Parameter TMP_DATA has value file1 MPRINT(FAM_DATA): data _null_; MPRINT(FAM_DATA): set file1; MPRINT(FAM_DATA): put 'cnt = ' cnt; MPRINT(FAM_DATA): call symput ('cnt1',trim(left(put(cnt,best12.)))); MPRINT(FAM_DATA): run;

cnt = 1 NOTE: There were 1 observations read from the data set WORK.FILE1. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

MLOGIC(FAM_DATA): %PUT '&cnt = ' &cnt1 '&cnt = ' 1 ------------------>>>>>>>>>>>>>>>> NOTICE HOW MACRO &CNT1 IS NOW RESOLVED MLOGIC(FAM_DATA): Ending execution. 2 + %fam_data(file2 ) MLOGIC(FAM_DATA): Beginning execution. MLOGIC(FAM_DATA): Parameter TMP_DATA has value file2 MPRINT(FAM_DATA): data _null_; MPRINT(FAM_DATA): set file2; MPRINT(FAM_DATA): put 'cnt = ' cnt; MPRINT(FAM_DATA): call symput ('cnt1',trim(left(put(cnt,best12.)))); MPRINT(FAM_DATA): run;

cnt = 25 NOTE: There were 1 observations read from the data set WORK.FILE2. NOTE: DATA statement used: real time 0.01 seconds cpu time 0.01 seconds

MLOGIC(FAM_DATA): %PUT '&cnt = ' &cnt1 '&cnt = ' 25 MLOGIC(FAM_DATA): Ending execution. 3 + %fam_data(file3 ) MLOGIC(FAM_DATA): Beginning execution. MLOGIC(FAM_DATA): Parameter TMP_DATA has value file3 MPRINT(FAM_DATA): data _null_; MPRINT(FAM_DATA): set file3; MPRINT(FAM_DATA): put 'cnt = ' cnt; MPRINT(FAM_DATA): call symput ('cnt1',trim(left(put(cnt,best12.)))); MPRINT(FAM_DATA): run;

cnt = 101 NOTE: There were 1 observations read from the data set WORK.FILE3. NOTE: DATA statement used: real time 0.00 seconds cpu time 0.00 seconds

MLOGIC(FAM_DATA): %PUT '&cnt = ' &cnt1 '&cnt = ' 101 MLOGIC(FAM_DATA): Ending execution.


Back to: Top of message | Previous page | Main SAS-L page