BookmarkSubscribeRSS Feed
tom12122
Obsidian | Level 7

Hi.

I've got problem apparently with some macro execution timing.

I've got macro A from which I execute macro C in a loop %do %while%.

I need to assure that macro C finished executing in iteration n before executing macro C in iteration n+1.

Now I get errors:

Line 696: ERROR: The macro C is still executing and cannot be redefined.

Line 697: ERROR: A dummy macro will be compiled.

and in the log i see that some iterations of macro C did not start at all.

Is there a way to force SAS to woit for macro execution?

Thanks for help.

9 REPLIES 9
Tom
Super User Tom
Super User

Sounds like you have code like:

%macro a;

  %macro c;

  %mend c;

  %c;

%mend a;

Move the definition of macro c outside of the definition of macro a.

%macro c;

%mend c;

%macro a;

  %c;

%mend a;

tom12122
Obsidian | Level 7

i have;

%macro c;

%mend c;

%macro a;

     %do %while ...

     %c;

    

     

     %end;

%mend a;

Tom
Super User Tom
Super User

Next suspect is unbalanced quoting.  Try starting SAS fresh.  Does the macro A work the first time it is called?

Does it matter the values that are passed to it?

thepushkarsingh
Quartz | Level 8

I am facing the same issue.

The macro 'c' works perfectly when stand alone, but when called in loop like - 

%macro a;

%do i=1 %to 20;

%c;

%end;

%mend;

%a;

 

It gets stuck at some point and goes in never ending loop. And when forced 'STOP', any code I try to run that loop starts its run. Each time I had to close the project.

gamotte
Rhodochrosite | Level 12

Hello,

 

Without knowing what the macro c contains, it is difficult to answer.

 

Could there be a conflict between macrovariables used in a and c ?

For instance, if you use the same counter i in both macros they have

to be declared as local.

thepushkarsingh
Quartz | Level 8

macro 'c':

%macro combos(trxn=);
%let I=1;
data _ben_;
set _benef_(obs=&I. firstobs=&I.);
if senders gt 1 then do;
call symput('n_connect',senders);
end;
run;

proc surveyselect
data= _senders_ (where=(trxn_per_benef=compress(&trxn.))) out= _sen_ method=srs n= Compress(&n_connect.) noprint;
run;

data _tmp_;
merge _ben_ _sen_;
run;

data _tmp_;
set _tmp_;
n=_n_;
if missing(benef_id) then
do;
do until (not missing(benef_id));
n=n-1;
set _tmp_(keep=benef_id n_ben_f senders in_trxn trxn_per_sender) point=n; *second SET statement;
end;
end;
run;
%reset;
%if &upto. >= 100 %then %goto exit;

%fill_s: %do I=&I. %to &upto.;
/*Switch to Senders*/
%fill_senders;
%end;
%reset;
%if &upto. >= 100 %then %goto exit;

%do I=&I. %to &upto.;
/*Switch to Recipients*/
%fill_benefs;
%end;
%reset;
%if &upto. < 100 %then %goto fill_s;
%exit:

%mend;
%combos(trxn=1);

 

Macro 'a' :

%macro create_combos;

%do t=1 %to 20;

%combos(trxn=&t.);

%end;

%mend;

 

But then again the other two macros 'fill_benefs' and 'fill_senders' are using macro variables 'I' and 'TRXN', common to them but I need them as start from the value one ends like if 'I' ends in %fill_benefs at 15, I need the I starting from 16 in %fill_senders.

 

 

gamotte
Rhodochrosite | Level 12

Please use the" little running man" icon to post code with proper identation.

 

%macro combos(trxn=);

    %let I=1;
    
    data _ben_;
        set _benef_(obs=&I. firstobs=&I.);
        if senders gt 1 then do;
            call symput('n_connect',senders);
        end;
    run;

    proc surveyselect
        data= _senders_ (where=(trxn_per_benef=compress(&trxn.))) out= _sen_ method=srs n= Compress(&n_connect.) noprint;
    run;

    data _tmp_;
        merge _ben_ _sen_;
    run;

    data _tmp_;
        set _tmp_;
        n=_n_;
        if missing(benef_id) then
        do;
            do until (not missing(benef_id));
                n=n-1;
                set _tmp_(keep=benef_id n_ben_f senders in_trxn trxn_per_sender) point=n; *second SET statement;
            end;
        end;
    run;

    %reset;
    
    %if &upto. >= 100 %then %goto exit;

    %fill_s: 

    %do I=&I. %to &upto.;
        /*Switch to Senders*/
        %fill_senders;
    %end;
    
    %reset;
    
    %if &upto. >= 100 %then %goto exit;

    %do I=&I. %to &upto.;
        /*Switch to Recipients*/
        %fill_benefs;
    %end;

    %reset;
    
    %if &upto. < 100 %then %goto fill_s;
    
    %exit:

%mend;

%macro create_combos;

    %do t=1 %to 20;

        %combos(trxn=&t.);

    %end;

%mend;

You still have loops calling macros that are black boxes to us. Do these macro modify the macrovariable upto ?

If not why testing the same condition several times. Insetad of using gotos, you should enlose treatments with do end

so that it's easier to follow the logic.

 

You initialize loops on macrovariable I with its own value &i. I guess the reset macro reinitialise I otherwise your second loop will then go from &upto+1 to &upto. which i doubt you really want.

 

Can you try to post a minimal executable example replicating the issue ?

thepushkarsingh
Quartz | Level 8

As you said, in some cases I got stuck with "otherwise your second loop will then go from &upto+1 to &upto.". Thanks a lot!

Tom
Super User Tom
Super User

The first line of the inner macro should give a good hint into the most likely source of your problem.

%macro combos(trxn=);
%let I=1;

Macro variable scoping.

 

If the environment that has called %COMBOS() already had a macro variable named I that it was using to control a loop then the first line in COMBOS just changed the value of that existing macro variable.  Follow these simple rules and you should be ok.

 

  1. Always define your macro variable's scope before you use them.
  2. Unless you intend to modify an existing macro variable or need to reference the value after the macro finishes then define your macro variable as LOCAL.
  3. Always test if a macro variable exists before defining it as GLOBAL.

The macro COMBOS has defined one local macro variable TRXN (all parameters are by definition local macro variables) but it is referencing these macro variables without defining their scope.

I
N_CONNECT
UPTO

And it is also calling other macros that might be lackadaisical in their use of macro variable scoping. 

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 9 replies
  • 9952 views
  • 2 likes
  • 4 in conversation