Hello,
I try to define macro variables in an iterative loop. An altough the code underneath does what it should (SAS 9.4), we can expect a warning message "apparent symbolic references not resolved". Actually I have no idea how a more elegant solution might look. Can you help me?
%MACRO a(XVAR1=, CCENT=, GCENT=);
%MACRO NAMEP(prefix,maxnum);
%DO i=1 %to &maxnum;
&prefix&i
%END;
%MEND NAMEP;
%if %sysevalf(%superq(XVAR1)=,boolean) = 0 %then %do;
%let NXVAR1 = 1;
%do %while(%length(%scan(&XVAR1,&NXVAR1)));
%let NXVAR1 = %EVAL(&NXVAR1 + 1);
%end;
%Let NXVAR1 = %eval(&NXVAR1 -1);
%Do N1 = 1 %to &NXVAR1;
%Let a=%scan(&XVAR1,&N1);
%Let b=%index(&CCENT,&a);
%Let c=%index(&GCENT,&a);
%if &b > 0 %then %do;
%Let X1&N1 = &a.cc;
%end;
%else %if &c > 0 %then %do;
%Let X1&N1 = &a.gc;
%end;
%else %do;
%Let X1&N1 = &a;
%end;
%end;
%let XVAR1n = %namep(&X1,&NXVAR1);
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
%a(XVAR1=xvar1a xvar1b, CCENT=xvar1b, GCENT=xvar1a);
Bye, Daniel
First as was mentioned by @ballardw embedded macro definitions are not needed and almost always counter productive. The macro definitions would appear as:
%MACRO NAMEP(prefix,maxnum);
%DO i=1 %to &maxnum;
&prefix&i
%END;
%MEND NAMEP;
%MACRO a(XVAR1=, CCENT=, GCENT=);
%local xvar1n;
....
The better news is that you don't need the %NAMEP macro anyway. Let's look at your other code a bit. This portion counts the number of words in &XVAR1.
%let NXVAR1 = 1;
%do %while(%length(%scan(&XVAR1,&NXVAR1)));
%let NXVAR1 = %EVAL(&NXVAR1 + 1);
%end;
%Let NXVAR1 = %eval(&NXVAR1 -1);
This is simplified with the COUNTW function.
%let NXVAR1 = %sysfunc(countw( &XVAR1));
The call to the %NAMEP is causing an error (unitialized variable because &X1 is not defined). Since you already have a loop. the definition of &XVAR1N can be moved insite the loop.
%else %do;
%Let X1&N1 = &a;
%end;
%let XVAR1n = &xvar1n &&x1&n1;
%end;
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
Notice that &XVAR1N is initialized as a local macro variable just below the macro statement. Other cleanup in the macro is possible, but this should get you started.
I can't work out exactly what you're trying to do, but is it simply a case of:
%let XVAR1n = %namep(X1, &NXVAR1);
What exactly is it your trying to do? I can guarentee you thre is a far simpler and easier to maintain way of doing things thatn that, be it re-modelling your data, or using inbuilt SAS functionality. Creating endless macro lists, macros and such like is a recipe for obfuscatd, unmaintable code which will fall over every time you run it.
Defining a macro to include another macro, especially one such as your NAMEP that has no dependencies on the parameters of the outmacro is poor practice. As a minimum you waste compute cycles recompiling it everytime the outer macro executes.
And it really helps to provide an example of what you expect this macro to produce.
First as was mentioned by @ballardw embedded macro definitions are not needed and almost always counter productive. The macro definitions would appear as:
%MACRO NAMEP(prefix,maxnum);
%DO i=1 %to &maxnum;
&prefix&i
%END;
%MEND NAMEP;
%MACRO a(XVAR1=, CCENT=, GCENT=);
%local xvar1n;
....
The better news is that you don't need the %NAMEP macro anyway. Let's look at your other code a bit. This portion counts the number of words in &XVAR1.
%let NXVAR1 = 1;
%do %while(%length(%scan(&XVAR1,&NXVAR1)));
%let NXVAR1 = %EVAL(&NXVAR1 + 1);
%end;
%Let NXVAR1 = %eval(&NXVAR1 -1);
This is simplified with the COUNTW function.
%let NXVAR1 = %sysfunc(countw( &XVAR1));
The call to the %NAMEP is causing an error (unitialized variable because &X1 is not defined). Since you already have a loop. the definition of &XVAR1N can be moved insite the loop.
%else %do;
%Let X1&N1 = &a;
%end;
%let XVAR1n = &xvar1n &&x1&n1;
%end;
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
Notice that &XVAR1N is initialized as a local macro variable just below the macro statement. Other cleanup in the macro is possible, but this should get you started.
Thank you for the valuable thoughts and the time that you have spent on my problem.
For the sake of completeness here the working code:
%MACRO a(XVAR1=, CCENT=, GCENT=);
%local xvar1n;
%if %sysevalf(%superq(XVAR1)=,boolean) = 0 %then %do;
%let NXVAR1 = %sysfunc(countw(&XVAR1));
%Do N1 = 1 %to &NXVAR1;
%Let a=%scan(&XVAR1,&N1);
%Let b=%index(&CCENT,&a);
%Let c=%index(&GCENT,&a);
%if &b > 0 %then %do;
%Let X1&N1 = &a.cc;
%end;
%else %if &c > 0 %then %do;
%Let X1&N1 = &a.gc;
%end;
%else %do;
%Let X1&N1 = &a;
%end;
%let XVAR1n = &XVAR1n &&X1&N1;
%end;
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
%a(XVAR1=xvar1a xvar1b, CCENT=xvar1b, GCENT=xvar1a);
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: