6

I am running a macro multiple times in SAS as follows:

%mymac(a,b);
%mymac(a,c);
.
%mymac(a,a)
%mymac(a,w);
.

My program/macro is similar to:

/* begin program here */

data original_data;
set mylib.mydata;
run;

%macro mymac(x,y);

data mydata1;
set original_data;
where school_district="&x";
run;

proc means data=mydata1;
var income;
run;

%mend mymac;

I realized I had forgotten a semicolon (as in the (a,a) one) and SAS didnt seem to mind. It ran all of the macro calls without a problem. I compared the output when I added a semicolon in and I couldnt see a difference.

Is this normal that SAS is not giving an error with the missing semicolon?

Joe
  • 62,789
  • 6
  • 49
  • 67
user27008
  • 600
  • 3
  • 15
  • 24
  • 2
    So if I am understanding this all correctly, I don't need a semicolon at the end of the above macro because the very last statement has a semicolon in it, so adding a semicolon to %mymac(a,a) would essentially be the same as typing run;; at the end of the means statement? – user27008 Oct 21 '14 at 16:22
  • 1
    Yes, that is exactly correct. – sparc_spread Oct 21 '14 at 16:28

3 Answers3

5

Semicolons are not required for macro calls.

Often they are included as people are used to seeing semicolons as a way of "terminating the statement" or ending the line. I personally prefer to include them when possible as I believe it makes my code more readable.

Remember that macros simply evaluate themselves and return whatever it is that they resolve to which could be a block of code that looks like a number, a string, or anything else...

Take this example where no semicolon is used:

%macro field_list();
    name, 
    age, 
    sex, 
    height
%mend;

proc sql;
  select %field_list()
  from sashelp.class
  ;
quit;

Try running it on your own machine with option mprint; enabled. The result of running the macro simply returns the block of code within it. This results in the following code being executed:

proc sql;
  select  name, age, sex, height
  from sashelp.class
  ;
quit;

If we had a semicolon after the call to our macro, then the code that SAS would try to run would include the semicolon which would be invalid syntax like so (note the semicolon after height):

proc sql;
  select  name, age, sex, height ;
  from sashelp.class
  ;
quit;

This is because the semicolon is NOT required for calling macros, so it just gets left behind and included in the execution of the step.

When you call a macro like you do in the example you give above, it's fine to include the semicolon, because your macro is a fully self contained step. And in open code there's no harm having extraneous semicolons like so:

%macro example2(inDS=, outDs=);
  data &outDs;
    set &inDs;
  run;
%mend;

%example2(inDS=sashelp.class, outDs=tmp_class);

This basically evaluates to:

data tmp_class;
  set sashelp.class;
run;;

Note the extra semicolon at the end left over from our call? We could have as many as we wanted and the code will still run fine, ie:

%example2(inDS=sashelp.class, outDs=tmp_class);;;;;;

Resolves to:

data tmp_class;
  set sashelp.class;
run;;;;;;;

Which will still run fine as it is valid syntax.

Robert Penridge
  • 8,424
  • 2
  • 34
  • 55
4

It is usually fine. The main thing to understand about SAS Macro is that it is a code-generating tool, not a real programming language. While %my_mac(x,y); looks like a traditional function call in a C-like language, where you would want to end every statement with a ;, here a terminating ; has no real significance. Rather, it is the SAS code that is generated inside of %my_mac(x,y) that does. In your case, that code is grammatical SAS and is fine. If you mentally replace the %my_mac(x,y) call with the code that it generates (i.e. data mydata.....run;) you see that it is grammatical even without ending %my_mac(x,y) with a ;. If you wrote %my_mac(x,y); instead, it would just generate data mydate.....run;;, which is fine, but the ; is redundant.

As a matter of fact, skipping a semi-colon is also a hack for having a return value for a macro. For example:

%MACRO x_plus_n (x = , y= );
    %SYSEVALF (&x + &y)
%MEND;

%LET x = 3 ;
%LET y = 4 ;
%LET z = %x_plus_n (x = &x , y= &y) is the result;
%PUT ------------- &z;

Notice the missing ; on the %SYSEVALF line. This allows the macro to not terminate until the end of the line beginning %LET z = ...., where there is a ;. The output created by x_plus_n becomes a kind of return value for the macro.

sparc_spread
  • 10,643
  • 11
  • 45
  • 59
  • Basically my macro is creating the my mydata1 dataset each time it is called. I am not the best with macros and am not sure I fully understand your example. – user27008 Oct 21 '14 at 16:12
  • 3
    @sparc_spread - I made the example more meaningful by adding text between the macro call and the semicolon. Without additional text there, the point you are trying to make is not so obvious. – Robert Penridge Oct 21 '14 at 16:16
  • 2
    Without that edit this is basically the opposite of what the question is asking (it was missing the `;` inside the macro, which is useful, but not what the original question was doing, which is skipping it *outside* the macro). With that edit it's appropriate. – Joe Oct 21 '14 at 16:18
  • 2
    @Joe agreed. I made an edit with a new beginning paragraph that more directly addresses the question, with the "return value hack" now being a useful afterthought. – sparc_spread Oct 21 '14 at 16:24
2

Macros are just text replacements. They're not usually executable statements themselves (though they can sometimes execute statements using %SYSFUNC). As such, a semicolon isn't required after a macro invocation unless it would be required after the text contained in the macro (and isn't actually contained in the macro itself).

IE:

%macro test;
proc freq data=sashelp.class;
run
%mend test;

has to be executed as

%test;

because the run doesn't have the terminal semicolon. If you put a semicolon after run inside the macro, then you could run it as %test without a semicolon.

Keep the first sentence above in mind: Macros are just text replacements. Whatever text is produced by the macro is then plopped into the SAS program and executed as if you'd typed it (maybe you used %do i=1 %to 100; - so it puts 100 copies of whatever is in the loop - but it's as if you typed all 100 yourself). Hence the need for a ; is based on whether or not it would be needed for you to type it.

Joe
  • 62,789
  • 6
  • 49
  • 67