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

 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 3 replies
  • 588 views
  • 1 like
  • 2 in conversation