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