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

I have written a macro function, and the following toy example shows my problem. So my problem is that my validation of arguments does not work. For example, I would like to check that: 
SomeMacroVariableArgument is 1 (My original function will take a macro variable argument and that's why I added it here to replicate my original example as much as possible).
- Boolean1 and Boolean2 are either 0 or 1.

Running this code: 

 

%let TestVar = 1; 

%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2); /minoperator mindelimiter=' ';

/*--------------------------------------------------------------*/
/* Some Validation*/
/*--------------------------------------------------------------*/

	%if &TestVar. NE 1 or &Boolean1. not in (0 1) or &Boolean2. not in (0 1) %then %do; 
		%if &SomeMacroVariableArgument. NE 1 %then %do; 
			%put ERROR: This variable should be 1 ;
		%end; 

		%if &Boolean1. not in (0 1) %then %do; 
			%put ERROR: Boolean1 should be 0 or 1 ;
		%end; 

		%if &Boolean2. not in (0 1) %then %do; 
			%put ERROR: Boolean2 should be 0 or 1 ;
		%end; 

	%put ERROR: Macro not executed due to invalid parameters ;
	%end; 
/*--------------------------------------------------------------*/
/* The main functionality of the Macro given that the validation showed no error.*/
/*--------------------------------------------------------------*/
	%else %do; 
		data MyData; 
			Argument1 = &Argument1.; 
		run; 
	%end;
 
%mend MyFun; 

%put test = %MyFun(1,&Testvar. ,0,0);  /* This yields an error message /*


The error message I got is: 

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: 
&TestVar. NE 1 or &Boolean1. not in (0 1) or &Boolean2. not in (0 1)
ERROR: The macro MYFUN will stop executing.

 

What is the problem and how can I fix it? I believe it is clear that the purpose with the validation is to check that SomeMacroVariableArgument is 1 and the Boolean1 and Boolean2 arguments are either 0 or 1. 


Extra question 1: 
When using the logical or, I assume it means that atleast one of the conditions is forfilled, not that just one of them is? 

Extra question 2: 
According to https://go.documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lrcon/p00iah2thp63bmn1lt20esag14lh.htm , the symbol for the logical NE depends on your computer. I could for instance use ^= or ~= instead of NE; how do I know which "my computer" uses? 

All advice appreciated. 


1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

The macro processor does understand the IN operator, but not the NOT IN operator combination. You need to negate your conditions differently:

%let TestVar = 1; 

%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2) /minoperator mindelimiter=' ';

/*--------------------------------------------------------------*/
/* Some Validation*/
/*--------------------------------------------------------------*/

	%if &TestVar. NE 1 or not (&Boolean1. in (0 1)) or not (&Boolean2. in (0 1)) %then %do; 
		%if &SomeMacroVariableArgument. NE 1 %then %do; 
			%put ERROR: This variable should be 1 ;
		%end; 

		%if not (&Boolean1. in (0 1)) %then %do; 
			%put ERROR: Boolean1 should be 0 or 1 ;
		%end; 

		%if not (&Boolean2. in (0 1)) %then %do; 
			%put ERROR: Boolean2 should be 0 or 1 ;
		%end; 

	%put ERROR: Macro not executed due to invalid parameters ;
	%end; 
/*--------------------------------------------------------------*/
/* The main functionality of the Macro given that the validation showed no error.*/
/*--------------------------------------------------------------*/
	%else %do; 
		data MyData; 
			Argument1 = &Argument1.; 
		run; 
	%end;
 
%mend MyFun; 

%MyFun(1,&Testvar. ,0,0);

Since the macro generates data step code, do not use it in a %PUT statement, as the first semicolon created will terminate that %PUT, but the adjacent statement will not be recognized, as it becomes part of the %PUT.

View solution in original post

5 REPLIES 5
Kurt_Bremser
Super User

The macro processor does understand the IN operator, but not the NOT IN operator combination. You need to negate your conditions differently:

%let TestVar = 1; 

%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2) /minoperator mindelimiter=' ';

/*--------------------------------------------------------------*/
/* Some Validation*/
/*--------------------------------------------------------------*/

	%if &TestVar. NE 1 or not (&Boolean1. in (0 1)) or not (&Boolean2. in (0 1)) %then %do; 
		%if &SomeMacroVariableArgument. NE 1 %then %do; 
			%put ERROR: This variable should be 1 ;
		%end; 

		%if not (&Boolean1. in (0 1)) %then %do; 
			%put ERROR: Boolean1 should be 0 or 1 ;
		%end; 

		%if not (&Boolean2. in (0 1)) %then %do; 
			%put ERROR: Boolean2 should be 0 or 1 ;
		%end; 

	%put ERROR: Macro not executed due to invalid parameters ;
	%end; 
/*--------------------------------------------------------------*/
/* The main functionality of the Macro given that the validation showed no error.*/
/*--------------------------------------------------------------*/
	%else %do; 
		data MyData; 
			Argument1 = &Argument1.; 
		run; 
	%end;
 
%mend MyFun; 

%MyFun(1,&Testvar. ,0,0);

Since the macro generates data step code, do not use it in a %PUT statement, as the first semicolon created will terminate that %PUT, but the adjacent statement will not be recognized, as it becomes part of the %PUT.

Kurt_Bremser
Super User

And the MINDELIMITER and MINOPERATOR options have to be part of the %MACRO statement, so there must not be a semicolon after the closing bracket of the macro parameters.

SasStatistics
Pyrite | Level 9
Is this not the case in the example code?
Kurt_Bremser
Super User

@SasStatistics wrote:
Is this not the case in the example code?

Quote from your post:

%macro MyFun(Argument1, SomeMacroVariableArgument, Boolean1, Boolean2); /minoperator mindelimiter=' ';
Tom
Super User Tom
Super User

@SasStatistics wrote:

...

Extra question 2: 
According to https://go.documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lrcon/p00iah2thp63bmn1lt20esag14lh.htm , the symbol for the logical NE depends on your computer. I could for instance use ^= or ~= instead of NE; how do I know which "my computer" uses? 


Why not just use NE then you don't need to know.  

Note that on a EBCDIC computer (IBM mainframe) the standard logical NOT symbol is ¬, which corresponds to EBCDIC code point X'5F'.

Just don't try to use <> as meaning NE because you will very surprised by the results.  You can get away with it in SQL code (but why confuse yourself?).

 

You can always try it to see:

434   data test;
435     x1= 3 ne 2;
436     x2= 3 ^= 2;
437     x3= 3 ~= 2;
438   /* for ebcidic computers use the actual not symbol instead of ascii characters ~ or ^ */
439   * But never do this ! ;
440     x4= 3 <> 2;
NOTE: The "<>" operator is interpreted as "MAX".
441     x5= 3 >< 2;
442     put (x1-x5) (=);
443   run;

x1=1 x2=1 x3=1 x4=3 x5=2
NOTE: The data set WORK.TEST has 1 observations and 5 variables.

 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 5 replies
  • 665 views
  • 7 likes
  • 3 in conversation