2
votes

this is a toy example in order to help with a larger problem I have. It essentially involves using a %eval() macro when referencing a bigger macro variable name.

I have created a macro variable x_2, which uses the values of the loop, '&it', the variable is created successfully as can be seen by the final output, however I can only put it to the log without evaluating &it+1, which I will need to do when using a loop bigger than size 1.

It seems to resolve x_ first, giving a warning, before then evaluating x_2 as a whole and giving the output.

I realise this is just a problem about how to reference macros correctly, but I cannot find any examples where it uses an evaluation as part of a macro variable name.

Thanks.

%macro testing;

%DO it = 1 %TO 1; 

data dataset;
    s=100;
    t=99;
run;

data _null_;
    set dataset;
    if s = 100 then do;
        call symput("x_%eval(&it+1)",t);
    end;
run;

%put "&x_%eval(&it+1)";

%put &x_2;

%END;

%mend testing;

%testing;

LOG OUTPUT

MLOGIC(TESTING):  %PUT "&x_%eval(&it+1)"

WARNING: Apparent symbolic reference X_ not resolved.

SYMBOLGEN:  Macro variable IT resolves to 1

SYMBOLGEN:  Macro variable X_2 resolves to           99

"          99"

MLOGIC(TESTING):  %PUT &x_2

SYMBOLGEN:  Macro variable X_2 resolves to           99

99

MLOGIC(TESTING):  %DO loop index variable IT is now 2; loop will not iterate again.

MLOGIC(TESTING):  Ending execution.
4

4 Answers

5
votes

Indeed, SAS does the variable substitution before calling the %eval function The easiest solution is to call %eval in an earlier statement

%let xNr = %eval(&it+1);
%put "&&x_&xNr";

The double ampersand serves to delay the evaluation of x_&xNruntil &xNr is evaluated to 2 and not have the warning that x_ is undefined.

SYMBOLGEN:  Macro variable IT resolves to 1
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable XNR resolves to 2
SYMBOLGEN:  Macro variable X_2 resolves to           99
"          99"
3
votes

Agree with Dirk's answer. But as a thought exercise, it is possible to achieve the desired result with ugly use of quoting functions:

%let x_2=99;
%let it=1;
%put %unquote(%nrstr(&x_)%eval(&it+1));

So %nrstr hides the & until after the %eval has done its work (I think. :)

Update:

@Shenglin added a similar answer in a comment that I like better than my approach above:

%put %superq(x_%eval(&it+1));

This works because %superq() is unusual in taking a macro variable name as a parameter (no leading &), not a macro variable reference. So you can use %EVAL to generate part of the name of the macro variable. You could %unquote() if wanted, but it should not be necesssary.

2
votes

It is much easier to build the macro variable name into another variable and then expand the value.

%let t2=found;
%let mvar=t%eval(1+1);
%put &&&mvar;
0
votes

Could you try "&&x_%eval(&it+1)"?