BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
MrTh
Obsidian | Level 7

OK I read few topics on that one and still am stumped - apologies in advance if it's obvious for some of you.

The difference in my code is that I try create a macro variables iteratively. I think I manage to do that but the dreaded %put tells me otherwise.

I tried several things around %global but nothing really works (I tried symput instead of symputx).

 

My code is simple.

%macro ALLx ;
%let j=1 ;
%let k=2 ;  run ;
%do i = 1 %to &ntrait. ;
	data _NULL_ ;
	set f2 ;
	if par1 = &j. ;
	call symputx("x&i.",est,g) ; run ;
	%let j = %eval(&j.+&k.) ; run ;
	%let k= %eval(&k.+1) ; run ;
%put &i. &j. &k. &&x&i. ; run ; quit ;
%end ;
%mend ALLx ;
%ALLx ; 
%put &x1. &x2. &x3. &x4. &x5. &x6. ; run 

 

the log gives me hope - I only give you the last round of iteration.

[...]
MLOGIC(ALLX):  %LET (variable name is J)
SYMBOLGEN:  Macro variable J resolves to 21
SYMBOLGEN:  Macro variable K resolves to 7
MPRINT(ALLX):   run ;
MLOGIC(ALLX):  %LET (variable name is K)
SYMBOLGEN:  Macro variable K resolves to 7
MPRINT(ALLX):   run ;
MLOGIC(ALLX):  %PUT &i. &j. &k. &&x&i.
SYMBOLGEN:  Macro variable I resolves to 6
SYMBOLGEN:  Macro variable J resolves to 28
SYMBOLGEN:  Macro variable K resolves to 8
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable I resolves to 6
SYMBOLGEN:  Macro variable X6 resolves to 6.2460106
6 28 8 6.2460106
MPRINT(ALLX):   run ;
MPRINT(ALLX):   quit ;
MLOGIC(ALLX):  %DO loop index variable I is now 7; loop will not iterate again.
MLOGIC(ALLX):  Ending execution.

I can see that variable X6 is resolve to 6.2460106 - great.

 

but the %put statement wipes my smile away as I got the WARNING: Apparent ...not resolved.

 

 

 

anyway if any of you have hints, please forward.

cheers

 

Th.

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

 

As previously explained your confusion is that you do not understand the relationship between the macro processor (the macro PRE processor) and SAS code.  The macro processor is trying to evaluate the %PUT statement BEFORE the CALL SYMPUTX() statement has run. So the macro variable hasn't been created yet.

 

Does your data really have a variable named G that you are using to determine if the X&i macro variable should be created as LOCAL or GLOBAL?  Or did you mean to put G in quotes so that it is character constant?

 

Plus your CALL SYMPUTX() is being run conditionally (because of the subsetting IF statement in the data step) so depending on the input data it might never run. Hence it might never create the macro variable.

 

Also why not just create the macro variables as part of the looping so you are sure the macro variable is created whether or not the data step finds a value?  You could set the value to an empty string or some other default value.

%macro ALLx ;
%local i j k ;
%global ntrait;
%let j=1;
%let k=2 ;
%do i = 1 %to &ntrait. ;
  %global x&i;
  %let x&i=;
data _NULL_ ;
  set f2 ;
  if par1 = &j. ;
  call symputx("x&i.",est,'g') ; 
run ;
  %let j = %eval(&j.+&k.);
  %let k= %eval(&k.+1) ;
  %put &=i &=j &=k X&i=&&x&i.. ; 
%end ;
%mend ALLx ;

View solution in original post

11 REPLIES 11
RW9
Diamond | Level 26 RW9
Diamond | Level 26

I am sorry, but thats really not a good way of working.  Macro language is a text based find/replace pre-processor, used for generalising code.  It is not a replacement for Base SAS - the programming language, which has all datatypes/functions etc.  Your just creating code which will cause you headaches and break half the time.  Do you data processing in a dataset, I can't really provide code as you have not provided test data/required output, but what I can say is there is a fair bit wrong with the code and the understanding.

First, you have lots of run; statements in there, some will cause problems, others are just irrelevant.

The key problem here however is your mixing datastep (Base SAS) with Macro which operate at different levels and so are incompatible.  Lets take an example, Macro is resolved first by the macro pre-processor so your code becomes (note ntrait is never defined - another issue in the code):

data _NULL_ ;
  set f2 ;
  if par1=1;
  call symputx("x1",est,g) ; run ;
 ; run ;
 ; run ;
 ; run ; quit ;

This code is repeated to the number in ntrait.

 

If you would like working code, please provide test data in the form of  datastep:

https://communities.sas.com/t5/SAS-Communities-Library/How-to-create-a-data-step-version-of-your-dat...

 

And show what you want out at the end, I am 100% certain there is a simpler more robust approach.

MrTh
Obsidian | Level 7

Hi RW9

Thanks for the quick answer.

Couple of things: I did not provide the whole code as it would be too cumbersome, but trust me ntrait is well defined.. Also the multiple 'run' statements are the results of several try and fail; I usually keep them short.

The macro however badly built it can be seem to give me the correct result. My question is more why when I want to print %put &X6. I get the Warning: apparent symbolic reference not resolved?

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Look at the code generated:

