BookmarkSubscribeRSS Feed
Rain_28
Fluorite | Level 6

Hi,

Thanks in advance for stopping by and helping.

I am getting an error while writing to a text file using PUT statement. If I remove the inner j loop, the program works fine. Here is the piece of problematic code:

put "%nrstr(%xx());"//
"options validavarname= v7;"//;

%do i=1 %to &n;
put "data &&fm&i.;"/
    "set xx;"/
    %do j = 1 %to &&cnt&i;
	if type = 2 then
	do;
	  if x ne y then 
	  do;
		put +2 x " = " y ";"//
	  end;
	end;
    %end;
"run;"//;
%end;

 Here is the error:

Rain_28_0-1770254685398.png

Please suggest the solution. Thanks again!

8 REPLIES 8
ballardw
Super User

A tool that is good to learn for use in debugging macro related code, your %Do loops are macro code, is to turn on one or more options of Mprint, Symbolgen or Mlogic.  Add something like

options MPRINT;

before the code in question when executed. Use Options nomprint; to turn off.

 

You should see that the resolved code in the LOG using the Mprint that you get a separate instruction code line of "run;" because your current' code does not have that quoted string as part of the argument for the PUT instruction. The current "If type= 2" and related code ends the PUT. So you need another PUT before the "run;".

 

Hint: It is usually a good idea to include the entire code for a data step or procedure that is having issues and better to include a small data set in the form of working data step code that could be used to test the code. Since your code doesn't define where the values of Type, X or Y variables come from I have to assume there is another data set involved and more code using that data set prior to what you have shown.

Tom
Super User Tom
Super User

Your code does not appear to make much sense as written. And there are not any comments explaining what it is trying to do.

 

We could try to add some more code so that we can see what SAS code it is trying to generate.

%macro xx(); This is what XX emits. %mend xx;
%macro test;

put "%nrstr(%xx());"//
"options validavarname= v7;"//;

%do i=1 %to &n;
put "data &&fm&i.;"/
    "set xx;"/
    %do j = 1 %to &&cnt&i;
  if type = 2 then
  do;
    if x ne y then 
    do;
    put +2 x " = " y ";"//
    end;
  end;
    %end;
"run;"//;
%end;

%mend test;

But to test it we will have to make a lot of assumptions about the macro variables it is referencing.

%let n=2;
%let fm=fm;
%let fm1=out1;
%let fm2=out2;
%let cnt=cnt;
%let cnt1=2 ;
%let cnt2=3;

Now we can try calling the macro in the middle of a data step and see what the data step compiler makes of the SAS statements the macro code generates.

options mprint;
data _null_;
%test;
run;

You can see that the macro generates that quoted string outside of any of the other SAS statements it generates.

 MPRINT(TEST):   put "%xx();"// "options validavarname= v7;"//;
 MPRINT(TEST):   put "data out1;"/ "set xx;"/ if type = 2 then do;
 MPRINT(TEST):   if x ne y then do;
 MPRINT(TEST):   put +2 x " = " y ";"// end;
 MPRINT(TEST):   end;
 MPRINT(TEST):   if type = 2 then do;
 MPRINT(TEST):   if x ne y then do;
 MPRINT(TEST):   put +2 x " = " y ";"// end;
 MPRINT(TEST):   end;
 NOTE: Line generated by the invoked macro "TEST".
 106         "run;"//;
             ______
             180
 MPRINT(TEST):   "run;"//;
 MPRINT(TEST):   put "data out2;"/ "set xx;"/ if type = 2 then do;
 MPRINT(TEST):   if x ne y then do;
 MPRINT(TEST):   put +2 x " = " y ";"// end;
 MPRINT(TEST):   end;
 MPRINT(TEST):   if type = 2 then do;
 MPRINT(TEST):   if x ne y then do;
 MPRINT(TEST):   put +2 x " = " y ";"// end;
 MPRINT(TEST):   end;
 MPRINT(TEST):   if type = 2 then do;
 MPRINT(TEST):   if x ne y then do;
 MPRINT(TEST):   put +2 x " = " y ";"// end;
 MPRINT(TEST):   end;
 NOTE: Line generated by the invoked macro "TEST".
 106         "run;"//;
             ______
             180
 MPRINT(TEST):   "run;"//;
 ERROR 180-322: Statement is not valid or it is used out of proper order.
 
 107        run;
 
 NOTE: The SAS System stopped processing this step because of errors.
 NOTE: DATA statement used (Total process time):
       real time           0.00 seconds
       cpu time            0.00 seconds

But it is also generating other silly SAS statements, like:

MPRINT(TEST):   put "data out2;"/ "set xx;"/ if type = 2 then do;
MPRINT(TEST):   put +2 x " = " y ";"// end;

