Help using Base SAS procedures

do statement

Reply
Regular Contributor
Posts: 161

do statement

Hi,
what dose this error mean?
and How can I figure out what a Macro doing line by line without running the whole thing or with running a whole thing

ERROR: The %DO statement is not valid in open code

Thanks

This is my code:

* Merges (then deletes) datasets from eaach attribute together; */
%MACRO ClassPattern;
%LET divisor=2;
%LET repeat = 1;
%LET numclass= 8;
%LET totclass = &numclass.;
%LET NUMITEM= 7;
%LET numatt = 3;
%DO a=1 %TO &numatt.;
%DO r=1 %TO %EVAL(&repeat.);
DATA att&a.&r.;
DO c=1 TO &totclass.;
IF c LE (&totclass./&divisor.) THEN classatt&a.=0; ELSE classatt&a.=1;
OUTPUT;
END; DROP c;
run;
%LET repeat = %EVAL(&repeat.+1);
%END;
%IF &a.=1 %THEN %LET order = 1; %ELSE %LET order=%EVAL(&order.*2);
DATA att&a.; SET %DO loop=1 %TO &order.; Att&a.&loop. %END; ; run;
PROC DATASETS LIB=WORK NOLIST; DELETE %DO loop=1 %TO &order.; Att&a.&loop. %END; ;
RUN; QUIT;
%LET totclass = %EVAL(&totclass./2);
%END;
%MEND ClassPattern;
%ClassPattern;
%MACRO MergeIt;
DATA classpattern; RETAIN class; MERGE
%DO a=1 %TO &numatt.; Att&a. %END; ;
class = _N_; RUN;
PROC DATASETS LIB=WORK NOLIST; DELETE %DO a=1 %TO &numatt.; Att&a. %END; ;
RUN; QUIT;
%MEND MergeIt;
%MergeIt;
Valued Guide
Posts: 2,177

Re: do statement

> and How can I figure out what a Macro doing line by
> line without running the whole thing

almost impossible to figure out, with a mix of open and macro code.

before starting a test run set the 4 options:
use mlogic to follow the logic in the macro (appears in log)
use obs=5 to ensure no time wasted on data
use symbolgen to see the values used ( in log)
use mprint to ensure the generated code has all the semicolons needed ( in log)
Regular Contributor
Posts: 161

Re: do statement

how about the errors what do they mean?
SAS Super FREQ
Posts: 8,868

Re: do statement

Hi:
They generally mean that something is not resolving correctly or was defined wrong -- or in such a way that a %DO appears as if it is in "open code" and not part of a macro program definition. One of the links I provided in your other posting was the documentation on the iterative %DO loop.

The whole point of the %DO loop is usually to generate multiple statements -- for example, let's imagine that I have 100 datasets -- each numbered data1-data100 and I want to write the SAME program to create them. But, I don't want to write 100 DATA step programs -- instead, I write 1 macro program with a %DO loop inside the macro program and I have the macro program generate the 100 data step programs for me. The SAS compiler still needs to get 100 DATA step programs -- the only difference is whether I type and edit all 100 programs or whether the 100 programs are generated for me by the SAS Macro Facility.

A %DO loop can ONLY be used inside a MACRO program -- if in the resolution of your code, a %DO gets sent forward to the compiler in such a way that the compiler thinks the %DO is in "open" code, then you will receive such an error message. Let's look at a simpler example than generating 100 data step program -- let's say that I need to create 10 (or 100 or 1000 numbered variables) -- but I don't want to do that much typing. So, I decide I'm going to use a macro %DO loop to generate my numbered macro variables, I can actually duplicate your error message by using a %DO like this:
[pre]
561 %let numcount = 10;
562 data new;
563 %do i = 1 %to &numcount;
ERROR: The %DO statement is not valid in open code.
564 var&i = 'xxx';
---
180
WARNING: Apparent symbolic reference I not resolved.
ERROR 180-322: Statement is not valid or it is used out of proper order.

565 %end;
ERROR: The %END statement is not valid in open code.
566 run;

NOTE: The SAS System stopped processing this step because of errors.
WARNING: The data set WORK.NEW may be incomplete. When this step was stopped there were
0 observations and 0 variables.
[/pre]

My DATA step program is "open code" -- it is not appropriate for the %DO to be there. On the other hand, if I defined this macro program:
[pre]
%macro makenew(numcount=);
data new;
%do i = 1 %to &numcount;
var&i = 'xxx';
%end;
run;
%mend makenew;
[/pre]

Then, when I invoked it, this is what I would see in the LOG with the appropriate options turned on:
[pre]578 options mprint symbolgen mlogic;
579 %makenew(numcount=10)
MLOGIC(MAKENEW): Beginning execution.
MLOGIC(MAKENEW): Parameter NUMCOUNT has value 10
MPRINT(MAKENEW): data new;
SYMBOLGEN: Macro variable NUMCOUNT resolves to 10
MLOGIC(MAKENEW): %DO loop beginning; index variable I; start value is 1; stop value is
10; by value is 1.
SYMBOLGEN: Macro variable I resolves to 1
MPRINT(MAKENEW): var1 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 2; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 2
MPRINT(MAKENEW): var2 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 3; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 3
MPRINT(MAKENEW): var3 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 4; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 4
MPRINT(MAKENEW): var4 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 5; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 5
MPRINT(MAKENEW): var5 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 6; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 6
MPRINT(MAKENEW): var6 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 7; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 7
MPRINT(MAKENEW): var7 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 8; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 8
MPRINT(MAKENEW): var8 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 9; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 9
MPRINT(MAKENEW): var9 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 10; loop will iterate again.
SYMBOLGEN: Macro variable I resolves to 10
MPRINT(MAKENEW): var10 = 'xxx';
MLOGIC(MAKENEW): %DO loop index variable I is now 11; loop will not iterate again.
MPRINT(MAKENEW): run;

NOTE: The data set WORK.NEW has 1 observations and 10 variables.
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.00 seconds


MLOGIC(MAKENEW): Ending execution.
[/pre]

So, it is as though this program was written or generated for me, and sent to the SAS compiler:
[pre]
data new;
var1 = 'xxx';
var2 = 'xxx';
var3 = 'xxx';
var4 = 'xxx';
var5 = 'xxx';
var6 = 'xxx';
var7 = 'xxx';
var8 = 'xxx';
var9 = 'xxx';
var10 = 'xxx';
run;
[/pre]

Notice, that by the time the code got to the compiler, there were only regular statements -- no %DO appears in the code that the compiler got.

(And, before 100 people post that I shouldn't even use a %DO loop for generating 10 numbered variables, I agree. But the point is showing that the %DO goes away -- not to argue about arrays versus macro.)

I made some debugging recommendations in your other post and folks here have made some good debugging recommendations. Essential to figuring out this macro program is understanding how the SAS Macro Facility really works and what it is really doing.

cynthia
Regular Contributor
Posts: 161

Re: do statement

Posted in reply to Cynthia_sas
Thanks Cynthia,
I have started working with SAS since Dec, it has been very difficult so far. The suggested readings will definitely helps.
Ask a Question
Discussion stats
  • 4 replies
  • 191 views
  • 0 likes
  • 3 in conversation