BookmarkSubscribeRSS Feed
FK1
Lapis Lazuli | Level 10 FK1
Lapis Lazuli | Level 10

Hi Folks,

 

I have three Macros "outer_m", "inner_m" and "upper_limit_loop". "inner_m" is nested in "outer_m". See here:

 

%MACRO outer_m;

%LET outer_out = DAS IST DER TEXT, WELCHER IM AEUSSEREN MACRO DURCHLÄUFT ;
%*let obergrenze = %upper_limit_loop(inval=10);

%MACRO inner_m;
%LET inner_out = HIER DER TEXT DES INNEREN MACROS  ;

%do i=1 %TO 10 /*&obergrenze.*/;
%PUT &i: &inner_out;
%END;
%MEND;

%do j=1 %TO 10;
%PUT &j: &outer_out;
%inner_m;
%END;

%MEND;

I have saved the two files "outer_m.sas" and "upper_limit_loop.sas" in a directory  /this/is/the/path/for/autocall/.

 

I then tell SAS the following:

filename Macros "/this/is/the/path/for/autocall/" ;
options mautolocdisplay mautosource sasautos = (sasautos, Macros) /*MRECALL*/;

options mprint mprintnest mlogic mlogicnest mcompilenote=ALL ;

Everything works perfect. SAS writes in the log, that it compiled the macros from the autocall library, etc.

 

However, when I replace the hard coded "10" in the Do-Loop with Index "i" and use a macro variable

 

%let obergrenze = %upper_limit_loop(inval=10);

which shell bel resolved by running another macro, which is also in the autocall-library, I get the following Error:

ERROR: %EVAL function has no expression to evaluate, or %IF statement has no condition.
ERROR: The %TO value of the %DO I loop is invalid.
ERROR: The macro INNER_M will stop executing.

 

Obviously, the macrovariable cannot be resolved! But is it, because it has to call another member, i.e. another macro, within the autocall library or do I have some sort of syntax error?

 

Generally I would like to know:

Is it possible to nest macros, which are all seperately saved within a autocall-library-path, this way?

 

Thank you for any helpful advice on this matter in advance,

FK1

 

 

3 REPLIES 3
Kurt_Bremser
Super User

First of all, nested macro definitions make no sense and only serve to cause confusion. All macros are defined globally.

So your code should be

%MACRO inner_m;
%LET inner_out = HIER DER TEXT DES INNEREN MACROS  ;

%do i=1 %TO 10 /*&obergrenze.*/;
%PUT &i: &inner_out;
%END;
%MEND;

%MACRO outer_m;

%LET outer_out = DAS IST DER TEXT, WELCHER IM AEUSSEREN MACRO DURCHLÄUFT ;
%*let obergrenze = %upper_limit_loop(inval=10);

%do j=1 %TO 10;
%PUT &j: &outer_out;
%inner_m;
%END;

%MEND;

The crucial information missing here is the code for %upper_limit_loop. Please supply it.

FK1
Lapis Lazuli | Level 10 FK1
Lapis Lazuli | Level 10

Hello Kurt,

 

I absolutely agree with you, that it is a bad practice to nest macros. However, I was still curious as to why it does not work.

 

I found out, that when assigning a value to a macro variable (here "obergrenze"), the compiler recognizes the percent sign and compiles the macro (here: "upper_limit_loop(inval=10)"). It then also resolves the macrovariable "obergrenze" correctly in the do-loop. But it seems that at run-time it is not possible to "switch back" to compiling another time as the value of obergrenze is a macro...

 

It seems to be impossible to assign a value in a do-loop at run-time that has to be generated out of a macro...

 

The code for "upper_limit_loop(inval=)" is as follows:

%MACRO upper_limit_loop(inval=);

%GLOBAL ul;

%let ul = &inval;

%PUT &ul.;

%mend;

Is it not possible to construct somethine like this?:

 

%MACRO inner_m;
%LET inner_out = HIER DER TEXT DES INNEREN MACROS  ;

%do i=1 %TO %upper_limit_loop(inval=10) ;
%PUT &i: &inner_out;
%END;
%MEND;

 

Kurt_Bremser
Super User

When you want to create a "function style" macro, do not use %put. %put writes messages to the log, but leaves nothing in the code execution queue. Write your macro like this instead:

%macro upper_limit_loop(inval=);
&inval
%mend;

and the whole construct will run:

%macro upper_limit_loop(inval=);
&inval
%mend;

%macro inner_m;
%let inner_out = HIER DER TEXT DES INNEREN MACROS  ;
%do i=1 %to &obergrenze.;
%put &i: &inner_out;
%end;
%mend;

%macro outer_m;
%let outer_out = DAS IST DER TEXT, WELCHER IM AEUSSEREN MACRO DURCHLÄUFT ;
%let obergrenze = %upper_limit_loop(inval=10);
%do j=1 %to 10;
  %put &j: &outer_out;
  %inner_m;
%end;
%mend;

%outer_m

 

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 3 replies
  • 1226 views
  • 1 like
  • 2 in conversation