Mark
Mark

Reputation: 21

SAS V9.1.3 - Error when combining %INC and CALL EXECUTE

I am getting a resolution error with some SAS v9.1.3 code.

Here is some code I want to store in a .txt file (called problem2.txt) and bring into SAS with a %INC

%macro email020;                  
   %if &email = 1 %then %do;       
     %put THIS RESOLVED AT 1;      
   %end;                           
   %else %if &email = 2 %then %do; 
     %put THIS RESOVLED AT 2;      
   %end;                           
   %put _user_;                    
%mend email020;                   

%email020; 

Then this is the main code:

filename problem2 'C:\Documents and Settings\Mark\My Documents\problem2.txt';

%macro report1;                            
  %let email = 1;
  %inc problem2;
%mend report1;                             

%macro report2 (inc);                            
  %let email = 2;                          
  %inc problem2;
%mend report2;                             

data test;                                 
  run = 'YES';                             
run;                                       

data _null_;                               
  set test; 
  call execute("%report1");  
  call execute("%report2");  
run;

The log shows:

NOTE: CALL EXECUTE generated line.
1   +  %inc problem2;
MLOGIC(EMAIL020):  Beginning execution.

WARNING: Apparent symbolic reference EMAIL not resolved.

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: &email = 1

ERROR: The macro EMAIL020 will stop executing.

MLOGIC(EMAIL020):  Ending execution.

So the question is why does CALL EXECUTE generate %inc problem2 rather than %report1, causing SAS to miss the assignment and what can I do about it?

Upvotes: 2

Views: 1038

Answers (2)

Chang Chung
Chang Chung

Reputation: 2307

%include is not a macro call but sort of a compiler directive to include code from an outside file. When the macro %report1 is compiled, there is no macro variable email (because the macro never ran before), thus the reference remains as it is, &email. Then the implicit %eval() sees &email = 1 and complains because it looks like you are comparing a text(&email) against a number (1).

Introducing the %global is to be avoided if possible. I would do away with %include completely. much simpler, below is. :-)

%macro doSomething(email=);                  
  %if &email = [email protected] %then %do;       
    %put THIS RESOLVED AT 1;      
  %end; %else %if &email = [email protected] %then %do; 
    %put THIS RESOVLED AT 2;      
  %end;                           
  %put _user_;                    
%mend doSomething;                   


data emails;
  email="[email protected]"; output;
  email="[email protected]"; output;
run;

data _null_;
  set emails;
  call execute(catx(email, '%doSomething(email=', ')'));
run;

/* on log
THIS RESOLVED AT 1
DOSOMETHING EMAIL [email protected]
THIS RESOVLED AT 2
DOSOMETHING EMAIL [email protected]
*/

Upvotes: 1

Ville Koskinen
Ville Koskinen

Reputation: 1276

It seems to be a macro varible scope issue. Try:

%macro report1;   
  %global email; 
  %let email = 1;
  %inc problem2;
%mend report1;                             

%macro report2;            
%global email; 
  %let email = 2;                          
  %inc problem2;
%mend report2;                             

However, I think it would be better to pass email as a parameter to %email020 rather than using global macro variables. Also, I'd avoid using nested macro definitions.

To get more data on macro variable scope, you could query the dictionary.macros view during macro execution. You can get the description of dictionary.macros with

proc sql;
    describe table dictionary.macros;
quit;

Upvotes: 2

Related Questions