Does your input dataset actually have variables named IF, TYPE , THEN, DO and END? 

 

And that inner %DO loop over the macro variable J makes no sense becuase it is just generating the same code multiple times.  Only way it makes sense is if those macro variables it is referencing can only have values of 0 or 1.  In which case why not just use an %IF %THEN %DO block instead of %DO loop.

 

And how did you get those series of &&FM&I and &&CNT&I variables?  Did you generate them from a dataset? Why not just use the data step that reads in that dataset to drive the loop instead of converting the dataset variables into macro variables and then passing the macro variables back a data step as quoted strings to then write out?

 

 

 

Rain_28
Fluorite | Level 6

I do use mprint, symbolgen, etc options before macro but am not getting this Put statement. It's the first time I am trying to write to a file using PUT. So have a big time confusion where it is ending. I am pretty sure, there must be some issue ending this put statement in the J loop.

This code is part of bigger code and I don't know how much I can copy here. The 2 loops may not be making sense here but they are doing what they are supposed to do. I can try to explain here what they are for:

variable i has count for no. of datasets, for ex: 2 (A & B)

variable j has count of no. of variables in those datasets - For example A has 10 variables & B has 100. I am trying to assign these data variables to another variables and put out in a text file. So that I don't have to manually assign each variables.

 

I had tried as much I could... like adding the PUT statement before run ---> getting error:

Rain_28_0-1770264821868.png

 

If I add extra semi-colon before // , that is also not helping.

put +2 x " = " y ";" ; //

 

Kathryn_SAS
SAS Employee

I am not exactly sure what your code is supposed to be doing either, but maybe you could try %PUT as shown below rather than PUT. 

%let n=2;
%let fm=fm;
%let fm1=out1;
%let fm2=out2;
%let cnt=cnt;
%let cnt1=1 ;
%let cnt2=2;

%macro test;

%put /*"%nrstr(%xx());"//*/ /* commented this out since uncertain what it does */
options validavarname= v7; ;

%do i=1 %to &n;
%put %str(data &&fm&i.;) ;
 %put %str(set xx;) ;
    %do j = 1 %to &&cnt&i;
%put %str(if type = 2 then
	do;
	  if x ne y then 
	  do;
		put +2 x " = " y ";"//
	  end;
	end;) ;
    %end;

%put %str(run;) ;
%end;

%mend;
options mprint mlogic symbolgen;
%test
Tom
Super User Tom
Super User

First figure out what code you want to generate.

Perhaps something like:

data out1;
  set in1;
  new1 = old1;
  new2 = old2;
run;

So then if you had a dataset that looked like:

data meta ;
   input (oldds newds oldvar newvar) (:$32.);
cards;
in1 out1 old1 new1
in1 out1 old2 new2
;

You could use a data step like this to generate the code.

data _null_;
  set meta;
  by oldds ;
  file 'newfile.sas';
  if first.oldds then put 
    'data ' newds ';'
  / '  set ' oldds ';'
  ;
  put newvar '=' oldvar ';' ;
  if last.oldds then put
    'run;'
  ;
run;
andreas_lds
Jade | Level 19

The code posted does not make any sense at all. Please post the complete data step / macro.

quickbluefish
Barite | Level 11

I think you should tell us what the overall *goal* is, because most likely there is a much more straightforward way to output code to a file.  Basically, you seem to be trying to write out code that is conditional on (or parameterized with) values from the data, but what is the purpose of that resulting code?  What would be the goal of running that resulting code that could not be accomplished directly by the program / macro that's reading the data in the first place?  

If you really do need to do this, I would just start very simple so that you can see what the code is actually doing, e.g.:

data _null_;
put "data somefile;"/"set indata;"/;
x=3; y=3;
if x=y then put x "=" y ";"/;
put "run;";
run;

...and then look at what that is writing to the log file (or wherever you've directed the output).

Tom
Super User Tom
Super User

It really helps a lot to use well planned indentation strategy to make sure you don't mix your macro code loops and your data step loops. (And in your case the loops in the code that is being written to the file.)

So keep the indentation of the MACRO code separate from the indentation of the SAS code that the macro is generating.

data _null_;
  ...
  put "%nrstr(%xx());"
    / "options validavarname= v7;"
  ;

%do i=1 %to &n;
  put "data &&fm&i.;"
    / "  set xx;"
    /
/* Where is the semicolon to end this PUT statement? */
  %do j = 1 %to &&cnt&i;
  if type = 2 then do;
    if x ne y then do;
      put +2 x " = " y ";"
        /
/* Where is the semicolon to end this PUT statement? */        
    end;
  end;
  %end;
/* This is not a valid SAS statement. */  
  "run;"//;
%end;
   ...
run;

 

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 213 views
  • 2 likes
  • 6 in conversation