|
1 /****************************************************************************** |
|
2 * |
|
3 * |
|
4 * |
|
5 * Copyright (C) 1997-2008 by Dimitri van Heesch. |
|
6 * |
|
7 * Permission to use, copy, modify, and distribute this software and its |
|
8 * documentation under the terms of the GNU General Public License is hereby |
|
9 * granted. No representations are made about the suitability of this software |
|
10 * for any purpose. It is provided "as is" without express or implied warranty. |
|
11 * See the GNU General Public License for more details. |
|
12 * |
|
13 * Documents produced by Doxygen are derivative works derived from the |
|
14 * input used in their production; they are not affected by this license. |
|
15 * |
|
16 */ |
|
17 |
|
18 %{ |
|
19 |
|
20 /* |
|
21 * includes |
|
22 */ |
|
23 |
|
24 #include <stdio.h> |
|
25 #include <assert.h> |
|
26 #include <ctype.h> |
|
27 #include <errno.h> |
|
28 |
|
29 #include "qtbc.h" |
|
30 #include <qarray.h> |
|
31 #include <qstack.h> |
|
32 #include <qfile.h> |
|
33 #include <qstrlist.h> |
|
34 #include <qdict.h> |
|
35 #include <qregexp.h> |
|
36 #include <qfileinfo.h> |
|
37 #include <qdir.h> |
|
38 #include <qmap.h> |
|
39 |
|
40 #include "pre.h" |
|
41 #include "constexp.h" |
|
42 #include "define.h" |
|
43 #include "doxygen.h" |
|
44 #include "message.h" |
|
45 #include "util.h" |
|
46 #include "defargs.h" |
|
47 #include "debug.h" |
|
48 #include "bufstr.h" |
|
49 #include "portable.h" |
|
50 #include "bufstr.h" |
|
51 |
|
52 #define YY_NEVER_INTERACTIVE 1 |
|
53 |
|
54 struct FileState |
|
55 { |
|
56 FileState(int size) : fileBuf(size), oldFileBuf(0), oldFileBufPos(0) {} |
|
57 int lineNr; |
|
58 //FILE *filePtr; |
|
59 BufStr fileBuf; |
|
60 //FILE *oldYYin; |
|
61 BufStr *oldFileBuf; |
|
62 int oldFileBufPos; |
|
63 //bool isPlainFile; |
|
64 YY_BUFFER_STATE bufState; |
|
65 QCString fileName; |
|
66 }; |
|
67 |
|
68 /* ----------------------------------------------------------------- |
|
69 * |
|
70 * scanner's state |
|
71 */ |
|
72 |
|
73 static int g_yyLineNr = 1; |
|
74 static QCString g_yyFileName; |
|
75 static FileDef *g_yyFileDef; |
|
76 static FileDef *g_inputFileDef; |
|
77 static int g_ifcount = 0; |
|
78 static QStrList *g_pathList = 0; |
|
79 static QStack<FileState> g_includeStack; |
|
80 static QDict<int> *g_argDict; |
|
81 static int g_defArgs = -1; |
|
82 static QCString g_defName; |
|
83 static QCString g_defText; |
|
84 static QCString g_defLitText; |
|
85 static QCString g_defArgsStr; |
|
86 static bool g_defVarArgs; |
|
87 static int g_level; |
|
88 static int g_lastCContext; |
|
89 static int g_lastCPPContext; |
|
90 static QArray<int> g_levelGuard; |
|
91 static BufStr *g_inputBuf; |
|
92 static int g_inputBufPos; |
|
93 static BufStr *g_outputBuf; |
|
94 static int g_roundCount; |
|
95 static bool g_quoteArg; |
|
96 static DefineDict *g_fileDefineDict = new DefineDict(10009); |
|
97 static DefineDict *g_expandedDict; |
|
98 static int g_findDefArgContext; |
|
99 static QCString g_lastGuardName; |
|
100 static QCString g_incName; |
|
101 static QCString g_guardExpr; |
|
102 static int g_curlyCount; |
|
103 static bool g_nospaces; // add extra spaces during macro expansion |
|
104 |
|
105 static bool g_macroExpansion; // from the configuration |
|
106 static bool g_expandOnlyPredef; // from the configuration |
|
107 static int g_commentCount; |
|
108 static bool g_insideComment; |
|
109 static bool g_isImported; |
|
110 static QCString g_blockName; |
|
111 static int g_condCtx; |
|
112 static bool g_skip; |
|
113 static QStack<bool> g_condStack; |
|
114 static bool g_insideCS; // C# has simpler preprocessor |
|
115 |
|
116 static bool g_lexInit = FALSE; |
|
117 |
|
118 DefineDict* getFileDefineDict() |
|
119 { |
|
120 return g_fileDefineDict; |
|
121 } |
|
122 |
|
123 static void setFileName(const char *name) |
|
124 { |
|
125 bool ambig; |
|
126 QFileInfo fi(name); |
|
127 g_yyFileName=convertToQCString(fi.absFilePath()); |
|
128 g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig); |
|
129 if (g_yyFileDef == 0 && Config_getBool("PREPROCESS_INCLUDES")) { |
|
130 // Search again using Doxygen::includeNameDict |
|
131 // First insert the include file in the Doxygen::includeNameDict if |
|
132 // it is not there already. This can happen if the Doxygen::includeNameDict |
|
133 // has scanned .../inc but the #include "usr/usr.h" |
|
134 // The Doxygen::includeNameDict will not have usr.h in it so we poke it in. |
|
135 if (!Doxygen::includeNameDict->find(g_yyFileName.data())) { |
|
136 //Debug::print(Debug::IncludeGraph, 0, "pre.l setFileName() inserting in Doxygen::includeNameDict: %s\n", name); |
|
137 FileDef *fd=new FileDef(fi.dirPath()+"/", fi.fileName()); |
|
138 FileName *fn=0; |
|
139 if (!fi.absFilePath().isEmpty() && (fn=(*Doxygen::includeNameDict)[name])) { |
|
140 fn->append(fd); |
|
141 } else { |
|
142 fn = new FileName(fi.absFilePath(), name); |
|
143 fn->append(fd); |
|
144 Doxygen::includeNameDict->insert(name, fn); |
|
145 } |
|
146 g_yyFileDef = fd; |
|
147 } else { |
|
148 // Search the dictionary |
|
149 FileName *fn = Doxygen::includeNameDict->find(g_yyFileName.data()); |
|
150 FileNameIterator fni(*fn); |
|
151 FileDef *fd = 0; |
|
152 for (fni.toFirst(); (fd=fni.current()); ++fni) { |
|
153 if (fd && fd->absFilePath() == g_yyFileName) { |
|
154 break; |
|
155 } |
|
156 fd = 0; |
|
157 } |
|
158 g_yyFileDef = fd; |
|
159 } |
|
160 //printf("pre.l setFileName() searching Doxygen::includeNameDict for %s, result=%p\n", name, g_yyFileDef); |
|
161 //Debug::print(Debug::IncludeGraph, 0, "pre.l setFileName() searching Doxygen::includeNameDict for %s, result=%p\n", name, g_yyFileDef); |
|
162 } |
|
163 if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0; |
|
164 g_insideCS = g_yyFileName.right(3)==".cs"; |
|
165 } |
|
166 |
|
167 static void incrLevel() |
|
168 { |
|
169 g_level++; |
|
170 g_levelGuard.resize(g_level); |
|
171 g_levelGuard[g_level-1]=FALSE; |
|
172 //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level); |
|
173 } |
|
174 |
|
175 static void decrLevel() |
|
176 { |
|
177 //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level); |
|
178 if (g_level > 0) |
|
179 { |
|
180 g_level--; |
|
181 g_levelGuard.resize(g_level); |
|
182 } |
|
183 else |
|
184 { |
|
185 err("%s:%d: Error: More #endif's than #if's found.\n", |
|
186 g_yyFileName.data(),g_yyLineNr); |
|
187 } |
|
188 } |
|
189 |
|
190 static bool otherCaseDone() |
|
191 { |
|
192 if (g_level==0) |
|
193 { |
|
194 err("%s:%d: Error: Found an #else without a preceding #if.\n", |
|
195 g_yyFileName.data(),g_yyLineNr); |
|
196 return TRUE; |
|
197 } |
|
198 else |
|
199 { |
|
200 return g_levelGuard[g_level-1]; |
|
201 } |
|
202 } |
|
203 |
|
204 static void setCaseDone(bool value) |
|
205 { |
|
206 g_levelGuard[g_level-1]=value; |
|
207 } |
|
208 |
|
209 static Define *isDefined(const char *name) |
|
210 { |
|
211 if (name) |
|
212 { |
|
213 Define *def; |
|
214 //if ((def=fileDefineCache->findDefine(g_yyFileName,name)) && !def->undef) |
|
215 // return def; |
|
216 if ((def=g_fileDefineDict->find(name)) && !def->undef) return def; |
|
217 } |
|
218 return 0; |
|
219 } |
|
220 |
|
221 static QDict<void> g_allIncludes(10009); |
|
222 |
|
223 static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded) |
|
224 { |
|
225 alreadyIncluded = FALSE; |
|
226 FileState *fs = 0; |
|
227 //msg("checkAndOpenFile(%s)\n", fileName.data()); |
|
228 QFileInfo fi(fileName); |
|
229 if (fi.exists() && fi.isFile()) |
|
230 { |
|
231 QCString absName = convertToQCString(fi.absFilePath()); |
|
232 //msg("checkAndOpenFile() found: %s\n", absName.data()); |
|
233 // global guard |
|
234 if (g_curlyCount==0) // not #include inside { ... } |
|
235 { |
|
236 if (g_allIncludes.find(absName)!=0) |
|
237 { |
|
238 alreadyIncluded = TRUE; |
|
239 //printf(" already included 1\n"); |
|
240 if (!Config_getBool("PREPROCCESS_FULL_TU")) { |
|
241 return 0; // already done |
|
242 } |
|
243 } else { |
|
244 g_allIncludes.insert(absName,(void *)0x8); |
|
245 } |
|
246 } |
|
247 // check include stack for absName |
|
248 // This is equivelent to walking the stack and setting alreadyIncluded to |
|
249 // TRUE if absName matches any filename |
|
250 QStack<FileState> tmpStack; |
|
251 g_includeStack.setAutoDelete(FALSE); |
|
252 while ((fs=g_includeStack.pop())) |
|
253 { |
|
254 if (fs->fileName==absName) alreadyIncluded=TRUE; |
|
255 tmpStack.push(fs); |
|
256 } |
|
257 while ((fs=tmpStack.pop())) |
|
258 { |
|
259 g_includeStack.push(fs); |
|
260 } |
|
261 g_includeStack.setAutoDelete(TRUE); |
|
262 |
|
263 if (alreadyIncluded) |
|
264 { |
|
265 //printf(" already included 2\n"); |
|
266 return 0; |
|
267 } |
|
268 //printf("#include %s\n",absName.data()); |
|
269 |
|
270 fs = new FileState(fi.size()+4096); |
|
271 alreadyIncluded = FALSE; |
|
272 if (!readInputFile(absName,fs->fileBuf)) |
|
273 { // error |
|
274 //printf(" error reading\n"); |
|
275 delete fs; |
|
276 fs=0; |
|
277 } |
|
278 else |
|
279 { |
|
280 fs->oldFileBuf = g_inputBuf; |
|
281 fs->oldFileBufPos = g_inputBufPos; |
|
282 } |
|
283 |
|
284 #if 0 |
|
285 QCString filterName = getFileFilter(absName); |
|
286 if (!filterName.isEmpty()) |
|
287 { |
|
288 fs->isPlainFile = FALSE; |
|
289 QCString cmd = filterName+" \""+absName+"\""; |
|
290 fs->filePtr=portable_popen(cmd,"r"); |
|
291 if (!fs->filePtr) |
|
292 { |
|
293 err("Error: could not execute filter %s, reason: %s\n",cmd.data(), |
|
294 strerror(errno)); |
|
295 } |
|
296 } |
|
297 else |
|
298 { |
|
299 fs->isPlainFile = TRUE; |
|
300 fs->filePtr=fopen(absName,"r"); |
|
301 if (!fs->filePtr) |
|
302 { |
|
303 err("Error: could not open file %s for reading, reason: %s \n", |
|
304 absName.data(),strerror(errno)); |
|
305 } |
|
306 } |
|
307 if (!fs->filePtr) // error -> cleanup |
|
308 { |
|
309 delete fs; |
|
310 fs=0; |
|
311 } |
|
312 else |
|
313 { |
|
314 fs->oldYYin = preYYin; |
|
315 } |
|
316 #endif |
|
317 |
|
318 } |
|
319 return fs; |
|
320 } |
|
321 |
|
322 static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded) |
|
323 { |
|
324 //msg("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data()); |
|
325 if (localInclude && !g_yyFileName.isEmpty()) |
|
326 { |
|
327 QFileInfo fi(g_yyFileName); |
|
328 if (fi.exists()) |
|
329 { |
|
330 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName; |
|
331 FileState *fs = checkAndOpenFile(absName,alreadyIncluded); |
|
332 if (fs) |
|
333 { |
|
334 setFileName(absName); |
|
335 g_yyLineNr=1; |
|
336 return fs; |
|
337 } |
|
338 else if (alreadyIncluded) |
|
339 { |
|
340 return 0; |
|
341 } |
|
342 } |
|
343 } |
|
344 if (g_pathList==0) |
|
345 { |
|
346 return 0; |
|
347 } |
|
348 char *s=g_pathList->first(); |
|
349 while (s) |
|
350 { |
|
351 QCString absName = (QCString)s+"/"+fileName; |
|
352 FileState *fs = checkAndOpenFile(absName,alreadyIncluded); |
|
353 if (fs) |
|
354 { |
|
355 setFileName(absName); |
|
356 g_yyLineNr=1; |
|
357 return fs; |
|
358 } |
|
359 else if (alreadyIncluded) |
|
360 { |
|
361 return 0; |
|
362 } |
|
363 |
|
364 s=g_pathList->next(); |
|
365 } |
|
366 return 0; |
|
367 } |
|
368 |
|
369 static QCString extractTrailingComment(const char *s) |
|
370 { |
|
371 if (s==0) return ""; |
|
372 int i=strlen(s)-1; |
|
373 while (i>=0) |
|
374 { |
|
375 char c=s[i]; |
|
376 switch (c) |
|
377 { |
|
378 case '/': |
|
379 { |
|
380 i--; |
|
381 if (i>=0 && s[i]=='*') // end of a comment block |
|
382 { |
|
383 i--; |
|
384 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--; |
|
385 if (i==0) return s; else return &s[i-1]; |
|
386 } |
|
387 else |
|
388 { |
|
389 return ""; |
|
390 } |
|
391 } |
|
392 break; |
|
393 // whitespace or line-continuation |
|
394 case ' ': |
|
395 case '\t': |
|
396 case '\r': |
|
397 case '\n': |
|
398 case '\\': |
|
399 break; |
|
400 default: |
|
401 return ""; |
|
402 } |
|
403 i--; |
|
404 } |
|
405 return ""; |
|
406 } |
|
407 |
|
408 static int getNextChar(const QCString &expr,QCString *rest,uint &pos); |
|
409 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos); |
|
410 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c); |
|
411 static void expandExpression(QCString &expr,QCString *rest,int pos); |
|
412 |
|
413 static QCString stringize(const QCString &s) |
|
414 { |
|
415 QCString result; |
|
416 uint i=0; |
|
417 bool inString=FALSE; |
|
418 bool inChar=FALSE; |
|
419 char c,pc; |
|
420 while (i<s.length()) |
|
421 { |
|
422 if (!inString && !inChar) |
|
423 { |
|
424 while (i<s.length() && !inString && !inChar) |
|
425 { |
|
426 c=s.at(i++); |
|
427 if (c=='"') |
|
428 { |
|
429 result+="\\\""; |
|
430 inString=TRUE; |
|
431 } |
|
432 else if (c=='\'') |
|
433 { |
|
434 result+=c; |
|
435 inChar=TRUE; |
|
436 } |
|
437 else |
|
438 { |
|
439 result+=c; |
|
440 } |
|
441 } |
|
442 } |
|
443 else if (inChar) |
|
444 { |
|
445 while (i<s.length() && inChar) |
|
446 { |
|
447 c=s.at(i++); |
|
448 if (c=='\'') |
|
449 { |
|
450 result+='\''; |
|
451 inChar=FALSE; |
|
452 } |
|
453 else if (c=='\\') |
|
454 { |
|
455 result+="\\\\"; |
|
456 } |
|
457 else |
|
458 { |
|
459 result+=c; |
|
460 } |
|
461 } |
|
462 } |
|
463 else |
|
464 { |
|
465 pc=0; |
|
466 while (i<s.length() && inString) |
|
467 { |
|
468 char c=s.at(i++); |
|
469 if (c=='"') |
|
470 { |
|
471 result+="\\\""; |
|
472 inString= pc=='\\'; |
|
473 } |
|
474 else if (c=='\\') |
|
475 result+="\\\\"; |
|
476 else |
|
477 result+=c; |
|
478 pc=c; |
|
479 } |
|
480 } |
|
481 } |
|
482 //printf("stringize `%s'->`%s'\n",s.data(),result.data()); |
|
483 return result; |
|
484 } |
|
485 |
|
486 /*! Execute all ## operators in expr. |
|
487 * If the macro name before or after the operator contains a no-rescan |
|
488 * marker (@-) then this is removed (before the concatenated macro name |
|
489 * may be expanded again. |
|
490 */ |
|
491 static void processConcatOperators(QCString &expr) |
|
492 { |
|
493 //printf("processConcatOperators: in=`%s'\n",expr.data()); |
|
494 QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); |
|
495 int l,n,i=0; |
|
496 if (expr.isEmpty()) return; |
|
497 while ((n=r.match(expr,i,&l))!=-1) |
|
498 { |
|
499 //printf("Match: `%s'\n",expr.data()+i); |
|
500 if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-') |
|
501 { |
|
502 // remove no-rescan marker after ID |
|
503 l+=2; |
|
504 } |
|
505 //printf("found `%s'\n",expr.mid(n,l).data()); |
|
506 // remove the ## operator and the surrounding whitespace |
|
507 expr=expr.left(n)+expr.right(expr.length()-n-l); |
|
508 int k=n-1; |
|
509 while (k>=0 && isId(expr.at(k))) k--; |
|
510 if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@') |
|
511 { |
|
512 // remove no-rescan marker before ID |
|
513 expr=expr.left(k-1)+expr.right(expr.length()-k-1); |
|
514 n-=2; |
|
515 } |
|
516 i=n; |
|
517 } |
|
518 //printf("processConcatOperators: out=`%s'\n",expr.data()); |
|
519 } |
|
520 |
|
521 static void yyunput (int c,char *buf_ptr ); |
|
522 static void returnCharToStream(char c) |
|
523 { |
|
524 unput(c); |
|
525 } |
|
526 |
|
527 static inline void addTillEndOfString(const QCString &expr,QCString *rest, |
|
528 uint &pos,char term,QCString &arg) |
|
529 { |
|
530 int cc; |
|
531 while ((cc=getNextChar(expr,rest,pos))!=EOF) |
|
532 { |
|
533 if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos); |
|
534 else if (cc==term) return; |
|
535 arg+=(char)cc; |
|
536 } |
|
537 } |
|
538 |
|
539 /*! replaces the function macro \a def whose argument list starts at |
|
540 * \a pos in expression \a expr. |
|
541 * Notice that this routine may scan beyond the \a expr string if needed. |
|
542 * In that case the characters will be read from the input file. |
|
543 * The replacement string will be returned in \a result and the |
|
544 * length of the (unexpanded) argument list is stored in \a len. |
|
545 */ |
|
546 static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result) |
|
547 { |
|
548 //printf("replaceFunctionMacro(expr=%s,rest=%s,pos=%d,def=%s) level=%d\n",expr.data(),rest ? rest->data() : 0,pos,def->name.data(),g_level); |
|
549 uint j=pos; |
|
550 len=0; |
|
551 result.resize(0); |
|
552 int cc; |
|
553 while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc)) |
|
554 { |
|
555 len++; |
|
556 getNextChar(expr,rest,j); |
|
557 } |
|
558 if (cc!='(') |
|
559 { |
|
560 unputChar(expr,rest,j,' '); |
|
561 return FALSE; |
|
562 } |
|
563 getNextChar(expr,rest,j); // eat the `(' character |
|
564 |
|
565 QDict<QCString> argTable; // list of arguments |
|
566 argTable.setAutoDelete(TRUE); |
|
567 QCString arg; |
|
568 int argCount=0; |
|
569 bool done=FALSE; |
|
570 |
|
571 // PHASE 1: read the macro arguments |
|
572 if (def->nargs==0) |
|
573 { |
|
574 while ((cc=getNextChar(expr,rest,j))!=EOF) |
|
575 { |
|
576 char c = (char)cc; |
|
577 if (c==')') break; |
|
578 } |
|
579 } |
|
580 else |
|
581 { |
|
582 while (!done && (argCount<def->nargs || def->varArgs) && |
|
583 ((cc=getNextChar(expr,rest,j))!=EOF) |
|
584 ) |
|
585 { |
|
586 char c=(char)cc; |
|
587 if (c=='(') // argument is a function => search for matching ) |
|
588 { |
|
589 int level=1; |
|
590 arg+=c; |
|
591 //char term='\0'; |
|
592 while ((cc=getNextChar(expr,rest,j))!=EOF) |
|
593 { |
|
594 char c=(char)cc; |
|
595 //printf("processing %c: term=%c (%d)\n",c,term,term); |
|
596 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings |
|
597 { |
|
598 arg+=c; |
|
599 addTillEndOfString(expr,rest,j,c,arg); |
|
600 } |
|
601 if (c==')') |
|
602 { |
|
603 level--; |
|
604 arg+=c; |
|
605 if (level==0) break; |
|
606 } |
|
607 else if (c=='(') |
|
608 { |
|
609 level++; |
|
610 arg+=c; |
|
611 } |
|
612 else |
|
613 arg+=c; |
|
614 } |
|
615 } |
|
616 else if (c==')' || c==',') // last or next argument found |
|
617 { |
|
618 if (c==',' && argCount==def->nargs-1 && def->varArgs) |
|
619 { |
|
620 arg=arg.stripWhiteSpace(); |
|
621 arg+=','; |
|
622 } |
|
623 else |
|
624 { |
|
625 QCString argKey; |
|
626 argKey.sprintf("@%d",argCount++); // key name |
|
627 arg=arg.stripWhiteSpace(); |
|
628 // add argument to the lookup table |
|
629 argTable.insert(argKey, new QCString(arg)); |
|
630 arg.resize(0); |
|
631 if (c==')') // end of the argument list |
|
632 { |
|
633 done=TRUE; |
|
634 } |
|
635 } |
|
636 } |
|
637 else if (c=='\"') // append literal strings |
|
638 { |
|
639 arg+=c; |
|
640 bool found=FALSE; |
|
641 while (!found && (cc=getNextChar(expr,rest,j))!=EOF) |
|
642 { |
|
643 found = cc=='"'; |
|
644 if (cc=='\\') |
|
645 { |
|
646 c=(char)cc; |
|
647 arg+=c; |
|
648 if ((cc=getNextChar(expr,rest,j))==EOF) break; |
|
649 } |
|
650 c=(char)cc; |
|
651 arg+=c; |
|
652 } |
|
653 } |
|
654 else if (c=='\'') // append literal characters |
|
655 { |
|
656 arg+=c; |
|
657 bool found=FALSE; |
|
658 while (!found && (cc=getNextChar(expr,rest,j))!=EOF) |
|
659 { |
|
660 found = cc=='\''; |
|
661 if (cc=='\\') |
|
662 { |
|
663 c=(char)cc; |
|
664 arg+=c; |
|
665 if ((cc=getNextChar(expr,rest,j))==EOF) break; |
|
666 } |
|
667 c=(char)cc; |
|
668 arg+=c; |
|
669 } |
|
670 } |
|
671 else // append other characters |
|
672 { |
|
673 arg+=c; |
|
674 } |
|
675 } |
|
676 } |
|
677 |
|
678 // PHASE 2: apply the macro function |
|
679 if (argCount==def->nargs || |
|
680 (argCount>def->nargs && def->varArgs)) // matching parameters lists |
|
681 { |
|
682 uint k=0; |
|
683 // substitution of all formal arguments |
|
684 QCString resExpr; |
|
685 const QCString d=def->definition.stripWhiteSpace(); |
|
686 //printf("Macro definition: %s\n",d.data()); |
|
687 bool inString=FALSE; |
|
688 while (k<d.length()) |
|
689 { |
|
690 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @ |
|
691 { |
|
692 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later) |
|
693 { |
|
694 k+=2; |
|
695 resExpr+="@@"; // we unescape these later |
|
696 } |
|
697 else if (d.at(k+1)=='-') // no-rescan marker |
|
698 { |
|
699 k+=2; |
|
700 resExpr+="@-"; |
|
701 } |
|
702 else // argument marker => read the argument number |
|
703 { |
|
704 QCString key="@"; |
|
705 QCString *subst=0; |
|
706 bool hash=FALSE; |
|
707 int l=k-1; |
|
708 // search for ## backward |
|
709 if (l>=0 && d.at(l)=='"') l--; |
|
710 while (l>=0 && d.at(l)==' ') l--; |
|
711 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE; |
|
712 k++; |
|
713 // scan the number |
|
714 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++); |
|
715 if (!hash) |
|
716 { |
|
717 // search for ## forward |
|
718 l=k; |
|
719 if (l<(int)d.length() && d.at(l)=='"') l++; |
|
720 while (l<(int)d.length() && d.at(l)==' ') l++; |
|
721 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE; |
|
722 } |
|
723 //printf("request key %s result %s\n",key.data(),argTable[key]->data()); |
|
724 if (key.length()>1 && (subst=argTable[key])) |
|
725 { |
|
726 QCString substArg=*subst; |
|
727 //printf("substArg=`%s'\n",substArg.data()); |
|
728 // only if no ## operator is before or after the argument |
|
729 // marker we do macro expansion. |
|
730 if (!hash) expandExpression(substArg,0,0); |
|
731 if (inString) |
|
732 { |
|
733 //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data()); |
|
734 |
|
735 // if the marker is inside a string (because a # was put |
|
736 // before the macro name) we must escape " and \ characters |
|
737 resExpr+=stringize(substArg); |
|
738 } |
|
739 else |
|
740 { |
|
741 if (hash && substArg.isEmpty()) |
|
742 { |
|
743 resExpr+="@E"; // empty argument will be remove later on |
|
744 } |
|
745 else if (g_nospaces) |
|
746 { |
|
747 resExpr+=substArg; |
|
748 } |
|
749 else |
|
750 { |
|
751 resExpr+=" "+substArg+" "; |
|
752 } |
|
753 } |
|
754 } |
|
755 } |
|
756 } |
|
757 else // no marker, just copy |
|
758 { |
|
759 if (!inString && d.at(k)=='\"') |
|
760 { |
|
761 inString=TRUE; // entering a literal string |
|
762 } |
|
763 else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\')) |
|
764 { |
|
765 inString=FALSE; // leaving a literal string |
|
766 } |
|
767 resExpr+=d.at(k++); |
|
768 } |
|
769 } |
|
770 len=j-pos; |
|
771 result=resExpr; |
|
772 //printf("result after substitution `%s' expr=`%s'\n", |
|
773 // result.data(),expr.mid(pos,len).data()); |
|
774 return TRUE; |
|
775 } |
|
776 return FALSE; |
|
777 } |
|
778 |
|
779 |
|
780 /*! returns the next identifier in string \a expr by starting at position \a p. |
|
781 * The position of the identifier is returned (or -1 if nothing is found) |
|
782 * and \a l is its length. Any quoted strings are skipping during the search. |
|
783 */ |
|
784 static int getNextId(const QCString &expr,int p,int *l) |
|
785 { |
|
786 int n; |
|
787 while (p<(int)expr.length()) |
|
788 { |
|
789 char c=expr.at(p++); |
|
790 if (isdigit(c)) // skip number |
|
791 { |
|
792 while (p<(int)expr.length() && isId(expr.at(p))) p++; |
|
793 } |
|
794 else if (isalpha(c) || c=='_') // read id |
|
795 { |
|
796 n=p-1; |
|
797 while (p<(int)expr.length() && isId(expr.at(p))) p++; |
|
798 *l=p-n; |
|
799 return n; |
|
800 } |
|
801 else if (c=='"') // skip string |
|
802 { |
|
803 char ppc=0,pc=c; |
|
804 if (p<(int)expr.length()) c=expr.at(p); |
|
805 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) |
|
806 // continue as long as no " is found, but ignoring \", but not \\" |
|
807 { |
|
808 ppc=pc; |
|
809 pc=c; |
|
810 c=expr.at(p); |
|
811 p++; |
|
812 } |
|
813 if (p<(int)expr.length()) ++p; // skip closing quote |
|
814 } |
|
815 else if (c=='/') // skip C Comment |
|
816 { |
|
817 char pc=c; |
|
818 if (p<(int)expr.length()) |
|
819 { |
|
820 c=expr.at(++p); |
|
821 if (c=='*') // Start of C comment |
|
822 { |
|
823 while (p<(int)expr.length() && !(pc=='*' && c=='/')) |
|
824 { |
|
825 pc=c; |
|
826 c=expr.at(++p); |
|
827 } |
|
828 p++; |
|
829 } |
|
830 } |
|
831 } |
|
832 } |
|
833 return -1; |
|
834 } |
|
835 |
|
836 /*! preforms recursive macro expansion on the string \a expr |
|
837 * starting at position \a pos. |
|
838 * May read additional characters from the input while re-scanning! |
|
839 * If \a expandAll is \c TRUE then all macros in the expression are |
|
840 * expanded, otherwise only the first is expanded. |
|
841 */ |
|
842 static void expandExpression(QCString &expr,QCString *rest,int pos) |
|
843 { |
|
844 //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0); |
|
845 QCString macroName; |
|
846 QCString expMacro; |
|
847 bool definedTest=FALSE; |
|
848 int i=pos,l,p,len; |
|
849 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name |
|
850 { |
|
851 bool replaced=FALSE; |
|
852 macroName=expr.mid(p,l); |
|
853 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker? |
|
854 { |
|
855 if (g_expandedDict->find(macroName)==0) // expand macro |
|
856 { |
|
857 Define *def=isDefined(macroName); |
|
858 if (definedTest) // macro name was found after defined |
|
859 { |
|
860 if (def) expMacro = " 1 "; else expMacro = " 0 "; |
|
861 replaced=TRUE; |
|
862 len=l; |
|
863 definedTest=FALSE; |
|
864 } |
|
865 else if (def && def->nargs==-1) // simple macro |
|
866 { |
|
867 // substitute the definition of the macro |
|
868 //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data()); |
|
869 if (g_nospaces) |
|
870 { |
|
871 expMacro=def->definition.stripWhiteSpace(); |
|
872 } |
|
873 else |
|
874 { |
|
875 expMacro=" "+def->definition.stripWhiteSpace()+" "; |
|
876 } |
|
877 //expMacro=def->definition.stripWhiteSpace(); |
|
878 replaced=TRUE; |
|
879 len=l; |
|
880 //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data()); |
|
881 } |
|
882 else if (def && def->nargs>=0) // function macro |
|
883 { |
|
884 replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro); |
|
885 len+=l; |
|
886 } |
|
887 else if (macroName=="defined") |
|
888 { |
|
889 //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data()); |
|
890 definedTest=TRUE; |
|
891 } |
|
892 |
|
893 if (replaced) // expand the macro and rescan the expression |
|
894 { |
|
895 |
|
896 //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data()); |
|
897 QCString resultExpr=expMacro; |
|
898 QCString restExpr=expr.right(expr.length()-len-p); |
|
899 processConcatOperators(resultExpr); |
|
900 if (def && !def->nonRecursive) |
|
901 { |
|
902 g_expandedDict->insert(macroName,def); |
|
903 expandExpression(resultExpr,&restExpr,0); |
|
904 g_expandedDict->remove(macroName); |
|
905 } |
|
906 expr=expr.left(p)+resultExpr+restExpr; |
|
907 i=p; |
|
908 //printf("new expression: %s\n",expr.data()); |
|
909 } |
|
910 else // move to the next macro name |
|
911 { |
|
912 //printf("moving to the next macro old=%d new=%d\n",i,p+l); |
|
913 i=p+l; |
|
914 } |
|
915 } |
|
916 else // move to the next macro name |
|
917 { |
|
918 expr=expr.left(p)+"@-"+expr.right(expr.length()-p); |
|
919 //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data()); |
|
920 i=p+l+2; |
|
921 //i=p+l; |
|
922 } |
|
923 } |
|
924 else // no re-scan marker found, skip the macro name |
|
925 { |
|
926 //printf("skipping marked macro\n"); |
|
927 i=p+l; |
|
928 } |
|
929 } |
|
930 } |
|
931 |
|
932 /*! replaces all occurrences of @@@@ in \a s by @@ |
|
933 * and removes all occurrences of @@E. |
|
934 * All identifiers found are replaced by 0L |
|
935 */ |
|
936 QCString removeIdsAndMarkers(const char *s) |
|
937 { |
|
938 //printf("removeIdsAndMarkers(%s)\n",s); |
|
939 const char *p=s; |
|
940 char c; |
|
941 bool inNum=FALSE; |
|
942 QCString result; |
|
943 if (p) |
|
944 { |
|
945 while ((c=*p)) |
|
946 { |
|
947 if (c=='@') // replace @@ with @ and remove @E |
|
948 { |
|
949 if (*(p+1)=='@') |
|
950 { |
|
951 result+=c; |
|
952 } |
|
953 else if (*(p+1)=='E') |
|
954 { |
|
955 // skip |
|
956 } |
|
957 p+=2; |
|
958 } |
|
959 else if (isdigit(c)) // number |
|
960 { |
|
961 result+=c; |
|
962 p++; |
|
963 inNum=TRUE; |
|
964 } |
|
965 else if (c=='d' && !inNum) // identifier starting with a `d' |
|
966 { |
|
967 if (strncmp(p,"defined ",8)==0 || strncmp(p,"defined(",8)==0) |
|
968 // defined keyword |
|
969 { |
|
970 p+=7; // skip defined |
|
971 } |
|
972 else |
|
973 { |
|
974 result+="0L"; |
|
975 p++; |
|
976 while ((c=*p) && isId(c)) p++; |
|
977 } |
|
978 } |
|
979 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L |
|
980 { |
|
981 result+="0L"; |
|
982 p++; |
|
983 while ((c=*p) && isId(c)) p++; |
|
984 } |
|
985 else if (c=='/') // skip C comments |
|
986 { |
|
987 char pc=c; |
|
988 c=*++p; |
|
989 if (c=='*') // start of C comment |
|
990 { |
|
991 while (*p && !(pc=='*' && c=='/')) // search end of comment |
|
992 { |
|
993 pc=c; |
|
994 c=*++p; |
|
995 } |
|
996 p++; |
|
997 } |
|
998 else // oops, not comment but division |
|
999 { |
|
1000 result+=pc; |
|
1001 goto nextChar; |
|
1002 } |
|
1003 } |
|
1004 else |
|
1005 { |
|
1006 nextChar: |
|
1007 result+=c; |
|
1008 char lc=tolower(c); |
|
1009 if (!isId(lc) && lc!='.' && lc!='-' && lc!='+') inNum=FALSE; |
|
1010 p++; |
|
1011 } |
|
1012 } |
|
1013 } |
|
1014 //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data()); |
|
1015 return result; |
|
1016 } |
|
1017 |
|
1018 /*! replaces all occurrences of @@ in \a s by @ |
|
1019 * \par assumption: |
|
1020 * \a s only contains pairs of @@'s |
|
1021 */ |
|
1022 QCString removeMarkers(const char *s) |
|
1023 { |
|
1024 const char *p=s; |
|
1025 char c; |
|
1026 QCString result; |
|
1027 if (p) |
|
1028 { |
|
1029 while ((c=*p)) |
|
1030 { |
|
1031 switch(c) |
|
1032 { |
|
1033 case '@': // replace @@ with @ |
|
1034 { |
|
1035 if (*(p+1)=='@') |
|
1036 { |
|
1037 result+=c; |
|
1038 } |
|
1039 p+=2; |
|
1040 } |
|
1041 break; |
|
1042 case '/': // skip C comments |
|
1043 { |
|
1044 result+=c; |
|
1045 char pc=c; |
|
1046 c=*++p; |
|
1047 if (c=='*') // start of C comment |
|
1048 { |
|
1049 while (*p && !(pc=='*' && c=='/')) // search end of comment |
|
1050 { |
|
1051 if (*p=='@' && *(p+1)=='@') |
|
1052 result+=c,p++; |
|
1053 else |
|
1054 result+=c; |
|
1055 pc=c; |
|
1056 c=*++p; |
|
1057 } |
|
1058 if (*p) |
|
1059 { |
|
1060 result+=c; |
|
1061 p++; |
|
1062 } |
|
1063 } |
|
1064 } |
|
1065 break; |
|
1066 case '"': // skip string literals |
|
1067 { |
|
1068 result+=c; |
|
1069 char pc=c; |
|
1070 c=*++p; |
|
1071 while (*p && (c!='"' || pc=='\\')) // no end quote |
|
1072 { |
|
1073 result+=c; |
|
1074 c=*++p; |
|
1075 } |
|
1076 } |
|
1077 break; |
|
1078 case '\'': // skip char literals |
|
1079 { |
|
1080 result+=c; |
|
1081 char pc=c; |
|
1082 c=*++p; |
|
1083 while (*p && (c!='\'' || pc=='\\')) // no end quote |
|
1084 { |
|
1085 result+=c; |
|
1086 c=*++p; |
|
1087 } |
|
1088 } |
|
1089 break; |
|
1090 default: |
|
1091 { |
|
1092 result+=c; |
|
1093 p++; |
|
1094 } |
|
1095 break; |
|
1096 } |
|
1097 } |
|
1098 } |
|
1099 //printf("RemoveMarkers(%s)=%s\n",s,result.data()); |
|
1100 return result; |
|
1101 } |
|
1102 |
|
1103 /*! compute the value of the expression in string \a expr. |
|
1104 * If needed the function may read additional characters from the input. |
|
1105 */ |
|
1106 |
|
1107 bool computeExpression(const QCString &expr) |
|
1108 { |
|
1109 QCString e=expr; |
|
1110 expandExpression(e,0,0); |
|
1111 //printf("after expansion `%s'\n",e.data()); |
|
1112 e = removeIdsAndMarkers(e); |
|
1113 if (e.isEmpty()) return FALSE; |
|
1114 //printf("parsing `%s'\n",e.data()); |
|
1115 return parseCppExpression(g_yyFileName,g_yyLineNr,e); |
|
1116 } |
|
1117 |
|
1118 /*! expands the macro definition in \a name |
|
1119 * If needed the function may read additional characters from the input |
|
1120 */ |
|
1121 |
|
1122 QCString expandMacro(const QCString &name) |
|
1123 { |
|
1124 QCString n=name; |
|
1125 expandExpression(n,0,0); |
|
1126 n=removeMarkers(n); |
|
1127 //printf("expandMacro `%s'->`%s'\n",name.data(),n.data()); |
|
1128 return n; |
|
1129 } |
|
1130 |
|
1131 Define *newDefine() |
|
1132 { |
|
1133 Define *def=new Define; |
|
1134 def->name = g_defName; |
|
1135 def->definition = g_defText.stripWhiteSpace(); |
|
1136 def->nargs = g_defArgs; |
|
1137 def->fileName = g_yyFileName; |
|
1138 def->lineNr = g_yyLineNr; |
|
1139 def->varArgs = g_defVarArgs; |
|
1140 //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data()); |
|
1141 if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name]) |
|
1142 { |
|
1143 def->isPredefined=TRUE; |
|
1144 } |
|
1145 return def; |
|
1146 } |
|
1147 |
|
1148 void addDefine() |
|
1149 { |
|
1150 if (g_skip) return; // do not add this define as it is inside a |
|
1151 // conditional section (cond command) that is disabled. |
|
1152 if (!Doxygen::gatherDefines) return; |
|
1153 |
|
1154 //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data()); |
|
1155 //ArgumentList *al = new ArgumentList; |
|
1156 //stringToArgumentList(g_defArgsStr,al); |
|
1157 MemberDef *md=new MemberDef( |
|
1158 g_yyFileName,g_yyLineNr, |
|
1159 "#define",g_defName,g_defArgsStr,0, |
|
1160 Public,Normal,FALSE,Member,MemberDef::Define,0,0); |
|
1161 if (!g_defArgsStr.isEmpty()) |
|
1162 { |
|
1163 ArgumentList *argList = new ArgumentList; |
|
1164 //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data()); |
|
1165 stringToArgumentList(g_defArgsStr,argList); |
|
1166 md->setArgumentList(argList); |
|
1167 } |
|
1168 //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data()); |
|
1169 int l=g_defLitText.find('\n'); |
|
1170 if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\") |
|
1171 { |
|
1172 // strip first line if it only contains a slash |
|
1173 g_defLitText = g_defLitText.right(g_defLitText.length()-l-1); |
|
1174 } |
|
1175 else if (l>0) |
|
1176 { |
|
1177 // align the items on the first line with the items on the second line |
|
1178 int k=l+1; |
|
1179 const char *p=g_defLitText.data()+k; |
|
1180 char c; |
|
1181 while ((c=*p++) && (c==' ' || c=='\t')) k++; |
|
1182 g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace(); |
|
1183 } |
|
1184 md->setInitializer(g_defLitText.stripWhiteSpace()); |
|
1185 |
|
1186 md->setFileDef(g_inputFileDef); |
|
1187 md->setDefinition("#define "+g_defName); |
|
1188 |
|
1189 MemberName *mn=Doxygen::functionNameSDict->find(g_defName); |
|
1190 if (mn==0) |
|
1191 { |
|
1192 mn = new MemberName(g_defName); |
|
1193 Doxygen::functionNameSDict->append(g_defName,mn); |
|
1194 } |
|
1195 mn->append(md); |
|
1196 if (g_yyFileDef) g_yyFileDef->insertMember(md); |
|
1197 |
|
1198 //Define *d; |
|
1199 //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); |
|
1200 } |
|
1201 |
|
1202 static inline void outputChar(char c) |
|
1203 { |
|
1204 if (Config_getBool("PREPROCESS_INCLUDES")) { |
|
1205 g_outputBuf->addChar(c); |
|
1206 } else { |
|
1207 // Only output if the initial translation unit |
|
1208 if (g_includeStack.isEmpty() || g_curlyCount>0) { |
|
1209 g_outputBuf->addChar(c); |
|
1210 } |
|
1211 } |
|
1212 } |
|
1213 |
|
1214 static inline void outputArray(const char *a,int len) |
|
1215 { |
|
1216 if (Config_getBool("PREPROCESS_INCLUDES")) { |
|
1217 g_outputBuf->addArray(a,len); |
|
1218 } else { |
|
1219 // Only output if the initial translation unit |
|
1220 if (g_includeStack.isEmpty() || g_curlyCount>0) { |
|
1221 g_outputBuf->addArray(a,len); |
|
1222 } |
|
1223 } |
|
1224 } |
|
1225 |
|
1226 static void readIncludeFile(const QCString &inc) |
|
1227 { |
|
1228 if (!Config_getBool("SEARCH_INCLUDES")) return; // do not read include files |
|
1229 uint i=0; |
|
1230 |
|
1231 // find the start of the include file name |
|
1232 while (i<inc.length() && |
|
1233 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<') |
|
1234 ) i++; |
|
1235 uint s=i; |
|
1236 |
|
1237 // was it a local include? |
|
1238 bool localInclude = s>0 && inc.at(s-1)=='"'; |
|
1239 |
|
1240 // find the end of the include file name |
|
1241 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++; |
|
1242 |
|
1243 if (s<inc.length() && i>s) // valid include file name found |
|
1244 { |
|
1245 // extract include path+name |
|
1246 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace(); |
|
1247 |
|
1248 QCString oldFileName = g_yyFileName.copy(); |
|
1249 FileDef *oldFileDef = g_yyFileDef; |
|
1250 int oldLineNr = g_yyLineNr; |
|
1251 //printf("Searching for `%s'\n",incFileName.data()); |
|
1252 |
|
1253 // findFile will overwrite g_yyFileDef if found |
|
1254 FileState *fs; |
|
1255 bool alreadyIncluded = FALSE; |
|
1256 //printf("calling findFile(%s)\n",incFileName.data()); |
|
1257 if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found |
|
1258 { |
|
1259 //printf("Found include file!\n"); |
|
1260 if (Debug::isFlagSet(Debug::Preprocessor)) |
|
1261 { |
|
1262 for (i=0;i<g_includeStack.count();i++) msg(" "); |
|
1263 msg("#include %s: parsing...\n",incFileName.data()); |
|
1264 } |
|
1265 if (oldFileDef) |
|
1266 { |
|
1267 // add include dependency to the file in which the #include was found |
|
1268 //Debug::print(Debug::IncludeGraph, 0, "pre.l readIncludeFile() adding dependency \"%s\" to \"%s\"\n", incFileName, oldFileDef->absFilePath().data()); |
|
1269 oldFileDef->addIncludeDependency(g_yyFileDef,incFileName,localInclude,g_isImported); |
|
1270 // add included by dependency |
|
1271 if (g_yyFileDef) |
|
1272 { |
|
1273 //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data()); |
|
1274 g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported); |
|
1275 } |
|
1276 } |
|
1277 fs->bufState=YY_CURRENT_BUFFER; |
|
1278 fs->lineNr=oldLineNr; |
|
1279 fs->fileName=oldFileName; |
|
1280 // push the state on the stack |
|
1281 g_includeStack.push(fs); |
|
1282 // set the scanner to the include file |
|
1283 |
|
1284 // Deal with file changes due to |
|
1285 // #include's within { .. } blocks |
|
1286 QCString lineStr(g_yyFileName.length()+20); |
|
1287 lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data()); |
|
1288 outputArray(lineStr.data(),lineStr.length()); |
|
1289 |
|
1290 //fprintf(stderr,"Switching to include file %s\n",incFileName.data()); |
|
1291 //preYYin=fs->filePtr; |
|
1292 //yy_switch_to_buffer(yy_create_buffer(preYYin, YY_BUF_SIZE)); |
|
1293 g_inputBuf=&fs->fileBuf; |
|
1294 g_inputBufPos=0; |
|
1295 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE)); |
|
1296 } |
|
1297 else |
|
1298 { |
|
1299 //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded); |
|
1300 if (oldFileDef) |
|
1301 { |
|
1302 bool ambig; |
|
1303 FileDef *fd = findFileDef(Doxygen::inputNameDict,incFileName,ambig); |
|
1304 //printf("findFileDef(%s)=%p\n",incFileName.data(),fd); |
|
1305 // add include dependency to the file in which the #include was found |
|
1306 oldFileDef->addIncludeDependency(fd,incFileName,localInclude,g_isImported); |
|
1307 // add included by dependency |
|
1308 if (fd) |
|
1309 { |
|
1310 //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig); |
|
1311 fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported); |
|
1312 } |
|
1313 } |
|
1314 if (Debug::isFlagSet(Debug::Preprocessor)) |
|
1315 { |
|
1316 msg("#include %s: not found or already included! skipping...\n",incFileName.data()); |
|
1317 //printf("Error: include file %s not found\n",yytext); |
|
1318 } |
|
1319 if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... } |
|
1320 { |
|
1321 warn(g_yyFileName,g_yyLineNr,"Warning: include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data()); |
|
1322 } |
|
1323 } |
|
1324 } |
|
1325 } |
|
1326 |
|
1327 /* ----------------------------------------------------------------- */ |
|
1328 |
|
1329 static void startCondSection(const char *sectId) |
|
1330 { |
|
1331 g_condStack.push(new bool(g_skip)); |
|
1332 if (Config_getList("ENABLED_SECTIONS").find(sectId)==-1) |
|
1333 { |
|
1334 g_skip=TRUE; |
|
1335 } |
|
1336 } |
|
1337 |
|
1338 static void endCondSection() |
|
1339 { |
|
1340 if (g_condStack.isEmpty()) |
|
1341 { |
|
1342 g_skip=FALSE; |
|
1343 } |
|
1344 else |
|
1345 { |
|
1346 bool *ctx = g_condStack.pop(); |
|
1347 g_skip=*ctx; |
|
1348 } |
|
1349 } |
|
1350 |
|
1351 static QCString escapeAt(const char *text) |
|
1352 { |
|
1353 QCString result; |
|
1354 if (text) |
|
1355 { |
|
1356 char c; |
|
1357 const char *p=text; |
|
1358 while ((c=*p++)) |
|
1359 { |
|
1360 if (c=='@') result+="@@"; else result+=c; |
|
1361 } |
|
1362 } |
|
1363 return result; |
|
1364 } |
|
1365 |
|
1366 static char resolveTrigraph(char c) |
|
1367 { |
|
1368 switch (c) |
|
1369 { |
|
1370 case '=': return '#'; |
|
1371 case '/': return '\\'; |
|
1372 case '\'': return '^'; |
|
1373 case '(': return '['; |
|
1374 case ')': return ']'; |
|
1375 case '!': return '|'; |
|
1376 case '<': return '{'; |
|
1377 case '>': return '}'; |
|
1378 case '-': return '~'; |
|
1379 } |
|
1380 return '?'; |
|
1381 } |
|
1382 |
|
1383 /* ----------------------------------------------------------------- */ |
|
1384 |
|
1385 #undef YY_INPUT |
|
1386 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); |
|
1387 |
|
1388 static int yyread(char *buf,int max_size) |
|
1389 { |
|
1390 #if 0 |
|
1391 int len = fread( buf, 1, max_size, preYYin ); |
|
1392 if (len==0 && ferror( yyin )) |
|
1393 { |
|
1394 yy_fatal_error( "input in flex scanner failed" ); |
|
1395 return len; |
|
1396 } |
|
1397 return filterCRLF(buf,len); |
|
1398 #endif |
|
1399 |
|
1400 int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos; |
|
1401 int bytesToCopy = QMIN(max_size,bytesInBuf); |
|
1402 memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy); |
|
1403 g_inputBufPos+=bytesToCopy; |
|
1404 return bytesToCopy; |
|
1405 } |
|
1406 |
|
1407 /* ----------------------------------------------------------------- */ |
|
1408 |
|
1409 %} |
|
1410 |
|
1411 ID [a-z_A-Z][a-z_A-Z0-9]* |
|
1412 B [ \t] |
|
1413 BN [ \t\r\n] |
|
1414 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) |
|
1415 |
|
1416 %option noyywrap |
|
1417 |
|
1418 %x Start |
|
1419 %x Command |
|
1420 %x SkipCommand |
|
1421 %x SkipLine |
|
1422 %x CopyLine |
|
1423 %x CopyString |
|
1424 %x Include |
|
1425 %x IncludeID |
|
1426 %x EndImport |
|
1427 %x DefName |
|
1428 %x DefineArg |
|
1429 %x DefineText |
|
1430 %x SkipCPPBlock |
|
1431 %x Ifdef |
|
1432 %x Ifndef |
|
1433 %x SkipCComment |
|
1434 %x CopyCComment |
|
1435 %x SkipVerbatim |
|
1436 %x SkipCPPComment |
|
1437 %x RemoveCComment |
|
1438 %x RemoveCPPComment |
|
1439 %x Guard |
|
1440 %x DefinedExpr1 |
|
1441 %x DefinedExpr2 |
|
1442 %x SkipDoubleQuote |
|
1443 %x SkipSingleQuote |
|
1444 %x UndefName |
|
1445 %x IgnoreLine |
|
1446 %x FindDefineArgs |
|
1447 %x ReadString |
|
1448 %x CondLine |
|
1449 |
|
1450 %% |
|
1451 |
|
1452 <*>\x06 |
|
1453 <*>\x00 |
|
1454 <*>\r |
|
1455 <*>"??"[=/'()!<>-] { // Trigraph |
|
1456 unput(resolveTrigraph(yytext[2])); |
|
1457 } |
|
1458 <Start>^{B}*"#" { BEGIN(Command); } |
|
1459 <Start>^{B}*/[^#] { |
|
1460 outputArray(yytext,yyleng); |
|
1461 BEGIN(CopyLine); |
|
1462 } |
|
1463 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors? |
|
1464 int i; |
|
1465 for (i=yyleng-1;i>=0;i--) |
|
1466 { |
|
1467 unput(yytext[i]); |
|
1468 } |
|
1469 BEGIN(CopyLine); |
|
1470 } |
|
1471 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\(\)\n]*"("[^\)\n]*")"[^\)\n]*")"{B}*\n | // function list macro with one (...) argument, e.g. for K_GLOBAL_STATIC_WITH_ARGS |
|
1472 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"{B}*\n { // function like macro |
|
1473 static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS"); |
|
1474 QCString name(yytext); |
|
1475 name=name.left(name.find('(')).stripWhiteSpace(); |
|
1476 |
|
1477 Define *def=0; |
|
1478 if (skipFuncMacros && |
|
1479 name!="Q_PROPERTY" && |
|
1480 !( |
|
1481 (g_includeStack.isEmpty() || g_curlyCount>0) && |
|
1482 g_macroExpansion && |
|
1483 (def=g_fileDefineDict->find(name)) && |
|
1484 (!g_expandOnlyPredef || def->isPredefined) |
|
1485 ) |
|
1486 ) |
|
1487 { |
|
1488 outputChar('\n'); |
|
1489 g_yyLineNr++; |
|
1490 } |
|
1491 else // don't skip |
|
1492 { |
|
1493 int i; |
|
1494 for (i=yyleng-1;i>=0;i--) |
|
1495 { |
|
1496 unput(yytext[i]); |
|
1497 } |
|
1498 BEGIN(CopyLine); |
|
1499 } |
|
1500 } |
|
1501 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" { |
|
1502 QCString text=yytext; |
|
1503 g_yyLineNr+=text.contains('\n'); |
|
1504 outputArray(yytext,yyleng); |
|
1505 } |
|
1506 <CopyLine>"{" { // count brackets inside the main file |
|
1507 if (g_includeStack.isEmpty()) |
|
1508 { |
|
1509 g_curlyCount++; |
|
1510 } |
|
1511 outputChar(*yytext); |
|
1512 } |
|
1513 <CopyLine>"}" { // count brackets inside the main file |
|
1514 if (g_includeStack.isEmpty() && g_curlyCount>0) |
|
1515 { |
|
1516 g_curlyCount--; |
|
1517 } |
|
1518 outputChar(*yytext); |
|
1519 } |
|
1520 <CopyLine>"'"\\[0-7]{1,3}"'" { |
|
1521 outputArray(yytext,yyleng); |
|
1522 } |
|
1523 <CopyLine>"'"\\."'" { |
|
1524 outputArray(yytext,yyleng); |
|
1525 } |
|
1526 <CopyLine>"'"."'" { |
|
1527 outputArray(yytext,yyleng); |
|
1528 } |
|
1529 <CopyLine>\" { |
|
1530 outputChar(*yytext); |
|
1531 BEGIN( CopyString ); |
|
1532 } |
|
1533 <CopyString>[^\"\\\r\n]+ { |
|
1534 outputArray(yytext,yyleng); |
|
1535 } |
|
1536 <CopyString>\\. { |
|
1537 outputArray(yytext,yyleng); |
|
1538 } |
|
1539 <CopyString>\" { |
|
1540 outputChar(*yytext); |
|
1541 BEGIN( CopyLine ); |
|
1542 } |
|
1543 <CopyLine>{ID}/{BN}{0,80}"(" { |
|
1544 Define *def=0; |
|
1545 def=g_fileDefineDict->find(yytext); |
|
1546 //printf("Search for define %s found=%d g_includeStack.count()=%d " |
|
1547 // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d " |
|
1548 // "isPreDefined=%d tu=%d\n",yytext,def ? 1 : 0, |
|
1549 // g_includeStack.count(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef, |
|
1550 // def ? def->isPredefined : -1, |
|
1551 // Config_getBool("PREPROCCESS_FULL_TU") |
|
1552 // ); |
|
1553 if ((g_includeStack.isEmpty() || g_curlyCount>0 || Config_getBool("PREPROCCESS_FULL_TU")) && |
|
1554 g_macroExpansion && |
|
1555 (def=g_fileDefineDict->find(yytext)) && |
|
1556 (!g_expandOnlyPredef || def->isPredefined || Config_getBool("PREPROCCESS_FULL_TU")) |
|
1557 ) |
|
1558 { |
|
1559 //printf("Found it!\n"); |
|
1560 g_roundCount=0; |
|
1561 g_defArgsStr=yytext; |
|
1562 if (def->nargs==-1) // no function macro |
|
1563 { |
|
1564 QCString result = expandMacro(g_defArgsStr); |
|
1565 outputArray(result,result.length()); |
|
1566 } |
|
1567 else // zero or more arguments |
|
1568 { |
|
1569 g_findDefArgContext = CopyLine; |
|
1570 BEGIN(FindDefineArgs); |
|
1571 } |
|
1572 } |
|
1573 else |
|
1574 { |
|
1575 outputArray(yytext,yyleng); |
|
1576 } |
|
1577 } |
|
1578 <CopyLine>{ID} { |
|
1579 Define *def=0; |
|
1580 //printf("Search for define %s\n",yytext); |
|
1581 if ((g_includeStack.isEmpty() || g_curlyCount>0) && |
|
1582 g_macroExpansion && |
|
1583 (def=g_fileDefineDict->find(yytext)) && |
|
1584 def->nargs==-1 && |
|
1585 (!g_expandOnlyPredef || def->isPredefined) |
|
1586 ) |
|
1587 { |
|
1588 //printf("Found it!\n"); |
|
1589 QCString name=yytext; |
|
1590 QCString result=expandMacro(name); |
|
1591 //printf("result=`%s'\n",result.data()); |
|
1592 outputArray(result,result.length()); |
|
1593 } |
|
1594 else |
|
1595 { |
|
1596 outputArray(yytext,yyleng); |
|
1597 } |
|
1598 } |
|
1599 <CopyLine>"\\"\r?/\n { // strip line continuation characters |
|
1600 } |
|
1601 <CopyLine>. { |
|
1602 outputChar(*yytext); |
|
1603 } |
|
1604 <CopyLine>\n { |
|
1605 outputChar('\n'); |
|
1606 BEGIN(Start); |
|
1607 g_yyLineNr++; |
|
1608 } |
|
1609 <FindDefineArgs>"(" { |
|
1610 g_defArgsStr+='('; |
|
1611 g_roundCount++; |
|
1612 } |
|
1613 <FindDefineArgs>")" { |
|
1614 g_defArgsStr+=')'; |
|
1615 g_roundCount--; |
|
1616 if (g_roundCount==0) |
|
1617 { |
|
1618 QCString result=expandMacro(g_defArgsStr); |
|
1619 //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data()); |
|
1620 if (g_findDefArgContext==CopyLine) |
|
1621 { |
|
1622 outputArray(result,result.length()); |
|
1623 BEGIN(g_findDefArgContext); |
|
1624 } |
|
1625 else // g_findDefArgContext==IncludeID |
|
1626 { |
|
1627 readIncludeFile(result); |
|
1628 g_nospaces=FALSE; |
|
1629 BEGIN(Start); |
|
1630 } |
|
1631 } |
|
1632 } |
|
1633 /* |
|
1634 <FindDefineArgs>")"{B}*"(" { |
|
1635 g_defArgsStr+=yytext; |
|
1636 } |
|
1637 */ |
|
1638 <FindDefineArgs>{CHARLIT} { |
|
1639 g_defArgsStr+=yytext; |
|
1640 } |
|
1641 <FindDefineArgs>\" { |
|
1642 g_defArgsStr+=*yytext; |
|
1643 BEGIN(ReadString); |
|
1644 } |
|
1645 <FindDefineArgs>\n { |
|
1646 g_yyLineNr++; |
|
1647 outputChar('\n'); |
|
1648 } |
|
1649 <FindDefineArgs>"@" { |
|
1650 g_defArgsStr+="@@"; |
|
1651 } |
|
1652 <FindDefineArgs>. { |
|
1653 g_defArgsStr+=*yytext; |
|
1654 } |
|
1655 <ReadString>"\"" { |
|
1656 g_defArgsStr+=*yytext; |
|
1657 BEGIN(FindDefineArgs); |
|
1658 } |
|
1659 <ReadString>"//"|"/*" { |
|
1660 g_defArgsStr+=yytext; |
|
1661 } |
|
1662 <ReadString>\\. { |
|
1663 g_defArgsStr+=yytext; |
|
1664 } |
|
1665 <ReadString>. { |
|
1666 g_defArgsStr+=*yytext; |
|
1667 } |
|
1668 <Command>("include"|"import"){B}+/{ID} { |
|
1669 g_isImported = yytext[1]=='m'; |
|
1670 if (g_macroExpansion) |
|
1671 BEGIN(IncludeID); |
|
1672 } |
|
1673 <Command>("include"|"import"){B}*[<"] { |
|
1674 g_isImported = yytext[1]=='m'; |
|
1675 char c[2]; |
|
1676 c[0]=yytext[yyleng-1];c[1]='\0'; |
|
1677 g_incName=c; |
|
1678 BEGIN(Include); |
|
1679 } |
|
1680 <Command>("cmake")?"define"{B}+ { |
|
1681 //printf("!!!DefName\n"); |
|
1682 BEGIN(DefName); |
|
1683 } |
|
1684 <Command>"ifdef"/{B}*"(" { |
|
1685 incrLevel(); |
|
1686 g_guardExpr.resize(0); |
|
1687 BEGIN(DefinedExpr2); |
|
1688 } |
|
1689 <Command>"ifdef"/{B}+ { |
|
1690 //printf("Pre.l: ifdef\n"); |
|
1691 incrLevel(); |
|
1692 g_guardExpr.resize(0); |
|
1693 BEGIN(DefinedExpr1); |
|
1694 } |
|
1695 <Command>"ifndef"/{B}*"(" { |
|
1696 incrLevel(); |
|
1697 g_guardExpr="! "; |
|
1698 BEGIN(DefinedExpr2); |
|
1699 } |
|
1700 <Command>"ifndef"/{B}+ { |
|
1701 incrLevel(); |
|
1702 g_guardExpr="! "; |
|
1703 BEGIN(DefinedExpr1); |
|
1704 } |
|
1705 <Command>"if"/[ \t(!] { |
|
1706 incrLevel(); |
|
1707 g_guardExpr.resize(0); |
|
1708 BEGIN(Guard); |
|
1709 } |
|
1710 <Command>("elif"|"else"{B}*"if")/[ \t(!] { |
|
1711 if (!otherCaseDone()) |
|
1712 { |
|
1713 g_guardExpr.resize(0); |
|
1714 BEGIN(Guard); |
|
1715 } |
|
1716 else |
|
1717 { |
|
1718 g_ifcount=0; |
|
1719 BEGIN(SkipCPPBlock); |
|
1720 } |
|
1721 } |
|
1722 <Command>"else"/[^a-z_A-Z0-9] { |
|
1723 //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]); |
|
1724 if (otherCaseDone()) |
|
1725 { |
|
1726 g_ifcount=0; |
|
1727 BEGIN(SkipCPPBlock); |
|
1728 } |
|
1729 else |
|
1730 { |
|
1731 setCaseDone(TRUE); |
|
1732 //g_levelGuard[g_level-1]=TRUE; |
|
1733 } |
|
1734 } |
|
1735 <Command>"undef"{B}+ { |
|
1736 BEGIN(UndefName); |
|
1737 } |
|
1738 <Command>("elif"|"else"{B}*"if")/[ \t(!] { |
|
1739 if (!otherCaseDone()) |
|
1740 { |
|
1741 g_guardExpr.resize(0); |
|
1742 BEGIN(Guard); |
|
1743 } |
|
1744 } |
|
1745 <Command>"endif"/[^a-z_A-Z0-9] { |
|
1746 //printf("Pre.l: #endif\n"); |
|
1747 decrLevel(); |
|
1748 } |
|
1749 <Command,IgnoreLine>\n { |
|
1750 outputChar('\n'); |
|
1751 BEGIN(Start); |
|
1752 g_yyLineNr++; |
|
1753 } |
|
1754 <Command>{ID} { // unknown directive |
|
1755 BEGIN(IgnoreLine); |
|
1756 } |
|
1757 <IgnoreLine>\\[\r]?\n { |
|
1758 outputChar('\n'); |
|
1759 g_yyLineNr++; |
|
1760 } |
|
1761 <IgnoreLine>. |
|
1762 <Command>. |
|
1763 <UndefName>{ID} { |
|
1764 Define *def; |
|
1765 if ((def=isDefined(yytext)) |
|
1766 /*&& !def->isPredefined*/ |
|
1767 && !def->nonRecursive |
|
1768 ) |
|
1769 { |
|
1770 //printf("undefining %s\n",yytext); |
|
1771 def->undef=TRUE; |
|
1772 } |
|
1773 BEGIN(Start); |
|
1774 } |
|
1775 <Guard>\\[\r]?\n { |
|
1776 outputChar('\n'); |
|
1777 g_guardExpr+=' '; |
|
1778 g_yyLineNr++; |
|
1779 } |
|
1780 <Guard>"defined"/{B}*"(" { |
|
1781 BEGIN(DefinedExpr2); |
|
1782 } |
|
1783 <Guard>"defined"/{B}+ { |
|
1784 BEGIN(DefinedExpr1); |
|
1785 } |
|
1786 <Guard>{ID} { g_guardExpr+=yytext; } |
|
1787 <Guard>. { g_guardExpr+=*yytext; } |
|
1788 <Guard>\n { |
|
1789 unput(*yytext); |
|
1790 //printf("Guard: `%s'\n", |
|
1791 // g_guardExpr.data()); |
|
1792 bool guard=computeExpression(g_guardExpr); |
|
1793 setCaseDone(guard); |
|
1794 //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]); |
|
1795 if (guard) |
|
1796 { |
|
1797 BEGIN(Start); |
|
1798 } |
|
1799 else |
|
1800 { |
|
1801 g_ifcount=0; |
|
1802 BEGIN(SkipCPPBlock); |
|
1803 } |
|
1804 } |
|
1805 <DefinedExpr1,DefinedExpr2>\\\n { g_yyLineNr++; outputChar('\n'); } |
|
1806 <DefinedExpr1>{ID} { |
|
1807 if (isDefined(yytext)) |
|
1808 g_guardExpr+=" 1L "; |
|
1809 else |
|
1810 g_guardExpr+=" 0L "; |
|
1811 g_lastGuardName=yytext; |
|
1812 BEGIN(Guard); |
|
1813 } |
|
1814 <DefinedExpr2>{ID} { |
|
1815 if (isDefined(yytext)) |
|
1816 g_guardExpr+=" 1L "; |
|
1817 else |
|
1818 g_guardExpr+=" 0L "; |
|
1819 g_lastGuardName.resize(0); |
|
1820 } |
|
1821 <DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway |
|
1822 g_yyLineNr++; |
|
1823 g_ifcount=0; |
|
1824 BEGIN(SkipCPPBlock); |
|
1825 } |
|
1826 <DefinedExpr2>")" { |
|
1827 BEGIN(Guard); |
|
1828 } |
|
1829 <DefinedExpr1,DefinedExpr2>. |
|
1830 <SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); } |
|
1831 <SkipCPPBlock>^{B}*/[^#] { BEGIN(SkipLine); } |
|
1832 <SkipCPPBlock>\n { g_yyLineNr++; outputChar('\n'); } |
|
1833 <SkipCPPBlock>. |
|
1834 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] { |
|
1835 incrLevel(); |
|
1836 g_ifcount++; |
|
1837 //printf("#if... depth=%d\n",g_ifcount); |
|
1838 } |
|
1839 <SkipCommand>"else" { |
|
1840 //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone()); |
|
1841 if (g_ifcount==0 && !otherCaseDone()) |
|
1842 { |
|
1843 setCaseDone(TRUE); |
|
1844 //outputChar('\n'); |
|
1845 BEGIN(Start); |
|
1846 } |
|
1847 } |
|
1848 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] { |
|
1849 if (g_ifcount==0) |
|
1850 { |
|
1851 if (!otherCaseDone()) |
|
1852 { |
|
1853 g_guardExpr.resize(0); |
|
1854 g_lastGuardName.resize(0); |
|
1855 BEGIN(Guard); |
|
1856 } |
|
1857 else |
|
1858 { |
|
1859 BEGIN(SkipCPPBlock); |
|
1860 } |
|
1861 } |
|
1862 } |
|
1863 <SkipCommand>"endif" { |
|
1864 decrLevel(); |
|
1865 if (--g_ifcount<0) |
|
1866 { |
|
1867 //outputChar('\n'); |
|
1868 BEGIN(Start); |
|
1869 } |
|
1870 } |
|
1871 <SkipCommand>\n { |
|
1872 outputChar('\n'); |
|
1873 g_yyLineNr++; |
|
1874 BEGIN(SkipCPPBlock); |
|
1875 } |
|
1876 <SkipCommand>{ID} { // unknown directive |
|
1877 BEGIN(SkipLine); |
|
1878 } |
|
1879 <SkipCommand>. |
|
1880 <SkipLine>[^/\n]+ |
|
1881 <SkipLine>. |
|
1882 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* { |
|
1883 g_lastCPPContext=YY_START; |
|
1884 BEGIN(RemoveCPPComment); |
|
1885 } |
|
1886 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* { |
|
1887 g_lastCContext=YY_START; |
|
1888 BEGIN(RemoveCComment); |
|
1889 } |
|
1890 <SkipLine>\n { |
|
1891 outputChar('\n'); |
|
1892 g_yyLineNr++; |
|
1893 BEGIN(SkipCPPBlock); |
|
1894 } |
|
1895 <IncludeID>{ID}{B}*/"(" { |
|
1896 g_nospaces=TRUE; |
|
1897 g_roundCount=0; |
|
1898 g_defArgsStr=yytext; |
|
1899 g_findDefArgContext = IncludeID; |
|
1900 BEGIN(FindDefineArgs); |
|
1901 } |
|
1902 <IncludeID>{ID} { |
|
1903 g_nospaces=TRUE; |
|
1904 readIncludeFile(expandMacro(yytext)); |
|
1905 BEGIN(Start); |
|
1906 } |
|
1907 <Include>[^\">\n]+[\">] { |
|
1908 g_incName+=yytext; |
|
1909 readIncludeFile(g_incName); |
|
1910 if (g_isImported) |
|
1911 { |
|
1912 BEGIN(EndImport); |
|
1913 } |
|
1914 else |
|
1915 { |
|
1916 BEGIN(Start); |
|
1917 } |
|
1918 } |
|
1919 <EndImport>[^\\\n]*/\n { |
|
1920 BEGIN(Start); |
|
1921 } |
|
1922 <EndImport>\\[\r]?"\n" { |
|
1923 outputChar('\n'); |
|
1924 g_yyLineNr++; |
|
1925 } |
|
1926 <EndImport>. { |
|
1927 } |
|
1928 <DefName>{ID}/"(" { |
|
1929 //printf("Define() `%s'\n",yytext); |
|
1930 g_argDict = new QDict<int>(31); |
|
1931 g_argDict->setAutoDelete(TRUE); |
|
1932 g_defArgs = 0; |
|
1933 g_defArgsStr.resize(0); |
|
1934 g_defText.resize(0); |
|
1935 g_defLitText.resize(0); |
|
1936 g_defName = yytext; |
|
1937 g_defVarArgs = FALSE; |
|
1938 BEGIN(DefineArg); |
|
1939 } |
|
1940 <DefName>{ID}/{B}* { |
|
1941 //printf("Define `%s'\n",yytext); |
|
1942 g_argDict = 0; |
|
1943 g_defArgs = -1; |
|
1944 g_defArgsStr.resize(0); |
|
1945 g_defText.resize(0); |
|
1946 g_defLitText.resize(0); |
|
1947 g_defName = yytext; |
|
1948 g_defVarArgs = FALSE; |
|
1949 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr; |
|
1950 outputArray(tmp.data(),tmp.length()); |
|
1951 g_quoteArg=FALSE; |
|
1952 g_insideComment=FALSE; |
|
1953 BEGIN(DefineText); |
|
1954 } |
|
1955 <DefName>{ID}/{B}*"\n" { // bare define |
|
1956 g_argDict = 0; |
|
1957 g_defArgs = -1; |
|
1958 g_defName = yytext; |
|
1959 g_defArgsStr.resize(0); |
|
1960 g_defText.resize(0); |
|
1961 g_defLitText.resize(0); |
|
1962 g_defVarArgs = FALSE; |
|
1963 if ( g_defName!=g_lastGuardName || Config_getBool("PREPROCCESS_FULL_TU")) |
|
1964 { // define may appear in the output |
|
1965 QCString tmp=(QCString)"#define "+g_defName; |
|
1966 outputArray(tmp.data(),tmp.length()); |
|
1967 g_quoteArg=FALSE; |
|
1968 g_insideComment=FALSE; |
|
1969 if (g_insideCS) g_defText="1"; // for C#, use "1" as define text |
|
1970 BEGIN(DefineText); |
|
1971 } |
|
1972 else // define is a guard => hide |
|
1973 { |
|
1974 //printf("Found a guard %s\n",yytext); |
|
1975 #if 0 |
|
1976 Define *def=g_fileDefineDict->find(g_defName); |
|
1977 if (def==0) // new define name for this file |
|
1978 { |
|
1979 g_fileDefineDict->insert(g_defName,newDefine()); |
|
1980 } |
|
1981 else // name already exists |
|
1982 { |
|
1983 if (def->undef) // undefined name |
|
1984 { |
|
1985 def->undef = FALSE; |
|
1986 def->name = g_defName; |
|
1987 def->definition = g_defText.stripWhiteSpace(); |
|
1988 def->nargs = g_defArgs; |
|
1989 def->fileName = g_yyFileName.copy(); |
|
1990 def->lineNr = g_yyLineNr; |
|
1991 } |
|
1992 else |
|
1993 { |
|
1994 //printf("Error: define %s is defined more than once!\n",g_defName.data()); |
|
1995 } |
|
1996 } |
|
1997 #endif |
|
1998 g_lastGuardName.resize(0); |
|
1999 BEGIN(Start); |
|
2000 } |
|
2001 } |
|
2002 <DefineArg>","{B}* { g_defArgsStr+=yytext; } |
|
2003 <DefineArg>"("{B}* { g_defArgsStr+=yytext; } |
|
2004 <DefineArg>{B}*")"{B}* { |
|
2005 g_defArgsStr+=yytext; |
|
2006 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr; |
|
2007 outputArray(tmp.data(),tmp.length()); |
|
2008 g_quoteArg=FALSE; |
|
2009 g_insideComment=FALSE; |
|
2010 BEGIN(DefineText); |
|
2011 } |
|
2012 <DefineArg>"..." { // Variadic macro |
|
2013 g_defVarArgs = TRUE; |
|
2014 g_defArgsStr+=yytext; |
|
2015 g_argDict->insert("__VA_ARGS__",new int(g_defArgs)); |
|
2016 g_defArgs++; |
|
2017 } |
|
2018 <DefineArg>{ID}{B}*("..."?) { |
|
2019 //printf("Define addArg(%s)\n",yytext); |
|
2020 QCString argName=yytext; |
|
2021 g_defVarArgs = yytext[yyleng-1]=='.'; |
|
2022 if (g_defVarArgs) // strip ellipsis |
|
2023 { |
|
2024 argName=argName.left(argName.length()-3); |
|
2025 } |
|
2026 argName = argName.stripWhiteSpace(); |
|
2027 g_defArgsStr+=yytext; |
|
2028 g_argDict->insert(argName,new int(g_defArgs)); |
|
2029 g_defArgs++; |
|
2030 } |
|
2031 /* |
|
2032 <DefineText>"/ **"|"/ *!" { |
|
2033 g_defText+=yytext; |
|
2034 g_defLitText+=yytext; |
|
2035 g_insideComment=TRUE; |
|
2036 } |
|
2037 <DefineText>"* /" { |
|
2038 g_defText+=yytext; |
|
2039 g_defLitText+=yytext; |
|
2040 g_insideComment=FALSE; |
|
2041 } |
|
2042 */ |
|
2043 <DefineText>"/*" { |
|
2044 g_defText+=yytext; |
|
2045 g_defLitText+=yytext; |
|
2046 g_lastCContext=YY_START; |
|
2047 g_commentCount=1; |
|
2048 BEGIN(CopyCComment); |
|
2049 } |
|
2050 <DefineText>"//" { |
|
2051 outputChar('/');outputChar('/'); |
|
2052 g_lastCPPContext=YY_START; |
|
2053 g_defLitText+=' '; |
|
2054 BEGIN(SkipCPPComment); |
|
2055 } |
|
2056 <SkipCComment>[/]?"*/" { |
|
2057 if (yytext[0]=='/') outputChar('/'); |
|
2058 outputChar('*');outputChar('/'); |
|
2059 if (--g_commentCount<=0) |
|
2060 { |
|
2061 if (g_lastCContext==Start) |
|
2062 // small hack to make sure that ^... rule will |
|
2063 // match when going to Start... Example: "/*...*/ some stuff..." |
|
2064 { |
|
2065 YY_CURRENT_BUFFER->yy_at_bol=1; |
|
2066 } |
|
2067 BEGIN(g_lastCContext); |
|
2068 } |
|
2069 } |
|
2070 <SkipCComment>"//"("/")* { |
|
2071 outputArray(yytext,yyleng); |
|
2072 } |
|
2073 <SkipCComment>"/*" { |
|
2074 outputChar('/');outputChar('*'); |
|
2075 //g_commentCount++; |
|
2076 } |
|
2077 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") { |
|
2078 outputArray(yytext,yyleng); |
|
2079 } |
|
2080 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ { |
|
2081 outputArray(yytext,yyleng); |
|
2082 g_yyLineNr+=QCString(yytext).contains('\n'); |
|
2083 } |
|
2084 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ { |
|
2085 outputArray(yytext,yyleng); |
|
2086 g_yyLineNr+=QCString(yytext).contains('\n'); |
|
2087 if (yytext[1]=='f') |
|
2088 { |
|
2089 g_blockName="f"; |
|
2090 } |
|
2091 else |
|
2092 { |
|
2093 g_blockName=QCString(&yytext[1]).stripWhiteSpace(); |
|
2094 } |
|
2095 BEGIN(SkipVerbatim); |
|
2096 } |
|
2097 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t]+ { // conditional section |
|
2098 g_condCtx = YY_START; |
|
2099 outputArray(yytext,yyleng); |
|
2100 BEGIN(CondLine); |
|
2101 } |
|
2102 <CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]* { |
|
2103 startCondSection(yytext); |
|
2104 outputArray(yytext,yyleng); |
|
2105 BEGIN(g_condCtx); |
|
2106 } |
|
2107 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*\n | |
|
2108 <CondLine>. { |
|
2109 outputArray(yytext,yyleng); |
|
2110 g_yyLineNr+=QCString(yytext).contains('\n'); |
|
2111 startCondSection(" "); |
|
2112 if (YY_START==CondLine) BEGIN(g_condCtx); |
|
2113 } |
|
2114 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9] { |
|
2115 outputArray(yytext,yyleng); |
|
2116 endCondSection(); |
|
2117 } |
|
2118 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */ |
|
2119 outputArray(yytext,yyleng); |
|
2120 if (yytext[1]=='f' && g_blockName=="f") |
|
2121 { |
|
2122 BEGIN(SkipCComment); |
|
2123 } |
|
2124 else if (&yytext[4]==g_blockName) |
|
2125 { |
|
2126 BEGIN(SkipCComment); |
|
2127 } |
|
2128 } |
|
2129 <SkipVerbatim>"*/"|"/*" { |
|
2130 outputArray(yytext,yyleng); |
|
2131 } |
|
2132 <SkipCComment,SkipVerbatim>[^*\\@\x06\n\/]+ { |
|
2133 outputArray(yytext,yyleng); |
|
2134 } |
|
2135 <SkipCComment,SkipVerbatim>\n { |
|
2136 g_yyLineNr++; |
|
2137 outputChar('\n'); |
|
2138 } |
|
2139 <SkipCComment,SkipVerbatim>. { |
|
2140 outputChar(*yytext); |
|
2141 } |
|
2142 <CopyCComment>[^*a-z_A-Z\n]+ { |
|
2143 g_defLitText+=yytext; |
|
2144 g_defText+=escapeAt(yytext); |
|
2145 } |
|
2146 <CopyCComment>"*/" { |
|
2147 g_defLitText+=yytext; |
|
2148 g_defText+=yytext; |
|
2149 BEGIN(g_lastCContext); |
|
2150 } |
|
2151 <CopyCComment>\n { |
|
2152 g_yyLineNr++; |
|
2153 g_defLitText+=yytext; |
|
2154 g_defText+=' '; |
|
2155 } |
|
2156 <RemoveCComment>"*/" { BEGIN(g_lastCContext); } |
|
2157 <RemoveCComment>"//" |
|
2158 <RemoveCComment>"/*" |
|
2159 <RemoveCComment>[^*\x06\n]+ |
|
2160 <RemoveCComment>\n { g_yyLineNr++; outputChar('\n'); } |
|
2161 <RemoveCComment>. |
|
2162 <SkipCPPComment>[^\n\/\\@]+ { |
|
2163 outputArray(yytext,yyleng); |
|
2164 } |
|
2165 <SkipCPPComment,RemoveCPPComment>\n { |
|
2166 unput(*yytext); |
|
2167 BEGIN(g_lastCPPContext); |
|
2168 } |
|
2169 <SkipCPPComment>"/*" { |
|
2170 outputChar('/');outputChar('*'); |
|
2171 } |
|
2172 <SkipCPPComment>"//" { |
|
2173 outputChar('/');outputChar('/'); |
|
2174 } |
|
2175 <SkipCPPComment>[^\x06\@\\\n]+ { |
|
2176 outputArray(yytext,yyleng); |
|
2177 } |
|
2178 <SkipCPPComment>. { |
|
2179 outputChar(*yytext); |
|
2180 } |
|
2181 <RemoveCPPComment>"/*" |
|
2182 <RemoveCPPComment>"//" |
|
2183 <RemoveCPPComment>[^\x06\n]+ |
|
2184 <RemoveCPPComment>. |
|
2185 <DefineText>"#" { |
|
2186 g_quoteArg=TRUE; |
|
2187 g_defLitText+=yytext; |
|
2188 } |
|
2189 <DefineText,CopyCComment>{ID} { |
|
2190 g_defLitText+=yytext; |
|
2191 if (g_quoteArg) |
|
2192 { |
|
2193 g_defText+="\""; |
|
2194 } |
|
2195 if (g_defArgs>0) |
|
2196 { |
|
2197 int *n; |
|
2198 if ((n=(*g_argDict)[yytext])) |
|
2199 { |
|
2200 //if (!g_quoteArg) g_defText+=' '; |
|
2201 g_defText+='@'; |
|
2202 QCString numStr; |
|
2203 numStr.sprintf("%d",*n); |
|
2204 g_defText+=numStr; |
|
2205 //if (!g_quoteArg) g_defText+=' '; |
|
2206 } |
|
2207 else |
|
2208 { |
|
2209 g_defText+=yytext; |
|
2210 } |
|
2211 } |
|
2212 else |
|
2213 { |
|
2214 g_defText+=yytext; |
|
2215 } |
|
2216 if (g_quoteArg) |
|
2217 { |
|
2218 g_defText+="\""; |
|
2219 } |
|
2220 g_quoteArg=FALSE; |
|
2221 } |
|
2222 <CopyCComment>. { |
|
2223 g_defLitText+=yytext; |
|
2224 g_defText+=yytext; |
|
2225 } |
|
2226 <DefineText>\\[\r]?\n { |
|
2227 g_defLitText+=yytext; |
|
2228 outputChar('\n'); |
|
2229 g_defText += ' '; g_yyLineNr++; |
|
2230 } |
|
2231 <DefineText>\n { |
|
2232 QCString comment=extractTrailingComment(g_defLitText); |
|
2233 g_defLitText+=yytext; |
|
2234 if (!comment.isEmpty()) |
|
2235 { |
|
2236 outputArray(comment,comment.length()); |
|
2237 g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1); |
|
2238 } |
|
2239 outputChar('\n'); |
|
2240 Define *def=0; |
|
2241 //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data()); |
|
2242 if (g_includeStack.isEmpty() || g_curlyCount>0) |
|
2243 { |
|
2244 addDefine(); |
|
2245 } |
|
2246 def=g_fileDefineDict->find(g_defName); |
|
2247 if (def==0) // new define |
|
2248 { |
|
2249 //printf("new define!\n"); |
|
2250 g_fileDefineDict->insert(g_defName,newDefine()); |
|
2251 } |
|
2252 else if (def)// name already exists |
|
2253 { |
|
2254 //printf("existing define!\n"); |
|
2255 //printf("define found\n"); |
|
2256 if (def->undef) // undefined name |
|
2257 { |
|
2258 def->undef = FALSE; |
|
2259 def->name = g_defName; |
|
2260 def->definition = g_defText.stripWhiteSpace(); |
|
2261 def->nargs = g_defArgs; |
|
2262 def->fileName = g_yyFileName.copy(); |
|
2263 def->lineNr = g_yyLineNr; |
|
2264 } |
|
2265 else |
|
2266 { |
|
2267 //printf("Error: define %s is defined more than once!\n",g_defName.data()); |
|
2268 } |
|
2269 } |
|
2270 delete g_argDict; g_argDict=0; |
|
2271 g_yyLineNr++; |
|
2272 g_lastGuardName.resize(0); |
|
2273 BEGIN(Start); |
|
2274 } |
|
2275 <DefineText>{B}* { g_defText += ' '; g_defLitText+=yytext; } |
|
2276 <DefineText>{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; } |
|
2277 <DefineText>"@" { g_defText += "@@"; g_defLitText+=yytext; } |
|
2278 <DefineText>\" { |
|
2279 g_defText += *yytext; |
|
2280 g_defLitText+=yytext; |
|
2281 if (!g_insideComment) |
|
2282 { |
|
2283 BEGIN(SkipDoubleQuote); |
|
2284 } |
|
2285 } |
|
2286 <DefineText>\' { g_defText += *yytext; |
|
2287 g_defLitText+=yytext; |
|
2288 if (!g_insideComment) |
|
2289 { |
|
2290 BEGIN(SkipSingleQuote); |
|
2291 } |
|
2292 } |
|
2293 <SkipDoubleQuote>"//" { g_defText += yytext; g_defLitText+=yytext; } |
|
2294 <SkipDoubleQuote>"/*" { g_defText += yytext; g_defLitText+=yytext; } |
|
2295 <SkipDoubleQuote>\" { |
|
2296 g_defText += *yytext; g_defLitText+=yytext; |
|
2297 BEGIN(DefineText); |
|
2298 } |
|
2299 <SkipSingleQuote,SkipDoubleQuote>\\. { |
|
2300 g_defText += yytext; g_defLitText+=yytext; |
|
2301 } |
|
2302 <SkipSingleQuote>\' { |
|
2303 g_defText += *yytext; g_defLitText+=yytext; |
|
2304 BEGIN(DefineText); |
|
2305 } |
|
2306 <SkipDoubleQuote>. { g_defText += *yytext; g_defLitText+=yytext; } |
|
2307 <SkipSingleQuote>. { g_defText += *yytext; g_defLitText+=yytext; } |
|
2308 <DefineText>. { g_defText += *yytext; g_defLitText+=yytext; } |
|
2309 <<EOF>> { |
|
2310 //fprintf(stderr,"End of include file\n"); |
|
2311 //printf("Include stack depth=%d\n",g_includeStack.count()); |
|
2312 if (g_includeStack.isEmpty()) |
|
2313 { |
|
2314 //fprintf(stderr,"Terminating scanner!\n"); |
|
2315 yyterminate(); |
|
2316 } |
|
2317 else |
|
2318 { |
|
2319 FileState *fs=g_includeStack.pop(); |
|
2320 //fileDefineCache->merge(g_yyFileName,fs->fileName); |
|
2321 #if 0 |
|
2322 if (fs->isPlainFile) |
|
2323 { |
|
2324 if (fs->filePtr && fclose(fs->filePtr)!=0) |
|
2325 { |
|
2326 err("Error: could not close file %s: %s\n",fs->fileName.data(),strerror(errno)); |
|
2327 } |
|
2328 fs->filePtr=0; |
|
2329 } |
|
2330 else |
|
2331 { |
|
2332 if (fs->filePtr && portable_pclose(fs->filePtr)!=0) |
|
2333 { |
|
2334 err("Error: could not close pipe: %s\n",strerror(errno)); |
|
2335 } |
|
2336 fs->filePtr=0; |
|
2337 } |
|
2338 #endif |
|
2339 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; |
|
2340 yy_switch_to_buffer( fs->bufState ); |
|
2341 yy_delete_buffer( oldBuf ); |
|
2342 g_yyLineNr=fs->lineNr; |
|
2343 //preYYin = fs->oldYYin; |
|
2344 g_inputBuf = fs->oldFileBuf; |
|
2345 g_inputBufPos = fs->oldFileBufPos; |
|
2346 setFileName(fs->fileName.copy()); |
|
2347 //fprintf(stderr,"######## FileName %s\n",g_yyFileName.data()); |
|
2348 |
|
2349 // Deal with file changes due to |
|
2350 // #include's within { .. } blocks |
|
2351 QCString lineStr(15+g_yyFileName.length()); |
|
2352 lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data()); |
|
2353 outputArray(lineStr.data(),lineStr.length()); |
|
2354 |
|
2355 delete fs; fs=0; |
|
2356 } |
|
2357 } |
|
2358 <*>"/*"/"*/" | |
|
2359 <*>"/*"[*]? { |
|
2360 outputArray(yytext,yyleng); |
|
2361 g_lastCContext=YY_START; |
|
2362 g_commentCount=1; |
|
2363 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented! |
|
2364 BEGIN(SkipCComment); |
|
2365 } |
|
2366 <*>"//"[/]? { |
|
2367 outputArray(yytext,yyleng); |
|
2368 g_lastCPPContext=YY_START; |
|
2369 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented! |
|
2370 BEGIN(SkipCPPComment); |
|
2371 } |
|
2372 <*>\n { |
|
2373 outputChar('\n'); |
|
2374 g_yyLineNr++; |
|
2375 } |
|
2376 <*>. { |
|
2377 outputChar(*yytext); |
|
2378 } |
|
2379 |
|
2380 %% |
|
2381 |
|
2382 /*@ ---------------------------------------------------------------------------- |
|
2383 */ |
|
2384 |
|
2385 static int getNextChar(const QCString &expr,QCString *rest,uint &pos) |
|
2386 { |
|
2387 //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); |
|
2388 if (pos<expr.length()) |
|
2389 { |
|
2390 //printf("%c=expr()\n",expr.at(pos)); |
|
2391 return expr.at(pos++); |
|
2392 } |
|
2393 else if (rest && !rest->isEmpty()) |
|
2394 { |
|
2395 int cc=rest->at(0); |
|
2396 *rest=rest->right(rest->length()-1); |
|
2397 //printf("%c=rest\n",cc); |
|
2398 return cc; |
|
2399 } |
|
2400 else |
|
2401 { |
|
2402 int cc=yyinput(); |
|
2403 //printf("%c=yyinput()\n",cc); |
|
2404 return cc; |
|
2405 } |
|
2406 } |
|
2407 |
|
2408 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos) |
|
2409 { |
|
2410 //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); |
|
2411 if (pos<expr.length()) |
|
2412 { |
|
2413 //printf("%c=expr()\n",expr.at(pos)); |
|
2414 return expr.at(pos); |
|
2415 } |
|
2416 else if (rest && !rest->isEmpty()) |
|
2417 { |
|
2418 int cc=rest->at(0); |
|
2419 //printf("%c=rest\n",cc); |
|
2420 return cc; |
|
2421 } |
|
2422 else |
|
2423 { |
|
2424 int cc=yyinput(); |
|
2425 returnCharToStream(cc); |
|
2426 //unput((char)cc); |
|
2427 //printf("%c=yyinput()\n",cc); |
|
2428 return cc; |
|
2429 } |
|
2430 } |
|
2431 |
|
2432 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c) |
|
2433 { |
|
2434 //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); |
|
2435 if (pos<expr.length()) |
|
2436 { |
|
2437 pos++; |
|
2438 } |
|
2439 else if (rest) |
|
2440 { |
|
2441 //printf("Prepending to rest!\n"); |
|
2442 char cs[2];cs[0]=c;cs[1]='\0'; |
|
2443 rest->prepend(cs); |
|
2444 } |
|
2445 else |
|
2446 { |
|
2447 //unput(c); |
|
2448 returnCharToStream(c); |
|
2449 } |
|
2450 //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); |
|
2451 } |
|
2452 |
|
2453 void addSearchDir(const char *dir) |
|
2454 { |
|
2455 QFileInfo fi(dir); |
|
2456 if (fi.isDir()) g_pathList->append(fi.absFilePath()); |
|
2457 } |
|
2458 |
|
2459 void initPreprocessor() |
|
2460 { |
|
2461 g_pathList = new QStrList; |
|
2462 addSearchDir("."); |
|
2463 //defineNameList.setAutoDelete(TRUE); |
|
2464 //defineNameList.clear(); |
|
2465 //defineDict.clear(); |
|
2466 //fileDefineCache = new DefineCache(1009); |
|
2467 g_expandedDict = new DefineDict(17); |
|
2468 //g_fileDefineDict = new DefineDict(1009); |
|
2469 } |
|
2470 |
|
2471 void cleanUpPreprocessor() |
|
2472 { |
|
2473 //delete fileDefineCache; |
|
2474 //delete g_fileDefineDict; g_fileDefineDict=0; |
|
2475 delete g_expandedDict; g_expandedDict=0; |
|
2476 delete g_pathList; g_pathList=0; |
|
2477 } |
|
2478 |
|
2479 void dumpDefineDict(const DefineDict *theDefDict) |
|
2480 { |
|
2481 if (Debug::isFlagSet(Debug::Preprocessor)) { |
|
2482 // Make a map to sort the macros in alphbetical order |
|
2483 typedef QMap<QString, Define*> DefineMapType; |
|
2484 DefineMapType DefineMap; |
|
2485 Define *def = 0; |
|
2486 QDictIterator<Define> it(*theDefDict); |
|
2487 while (it.current()) { |
|
2488 def = it.current(); |
|
2489 DefineMap.insert(def->name, def); |
|
2490 ++it; |
|
2491 } |
|
2492 // Now write them out |
|
2493 DefineMapType::Iterator mapIt; |
|
2494 for (mapIt = DefineMap.begin(); mapIt != DefineMap.end(); ++mapIt) { |
|
2495 def = mapIt.data(); |
|
2496 QString myDecl = def->name; |
|
2497 if (def->nargs > 0) { |
|
2498 myDecl.append("("); |
|
2499 myDecl.append(def->args); |
|
2500 myDecl.append(")"); |
|
2501 } |
|
2502 printf("#define %s %s /* %s %d */\n", |
|
2503 myDecl.data(), |
|
2504 def->definition.data(), |
|
2505 def->fileName.data(), |
|
2506 def->lineNr |
|
2507 ); |
|
2508 } |
|
2509 } |
|
2510 } |
|
2511 |
|
2512 void dumpDefineDicts() |
|
2513 { |
|
2514 if (Debug::isFlagSet(Debug::Preprocessor)) { |
|
2515 printf("g_expandedDict:\n"); |
|
2516 dumpDefineDict(g_expandedDict); |
|
2517 printf("g_fileDefineDict:\n"); |
|
2518 dumpDefineDict(g_fileDefineDict); |
|
2519 } |
|
2520 } |
|
2521 |
|
2522 void preprocessFile(const char *fileName,BufStr &input,BufStr &output) |
|
2523 { |
|
2524 uint orgOffset=output.curPos(); |
|
2525 //printf("##########################\n%s\n####################\n", |
|
2526 // input.data()); |
|
2527 |
|
2528 g_macroExpansion = Config_getBool("MACRO_EXPANSION"); |
|
2529 g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF"); |
|
2530 g_curlyCount=0; |
|
2531 g_nospaces=FALSE; |
|
2532 g_inputBuf=&input; |
|
2533 g_inputBufPos=0; |
|
2534 g_outputBuf=&output; |
|
2535 g_includeStack.setAutoDelete(TRUE); |
|
2536 g_includeStack.clear(); |
|
2537 //g_fileDefineDict->setAutoDelete(TRUE); |
|
2538 //g_fileDefineDict->clear(); |
|
2539 g_expandedDict->setAutoDelete(FALSE); |
|
2540 g_expandedDict->clear(); |
|
2541 g_condStack.clear(); |
|
2542 g_condStack.setAutoDelete(TRUE); |
|
2543 static bool firstTime=TRUE; |
|
2544 if (firstTime) |
|
2545 { |
|
2546 // add predefined macros |
|
2547 char *defStr; |
|
2548 QStrList &predefList = Config_getList("PREDEFINED"); |
|
2549 QStrListIterator sli(predefList); |
|
2550 for (sli.toFirst();(defStr=sli.current());++sli) |
|
2551 { |
|
2552 QCString ds = defStr; |
|
2553 int i_equals=ds.find('='); |
|
2554 int i_obrace=ds.find('('); |
|
2555 int i_cbrace=ds.find(')'); |
|
2556 bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':'; |
|
2557 |
|
2558 if (i_obrace==0) continue; // no define name |
|
2559 |
|
2560 if (i_obrace<i_equals && i_cbrace<i_equals && |
|
2561 i_obrace!=-1 && i_cbrace!=-1 && |
|
2562 i_obrace<i_cbrace |
|
2563 ) // predefined function macro definition |
|
2564 { |
|
2565 QRegExp reId("[a-z_A-Z][a-z_A-Z0-9]*"); // regexp matching an id |
|
2566 QDict<int> argDict(17); |
|
2567 argDict.setAutoDelete(TRUE); |
|
2568 int i=i_obrace+1,p,l,count=0; |
|
2569 // gather the formal arguments in a dictionary |
|
2570 while (i<i_cbrace && (p=reId.match(ds,i,&l))) |
|
2571 { |
|
2572 argDict.insert(ds.mid(p,l),new int(count++)); |
|
2573 i=p+l; |
|
2574 } |
|
2575 // strip definition part |
|
2576 QCString tmp=ds.right(ds.length()-i_equals-1); |
|
2577 QCString definition; |
|
2578 i=0; |
|
2579 // substitute all occurrences of formal arguments by their |
|
2580 // corresponding markers |
|
2581 while ((p=reId.match(tmp,i,&l))!=-1) |
|
2582 { |
|
2583 if (p>i) definition+=tmp.mid(i,p-i); |
|
2584 int *argIndex; |
|
2585 if ((argIndex=argDict[tmp.mid(p,l)])!=0) |
|
2586 { |
|
2587 QCString marker; |
|
2588 marker.sprintf(" @%d ",*argIndex); |
|
2589 definition+=marker; |
|
2590 } |
|
2591 else |
|
2592 { |
|
2593 definition+=tmp.mid(p,l); |
|
2594 } |
|
2595 i=p+l; |
|
2596 } |
|
2597 if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i); |
|
2598 |
|
2599 // add define definition to the dictionary of defines for this file |
|
2600 QCString dname = ds.left(i_obrace); |
|
2601 if (!dname.isEmpty()) |
|
2602 { |
|
2603 Define *def = new Define; |
|
2604 def->name = dname; |
|
2605 def->definition = definition; |
|
2606 def->nargs = count; |
|
2607 def->isPredefined = TRUE; |
|
2608 def->nonRecursive = nonRecursive; |
|
2609 g_fileDefineDict->insert(def->name,def); |
|
2610 } |
|
2611 |
|
2612 //printf("#define `%s' `%s' #nargs=%d\n", |
|
2613 // def->name.data(),def->definition.data(),def->nargs); |
|
2614 } |
|
2615 else if ((i_obrace==-1 || i_obrace>i_equals) && |
|
2616 (i_cbrace==-1 || i_cbrace>i_equals) && |
|
2617 !ds.isEmpty() && (int)ds.length()>i_equals |
|
2618 ) // predefined non-function macro definition |
|
2619 { |
|
2620 Define *def = new Define; |
|
2621 if (i_equals==-1) // simple define without argument |
|
2622 { |
|
2623 def->name = ds; |
|
2624 def->definition = "1"; // substitute occurrences by 1 (true) |
|
2625 } |
|
2626 else // simple define with argument |
|
2627 { |
|
2628 int ine=i_equals - (nonRecursive ? 1 : 0); |
|
2629 def->name = ds.left(ine); |
|
2630 def->definition = ds.right(ds.length()-i_equals-1); |
|
2631 } |
|
2632 if (!def->name.isEmpty()) |
|
2633 { |
|
2634 def->nargs = -1; |
|
2635 def->isPredefined = TRUE; |
|
2636 def->nonRecursive = nonRecursive; |
|
2637 g_fileDefineDict->insert(def->name,def); |
|
2638 } |
|
2639 else |
|
2640 { |
|
2641 delete def; |
|
2642 } |
|
2643 |
|
2644 //printf("#define `%s' `%s' #nargs=%d\n", |
|
2645 // def->name.data(),def->definition.data(),def->nargs); |
|
2646 } |
|
2647 } |
|
2648 firstTime=FALSE; |
|
2649 } |
|
2650 |
|
2651 #if 0 |
|
2652 QCString inputFilter = getFileFilter(fileName); |
|
2653 if (inputFilter.isEmpty()) |
|
2654 { |
|
2655 preYYin = fopen(fileName,"r"); |
|
2656 if (!preYYin) |
|
2657 { |
|
2658 err("Error: could not open file %s\n",fileName); |
|
2659 return; |
|
2660 } |
|
2661 } |
|
2662 else |
|
2663 { |
|
2664 QCString cmd = inputFilter+" \""+fileName+"\""; |
|
2665 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data()); |
|
2666 preYYin = portable_popen(cmd,"r"); |
|
2667 if (!preYYin) |
|
2668 { |
|
2669 err("Error: could not execute filter %s\n",cmd.data()); |
|
2670 return; |
|
2671 } |
|
2672 } |
|
2673 #endif |
|
2674 g_yyLineNr = 1; |
|
2675 g_level = 0; |
|
2676 g_ifcount = 0; |
|
2677 setFileName(fileName); |
|
2678 g_inputFileDef = g_yyFileDef; |
|
2679 BEGIN( Start ); |
|
2680 |
|
2681 g_lastGuardName.resize(0); |
|
2682 g_guardExpr.resize(0); |
|
2683 |
|
2684 preYYlex(); |
|
2685 g_lexInit=TRUE; |
|
2686 |
|
2687 #if 0 |
|
2688 if (inputFilter.isEmpty()) |
|
2689 fclose(preYYin); |
|
2690 else |
|
2691 portable_pclose(preYYin); |
|
2692 #endif |
|
2693 |
|
2694 if (Debug::isFlagSet(Debug::Preprocessor)) |
|
2695 { |
|
2696 printf("preprocessFile() dump from %d to %d\n", orgOffset, output.curPos()); |
|
2697 char *orgPos=output.data()+orgOffset; |
|
2698 char *newPos=output.data()+output.curPos(); |
|
2699 printf("Preprocessor output (size: %d bytes):\n",newPos-orgPos); |
|
2700 int line=1; |
|
2701 printf("---------\n00001 "); |
|
2702 while (orgPos<newPos) |
|
2703 { |
|
2704 putchar(*orgPos); |
|
2705 if (*orgPos=='\n') printf("%05d ",++line); |
|
2706 orgPos++; |
|
2707 } |
|
2708 printf("\n---------\n"); |
|
2709 dumpDefineDicts(); |
|
2710 } |
|
2711 } |
|
2712 |
|
2713 void preFreeScanner() |
|
2714 { |
|
2715 #if defined(YY_FLEX_SUBMINOR_VERSION) |
|
2716 if (g_lexInit) |
|
2717 { |
|
2718 preYYlex_destroy(); |
|
2719 } |
|
2720 #endif |
|
2721 } |
|
2722 |
|
2723 #if !defined(YY_FLEX_SUBMINOR_VERSION) |
|
2724 extern "C" { // some bogus code to keep the compiler happy |
|
2725 // int preYYwrap() { return 1 ; } |
|
2726 void preYYdummy() { yy_flex_realloc(0,0); } |
|
2727 } |
|
2728 #endif |
|
2729 |