SASUnit Examples  Version 1.5.0
_crossreference.sas
Go to the documentation of this file.
1 
27 %MACRO _crossreference(i_includeSASUnit =0
28  ,i_examinee =
29  ,o_listcalling =
30  ,o_dependency =
31  ,o_macroList =
32  );
33 
34  %LOCAL l_callVar
35  l_DoxyHeader
36  l_filename
37  l_includeSASUnit
38  l_loop
39  l_mprint
40  l_nobs
41  l_notes
42  l_path
43  l_sasunit
44  l_source
45  l_path1
46  l_path2
47  n
48  nobs
49  nobs_old;
50 
51  %IF &g_verbose. =0 %THEN %DO;
52  %let l_source =%sysfunc(getoption(source));
53  %let l_notes =%sysfunc(getoption(notes));
54  %let l_mprint =%sysfunc(getoption(mprint));
55 
56  options nomprint nonotes nosource;
57  %END;
58 
59  /* Decide which macros to scan: 1 = all macros, 0 = skip SASUnit macros */
60  %IF &i_includeSASUnit. ne 0 %THEN %LET l_includeSASUnit=1;
61  %ELSE %LET l_includeSASUnit=0;
62 
63  /* Keep all .sas files and get macro names*/
64  DATA &o_macroList.;
65  length name $ 80;
66  SET &i_examinee.;
67  IF index(filename,'.sas') = 0 THEN delete;
68  loca = length(filename) - length(scan(filename,-1,'/')) + 1;
69  name = substr(filename,loca);
70  name = substr(name, 1, length(name)-4);
71  drop loca changed;
72  RUN;
73 
74  PROC SORT DATA=&o_macroList. NODUPKEY;
75  BY membername;
76  RUN;
77 
78  /* Generate macro variable with name of each macro in &o_macroList */
79  Data &o_macroList.;
80  IF _N_ = 1 THEN DO;
81  i=0;
82  END;
83  SET &o_macroList. end=eof;
84  Call Symputx(catt("var",i), name);
85  Call Symputx('l_name',name);
86 
87  IF eof THEN Call Symputx("l_count",i);
88  i+1;
89  RUN;
90 
91  /* Generate result data set */
92  DATA &o_listcalling.;
93  length caller called $ 80
94  line $ 256;
95  STOP;
96  RUN;
97 
98  /* l_includeSASUnit = 1: include sasunit macros in scan */
99  /* Paths for SASUnit macros will be omitted if l_includeSASUnit = 0 */
100  %IF &l_includeSASUnit. = 0 %THEN %DO;
101  PROC SQL noprint;
102  select tsu_sasunit_os into: l_sasunit_os
103  from target.tsu
104  ;
105  QUIT;
106 
107  %LET l_path1 = %_abspath(&g_root,&g_sasunit)/%;
108  %LET l_path2 = %_abspath(&g_root,&l_sasunit_os)/%;
109  *** Omit SASUnit macropaths ***;
110  DATA &o_macroList.;
111  SET &o_macroList.(WHERE=(filename not like "&l_path1" AND filename not like "&l_path2"));
112  RUN;
113  %END;
114 
115  /* Loop over macros to find references*/
116  %LET l_loop = 1;
117  %DO %WHILE (&l_loop);
118  %LET l_loop = 0;
119 
120  Data &o_macroList.;
121  Modify &o_macroList.(Where=(filename NE ''));
122  Call Symputx('l_filename',filename);
123  Call Symputx('l_name',name);
124  Call Symputx('l_loop' ,1);
125  filename ='';
126  Replace;
127  STOP;
128  RUN;
129 
130  %IF &l_loop %THEN %DO;
131 
132  /* Find all macro calls in a macro */
133  DATA helper;
134  IF _N_ = 1 THEN DO;
135  retain pattern1 ptrn_Com_1_o ptrn_Com_1_c;
136  retain l_DoxyHeader 0 comment 0;
137  length line $ 256
138  caller called $ 80;
139  pattern1 = prxparse('/%/');
140  ptrn_Com_1_o = prxparse('/\/\*/');
141  ptrn_Com_1_c = prxparse('/\*\//');
142  END;
143 
144  INFILE "&l_filename" truncover;
145  INPUT line;
146  line = trim(left(_infile_));
147 
148  /* Scan for comment: IF found delete it */
149  fnt_o = prxmatch(ptrn_Com_1_o, line);
150  /* Begin of comment found */
151  IF fnt_o > 0 and comment = 0 THEN DO;
152  fnt_c = prxmatch(ptrn_Com_1_c, line);
153  /* Comment closed on same line */
154  IF fnt_c > 0 THEN DO;
155  IF fnt_o = 1 THEN line = substr(line, fnt_c+2);
156  ELSE line = catt(substr(line,1,fnt_o-1), substr(line, fnt_c+2));
157  comment=0;
158  END;
159  /* Comment not closed on same line */
160  ELSE IF fnt_c = 0 THEN DO;
161  IF fnt_o = 1 THEN line = "";
162  ELSE line = substr(line,1,fnt_o-1);
163  comment = 1;
164  END;
165  END;
166  /* Line following an opened comment */
167  ELSE IF comment = 1 THEN DO;
168  fnt_c = prxmatch(ptrn_Com_1_c, line);
169  /* Comment not closed on line */
170  IF fnt_c = 0 THEN line = "";
171  ELSE DO;
172  line = substr(line, fnt_c+2);
173  comment = 0;
174  END;
175  END;
176 
177  /* '%' found in line: look for macro call */
178  IF prxmatch(pattern1, line) THEN DO;
179  DO x=0 to &l_count;
180  called = resolve(catt('&var',x));
181  calledMacro = catt('%',called);
182  findpos = find(line, trim(calledMacro), 'i');
183  /* candidate found */
184  IF findpos gt 0 THEN DO;
185  len = length(trim(calledMacro));
186  /* make sure found string is whole macro name and not only a substring */
187  substring = substr(line, findpos+len,1);
188  IF substring in ('(',' ',';') THEN DO;
189  caller = resolve("&l_name");
190  KEEP line caller called;
191  OUTPUT;
192  END;
193  END;
194  END;
195  END;
196  RUN;
197 
198  DATA _NULL_;
199  SET helper nobs=cnt_obs;
200  call symput('l_nobs', put(cnt_obs, 4.));
201  RUN;
202 
203  %IF &l_nobs GT 0 %THEN %DO;
204  /* Neglect multiple calls to the same macro */
205  PROC sort DATA = helper nodupkey;
206  BY called;
207  RUN;
208  /* Append data from helper to calling macro-data set */
209  PROC append base=&o_listcalling DATA=helper;
210  where caller ne called;
211  RUN;
212  %END;
213  %END; /* %IF &l_loop %THEN %DO */
214  %END;/* Loop over macros to find references*/
215 
216  /* Use results from scan to build hierarchy*/
217  PROC SQL noprint;
218  create table stage1 as
219  select distinct caller, called
220  from &o_listcalling as l1
221  ;
222  select count(caller) into: nobs
223  from stage1
224  ;
225  QUIT;
226 
227  %LET n = 1;
228  %LET l_loop = 1;
229 
230  /* Iterate over stageX data sets till no more observations are appended and all
231  dependencies are found */
232  %DO %while (&l_loop);
233  %LET nobs_old = &nobs.;
234  %LET n = %eval(&n. + 1);
235 
236  proc sql noprint;
237  create table stage&n. as
238  select distinct s.caller, l.called
239  from stage%eval(&n.-1) as s
240  join &o_listcalling. as l
241  on s.called = l.caller
242  ;
243  quit;
244  data stage&n.;
245  set stage&n. stage%eval(&n.-1);
246  run;
247  proc sort data=stage&n. noduplicate;
248  by caller called;
249  run;
250  PROC SQL noprint;
251  select count(caller) into: nobs
252  from stage&n.
253  ;
254  QUIT;
255  %IF &nobs eq &nobs_old %THEN %LET l_loop=0;
256  %END;
257 
258  /* Get dependency information for scenarios and all called macros */
259  DATA &o_dependency;
260  SET stage&n.;
261  keep caller calledByCaller;
262  caller = catt(caller,".sas");
263  cnt = count(called,',');
264  DO i=1 TO cnt+1;
265  calledByCaller = catt(scan(called,i,','),".sas");
266  OUTPUT;
267  END;
268  RUN;
269 
270  PROC SORT DATA=&o_dependency NODUPKEY;
271  BY caller calledByCaller;
272  RUN;
273 
274  %IF &g_verbose =0 %THEN %DO;
275  options &l_source &l_notes &l_mprint;
276  %END;
277 %MEND _crossreference;