data _NULL_ ;
  set f2 ;
  if par1=1;
  call symputx("x1",est,g) ; run ;
 ; run ;
 ; run ;
 ; run ; quit ;

G is not quoted in the call symputx.  I would still highly recommend you alter the code, just as something might work, does not make it a good idea, robust, simple or repeatable. 

gamotte
Rhodochrosite | Level 12

Apart from what has already been said by @RW9, you are using here a loop that

read several times the same dataset unecessarily increasing the run time.

Sine the input dataset is always the same, you only need to read it once and hence

there is no need to use a macro here.

 

Tell us what you wan't to do and we'll provide a non macro way to solve yuor problem.

 

Nothing wrong with macros but as @RW9 they are just a text replacement tool

and should not be used to manipulate data.

PaigeMiller
Diamond | Level 26

@MrTh wrote:

 

the log gives me hope - I only give you the last round of iteration.

[...]
MLOGIC(ALLX):  %LET (variable name is J)
SYMBOLGEN:  Macro variable J resolves to 21
SYMBOLGEN:  Macro variable K resolves to 7
MPRINT(ALLX):   run ;
MLOGIC(ALLX):  %LET (variable name is K)
SYMBOLGEN:  Macro variable K resolves to 7
MPRINT(ALLX):   run ;
MLOGIC(ALLX):  %PUT &i. &j. &k. &&x&i.
SYMBOLGEN:  Macro variable I resolves to 6
SYMBOLGEN:  Macro variable J resolves to 28
SYMBOLGEN:  Macro variable K resolves to 8
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable I resolves to 6
SYMBOLGEN:  Macro variable X6 resolves to 6.2460106
6 28 8 6.2460106
MPRINT(ALLX):   run ;
MPRINT(ALLX):   quit ;
MLOGIC(ALLX):  %DO loop index variable I is now 7; loop will not iterate again.
MLOGIC(ALLX):  Ending execution.

I can see that variable X6 is resolve to 6.2460106 - great.

 

but the %put statement wipes my smile away as I got the WARNING: Apparent ...not resolved.

 

 


There is no such WARNING in your SASLOG.

--
Paige Miller
MrTh
Obsidian | Level 7

apologies PaigeMiller

 

I did not put the log warning.

MLOGIC(ALLX):  Ending execution.
WARNING: Apparent symbolic reference X1 not resolved.
WARNING: Apparent symbolic reference X2 not resolved.
WARNING: Apparent symbolic reference X3 not resolved.
WARNING: Apparent symbolic reference X4 not resolved.
WARNING: Apparent symbolic reference X5 not resolved.
WARNING: Apparent symbolic reference X6 not resolved.
167  %put &x1. &x2. &x3. &x4. &x5. &x6. ; run ;
&x1. &x2. &x3. &x4. &x5. &x6.
Tom
Super User Tom
Super User

 

As previously explained your confusion is that you do not understand the relationship between the macro processor (the macro PRE processor) and SAS code.  The macro processor is trying to evaluate the %PUT statement BEFORE the CALL SYMPUTX() statement has run. So the macro variable hasn't been created yet.

 

Does your data really have a variable named G that you are using to determine if the X&i macro variable should be created as LOCAL or GLOBAL?  Or did you mean to put G in quotes so that it is character constant?

 

Plus your CALL SYMPUTX() is being run conditionally (because of the subsetting IF statement in the data step) so depending on the input data it might never run. Hence it might never create the macro variable.

 

Also why not just create the macro variables as part of the looping so you are sure the macro variable is created whether or not the data step finds a value?  You could set the value to an empty string or some other default value.

%macro ALLx ;
%local i j k ;
%global ntrait;
%let j=1;
%let k=2 ;
%do i = 1 %to &ntrait. ;
  %global x&i;
  %let x&i=;
data _NULL_ ;
  set f2 ;
  if par1 = &j. ;
  call symputx("x&i.",est,'g') ; 
run ;
  %let j = %eval(&j.+&k.);
  %let k= %eval(&k.+1) ;
  %put &=i &=j &=k X&i=&&x&i.. ; 
%end ;
%mend ALLx ;
MrTh
Obsidian | Level 7
@Tom Thanks a bunch for the code. I think I get some of it now. it works.
s_lassen
Meteorite | Level 14

It happens because you wrote 

call symputx("x&i.",est,g); 

the problem being that your g is seen as a reference to a datastep variable, not a constant expression. Try again with

call symputx("x&i.",est,'g'); 

 

 

SuryaKiran
Meteorite | Level 14

You need to understand how CALL SYMPUT works. 

 

You must specify a step boundary statement to force the DATA step to execute before referencing a value in a global statement following the program (for example, a TITLE statement). The boundary could be a RUN statement or another DATA or PROC statement.
 
For example:
/* This works */
data x;
   x='December';
   call symput('var',x);
proc print; /* Boundary */
%PUT "Report for &var";
run;

/* This will not work */
%symdel var;
data x;
   x='December';
   call symput('var',x);
/* No step boundary */
%PUT "Report for &var";
run;
 For more information check the documentation
 
Thanks,
Suryakiran
MrTh
Obsidian | Level 7
@ Suryakiran thanks for the input.

SAS Innovate 2025: Call for Content

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 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 11 replies
  • 13890 views
  • 0 likes
  • 7 in conversation