Sarah Deweert
Sarah Deweert

Reputation: 1

Macrovariable does not resolve when using %scan

Here is a very simplified version of my SAS code. I am not seeing the logic here. It resolves fine without the %scan function, and the displayed name suggests it resolves just fine. Why the warning "AUC_ not resolved"?

% let models = model1 model2;

%macro auc();
%do i = 1 %to %sysfunc(countw(&models.));
%let model = %scan(&models., &i.);
%global auc_&model.;
%let auc_&model. = &i.;
%end;
%mend auc;
%auc;

%macro put_auc();
%do i = 1 %to %sysfunc(countw(&models.));
%put &auc_%scan(&models.,&i.).;
%put &auc_model1.;
%end;
%mend put_auc;
%put_auc;

I tried with extra & or adding dots to the end. I would like to see the macrovariable resolved without a warning.

Upvotes: 0

Views: 53

Answers (3)

Richard
Richard

Reputation: 27508

Macro does token multi-pass resolution. Each resolution encountering && reduces to & for the next pass. Thus, you need three ampersands. Sometimes coding nested %superq() helps to jailbreak macro ampersand purgatory.

Exqamples:

%macro play ;

%let Jane = woman ;
%let Arthur = man ;

%let model1 = Jane ;
%let model2 = Arthur ;

%let models = model1 model2 ;

%do i = 1 %to %sysfunc(countw(&models)) ;
  %let item = %scan(&models,&i) ;
  %put NOTE: %nrstr(&item->)&item %nrstr(&&&item->)=&&&item %nrstr(&&&&&&&item->)=&&&&&&&item ;
  %put NOTE: %nrstr(%superq(item))->%superq(item)  ;
  %put NOTE: %nrstr(%superq(%superq(item)))->%superq(%superq(item));
  %put NOTE: %nrstr(%superq(%superq(%superq(item))))->%superq(%superq(%superq(item)));
%end ;

%mend play ;

options nosymbolgen ;
%play;
NOTE: &item->model1 &&&item->=Jane &&&&&&&item->=woman
NOTE: %superq(item)->model1
NOTE: %superq(%superq(item))->Jane
NOTE: %superq(%superq(%superq(item)))->woman
NOTE: &item->model2 &&&item->=Arthur &&&&&&&item->=man
NOTE: %superq(item)->model2
NOTE: %superq(%superq(item))->Arthur
NOTE: %superq(%superq(%superq(item)))->man

Upvotes: 0

Tom
Tom

Reputation: 51566

Trying to use the macro function in the middle of generating the macro variable name is causing the macro processor's tokenizer to see TWO tokens instead of one.

The simplest fix is put the result of the %SCAN() call into another macro variable.

 %let model=%scan(&models., &i.);

And then use that macro variable to generate the macro variable reference, like you did in the AUC macro.

 %put &&auc_&model;

Or put the name of the macro variable into a macro variable and then use that.

%let mvar=auc_%scan(&models,&i);
%put &&&mvar;

Remember to define your local macro variables so your macros will play nice with the programs that might call them.

%macro put_auc();
%local i model;
%do i = 1 %to %sysfunc(countw(&models.));
   %let model=%scan(&models., &i.);
   %put &=i &=model MVAR=AUC_&model -> &&auc_&model ;
%end;
%mend put_auc;

%let models = model1 model2;
%auc;
%put_auc;

Result

I=1 MODEL=model1 MVAR=AUC_model1 -> 1
I=2 MODEL=model2 MVAR=AUC_model2 -> 2

Upvotes: 1

PeterClemmensen
PeterClemmensen

Reputation: 4937

Try this

%let models = model1 model2;

%macro auc();
   %do i = 1 %to %sysfunc(countw(&models.));
      %let model = %scan(&models., &i.);
      %global auc_&model.;
      %let auc_&model. = &i.;
   %end;
%mend auc;

%auc;

%macro put_auc();
   %do i = 1 %to %sysfunc(countw(&models.));
      %let m = %scan(&models.,&i.).;
      %put &&auc_&m.;
   %end;
%mend put_auc;

%put_auc;

Upvotes: 0

Related Questions